[cvxopt] 01/64: Imported Upstream version 0.8.2

Andreas Tille tille at debian.org
Wed Jul 20 11:23:43 UTC 2016


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository cvxopt.

commit 75f86c3472baa31abfb0890093cd034ada980106
Author: Andreas Tille <tille at debian.org>
Date:   Wed Jul 20 08:26:47 2016 +0200

    Imported Upstream version 0.8.2
---
 INSTALL                                            |   74 +
 LICENSE                                            |  319 +
 doc/Makefile                                       |   14 +
 doc/README                                         |    2 +
 doc/base.tex                                       |  765 +++
 doc/base_sparse.tex                                |  712 ++
 doc/blas.tex                                       |  755 +++
 doc/c-api.tex                                      |  194 +
 doc/cvxopt.tex                                     |  121 +
 doc/cvxopt/about.html                              |  114 +
 doc/cvxopt/blank.gif                               |  Bin 0 -> 1958 bytes
 doc/cvxopt/c-fftw.html                             |  130 +
 doc/cvxopt/c-spsolvers.html                        |  136 +
 doc/cvxopt/contents.gif                            |  Bin 0 -> 438 bytes
 doc/cvxopt/contents.html                           |  179 +
 doc/cvxopt/cvxopt.css                              |  243 +
 doc/cvxopt/cvxopt.html                             |  183 +
 doc/cvxopt/e-covsel.html                           |  320 +
 doc/cvxopt/e-gevd.html                             |  185 +
 doc/cvxopt/e-kkt-example.html                      |  483 ++
 doc/cvxopt/e-nlcp.html                             |  594 ++
 doc/cvxopt/e-spA-example.html                      |  278 +
 doc/cvxopt/genindex.html                           |  539 ++
 doc/cvxopt/img1.gif                                |  Bin 0 -> 6624 bytes
 doc/cvxopt/img10.gif                               |  Bin 0 -> 1165 bytes
 doc/cvxopt/img100.gif                              |  Bin 0 -> 305 bytes
 doc/cvxopt/img101.gif                              |  Bin 0 -> 268 bytes
 doc/cvxopt/img102.gif                              |  Bin 0 -> 166 bytes
 doc/cvxopt/img103.gif                              |  Bin 0 -> 180 bytes
 doc/cvxopt/img104.gif                              |  Bin 0 -> 1545 bytes
 doc/cvxopt/img105.gif                              |  Bin 0 -> 137 bytes
 doc/cvxopt/img106.gif                              |  Bin 0 -> 143 bytes
 doc/cvxopt/img107.gif                              |  Bin 0 -> 1097 bytes
 doc/cvxopt/img108.gif                              |  Bin 0 -> 889 bytes
 doc/cvxopt/img109.gif                              |  Bin 0 -> 1181 bytes
 doc/cvxopt/img11.gif                               |  Bin 0 -> 1814 bytes
 doc/cvxopt/img110.gif                              |  Bin 0 -> 4670 bytes
 doc/cvxopt/img111.gif                              |  Bin 0 -> 2682 bytes
 doc/cvxopt/img112.gif                              |  Bin 0 -> 1258 bytes
 doc/cvxopt/img113.gif                              |  Bin 0 -> 904 bytes
 doc/cvxopt/img114.gif                              |  Bin 0 -> 771 bytes
 doc/cvxopt/img115.gif                              |  Bin 0 -> 1492 bytes
 doc/cvxopt/img116.gif                              |  Bin 0 -> 1371 bytes
 doc/cvxopt/img117.gif                              |  Bin 0 -> 1373 bytes
 doc/cvxopt/img118.gif                              |  Bin 0 -> 925 bytes
 doc/cvxopt/img119.gif                              |  Bin 0 -> 1150 bytes
 doc/cvxopt/img12.gif                               |  Bin 0 -> 231 bytes
 doc/cvxopt/img120.gif                              |  Bin 0 -> 3805 bytes
 doc/cvxopt/img121.gif                              |  Bin 0 -> 5461 bytes
 doc/cvxopt/img122.gif                              |  Bin 0 -> 2234 bytes
 doc/cvxopt/img123.gif                              |  Bin 0 -> 1887 bytes
 doc/cvxopt/img124.gif                              |  Bin 0 -> 2267 bytes
 doc/cvxopt/img125.gif                              |  Bin 0 -> 997 bytes
 doc/cvxopt/img126.gif                              |  Bin 0 -> 2953 bytes
 doc/cvxopt/img127.gif                              |  Bin 0 -> 3965 bytes
 doc/cvxopt/img128.gif                              |  Bin 0 -> 1677 bytes
 doc/cvxopt/img129.gif                              |  Bin 0 -> 184 bytes
 doc/cvxopt/img13.gif                               |  Bin 0 -> 220 bytes
 doc/cvxopt/img130.gif                              |  Bin 0 -> 1603 bytes
 doc/cvxopt/img131.gif                              |  Bin 0 -> 653 bytes
 doc/cvxopt/img132.gif                              |  Bin 0 -> 230 bytes
 doc/cvxopt/img133.gif                              |  Bin 0 -> 1548 bytes
 doc/cvxopt/img134.gif                              |  Bin 0 -> 1156 bytes
 doc/cvxopt/img135.gif                              |  Bin 0 -> 1638 bytes
 doc/cvxopt/img136.gif                              |  Bin 0 -> 1276 bytes
 doc/cvxopt/img137.gif                              |  Bin 0 -> 4859 bytes
 doc/cvxopt/img138.gif                              |  Bin 0 -> 1623 bytes
 doc/cvxopt/img139.gif                              |  Bin 0 -> 425 bytes
 doc/cvxopt/img14.gif                               |  Bin 0 -> 332 bytes
 doc/cvxopt/img140.gif                              |  Bin 0 -> 1051 bytes
 doc/cvxopt/img141.gif                              |  Bin 0 -> 1879 bytes
 doc/cvxopt/img142.gif                              |  Bin 0 -> 430 bytes
 doc/cvxopt/img143.gif                              |  Bin 0 -> 1014 bytes
 doc/cvxopt/img144.gif                              |  Bin 0 -> 1722 bytes
 doc/cvxopt/img145.gif                              |  Bin 0 -> 5410 bytes
 doc/cvxopt/img146.gif                              |  Bin 0 -> 1001 bytes
 doc/cvxopt/img147.gif                              |  Bin 0 -> 9236 bytes
 doc/cvxopt/img148.gif                              |  Bin 0 -> 2286 bytes
 doc/cvxopt/img149.gif                              |  Bin 0 -> 1239 bytes
 doc/cvxopt/img15.gif                               |  Bin 0 -> 234 bytes
 doc/cvxopt/img150.gif                              |  Bin 0 -> 1484 bytes
 doc/cvxopt/img151.gif                              |  Bin 0 -> 1620 bytes
 doc/cvxopt/img152.gif                              |  Bin 0 -> 1428 bytes
 doc/cvxopt/img153.gif                              |  Bin 0 -> 550 bytes
 doc/cvxopt/img154.gif                              |  Bin 0 -> 964 bytes
 doc/cvxopt/img155.gif                              |  Bin 0 -> 1111 bytes
 doc/cvxopt/img156.gif                              |  Bin 0 -> 2953 bytes
 doc/cvxopt/img157.gif                              |  Bin 0 -> 778 bytes
 doc/cvxopt/img158.gif                              |  Bin 0 -> 1373 bytes
 doc/cvxopt/img159.gif                              |  Bin 0 -> 700 bytes
 doc/cvxopt/img16.gif                               |  Bin 0 -> 223 bytes
 doc/cvxopt/img160.gif                              |  Bin 0 -> 1111 bytes
 doc/cvxopt/img161.gif                              |  Bin 0 -> 2830 bytes
 doc/cvxopt/img162.gif                              |  Bin 0 -> 1673 bytes
 doc/cvxopt/img163.gif                              |  Bin 0 -> 3107 bytes
 doc/cvxopt/img164.gif                              |  Bin 0 -> 1817 bytes
 doc/cvxopt/img165.gif                              |  Bin 0 -> 1839 bytes
 doc/cvxopt/img166.gif                              |  Bin 0 -> 3760 bytes
 doc/cvxopt/img167.gif                              |  Bin 0 -> 2329 bytes
 doc/cvxopt/img168.gif                              |  Bin 0 -> 2044 bytes
 doc/cvxopt/img169.gif                              |  Bin 0 -> 751 bytes
 doc/cvxopt/img17.gif                               |  Bin 0 -> 2024 bytes
 doc/cvxopt/img170.gif                              |  Bin 0 -> 2779 bytes
 doc/cvxopt/img171.gif                              |  Bin 0 -> 1534 bytes
 doc/cvxopt/img172.gif                              |  Bin 0 -> 1512 bytes
 doc/cvxopt/img173.gif                              |  Bin 0 -> 1936 bytes
 doc/cvxopt/img174.gif                              |  Bin 0 -> 770 bytes
 doc/cvxopt/img175.gif                              |  Bin 0 -> 137 bytes
 doc/cvxopt/img176.gif                              |  Bin 0 -> 478 bytes
 doc/cvxopt/img177.gif                              |  Bin 0 -> 1424 bytes
 doc/cvxopt/img178.gif                              |  Bin 0 -> 986 bytes
 doc/cvxopt/img179.gif                              |  Bin 0 -> 2521 bytes
 doc/cvxopt/img18.gif                               |  Bin 0 -> 462 bytes
 doc/cvxopt/img180.gif                              |  Bin 0 -> 7011 bytes
 doc/cvxopt/img181.gif                              |  Bin 0 -> 1550 bytes
 doc/cvxopt/img182.gif                              |  Bin 0 -> 1243 bytes
 doc/cvxopt/img183.gif                              |  Bin 0 -> 1453 bytes
 doc/cvxopt/img184.gif                              |  Bin 0 -> 1126 bytes
 doc/cvxopt/img185.gif                              |  Bin 0 -> 979 bytes
 doc/cvxopt/img19.gif                               |  Bin 0 -> 1513 bytes
 doc/cvxopt/img2.gif                                |  Bin 0 -> 7357 bytes
 doc/cvxopt/img20.gif                               |  Bin 0 -> 1489 bytes
 doc/cvxopt/img21.gif                               |  Bin 0 -> 2029 bytes
 doc/cvxopt/img22.gif                               |  Bin 0 -> 1510 bytes
 doc/cvxopt/img23.gif                               |  Bin 0 -> 1459 bytes
 doc/cvxopt/img24.gif                               |  Bin 0 -> 441 bytes
 doc/cvxopt/img25.gif                               |  Bin 0 -> 433 bytes
 doc/cvxopt/img26.gif                               |  Bin 0 -> 413 bytes
 doc/cvxopt/img27.gif                               |  Bin 0 -> 421 bytes
 doc/cvxopt/img28.gif                               |  Bin 0 -> 628 bytes
 doc/cvxopt/img29.gif                               |  Bin 0 -> 610 bytes
 doc/cvxopt/img3.gif                                |  Bin 0 -> 10930 bytes
 doc/cvxopt/img30.gif                               |  Bin 0 -> 824 bytes
 doc/cvxopt/img31.gif                               |  Bin 0 -> 741 bytes
 doc/cvxopt/img32.gif                               |  Bin 0 -> 2762 bytes
 doc/cvxopt/img33.gif                               |  Bin 0 -> 1343 bytes
 doc/cvxopt/img34.gif                               |  Bin 0 -> 2771 bytes
 doc/cvxopt/img35.gif                               |  Bin 0 -> 2835 bytes
 doc/cvxopt/img36.gif                               |  Bin 0 -> 1527 bytes
 doc/cvxopt/img37.gif                               |  Bin 0 -> 1479 bytes
 doc/cvxopt/img38.gif                               |  Bin 0 -> 1928 bytes
 doc/cvxopt/img39.gif                               |  Bin 0 -> 1869 bytes
 doc/cvxopt/img4.gif                                |  Bin 0 -> 5007 bytes
 doc/cvxopt/img40.gif                               |  Bin 0 -> 120 bytes
 doc/cvxopt/img41.gif                               |  Bin 0 -> 301 bytes
 doc/cvxopt/img42.gif                               |  Bin 0 -> 319 bytes
 doc/cvxopt/img43.gif                               |  Bin 0 -> 1648 bytes
 doc/cvxopt/img44.gif                               |  Bin 0 -> 454 bytes
 doc/cvxopt/img45.gif                               |  Bin 0 -> 1501 bytes
 doc/cvxopt/img46.gif                               |  Bin 0 -> 523 bytes
 doc/cvxopt/img47.gif                               |  Bin 0 -> 281 bytes
 doc/cvxopt/img48.gif                               |  Bin 0 -> 1138 bytes
 doc/cvxopt/img49.gif                               |  Bin 0 -> 1607 bytes
 doc/cvxopt/img5.gif                                |  Bin 0 -> 8885 bytes
 doc/cvxopt/img50.gif                               |  Bin 0 -> 120 bytes
 doc/cvxopt/img51.gif                               |  Bin 0 -> 94 bytes
 doc/cvxopt/img52.gif                               |  Bin 0 -> 452 bytes
 doc/cvxopt/img53.gif                               |  Bin 0 -> 138 bytes
 doc/cvxopt/img54.gif                               |  Bin 0 -> 471 bytes
 doc/cvxopt/img55.gif                               |  Bin 0 -> 611 bytes
 doc/cvxopt/img56.gif                               |  Bin 0 -> 891 bytes
 doc/cvxopt/img57.gif                               |  Bin 0 -> 934 bytes
 doc/cvxopt/img58.gif                               |  Bin 0 -> 646 bytes
 doc/cvxopt/img59.gif                               |  Bin 0 -> 944 bytes
 doc/cvxopt/img6.gif                                |  Bin 0 -> 9416 bytes
 doc/cvxopt/img60.gif                               |  Bin 0 -> 653 bytes
 doc/cvxopt/img61.gif                               |  Bin 0 -> 316 bytes
 doc/cvxopt/img62.gif                               |  Bin 0 -> 2226 bytes
 doc/cvxopt/img63.gif                               |  Bin 0 -> 2672 bytes
 doc/cvxopt/img64.gif                               |  Bin 0 -> 753 bytes
 doc/cvxopt/img65.gif                               |  Bin 0 -> 768 bytes
 doc/cvxopt/img66.gif                               |  Bin 0 -> 2121 bytes
 doc/cvxopt/img67.gif                               |  Bin 0 -> 151 bytes
 doc/cvxopt/img68.gif                               |  Bin 0 -> 1298 bytes
 doc/cvxopt/img69.gif                               |  Bin 0 -> 630 bytes
 doc/cvxopt/img7.gif                                |  Bin 0 -> 12520 bytes
 doc/cvxopt/img70.gif                               |  Bin 0 -> 188 bytes
 doc/cvxopt/img71.gif                               |  Bin 0 -> 933 bytes
 doc/cvxopt/img72.gif                               |  Bin 0 -> 1017 bytes
 doc/cvxopt/img73.gif                               |  Bin 0 -> 192 bytes
 doc/cvxopt/img74.gif                               |  Bin 0 -> 1271 bytes
 doc/cvxopt/img75.gif                               |  Bin 0 -> 1342 bytes
 doc/cvxopt/img76.gif                               |  Bin 0 -> 6872 bytes
 doc/cvxopt/img77.gif                               |  Bin 0 -> 6933 bytes
 doc/cvxopt/img78.gif                               |  Bin 0 -> 1112 bytes
 doc/cvxopt/img79.gif                               |  Bin 0 -> 1474 bytes
 doc/cvxopt/img8.gif                                |  Bin 0 -> 238 bytes
 doc/cvxopt/img80.gif                               |  Bin 0 -> 1647 bytes
 doc/cvxopt/img81.gif                               |  Bin 0 -> 1085 bytes
 doc/cvxopt/img82.gif                               |  Bin 0 -> 457 bytes
 doc/cvxopt/img83.gif                               |  Bin 0 -> 1803 bytes
 doc/cvxopt/img84.gif                               |  Bin 0 -> 1170 bytes
 doc/cvxopt/img85.gif                               |  Bin 0 -> 965 bytes
 doc/cvxopt/img86.gif                               |  Bin 0 -> 1375 bytes
 doc/cvxopt/img87.gif                               |  Bin 0 -> 1410 bytes
 doc/cvxopt/img88.gif                               |  Bin 0 -> 432 bytes
 doc/cvxopt/img89.gif                               |  Bin 0 -> 94 bytes
 doc/cvxopt/img9.gif                                |  Bin 0 -> 221 bytes
 doc/cvxopt/img90.gif                               |  Bin 0 -> 1542 bytes
 doc/cvxopt/img91.gif                               |  Bin 0 -> 716 bytes
 doc/cvxopt/img92.gif                               |  Bin 0 -> 823 bytes
 doc/cvxopt/img93.gif                               |  Bin 0 -> 269 bytes
 doc/cvxopt/img94.gif                               |  Bin 0 -> 397 bytes
 doc/cvxopt/img95.gif                               |  Bin 0 -> 358 bytes
 doc/cvxopt/img96.gif                               |  Bin 0 -> 363 bytes
 doc/cvxopt/img97.gif                               |  Bin 0 -> 265 bytes
 doc/cvxopt/img98.gif                               |  Bin 0 -> 303 bytes
 doc/cvxopt/img99.gif                               |  Bin 0 -> 278 bytes
 doc/cvxopt/index.gif                               |  Bin 0 -> 289 bytes
 doc/cvxopt/index.html                              |  183 +
 doc/cvxopt/modules.gif                             |  Bin 0 -> 385 bytes
 doc/cvxopt/next.gif                                |  Bin 0 -> 253 bytes
 doc/cvxopt/node1.html                              |  171 +
 doc/cvxopt/node13.html                             |  123 +
 doc/cvxopt/node14.html                             |  155 +
 doc/cvxopt/node19.html                             |  154 +
 doc/cvxopt/node20.html                             |  539 ++
 doc/cvxopt/node22.html                             |  338 +
 doc/cvxopt/node23.html                             |  182 +
 doc/cvxopt/node24.html                             |  402 ++
 doc/cvxopt/node25.html                             |  257 +
 doc/cvxopt/node27.html                             |  217 +
 doc/cvxopt/node28.html                             |  197 +
 doc/cvxopt/node3.html                              |  176 +
 doc/cvxopt/node30.html                             |  154 +
 doc/cvxopt/node31.html                             |  149 +
 doc/cvxopt/node32.html                             |  146 +
 doc/cvxopt/node33.html                             |  119 +
 doc/cvxopt/node37.html                             |  175 +
 doc/cvxopt/node38.html                             |  184 +
 doc/cvxopt/node39.html                             |  375 ++
 doc/cvxopt/node4.html                              |  124 +
 doc/cvxopt/node45.html                             |  119 +
 doc/cvxopt/node47.html                             |  341 +
 doc/cvxopt/node48.html                             |  293 +
 doc/cvxopt/node51.html                             |  558 ++
 doc/cvxopt/node52.html                             |  431 ++
 doc/cvxopt/node55.html                             |  127 +
 doc/cvxopt/node58.html                             |  209 +
 doc/cvxopt/node6.html                              |  200 +
 doc/cvxopt/node60.html                             |  358 +
 doc/cvxopt/node61.html                             |  135 +
 doc/cvxopt/node62.html                             |  162 +
 doc/cvxopt/node63.html                             |  241 +
 doc/cvxopt/previous.gif                            |  Bin 0 -> 252 bytes
 doc/cvxopt/pyfav.gif                               |  Bin 0 -> 125 bytes
 doc/cvxopt/s-arithmetic.html                       |  269 +
 doc/cvxopt/s-array-interface.html                  |  150 +
 doc/cvxopt/s-blas1.html                            |  344 +
 doc/cvxopt/s-blas2.html                            |  661 ++
 doc/cvxopt/s-blas3.html                            |  435 ++
 doc/cvxopt/s-builtinfuncs.html                     |  219 +
 doc/cvxopt/s-cholmod.html                          |  514 ++
 doc/cvxopt/s-conventions.html                      |  470 ++
 doc/cvxopt/s-creating-matrices.html                |  261 +
 doc/cvxopt/s-creating-spmatrix.html                |  359 ++
 doc/cvxopt/s-external.html                         |  129 +
 doc/cvxopt/s-functions.html                        |  511 ++
 doc/cvxopt/s-indexing.html                         |  263 +
 doc/cvxopt/s-lp.html                               |  359 ++
 doc/cvxopt/s-lpsolver.html                         |  290 +
 doc/cvxopt/s-orderings.html                        |  174 +
 doc/cvxopt/s-otherfuncs.html                       |  171 +
 doc/cvxopt/s-parameters.html                       |  401 ++
 doc/cvxopt/s-random.html                           |  167 +
 doc/cvxopt/s-sdpsolver.html                        |  483 ++
 doc/cvxopt/s-spmatrix-arith.html                   |  221 +
 doc/cvxopt/s-umfpack.html                          |  346 +
 doc/cvxopt/s-variables.html                        |  162 +
 doc/cvxopt/up.gif                                  |  Bin 0 -> 316 bytes
 doc/fftw.tex                                       |   92 +
 doc/figures/floorplan.eps                          | 2622 ++++++++
 doc/figures/normappr.eps                           | 6818 ++++++++++++++++++++
 doc/figures/portfolio1.eps                         | 2152 ++++++
 doc/figures/portfolio2.eps                         | 2805 ++++++++
 doc/intro.tex                                      |   56 +
 doc/lapack.tex                                     | 1041 +++
 doc/modeling.tex                                   |  747 +++
 doc/python.sty                                     | 1330 ++++
 doc/solvers.tex                                    | 1578 +++++
 doc/spsolvers.tex                                  |  566 ++
 examples/book/README                               |    7 +
 examples/book/chap4/portfolio                      |   57 +
 examples/book/chap4/rls                            |   79 +
 examples/book/chap4/rls.pic                        | 1125 ++++
 examples/book/chap6/basispursuit                   |  249 +
 examples/book/chap6/consumerpref                   |  135 +
 examples/book/chap6/cvxfit                         |   58 +
 examples/book/chap6/cvxfit.pic                     |  127 +
 examples/book/chap6/huber                          |   83 +
 examples/book/chap6/huber.pic                      |  109 +
 examples/book/chap6/inputdesign                    |   93 +
 examples/book/chap6/penalties                      |   98 +
 examples/book/chap6/polapprox                      |  148 +
 examples/book/chap6/polapprox.pic                  |  105 +
 examples/book/chap6/regsel                         |  127 +
 examples/book/chap6/regsel.pic                     |  235 +
 examples/book/chap6/robls                          |  161 +
 examples/book/chap6/robls.pic                      | 3551 ++++++++++
 examples/book/chap6/smoothrec                      |   84 +
 examples/book/chap6/tv                             |  286 +
 examples/book/chap7/chernoff                       |  104 +
 examples/book/chap7/expdesign                      |  185 +
 examples/book/chap7/logreg                         |   47 +
 examples/book/chap7/logreg.pic                     |  226 +
 examples/book/chap7/maxent                         |   95 +
 examples/book/chap7/probbounds                     |  204 +
 examples/book/chap8/centers                        |  206 +
 examples/book/chap8/ellipsoids                     |  228 +
 examples/book/chap8/floorplan                      |  210 +
 examples/book/chap8/linsep                         |  134 +
 examples/book/chap8/linsep.pic                     |  225 +
 examples/book/chap8/placement                      |  176 +
 examples/book/chap8/placement.pic                  |  118 +
 examples/doc/README                                |    1 +
 examples/doc/acent                                 |   77 +
 examples/doc/covsel                                |   90 +
 examples/doc/covsel.pic                            | 5261 +++++++++++++++
 examples/doc/l1                                    |  127 +
 examples/doc/mcsdp                                 |  121 +
 examples/doc/normappr                              |   34 +
 examples/filterdemo/README                         |   12 +
 examples/filterdemo/filterdemo_cli                 |  136 +
 examples/filterdemo/filterdemo_gui                 |  213 +
 src/C/SuiteSparse/AMD/Doc/AMD_UserGuide.bib        |   98 +
 src/C/SuiteSparse/AMD/Doc/AMD_UserGuide.pdf        |  Bin 0 -> 177382 bytes
 src/C/SuiteSparse/AMD/Doc/AMD_UserGuide.tex        | 1203 ++++
 src/C/SuiteSparse/AMD/Doc/ChangeLog                |  121 +
 src/C/SuiteSparse/AMD/Doc/License                  |   39 +
 src/C/SuiteSparse/AMD/Doc/Makefile                 |   33 +
 src/C/SuiteSparse/AMD/Doc/lesser.txt               |  504 ++
 src/C/SuiteSparse/AMD/Include/amd.h                |  412 ++
 src/C/SuiteSparse/AMD/Include/amd_internal.h       |  350 +
 src/C/SuiteSparse/AMD/Lib/libamd.def               |   12 +
 src/C/SuiteSparse/AMD/Makefile                     |   67 +
 src/C/SuiteSparse/AMD/README.txt                   |  214 +
 src/C/SuiteSparse/AMD/Source/GNUmakefile           |   79 +
 src/C/SuiteSparse/AMD/Source/Makefile              |   70 +
 src/C/SuiteSparse/AMD/Source/amd.f                 | 1214 ++++
 src/C/SuiteSparse/AMD/Source/amd_1.c               |  181 +
 src/C/SuiteSparse/AMD/Source/amd_2.c               | 1842 ++++++
 src/C/SuiteSparse/AMD/Source/amd_aat.c             |  185 +
 src/C/SuiteSparse/AMD/Source/amd_control.c         |   62 +
 src/C/SuiteSparse/AMD/Source/amd_defaults.c        |   37 +
 src/C/SuiteSparse/AMD/Source/amd_dump.c            |  177 +
 src/C/SuiteSparse/AMD/Source/amd_global.c          |   84 +
 src/C/SuiteSparse/AMD/Source/amd_info.c            |  119 +
 src/C/SuiteSparse/AMD/Source/amd_order.c           |  200 +
 src/C/SuiteSparse/AMD/Source/amd_post_tree.c       |  121 +
 src/C/SuiteSparse/AMD/Source/amd_postorder.c       |  207 +
 src/C/SuiteSparse/AMD/Source/amd_preprocess.c      |  119 +
 src/C/SuiteSparse/AMD/Source/amd_valid.c           |   92 +
 src/C/SuiteSparse/AMD/Source/amdbar.f              | 1206 ++++
 src/C/SuiteSparse/CHOLMOD/Check/License.txt        |   24 +
 src/C/SuiteSparse/CHOLMOD/Check/cholmod_check.c    | 2618 ++++++++
 src/C/SuiteSparse/CHOLMOD/Check/cholmod_read.c     | 1319 ++++
 src/C/SuiteSparse/CHOLMOD/Check/cholmod_write.c    |  742 +++
 src/C/SuiteSparse/CHOLMOD/Check/lesser.txt         |  504 ++
 src/C/SuiteSparse/CHOLMOD/Cholesky/License.txt     |   24 +
 src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_amd.c   |  212 +
 .../SuiteSparse/CHOLMOD/Cholesky/cholmod_analyze.c |  896 +++
 .../SuiteSparse/CHOLMOD/Cholesky/cholmod_colamd.c  |  210 +
 src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_etree.c |  227 +
 .../CHOLMOD/Cholesky/cholmod_factorize.c           |  429 ++
 .../CHOLMOD/Cholesky/cholmod_postorder.c           |  292 +
 src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_rcond.c |  161 +
 .../CHOLMOD/Cholesky/cholmod_resymbol.c            |  604 ++
 .../CHOLMOD/Cholesky/cholmod_rowcolcounts.c        |  535 ++
 .../SuiteSparse/CHOLMOD/Cholesky/cholmod_rowfac.c  |  677 ++
 src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_solve.c | 1195 ++++
 .../SuiteSparse/CHOLMOD/Cholesky/cholmod_spsolve.c |  397 ++
 src/C/SuiteSparse/CHOLMOD/Cholesky/lesser.txt      |  504 ++
 .../CHOLMOD/Cholesky/t_cholmod_lsolve.c            |  843 +++
 .../CHOLMOD/Cholesky/t_cholmod_ltsolve.c           |  841 +++
 .../CHOLMOD/Cholesky/t_cholmod_rowfac.c            |  456 ++
 .../SuiteSparse/CHOLMOD/Cholesky/t_cholmod_solve.c |  164 +
 src/C/SuiteSparse/CHOLMOD/Core/License.txt         |   25 +
 src/C/SuiteSparse/CHOLMOD/Core/cholmod_aat.c       |  300 +
 src/C/SuiteSparse/CHOLMOD/Core/cholmod_add.c       |  278 +
 src/C/SuiteSparse/CHOLMOD/Core/cholmod_band.c      |  374 ++
 .../CHOLMOD/Core/cholmod_change_factor.c           | 1227 ++++
 src/C/SuiteSparse/CHOLMOD/Core/cholmod_common.c    |  657 ++
 src/C/SuiteSparse/CHOLMOD/Core/cholmod_complex.c   |  547 ++
 src/C/SuiteSparse/CHOLMOD/Core/cholmod_copy.c      |  407 ++
 src/C/SuiteSparse/CHOLMOD/Core/cholmod_dense.c     |  640 ++
 src/C/SuiteSparse/CHOLMOD/Core/cholmod_error.c     |   80 +
 src/C/SuiteSparse/CHOLMOD/Core/cholmod_factor.c    |  935 +++
 src/C/SuiteSparse/CHOLMOD/Core/cholmod_memory.c    |  565 ++
 src/C/SuiteSparse/CHOLMOD/Core/cholmod_sparse.c    |  652 ++
 src/C/SuiteSparse/CHOLMOD/Core/cholmod_transpose.c | 1139 ++++
 src/C/SuiteSparse/CHOLMOD/Core/cholmod_triplet.c   |  773 +++
 src/C/SuiteSparse/CHOLMOD/Core/lesser.txt          |  504 ++
 .../CHOLMOD/Core/t_cholmod_change_factor.c         |  661 ++
 src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_dense.c   |  266 +
 .../SuiteSparse/CHOLMOD/Core/t_cholmod_transpose.c |  318 +
 src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_triplet.c |  176 +
 src/C/SuiteSparse/CHOLMOD/Doc/ChangeLog            |  146 +
 src/C/SuiteSparse/CHOLMOD/Doc/Makefile             |  227 +
 src/C/SuiteSparse/CHOLMOD/Doc/UserGuide.bib        |  196 +
 src/C/SuiteSparse/CHOLMOD/Doc/UserGuide.pdf        |  Bin 0 -> 460604 bytes
 src/C/SuiteSparse/CHOLMOD/Doc/UserGuide.tex        | 3366 ++++++++++
 src/C/SuiteSparse/CHOLMOD/Doc/footer.tex           |    6 +
 src/C/SuiteSparse/CHOLMOD/Doc/getmproto            |    4 +
 src/C/SuiteSparse/CHOLMOD/Doc/getproto             |    6 +
 src/C/SuiteSparse/CHOLMOD/Doc/header.tex           |    4 +
 src/C/SuiteSparse/CHOLMOD/Doc/mfile.awk            |    1 +
 src/C/SuiteSparse/CHOLMOD/Doc/mfooter.tex          |    4 +
 src/C/SuiteSparse/CHOLMOD/Doc/mheader.tex          |    5 +
 src/C/SuiteSparse/CHOLMOD/Doc/rule.awk             |    1 +
 src/C/SuiteSparse/CHOLMOD/Include/License.txt      |    9 +
 src/C/SuiteSparse/CHOLMOD/Include/README.txt       |   25 +
 src/C/SuiteSparse/CHOLMOD/Include/cholmod.h        |  122 +
 src/C/SuiteSparse/CHOLMOD/Include/cholmod_blas.h   |  451 ++
 src/C/SuiteSparse/CHOLMOD/Include/cholmod_check.h  |  417 ++
 .../SuiteSparse/CHOLMOD/Include/cholmod_cholesky.h |  498 ++
 .../CHOLMOD/Include/cholmod_complexity.h           |  264 +
 src/C/SuiteSparse/CHOLMOD/Include/cholmod_config.h |   83 +
 src/C/SuiteSparse/CHOLMOD/Include/cholmod_core.h   | 2257 +++++++
 .../SuiteSparse/CHOLMOD/Include/cholmod_internal.h |  385 ++
 src/C/SuiteSparse/CHOLMOD/Include/cholmod_io64.h   |   46 +
 .../CHOLMOD/Include/cholmod_matrixops.h            |  235 +
 src/C/SuiteSparse/CHOLMOD/Include/cholmod_modify.h |  304 +
 .../CHOLMOD/Include/cholmod_partition.h            |  233 +
 .../CHOLMOD/Include/cholmod_supernodal.h           |  147 +
 .../SuiteSparse/CHOLMOD/Include/cholmod_template.h |  238 +
 src/C/SuiteSparse/CHOLMOD/Lib/Makefile             |  473 ++
 src/C/SuiteSparse/CHOLMOD/Makefile                 |   59 +
 src/C/SuiteSparse/CHOLMOD/README.txt               |   76 +
 src/C/SuiteSparse/CHOLMOD/Supernodal/License.txt   |   25 +
 .../CHOLMOD/Supernodal/cholmod_super_numeric.c     |  295 +
 .../CHOLMOD/Supernodal/cholmod_super_solve.c       |  221 +
 .../CHOLMOD/Supernodal/cholmod_super_symbolic.c    |  794 +++
 src/C/SuiteSparse/CHOLMOD/Supernodal/gpl.txt       |  340 +
 .../CHOLMOD/Supernodal/t_cholmod_super_numeric.c   |  741 +++
 .../CHOLMOD/Supernodal/t_cholmod_super_solve.c     |  430 ++
 src/C/SuiteSparse/COLAMD/ChangeLog                 |  123 +
 src/C/SuiteSparse/COLAMD/Contents.m                |   18 +
 src/C/SuiteSparse/COLAMD/Makefile                  |   51 +
 src/C/SuiteSparse/COLAMD/README.txt                |  108 +
 src/C/SuiteSparse/COLAMD/colamd.c                  | 3611 +++++++++++
 src/C/SuiteSparse/COLAMD/colamd.h                  |  254 +
 src/C/SuiteSparse/COLAMD/colamd2.m                 |  103 +
 src/C/SuiteSparse/COLAMD/colamd_demo.m             |  178 +
 src/C/SuiteSparse/COLAMD/colamd_example.c          |  181 +
 src/C/SuiteSparse/COLAMD/colamd_example.out        |   50 +
 src/C/SuiteSparse/COLAMD/colamd_global.c           |   24 +
 src/C/SuiteSparse/COLAMD/colamd_l_example.c        |  185 +
 src/C/SuiteSparse/COLAMD/colamd_l_example.out      |   50 +
 src/C/SuiteSparse/COLAMD/colamd_make.m             |   18 +
 src/C/SuiteSparse/COLAMD/colamd_test.m             |  507 ++
 src/C/SuiteSparse/COLAMD/colamdmex.c               |  219 +
 src/C/SuiteSparse/COLAMD/colamdtestmex.c           |  576 ++
 src/C/SuiteSparse/COLAMD/lesser.txt                |  504 ++
 src/C/SuiteSparse/COLAMD/luflops.m                 |   35 +
 src/C/SuiteSparse/COLAMD/symamd2.m                 |  103 +
 src/C/SuiteSparse/COLAMD/symamdmex.c               |  200 +
 src/C/SuiteSparse/COLAMD/symamdtestmex.c           |  542 ++
 src/C/SuiteSparse/Contents.m                       |  134 +
 src/C/SuiteSparse/Makefile                         |   93 +
 src/C/SuiteSparse/README.txt                       |  120 +
 src/C/SuiteSparse/README_cvxopt                    |   28 +
 src/C/SuiteSparse/UFconfig/README.txt              |   25 +
 src/C/SuiteSparse/UFconfig/UFconfig.h              |  115 +
 src/C/SuiteSparse/UFconfig/UFconfig.mk             |  298 +
 src/C/SuiteSparse/UFconfig/xerbla/Makefile         |   31 +
 src/C/SuiteSparse/UFconfig/xerbla/xerbla.c         |   12 +
 src/C/SuiteSparse/UFconfig/xerbla/xerbla.f         |   46 +
 src/C/SuiteSparse/UFconfig/xerbla/xerbla.h         |    2 +
 src/C/SuiteSparse/UMFPACK/Doc/ChangeLog            |  452 ++
 src/C/SuiteSparse/UMFPACK/Doc/License              |   38 +
 src/C/SuiteSparse/UMFPACK/Doc/Makefile             |   59 +
 src/C/SuiteSparse/UMFPACK/Doc/QuickStart.pdf       |  Bin 0 -> 133992 bytes
 src/C/SuiteSparse/UMFPACK/Doc/QuickStart.tex       | 1020 +++
 src/C/SuiteSparse/UMFPACK/Doc/UserGuide.bib        |  322 +
 src/C/SuiteSparse/UMFPACK/Doc/UserGuide.pdf        |  Bin 0 -> 399999 bytes
 src/C/SuiteSparse/UMFPACK/Doc/UserGuide.sed1       |   33 +
 src/C/SuiteSparse/UMFPACK/Doc/UserGuide.sed2       |    3 +
 src/C/SuiteSparse/UMFPACK/Doc/UserGuide.stex       | 2695 ++++++++
 src/C/SuiteSparse/UMFPACK/Doc/lesser.txt           |  504 ++
 src/C/SuiteSparse/UMFPACK/Include/umfpack.h        |  438 ++
 .../UMFPACK/Include/umfpack_col_to_triplet.h       |  110 +
 .../SuiteSparse/UMFPACK/Include/umfpack_defaults.h |   69 +
 .../UMFPACK/Include/umfpack_free_numeric.h         |   67 +
 .../UMFPACK/Include/umfpack_free_symbolic.h        |   67 +
 .../UMFPACK/Include/umfpack_get_determinant.h      |  196 +
 .../SuiteSparse/UMFPACK/Include/umfpack_get_lunz.h |  137 +
 .../UMFPACK/Include/umfpack_get_numeric.h          |  254 +
 .../UMFPACK/Include/umfpack_get_symbolic.h         |  339 +
 src/C/SuiteSparse/UMFPACK/Include/umfpack_global.h |   22 +
 .../UMFPACK/Include/umfpack_load_numeric.h         |   95 +
 .../UMFPACK/Include/umfpack_load_symbolic.h        |   95 +
 .../SuiteSparse/UMFPACK/Include/umfpack_numeric.h  |  543 ++
 .../UMFPACK/Include/umfpack_qsymbolic.h            |  150 +
 .../UMFPACK/Include/umfpack_report_control.h       |   76 +
 .../UMFPACK/Include/umfpack_report_info.h          |   86 +
 .../UMFPACK/Include/umfpack_report_matrix.h        |  203 +
 .../UMFPACK/Include/umfpack_report_numeric.h       |  112 +
 .../UMFPACK/Include/umfpack_report_perm.h          |  112 +
 .../UMFPACK/Include/umfpack_report_status.h        |   90 +
 .../UMFPACK/Include/umfpack_report_symbolic.h      |  111 +
 .../UMFPACK/Include/umfpack_report_triplet.h       |  153 +
 .../UMFPACK/Include/umfpack_report_vector.h        |  133 +
 .../UMFPACK/Include/umfpack_save_numeric.h         |   90 +
 .../UMFPACK/Include/umfpack_save_symbolic.h        |   90 +
 src/C/SuiteSparse/UMFPACK/Include/umfpack_scale.h  |  112 +
 src/C/SuiteSparse/UMFPACK/Include/umfpack_solve.h  |  301 +
 .../SuiteSparse/UMFPACK/Include/umfpack_symbolic.h |  536 ++
 src/C/SuiteSparse/UMFPACK/Include/umfpack_tictoc.h |   60 +
 src/C/SuiteSparse/UMFPACK/Include/umfpack_timer.h  |   39 +
 .../UMFPACK/Include/umfpack_transpose.h            |  216 +
 .../UMFPACK/Include/umfpack_triplet_to_col.h       |  263 +
 src/C/SuiteSparse/UMFPACK/Include/umfpack_wsolve.h |  172 +
 src/C/SuiteSparse/UMFPACK/Lib/libumfpack.def       |  105 +
 src/C/SuiteSparse/UMFPACK/Makefile                 |   74 +
 src/C/SuiteSparse/UMFPACK/README.txt               |  409 ++
 src/C/SuiteSparse/UMFPACK/Source/GNUmakefile       |  257 +
 src/C/SuiteSparse/UMFPACK/Source/Makefile          |  482 ++
 src/C/SuiteSparse/UMFPACK/Source/cholmod_blas.h    |  451 ++
 src/C/SuiteSparse/UMFPACK/Source/umf_2by2.c        |  859 +++
 src/C/SuiteSparse/UMFPACK/Source/umf_2by2.h        |   36 +
 src/C/SuiteSparse/UMFPACK/Source/umf_analyze.c     |  704 ++
 src/C/SuiteSparse/UMFPACK/Source/umf_analyze.h     |   23 +
 src/C/SuiteSparse/UMFPACK/Source/umf_apply_order.c |   43 +
 src/C/SuiteSparse/UMFPACK/Source/umf_apply_order.h |   14 +
 src/C/SuiteSparse/UMFPACK/Source/umf_assemble.c    | 1215 ++++
 src/C/SuiteSparse/UMFPACK/Source/umf_assemble.h    |   17 +
 .../SuiteSparse/UMFPACK/Source/umf_blas3_update.c  |  175 +
 .../SuiteSparse/UMFPACK/Source/umf_blas3_update.h  |   10 +
 .../SuiteSparse/UMFPACK/Source/umf_build_tuples.c  |  159 +
 .../SuiteSparse/UMFPACK/Source/umf_build_tuples.h  |   11 +
 src/C/SuiteSparse/UMFPACK/Source/umf_colamd.c      | 3139 +++++++++
 src/C/SuiteSparse/UMFPACK/Source/umf_colamd.h      |  255 +
 src/C/SuiteSparse/UMFPACK/Source/umf_config.h      |  324 +
 .../UMFPACK/Source/umf_create_element.c            |  592 ++
 .../UMFPACK/Source/umf_create_element.h            |   12 +
 src/C/SuiteSparse/UMFPACK/Source/umf_dump.c        | 1209 ++++
 src/C/SuiteSparse/UMFPACK/Source/umf_dump.h        |  191 +
 .../SuiteSparse/UMFPACK/Source/umf_extend_front.c  |  392 ++
 .../SuiteSparse/UMFPACK/Source/umf_extend_front.h  |   11 +
 src/C/SuiteSparse/UMFPACK/Source/umf_free.c        |   45 +
 src/C/SuiteSparse/UMFPACK/Source/umf_free.h        |   10 +
 src/C/SuiteSparse/UMFPACK/Source/umf_fsize.c       |   69 +
 src/C/SuiteSparse/UMFPACK/Source/umf_fsize.h       |   15 +
 .../UMFPACK/Source/umf_garbage_collection.c        |  695 ++
 .../UMFPACK/Source/umf_garbage_collection.h        |   14 +
 src/C/SuiteSparse/UMFPACK/Source/umf_get_memory.c  |  222 +
 src/C/SuiteSparse/UMFPACK/Source/umf_get_memory.h  |   15 +
 src/C/SuiteSparse/UMFPACK/Source/umf_grow_front.c  |  293 +
 src/C/SuiteSparse/UMFPACK/Source/umf_grow_front.h  |   14 +
 src/C/SuiteSparse/UMFPACK/Source/umf_init_front.c  |  267 +
 src/C/SuiteSparse/UMFPACK/Source/umf_init_front.h  |   11 +
 src/C/SuiteSparse/UMFPACK/Source/umf_internal.h    |  734 +++
 .../UMFPACK/Source/umf_is_permutation.c            |   55 +
 .../UMFPACK/Source/umf_is_permutation.h            |   13 +
 src/C/SuiteSparse/UMFPACK/Source/umf_kernel.c      |  299 +
 src/C/SuiteSparse/UMFPACK/Source/umf_kernel.h      |   18 +
 src/C/SuiteSparse/UMFPACK/Source/umf_kernel_init.c | 1056 +++
 src/C/SuiteSparse/UMFPACK/Source/umf_kernel_init.h |   18 +
 .../SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.c |  466 ++
 .../SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.h |   12 +
 .../SuiteSparse/UMFPACK/Source/umf_local_search.c  | 1952 ++++++
 .../SuiteSparse/UMFPACK/Source/umf_local_search.h  |   12 +
 src/C/SuiteSparse/UMFPACK/Source/umf_lsolve.c      |  151 +
 src/C/SuiteSparse/UMFPACK/Source/umf_lsolve.h      |   12 +
 src/C/SuiteSparse/UMFPACK/Source/umf_ltsolve.c     |  225 +
 src/C/SuiteSparse/UMFPACK/Source/umf_ltsolve.h     |   19 +
 src/C/SuiteSparse/UMFPACK/Source/umf_malloc.c      |   91 +
 src/C/SuiteSparse/UMFPACK/Source/umf_malloc.h      |   25 +
 .../UMFPACK/Source/umf_mem_alloc_element.c         |   82 +
 .../UMFPACK/Source/umf_mem_alloc_element.h         |   17 +
 .../UMFPACK/Source/umf_mem_alloc_head_block.c      |   54 +
 .../UMFPACK/Source/umf_mem_alloc_head_block.h      |   11 +
 .../UMFPACK/Source/umf_mem_alloc_tail_block.c      |  133 +
 .../UMFPACK/Source/umf_mem_alloc_tail_block.h      |   11 +
 .../UMFPACK/Source/umf_mem_free_tail_block.c       |  142 +
 .../UMFPACK/Source/umf_mem_free_tail_block.h       |   11 +
 .../UMFPACK/Source/umf_mem_init_memoryspace.c      |   64 +
 .../UMFPACK/Source/umf_mem_init_memoryspace.h      |   10 +
 .../SuiteSparse/UMFPACK/Source/umf_multicompile.c  |   58 +
 src/C/SuiteSparse/UMFPACK/Source/umf_realloc.c     |   75 +
 src/C/SuiteSparse/UMFPACK/Source/umf_realloc.h     |   12 +
 src/C/SuiteSparse/UMFPACK/Source/umf_report_perm.c |   85 +
 src/C/SuiteSparse/UMFPACK/Source/umf_report_perm.h |   14 +
 .../SuiteSparse/UMFPACK/Source/umf_report_vector.c |  110 +
 .../SuiteSparse/UMFPACK/Source/umf_report_vector.h |   15 +
 src/C/SuiteSparse/UMFPACK/Source/umf_row_search.c  |  837 +++
 src/C/SuiteSparse/UMFPACK/Source/umf_row_search.h  |   32 +
 src/C/SuiteSparse/UMFPACK/Source/umf_scale.c       |   81 +
 src/C/SuiteSparse/UMFPACK/Source/umf_scale.h       |   12 +
 .../SuiteSparse/UMFPACK/Source/umf_scale_column.c  |  433 ++
 .../SuiteSparse/UMFPACK/Source/umf_scale_column.h  |   11 +
 src/C/SuiteSparse/UMFPACK/Source/umf_set_stats.c   |  133 +
 src/C/SuiteSparse/UMFPACK/Source/umf_set_stats.h   |   24 +
 src/C/SuiteSparse/UMFPACK/Source/umf_singletons.c  |  915 +++
 src/C/SuiteSparse/UMFPACK/Source/umf_singletons.h  |   31 +
 src/C/SuiteSparse/UMFPACK/Source/umf_solve.c       | 1395 ++++
 src/C/SuiteSparse/UMFPACK/Source/umf_solve.h       |   25 +
 src/C/SuiteSparse/UMFPACK/Source/umf_start_front.c |  283 +
 src/C/SuiteSparse/UMFPACK/Source/umf_start_front.h |   13 +
 src/C/SuiteSparse/UMFPACK/Source/umf_store_lu.c    | 1056 +++
 src/C/SuiteSparse/UMFPACK/Source/umf_store_lu.h    |   17 +
 .../UMFPACK/Source/umf_symbolic_usage.c            |   45 +
 .../UMFPACK/Source/umf_symbolic_usage.h            |   15 +
 src/C/SuiteSparse/UMFPACK/Source/umf_transpose.c   |  400 ++
 src/C/SuiteSparse/UMFPACK/Source/umf_transpose.h   |   27 +
 src/C/SuiteSparse/UMFPACK/Source/umf_triplet.c     |  428 ++
 src/C/SuiteSparse/UMFPACK/Source/umf_triplet.h     |   85 +
 .../SuiteSparse/UMFPACK/Source/umf_tuple_lengths.c |  135 +
 .../SuiteSparse/UMFPACK/Source/umf_tuple_lengths.h |   12 +
 src/C/SuiteSparse/UMFPACK/Source/umf_usolve.c      |  226 +
 src/C/SuiteSparse/UMFPACK/Source/umf_usolve.h      |   12 +
 src/C/SuiteSparse/UMFPACK/Source/umf_utsolve.c     |  331 +
 src/C/SuiteSparse/UMFPACK/Source/umf_utsolve.h     |   20 +
 .../SuiteSparse/UMFPACK/Source/umf_valid_numeric.c |   46 +
 .../SuiteSparse/UMFPACK/Source/umf_valid_numeric.h |   10 +
 .../UMFPACK/Source/umf_valid_symbolic.c            |   47 +
 .../UMFPACK/Source/umf_valid_symbolic.h            |   10 +
 src/C/SuiteSparse/UMFPACK/Source/umf_version.h     |  874 +++
 .../UMFPACK/Source/umfpack_col_to_triplet.c        |   72 +
 .../SuiteSparse/UMFPACK/Source/umfpack_defaults.c  |  114 +
 .../UMFPACK/Source/umfpack_free_numeric.c          |   57 +
 .../UMFPACK/Source/umfpack_free_symbolic.c         |   56 +
 .../UMFPACK/Source/umfpack_get_determinant.c       |  308 +
 .../SuiteSparse/UMFPACK/Source/umfpack_get_lunz.c  |   55 +
 .../UMFPACK/Source/umfpack_get_numeric.c           | 1057 +++
 .../UMFPACK/Source/umfpack_get_symbolic.c          |  191 +
 src/C/SuiteSparse/UMFPACK/Source/umfpack_global.c  |  130 +
 .../UMFPACK/Source/umfpack_load_numeric.c          |  161 +
 .../UMFPACK/Source/umfpack_load_symbolic.c         |  165 +
 src/C/SuiteSparse/UMFPACK/Source/umfpack_numeric.c |  792 +++
 .../SuiteSparse/UMFPACK/Source/umfpack_qsymbolic.c | 2411 +++++++
 .../UMFPACK/Source/umfpack_report_control.c        |  361 ++
 .../UMFPACK/Source/umfpack_report_info.c           |  611 ++
 .../UMFPACK/Source/umfpack_report_matrix.c         |  201 +
 .../UMFPACK/Source/umfpack_report_numeric.c        |  663 ++
 .../UMFPACK/Source/umfpack_report_perm.c           |   44 +
 .../UMFPACK/Source/umfpack_report_status.c         |  119 +
 .../UMFPACK/Source/umfpack_report_symbolic.c       |  228 +
 .../UMFPACK/Source/umfpack_report_triplet.c        |   99 +
 .../UMFPACK/Source/umfpack_report_vector.c         |   43 +
 .../UMFPACK/Source/umfpack_save_numeric.c          |   92 +
 .../UMFPACK/Source/umfpack_save_symbolic.c         |   95 +
 src/C/SuiteSparse/UMFPACK/Source/umfpack_scale.c   |  158 +
 src/C/SuiteSparse/UMFPACK/Source/umfpack_solve.c   |  245 +
 .../SuiteSparse/UMFPACK/Source/umfpack_symbolic.c  |   39 +
 src/C/SuiteSparse/UMFPACK/Source/umfpack_tictoc.c  |  106 +
 src/C/SuiteSparse/UMFPACK/Source/umfpack_timer.c   |   83 +
 .../SuiteSparse/UMFPACK/Source/umfpack_transpose.c |  108 +
 .../UMFPACK/Source/umfpack_triplet_to_col.c        |  225 +
 src/C/SuiteSparse_cvxopt_extra/README              |    7 +
 .../SuiteSparse_cvxopt_extra/umfpack/amd_global.c  |    1 +
 src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_1.c   |    3 +
 src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_2.c   |    3 +
 src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_aat.c |    3 +
 .../umfpack/amd_i_defaults.c                       |    3 +
 .../SuiteSparse_cvxopt_extra/umfpack/amd_i_dump.c  |    3 +
 .../SuiteSparse_cvxopt_extra/umfpack/amd_i_order.c |    3 +
 .../umfpack/amd_i_post_tree.c                      |    3 +
 .../umfpack/amd_i_postorder.c                      |    3 +
 .../umfpack/amd_i_preprocess.c                     |    3 +
 .../SuiteSparse_cvxopt_extra/umfpack/amd_i_valid.c |    3 +
 src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_1.c   |    3 +
 src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_2.c   |    3 +
 src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_aat.c |    3 +
 .../umfpack/amd_l_defaults.c                       |    3 +
 .../SuiteSparse_cvxopt_extra/umfpack/amd_l_dump.c  |    3 +
 .../SuiteSparse_cvxopt_extra/umfpack/amd_l_order.c |    3 +
 .../umfpack/amd_l_post_tree.c                      |    3 +
 .../umfpack/amd_l_postorder.c                      |    3 +
 .../umfpack/amd_l_preprocess.c                     |    3 +
 .../SuiteSparse_cvxopt_extra/umfpack/amd_l_valid.c |    3 +
 .../SuiteSparse_cvxopt_extra/umfpack/umf_di_2by2.c |    2 +
 .../umfpack/umf_di_assemble.c                      |    2 +
 .../umfpack/umf_di_assemble_fixq.c                 |    3 +
 .../umfpack/umf_di_blas3_update.c                  |    2 +
 .../umfpack/umf_di_build_tuples.c                  |    2 +
 .../umfpack/umf_di_create_element.c                |    2 +
 .../umfpack/umf_di_extend_front.c                  |    2 +
 .../umfpack/umf_di_garbage_collection.c            |    2 +
 .../umfpack/umf_di_get_memory.c                    |    2 +
 .../umfpack/umf_di_grow_front.c                    |    2 +
 .../umfpack/umf_di_init_front.c                    |    3 +
 .../umfpack/umf_di_kernel.c                        |    2 +
 .../umfpack/umf_di_kernel_init.c                   |    2 +
 .../umfpack/umf_di_kernel_wrapup.c                 |    2 +
 .../umfpack/umf_di_lhsolve.c                       |    3 +
 .../umfpack/umf_di_local_search.c                  |    2 +
 .../umfpack/umf_di_lsolve.c                        |    2 +
 .../umfpack/umf_di_ltsolve.c                       |    2 +
 .../umfpack/umf_di_mem_alloc_element.c             |    2 +
 .../umfpack/umf_di_mem_alloc_head_block.c          |    2 +
 .../umfpack/umf_di_mem_alloc_tail_block.c          |    2 +
 .../umfpack/umf_di_mem_free_tail_block.c           |    2 +
 .../umfpack/umf_di_mem_init_memoryspace.c          |    2 +
 .../umfpack/umf_di_row_search.c                    |    2 +
 .../umfpack/umf_di_scale.c                         |    2 +
 .../umfpack/umf_di_scale_column.c                  |    2 +
 .../umfpack/umf_di_set_stats.c                     |    2 +
 .../umfpack/umf_di_solve.c                         |    2 +
 .../umfpack/umf_di_start_front.c                   |    2 +
 .../umfpack/umf_di_store_lu.c                      |    2 +
 .../umfpack/umf_di_store_lu_drop.c                 |    3 +
 .../umfpack/umf_di_symbolic_usage.c                |    2 +
 .../umfpack/umf_di_transpose.c                     |    2 +
 .../umfpack/umf_di_tuple_lengths.c                 |    2 +
 .../umfpack/umf_di_uhsolve.c                       |    3 +
 .../umfpack/umf_di_usolve.c                        |    2 +
 .../umfpack/umf_di_utsolve.c                       |    2 +
 .../umfpack/umf_di_valid_numeric.c                 |    2 +
 .../umfpack/umf_di_valid_symbolic.c                |    2 +
 .../SuiteSparse_cvxopt_extra/umfpack/umf_dl_2by2.c |    3 +
 .../umfpack/umf_dl_assemble.c                      |    3 +
 .../umfpack/umf_dl_assemble_fixq.c                 |    3 +
 .../umfpack/umf_dl_blas3_update.c                  |    3 +
 .../umfpack/umf_dl_build_tuples.c                  |    3 +
 .../umfpack/umf_dl_create_elememt.c                |    3 +
 .../umfpack/umf_dl_extend_front.c                  |    3 +
 .../umfpack/umf_dl_garbage_collection.c            |    3 +
 .../umfpack/umf_dl_get_memory.c                    |    3 +
 .../umfpack/umf_dl_grow_front.c                    |    3 +
 .../umfpack/umf_dl_init_front.c                    |    3 +
 .../umfpack/umf_dl_kernel.c                        |    3 +
 .../umfpack/umf_dl_kernel_init.c                   |    3 +
 .../umfpack/umf_dl_kernel_wrapup.c                 |    3 +
 .../umfpack/umf_dl_lhsolve.c                       |    4 +
 .../umfpack/umf_dl_local_search.c                  |    3 +
 .../umfpack/umf_dl_lsolve.c                        |    3 +
 .../umfpack/umf_dl_ltsolve.c                       |    3 +
 .../umfpack/umf_dl_mem_alloc_element.c             |    3 +
 .../umfpack/umf_dl_mem_alloc_head_block.c          |    3 +
 .../umfpack/umf_dl_mem_alloc_tail_block.c          |    3 +
 .../umfpack/umf_dl_mem_free_tail_block.c           |    3 +
 .../umfpack/umf_dl_mem_init_memoryspace.c          |    3 +
 .../umfpack/umf_dl_row_search.c                    |    3 +
 .../umfpack/umf_dl_scale.c                         |    3 +
 .../umfpack/umf_dl_scale_column.c                  |    3 +
 .../umfpack/umf_dl_set_stats.c                     |    3 +
 .../umfpack/umf_dl_solve.c                         |    3 +
 .../umfpack/umf_dl_start_front.c                   |    3 +
 .../umfpack/umf_dl_store_lu.c                      |    3 +
 .../umfpack/umf_dl_store_lu_drop.c                 |    3 +
 .../umfpack/umf_dl_symbolic_usage.c                |    3 +
 .../umfpack/umf_dl_transpose.c                     |    3 +
 .../umfpack/umf_dl_tuple_lengths.c                 |    3 +
 .../umfpack/umf_dl_uhsolve.c                       |    4 +
 .../umfpack/umf_dl_usolve.c                        |    3 +
 .../umfpack/umf_dl_utsolve.c                       |    3 +
 .../umfpack/umf_dl_valid_numeric.c                 |    3 +
 .../umfpack/umf_dl_valid_symbolic.c                |    3 +
 .../umfpack/umf_i_analyze.c                        |    2 +
 .../umfpack/umf_i_apply_order.c                    |    2 +
 .../umfpack/umf_i_colamd.c                         |    2 +
 .../SuiteSparse_cvxopt_extra/umfpack/umf_i_free.c  |    2 +
 .../SuiteSparse_cvxopt_extra/umfpack/umf_i_fsize.c |    2 +
 .../umfpack/umf_i_is_permutation.c                 |    2 +
 .../umfpack/umf_i_malloc.c                         |    2 +
 .../umfpack/umf_i_realloc.c                        |    2 +
 .../umfpack/umf_i_singletons.c                     |    2 +
 .../umfpack/umf_l_analyze.c                        |    3 +
 .../umfpack/umf_l_apply_order.c                    |    2 +
 .../umfpack/umf_l_colamd.c                         |    3 +
 .../SuiteSparse_cvxopt_extra/umfpack/umf_l_free.c  |    3 +
 .../SuiteSparse_cvxopt_extra/umfpack/umf_l_fsize.c |    3 +
 .../umfpack/umf_l_is_permutation.c                 |    3 +
 .../umfpack/umf_l_malloc.c                         |    3 +
 .../umfpack/umf_l_realloc.c                        |    3 +
 .../umfpack/umf_l_singletons.c                     |    3 +
 .../SuiteSparse_cvxopt_extra/umfpack/umf_zi_2by2.c |    2 +
 .../umfpack/umf_zi_assemble.c                      |    2 +
 .../umfpack/umf_zi_assemble_fixq.c                 |    3 +
 .../umfpack/umf_zi_blas3_update.c                  |    2 +
 .../umfpack/umf_zi_build_tuples.c                  |    2 +
 .../umfpack/umf_zi_create_element.c                |    2 +
 .../umfpack/umf_zi_extend_front.c                  |    2 +
 .../umfpack/umf_zi_garbage_collection.c            |    2 +
 .../umfpack/umf_zi_get_memory.c                    |    2 +
 .../umfpack/umf_zi_grow_front.c                    |    2 +
 .../umfpack/umf_zi_init_front.c                    |    3 +
 .../umfpack/umf_zi_kernel.c                        |    2 +
 .../umfpack/umf_zi_kernel_init.c                   |    2 +
 .../umfpack/umf_zi_kernel_wrapup.c                 |    2 +
 .../umfpack/umf_zi_lhsolve.c                       |    3 +
 .../umfpack/umf_zi_local_search.c                  |    2 +
 .../umfpack/umf_zi_lsolve.c                        |    2 +
 .../umfpack/umf_zi_ltsolve.c                       |    2 +
 .../umfpack/umf_zi_mem_alloc_element.c             |    2 +
 .../umfpack/umf_zi_mem_alloc_head_block.c          |    2 +
 .../umfpack/umf_zi_mem_alloc_tail_block.c          |    2 +
 .../umfpack/umf_zi_mem_free_tail_block.c           |    2 +
 .../umfpack/umf_zi_mem_init_memoryspace.c          |    2 +
 .../umfpack/umf_zi_row_search.c                    |    2 +
 .../umfpack/umf_zi_scale.c                         |    2 +
 .../umfpack/umf_zi_scale_column.c                  |    2 +
 .../umfpack/umf_zi_set_stats.c                     |    2 +
 .../umfpack/umf_zi_solve.c                         |    2 +
 .../umfpack/umf_zi_start_front.c                   |    2 +
 .../umfpack/umf_zi_store_lu.c                      |    2 +
 .../umfpack/umf_zi_store_lu_drop.c                 |    3 +
 .../umfpack/umf_zi_symbolic_usage.c                |    2 +
 .../umfpack/umf_zi_transpose.c                     |    2 +
 .../umfpack/umf_zi_tuple_lengths.c                 |    2 +
 .../umfpack/umf_zi_uhsolve.c                       |    3 +
 .../umfpack/umf_zi_usolve.c                        |    2 +
 .../umfpack/umf_zi_utsolve.c                       |    2 +
 .../umfpack/umf_zi_valid_numeric.c                 |    2 +
 .../umfpack/umf_zi_valid_symbolic.c                |    2 +
 .../SuiteSparse_cvxopt_extra/umfpack/umf_zl_2by2.c |    3 +
 .../umfpack/umf_zl_assemble.c                      |    3 +
 .../umfpack/umf_zl_assemble_fixq.c                 |    3 +
 .../umfpack/umf_zl_blas3_update.c                  |    3 +
 .../umfpack/umf_zl_build_tuples.c                  |    3 +
 .../umfpack/umf_zl_create_elememt.c                |    3 +
 .../umfpack/umf_zl_extend_front.c                  |    3 +
 .../umfpack/umf_zl_garbage_collection.c            |    3 +
 .../umfpack/umf_zl_get_memory.c                    |    3 +
 .../umfpack/umf_zl_grow_front.c                    |    3 +
 .../umfpack/umf_zl_init_front.c                    |    3 +
 .../umfpack/umf_zl_kernel.c                        |    3 +
 .../umfpack/umf_zl_kernel_init.c                   |    3 +
 .../umfpack/umf_zl_kernel_wrapup.c                 |    3 +
 .../umfpack/umf_zl_lhsolve.c                       |    4 +
 .../umfpack/umf_zl_local_search.c                  |    3 +
 .../umfpack/umf_zl_lsolve.c                        |    3 +
 .../umfpack/umf_zl_ltsolve.c                       |    3 +
 .../umfpack/umf_zl_mem_alloc_element.c             |    3 +
 .../umfpack/umf_zl_mem_alloc_head_block.c          |    3 +
 .../umfpack/umf_zl_mem_alloc_tail_block.c          |    3 +
 .../umfpack/umf_zl_mem_free_tail_block.c           |    3 +
 .../umfpack/umf_zl_mem_init_memoryspace.c          |    3 +
 .../umfpack/umf_zl_row_search.c                    |    3 +
 .../umfpack/umf_zl_scale.c                         |    3 +
 .../umfpack/umf_zl_scale_column.c                  |    3 +
 .../umfpack/umf_zl_set_stats.c                     |    3 +
 .../umfpack/umf_zl_solve.c                         |    3 +
 .../umfpack/umf_zl_start_front.c                   |    3 +
 .../umfpack/umf_zl_store_lu.c                      |    3 +
 .../umfpack/umf_zl_store_lu_drop.c                 |    3 +
 .../umfpack/umf_zl_symbolic_usage.c                |    3 +
 .../umfpack/umf_zl_transpose.c                     |    3 +
 .../umfpack/umf_zl_tuple_lengths.c                 |    3 +
 .../umfpack/umf_zl_uhsolve.c                       |    4 +
 .../umfpack/umf_zl_usolve.c                        |    3 +
 .../umfpack/umf_zl_utsolve.c                       |    3 +
 .../umfpack/umf_zl_valid_numeric.c                 |    3 +
 .../umfpack/umf_zl_valid_symbolic.c                |    3 +
 .../umfpack/umfpack_di_free_numeric.c              |    2 +
 .../umfpack/umfpack_di_free_symbolic.c             |    2 +
 .../umfpack/umfpack_di_numeric.c                   |    2 +
 .../umfpack/umfpack_di_qsymbolic.c                 |    2 +
 .../umfpack/umfpack_di_solve.c                     |    2 +
 .../umfpack/umfpack_di_symbolic.c                  |    2 +
 .../umfpack/umfpack_dl_free_numeric.c              |    3 +
 .../umfpack/umfpack_dl_free_symbolic.c             |    3 +
 .../umfpack/umfpack_dl_numeric.c                   |    3 +
 .../umfpack/umfpack_dl_qsymbolic.c                 |    3 +
 .../umfpack/umfpack_dl_solve.c                     |    3 +
 .../umfpack/umfpack_dl_symbolic.c                  |    2 +
 .../umfpack/umfpack_zi_free_numeric.c              |    2 +
 .../umfpack/umfpack_zi_free_symbolic.c             |    2 +
 .../umfpack/umfpack_zi_numeric.c                   |    2 +
 .../umfpack/umfpack_zi_qsymbolic.c                 |    2 +
 .../umfpack/umfpack_zi_solve.c                     |    2 +
 .../umfpack/umfpack_zi_symbolic.c                  |    2 +
 .../umfpack/umfpack_zl_free_numeric.c              |    3 +
 .../umfpack/umfpack_zl_free_symbolic.c             |    3 +
 .../umfpack/umfpack_zl_numeric.c                   |    3 +
 .../umfpack/umfpack_zl_qsymbolic.c                 |    3 +
 .../umfpack/umfpack_zl_solve.c                     |    3 +
 .../umfpack/umfpack_zl_symbolic.c                  |    2 +
 src/C/amd.c                                        |  198 +
 src/C/base.c                                       |  950 +++
 src/C/blas.c                                       | 3316 ++++++++++
 src/C/blas_redefines.h                             |  140 +
 src/C/cholmod.c                                    |  947 +++
 src/C/cvxopt.h                                     |  127 +
 src/C/dense.c                                      | 2129 ++++++
 src/C/dsdp.c                                       |  437 ++
 src/C/fftw.c                                       |  290 +
 src/C/glpk.c                                       |  358 +
 src/C/lapack.c                                     | 5088 +++++++++++++++
 src/C/misc.h                                       |   85 +
 src/C/mosek.c                                      |  778 +++
 src/C/random.c                                     |  144 +
 src/C/rngs/README.cvxopt                           |    3 +
 src/C/rngs/rngs.c                                  |  179 +
 src/C/rngs/rngs.h                                  |   19 +
 src/C/rngs/rvgs.c                                  |  218 +
 src/C/rngs/rvgs.h                                  |   28 +
 src/C/sparse.c                                     | 3992 ++++++++++++
 src/C/umfpack.c                                    |  448 ++
 src/python/__init__.py                             |    2 +
 src/python/coneprog.py                             | 2151 ++++++
 src/python/cvxprog.py                              | 1074 +++
 src/python/info.py                                 |   41 +
 src/python/misc.py                                 |  515 ++
 src/python/modeling.py                             | 3214 +++++++++
 src/python/solvers.py                              |   24 +
 src/setup.py                                       |  165 +
 898 files changed, 185779 insertions(+)

diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..a9ffc1a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,74 @@
+Installation instructions for CVXOPT Version 0.8.2.
+
+The package requires version 2.3 or newer of Python, and is built 
+from source, so the header files and libraries for Python must be 
+installed, as well as the core binaries.
+
+The installation requires either ATLAS or BLAS + LAPACK.  Using 
+architecture optimized ATLAS libraries is recommended and gives a 
+large performance improvement over standard BLAS & LAPACK libraries.  
+Both header files and libraries must be installed.  
+
+The following software libraries are optional.  
+
+1) FFTW (www.fftw.org) is a C library for discrete Fourier transforms.
+
+1) GLPK (www.gnu.org/software/glpk/glpk.html) is a linear programming 
+package.  
+
+2) MOSEK version 4 (www.mosek.com) is a commercial library of convex 
+optimization solvers.  
+
+3) DSDP5.8 (www-unix.mcs.anl.gov/DSDP) is a semidefinite programming
+solver. 
+
+
+Configuration script:
+---------------------
+Edit src/setup.py and update the following variables:
+
+- ATLAS_LIB_DIR: the directory containing the lapack and blas libraries
+
+- BUILD_FFTW: set this variable to 1 to enable FFTW support
+- FFTW_LIB_DIR: the directory containing the libfftw3
+- FFTW_INC_DIR: the directory containing fftw.h
+
+- BUILD_GLPK: set this variable to 1 to enable GLPK support
+- GLPK_LIB_DIR: the directory containing libglpk
+- GLPK_INC_DIR: the directory containing glpk.h 
+
+- BUILD_MOSEK: set this variable to 1 to enable MOSEK support
+- MOSEK_LIB_DIR: the directory containing libmosek
+- MOSEK_INC_DIR: the directory containing mosek.h
+
+- BUILD_DSDP: set this variable to 1 to enable DSDP support
+- DSDP_LIB_DIR: the directory containing libdsdp
+- DSDP_INC_DIR: the directory containing dsdp5.h
+
+
+Compilation:
+------------
+CVXOPT can be installed globally (for all users on a UNIX system) by 
+writing:
+
+    python setup.py install
+
+It can also be installed locally in the home directory by typing:
+
+    python setup.py install --home=~
+
+This will install the libraries in /home/username/lib/python. In this
+case PYTHONPATH must be updated, e.g., under Bash write
+
+    export PYTHONPATH=$PYTHONPATH:/home/username/lib/python
+
+
+Test it:
+--------
+To test that the installation was successful, go to the examples
+directory and try one of the examples, for example,
+
+    $ cd examples/doc
+    $ python acent
+
+If Python does not issue an error message installation was successful.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..62afd96
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,319 @@
+CVXOPT version 0.8.2. 
+Copyright (C) 2004-2007  J. Dahl and L. Vandenberghe.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is enclosed below.
+See also www.gnu.org/copyleft/gpl.html.
+------------------------------------------------------------------------
+
+The CVXOPT distribution includes source code for the following software
+libraries.
+
+AMD Version 2.0.  Copyright (c) 2006 by Timothy A. Davis, Patrick R. 
+Amestoy, and Iain S. Duff.  
+See www.cise.ufl.edu/research/sparse/amd.
+
+CHOLMOD Version 1.4.  Copyright (c) 2005-2006 by University of Florida,
+Timothy A. Davis and William W. Hager.
+See www.cise.ufl.edu/research/sparse/cholmod.
+
+COLAMD version 2.6.  Copyright (c) 1998-2006 by Timothy A. Davis.
+See www.cise.ufl.edu/research/sparse/colamd.
+
+UMFPACK Version 5.0.2. Copyright (c) 1995-2006 by Timothy A. Davis.
+See www.cise.ufl.edu/research/sparse/umfpack.
+
+RNGS Random Number Generation - Multiple Streams (Sep. 22, 1998) by
+Steve Park & Dave Geyer.  
+See www.cs.wm.edu/~va/software/park/park.html.
+------------------------------------------------------------------------
+
+                GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+  
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+

+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+  
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000..00879d3
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,14 @@
+MKHOWTO	= /usr/lib/python2.4/doc/tools/mkhowto
+SOURCES	= cvxopt.tex intro.tex base.tex blas.tex lapack.tex \
+	spsolvers.tex modeling.tex solvers.tex c-api.tex 
+
+all: html 
+
+ps: Makefile $(SOURCES)      
+	$(MKHOWTO) --ps cvxopt.tex
+
+html: Makefile $(SOURCES) 
+	$(MKHOWTO) --html --image-type gif cvxopt.tex
+
+clean:	
+	rm -rf *.dvi *.idx *.ind *.l2h *.log *.toc *.aux *~ *.ps cvxopt
diff --git a/doc/README b/doc/README
new file mode 100644
index 0000000..f47740c
--- /dev/null
+++ b/doc/README
@@ -0,0 +1,2 @@
+python.sty in this directory is the style file from the standard Python
+distribution with lines 555--563 commented out.
diff --git a/doc/base.tex b/doc/base.tex
new file mode 100644
index 0000000..c723608
--- /dev/null
+++ b/doc/base.tex
@@ -0,0 +1,765 @@
+\chapter{Dense Matrices (\module{cvxopt.base})}\label{chap:matrix}
+
+The \module{cvxopt.base} module defines two new Python types: 
+\mtrx\ objects, used for dense matrix computations, and 
+\spmtrx\ objects, used for sparse matrix computations.
+In this chapter we describe the dense \mtrx\ object.
+
+\section{Creating Matrices}\label{s-creating-matrices}
+A \mtrx\ object is created by calling the function \function{matrix()}. 
+The arguments specify the values of the coefficients, the
+dimensions, and the type (integer, double or complex) of the matrix.
+
+\begin{funcdesc}{matrix}{x\optional{, size\optional{, tc}}}
+\var{size} is a tuple of length two with the matrix dimensions.
+The number of rows and/or the number of columns can be zero.
+
+\var{tc} stands for typecode. The possible values are \itc, \dtc\ and 
+\ztc, for integer, real (double) and complex matrices, respectively.  
+
+\var{x} can be a number, a sequence of numbers, a dense or sparse 
+matrix, a two-dimensional \module{numarray} array, or a list of
+lists of matrices and numbers.  
+\BIT
+\item If \var{x} is a number (Python \intgr, \flt\ or \cmplx), a matrix
+is created with the dimensions specified by \var{size} and with all the 
+coefficients equal to \var{x}.  
+The default value of \var{size} is (1,1), and the default value
+of \var{tc} is the type of \var{x}.
+If necessary, the type of \var{x} is converted (from integer to double
+when used to create a matrix of type \dtc, and from integer or
+double to complex when used to create a matrix of type \ztc).
+
+\begin{verbatim}
+>>> from cvxopt.base import matrix
+>>> A = matrix(1, (1,4))   
+>>> print A
+   1      1      1      1
+>>> A = matrix(1.0, (1,4))   
+>>> print A
+   1.0000e+00   1.0000e+00   1.0000e+00   1.0000e+00
+>>> A = matrix(1+1j)     
+>>> print A
+   1.0000e+00+j1.0000e+00
+\end{verbatim}
+
+\item If \var{x} is a sequence of numbers (list, tuple, \module{array}
+array, xrange object, one-dimensional \module{numarray} array, \ldots),
+then the numbers are interpreted as the coefficients of a matrix in 
+column-major order.  The length of \var{x} must be equal to the product 
+of \var{size}[0] and \var{size}[1].
+If \var{size} is not specified, a matrix with one column is created. 
+If \var{tc} is not specified, it is determined from the elements of 
+\var{x} (and if that is impossible, for example because \var{x} is
+an empty list, a value \itc\ is used).  
+Type conversion takes place as for scalar \var{x}.
+
+The following example shows several ways to define the same integer 
+matrix.
+\begin{verbatim}
+>>> A = matrix([0, 1, 2, 3], (2,2))  
+>>> A = matrix((0, 1, 2, 3), (2,2))  
+>>> A = matrix(xrange(4), (2,2))
+>>> from array import array
+>>> A = matrix(array('i', [0,1,2,3]), (2,2))
+>>> print A
+   0      2
+   1      3
+\end{verbatim}
+
+\item If \var{x} is a dense or sparse matrix (a \mtrx\ or a \spmtrx\ 
+object), or a two-dimensional \module{numarray} array of type \itc, 
+\dtc\ or \ztc, then the  coefficients of \var{x} are copied, in 
+column-major order, to a new matrix of the given size.  
+The total number of elements in the new matrix (the product of 
+\var{size}[0] and \var{size}[1]) must be the same as the product of  
+the dimensions of \var{x}.  If \var{size} is not specified, the 
+dimensions of \var{x} are used.  
+The default value of \var{tc} is the type of \var{x}. 
+Type conversion takes place when the type of \var{x} differs from 
+\var{tc}, in a similar way as for scalar \var{x}.  
+
+\begin{verbatim}
+>>> A = matrix([1., 2., 3., 4., 5., 6.], (2,3))  
+>>> print A
+   1.0000e+00   3.0000e+00   5.0000e+00   
+   2.0000e+00   4.0000e+00   6.0000e+00   
+>>> B = matrix(A, (3,2))  
+>>> print B
+   1.0000e+00   4.0000e+00   
+   2.0000e+00   5.0000e+00   
+   3.0000e+00   6.0000e+00   
+>>> C = matrix(B, tc='z')      
+>>> print C
+   1.0000e+00-j0.0000e+00   4.0000e+00-j0.0000e+00
+   2.0000e+00-j0.0000e+00   5.0000e+00-j0.0000e+00
+   3.0000e+00-j0.0000e+00   6.0000e+00-j0.0000e+00
+>>> from numarray import array
+>>> x = array([1., 2., 3., 4., 5., 6.], shape=(2,3))
+>>> print x
+[[ 1.  2.  3.]
+ [ 4.  5.  6.]]
+>>> y = matrix(x)
+>>> print y
+   1.0000e+00   2.0000e+00   3.0000e+00
+   4.0000e+00   5.0000e+00   6.0000e+00
+\end{verbatim}
+
+\item If \var{x} is a list of lists of matrices 
+(\mtrx\ or \spmtrx\ objects) or numbers (Python \intgr, \flt\ or 
+\cmplx), then each element of \var{x} is interpreted as a 
+block-column stored in column-major order. 
+If \var{size} is not specified, the block-columns are juxtaposed
+to obtain a matrix with \code{len(\var{x})} block-columns.
+If \var{size} is specified, then the matrix with \code{len(\var{x})}
+block-columns is resized by copying its elements in column-major order 
+into a matrix of the dimensions given by \var{size}.  
+If \var{tc} is not specified, it is determined from the elements of 
+\var{x} (and if that is impossible, for example because \var{x} is
+a list of empty lists, a value \itc\ is used).  
+The same rules for type conversion apply as for scalar \var{x}.
+
+\begin{verbatim}
+>>> A = matrix([[1., 2.], [3., 4.], [5., 6.]])
+>>> print A
+   1.0000e+00   3.0000e+00   5.0000e+00
+   2.0000e+00   4.0000e+00   6.0000e+00
+>>> A1 = matrix([1, 2], (2,1))
+>>> B1 = matrix([6, 7, 8, 9, 10, 11], (2,3))
+>>> B2 = matrix([12, 13, 14, 15, 16, 17], (2,3))
+>>> B3 = matrix([18, 19, 20], (1,3))
+>>> print matrix([[A1, 3.0, 4.0, 5.0], [B1, B2, B3]])
+   1.0000e+00   6.0000e+00   8.0000e+00   1.0000e+01
+   2.0000e+00   7.0000e+00   9.0000e+00   1.1000e+01
+   3.0000e+00   1.2000e+01   1.4000e+01   1.6000e+01
+   4.0000e+00   1.3000e+01   1.5000e+01   1.7000e+01
+   5.0000e+00   1.8000e+01   1.9000e+01   2.0000e+01
+\end{verbatim}
+
+A matrix with a single block-column can be represented by a single 
+list (\ie, when the length of \var{x} is one, it can be replaced with
+\code{\var{x}[0]}).
+\begin{verbatim}
+>>> print matrix([B1, B2, B3])
+   6      8      10  
+   7      9      11  
+   12     14     16  
+   13     15     17  
+   18     19     20  
+\end{verbatim}
+\EIT
+\end{funcdesc}
+
+\section{Attributes and Methods} 
+A \mtrx\ has the following attributes.
+
+\begin{memberdesc}[tuple]{size}
+A tuple with the dimensions of the matrix. This is a read-only 
+attribute; operations that change the size of a matrix are not 
+permitted.
+\end{memberdesc} 
+
+\begin{memberdesc}[char]{typecode}
+A \ctype{char}, either \itc, \dtc, or \ztc, for integer, real
+and complex matrices, respectively.  A read-only attribute.
+\end{memberdesc} 
+
+\begin{methoddesc}{trans}{}
+Returns the transpose of the matrix as a new matrix.
+One can also use \code{A.T} instead of \code{A.trans()}.
+\end{methoddesc}
+
+\begin{methoddesc}{ctrans}{}
+Returns the conjugate transpose of the matrix as a new matrix.
+One can also use \code{A.H} instead of \code{A.ctrans()}.
+\end{methoddesc}
+
+\begin{methoddesc}{real}{}
+For complex matrices, returns the real part as a real matrix.
+For integer and real matrices, returns a copy of the matrix.
+\end{methoddesc}
+
+\begin{methoddesc}{imag}{}
+For complex matrices, returns the imaginary part as a real matrix.
+For integer and real matrices, returns an integer or real zero matrix.
+\end{methoddesc}
+
+\begin{memberdesc}[PyCObject]{\_\_array\_struct\_\_}
+A PyCObject implementing the NumPy array interface  
+(see section~\ref{s-array-interface} for details).
+\end{memberdesc} 
+
+\begin{methoddesc}{tofile}{f}
+Writes the elements of the matrix in column-major order to a binary 
+file \var{f}. 
+\end{methoddesc}
+
+\begin{methoddesc}{fromfile}{f}
+Reads the contents of a binary file \var{f} into the matrix object.
+\end{methoddesc}
+
+The last two methods are illustrated in the following example.
+\begin{verbatim}
+>>> from cvxopt.base import matrix
+>>> A = matrix([[1.,2.,3.], [4.,5.,6.]])  
+>>> print A
+  1.0000e+00  4.0000e+00
+  2.0000e+00  5.0000e+00
+  3.0000e+00  6.0000e+00
+>>> f = open('mat.bin','w')
+>>> A.tofile(f)
+>>> f.close()
+>>> B = matrix(0.0, (2,3))
+>>> f = open('mat.bin','r')
+>>> B.fromfile(f)
+>>> f.close()
+>>> print B
+  1.0000e+00  3.0000e+00  5.0000e+00
+  2.0000e+00  4.0000e+00  6.0000e+00
+\end{verbatim}
+
+Matrices can also be written to or read from files using the 
+\function{dump()} and \function{load()} functions in the 
+\module{pickle} module. 
+
+
+\section{Arithmetic Operations} \label{s-arithmetic}
+The following table lists the arithmetic operations defined for 
+dense matrices.  In this table \var{A} and \var{B} are dense matrices 
+with compatible dimensions, \var{c} is a scalar (a Python number 
+or a dense 1 by 1 matrix), and \var{d} is a Python number.
+
+\begin{center}
+\begin{tabular}{l|l}
+Unary plus/minus & \code{+\var{A}}, \code{-\var{A}} \\
+Addition & \code{\var{A}+\var{B}}, \code{\var{A}+\var{c}}, 
+    \code{\var{c}+\var{A}}\\
+Subtraction & \code{\var{A}-\var{B}}, \code{\var{A}-\var{c}}, 
+    \code{\var{c}-\var{A}}\\
+Matrix multiplication & {\var{A}*\var{B}} \\
+Scalar multiplication and division & \code{\var{c}*\var{A}}, 
+    \code{\var{A}*\var{c}}, \code{\var{A}/\var{c}} \\
+Remainder after division & \code{\var{A}\%\var{c}} \\
+Elementwise exponentiation  & \code{\var{A}**\var{d}}
+\end{tabular}
+\end{center}
+
+If \var{c} in the expressions \code{\var{A}+\var{c}}, 
+\code{\var{c}+\var{A}}, \code{\var{A}-\var{c}}, 
+\code{\var{c}-\var{A}} is a number, then it is interpreted as a 
+matrix with the same dimensions as \var{A}, type given by the type 
+of \var{c}, and all entries equal to \var{c}.
+If \var{c}  is a 1 by 1 matrix and \var{A} is not 1 by 1, then \var{c} 
+is interpreted as a matrix with the same size of \var{A} and all 
+entries equal to \code{\var{c}[0]}.
+
+Postmultiplying a matrix with a number \var{c} means the same as 
+premultiplying, \ie, scalar multiplication.  Dividing a matrix by 
+\var{c} means dividing all entries by \var{c}.  
+If \var{c} is a 1 by 1 matrix and the product
+\code{\var{c}*\var{A}} or \code{\var{A}*\var{c}} cannot be 
+interpreted as a matrix-matrix product, then it is interpreted as 
+\code{\var{c}[0]*\var{A}}. 
+The division \code{\var{A}/\var{c}} and remainder 
+\code{\var{A}\%\var{c}} with \var{c} a 1 by 1 matrix are always 
+interpreted as \code{\var{A}/\var{c}[0]}, resp.,
+\code{\var{A}\%\var{c}[0]}.
+
+If one of the operands in the arithmetic operations is integer 
+(a scalar \intgr\ or a matrix of type \itc) and the other operand 
+is double (a scalar \flt\ or a matrix of type \dtc), then the 
+integer operand is converted to double, and the result is a matrix of 
+type \dtc.
+If one of the operands is integer or double, and the other operand is 
+complex (a scalar \cmplx\ or a matrix of type \ztc), 
+then the first operand is converted to complex, and the result is 
+a matrix of type \ztc.  
+
+The result of \code{\var{A}**\var{d}} is a complex matrix
+if \var{A} or \var{d} are complex, and real otherwise.
+
+Note that Python rounds the result of an integer division towards minus 
+infinity.
+
+The following in-place operations are also defined, but only if 
+they do not change the type or the size of the matrix \var{A}: 
+\begin{center}\begin{tabular}{l|l}
+ In-place addition & 
+    \code{\var{A}+=\var{B}}, \code{\var{A}+=\var{c}} \\
+ In-place subtraction & 
+    \code{\var{A}-=\var{B}}, \code{\var{A}-=\var{c}} \\    
+ In-place scalar multiplication and division & 
+    \code{\var{A}*=\var{c}}, \code{\var{A}/=\var{c}} \\
+ In-place remainder & \code{\var{A}\%=\var{c}} 
+\end{tabular}\end{center}
+
+For example, if \var{A} has type \itc, then \code{\var{A}+=\var{B}} 
+is allowed if \var{B} has type \itc.
+It is not allowed if \var{B} has type \dtc or \ztc because the 
+addition \code{\var{A}+\var{B}} results in a matrix of 
+type \dtc or \ztc and therefore cannot be assigned to \var{A} 
+without changing its type.
+
+In-place matrix-matrix products are not allowed.  (Except when
+\var{c} is a 1 by 1 matrix, in which case \code{\var{A}*=\var{c}} is 
+interpreted as the scalar product \code{\var{A}*=\var{c}[0]}.)
+
+It is important to know when a matrix operation creates
+a new object.  The following rules apply.
+\begin{itemize}
+\item A simple assignment (\samp{A = B}) is given the standard 
+Python interpretation, \ie, it assigns to the variable \var{A} a 
+reference (or pointer) to the object referenced by \var{B}.
+\begin{verbatim}
+>>> B = matrix([[1.,2.], [3.,4.]])  
+>>> print B
+ 1.0000e+00   3.0000e+00
+ 2.0000e+00   4.0000e+00
+>>> A = B
+>>> A[0,0] = -1 
+>>> print B   # modifying A[0,0] also modified B[0,0]
+-1.0000e+00   3.0000e+00
+ 2.0000e+00   4.0000e+00
+\end{verbatim}
+
+\item The regular (\ie, not in-place) arithmetic operations always 
+return new objects.   Hence \samp{A = +B} is equivalent to 
+\samp{A = matrix(B)}.
+\begin{verbatim}
+>>> B = matrix([[1.,2.], [3.,4.]])  
+>>> A = +B
+>>> A[0,0] = -1 
+>>> print B   # modifying A[0,0] does not modify B[0,0]
+ 1.0000e+00   3.0000e+00
+ 2.0000e+00   4.0000e+00
+\end{verbatim}
+
+\item  The in-place operations directly modify the 
+ coefficients of the existing matrix object and do not create a new
+ object. 
+\begin{verbatim}
+>>> B = matrix([[1.,2.], [3.,4.]])  
+>>> A = B
+>>> A *= 2
+>>> print B   # in-place operation also changed B
+ 2.0000e+00   6.0000e+00
+ 4.0000e+00   8.0000e+00
+>>> A = 2*A
+>>> print B   # regular operation creates a new A, so does not change B
+ 2.0000e+00   6.0000e+00
+ 4.0000e+00   8.0000e+00
+\end{verbatim}
+\end{itemize}
+
+The restrictions on in-place operations follow the principle that once 
+a matrix object is created, its size and type cannot be modified.  
+The only matrix attributes that can be changed are the values of the 
+elements.  The values can be changed by in-place operations or by an 
+indexed assignment, as explained in the next section. 
+
+\section{Indexing and Slicing} \label{s-indexing}
+
+Matrices can be indexed using one or two arguments.  In single-argument
+indexing of a matrix \var{A}, the index runs from 
+\code{-len(\var{A})} to \code{len(\var{A})-1}, and is interpreted as an
+index in the one-dimensional array of coefficients of \var{A} 
+in column-major order.   Negative indices have the standard Python 
+interpretation: for negative \var{k}, \code{\var{A}[\var{k}]} is the 
+same element as  \code{\var{A}[len(\var{A})+\var{k}]}.
+
+Four different types of one-argument indexing are implemented.
+\begin{enumerate}
+\item The index can be a single integer.  This returns a 
+number, \eg, \code{\var{A}[0]} is the first element of \var{A}.
+
+\item The index can be an integer matrix.  This returns a 
+column matrix: the command \samp{A[matrix([0,1,2,3])]} 
+returns the 4 by 1 matrix consisting of the first four elements of
+\var{A}.   The size of the index matrix is ignored: 
+\samp{A[matrix([0,1,2,3], (2,2))]} returns the same 4 by 1 matrix.
+
+\item The index can be a list of integers.  This returns a column 
+matrix, \eg, \code{\var{A}[[0,1,2,3]]} is the 4 by 1 matrix consisting 
+of elements 0, 1, 2, 3 of \var{A}.   
+
+\item The index can be a Python slice.  This returns a matrix with one 
+column (possibly 0 by 1, or 1 by 1).  For example, \code{\var{A}[::2]} 
+is the column matrix defined by taking every other element of \var{A}, 
+stored in column-major order.  
+\code{\var{A}[0:0]} is a matrix with size (0,1).
+\end{enumerate}
+Thus, single-argument indexing returns a scalar (if the index is an 
+integer), or a matrix with one column.  This is consistent with the 
+interpretation that single-argument indexing accesses the matrix in 
+column-major order.
+
+Note that an index list or an index matrix are equivalent,
+but they are both useful, especially when we perform operations on 
+index sets.  For example, if \var{I} and \var{J} are lists then 
+\code{\var{I}+\var{J}} is the concatenated list, and \code{2*\var{I}} 
+is \var{I} repeated twice.  If they are matrices, these operations are 
+interpreted as arithmetic operations.
+For large index sets, indexing with integer matrices is also faster 
+than indexing with lists. 
+
+The following example illustrates one-argument indexing.
+\begin{verbatim}
+>>> from cvxopt.base import matrix 
+>>> A = matrix(range(16), (4,4), 'd')
+>>> print A
+   0.0000e+00   4.0000e+00   8.0000e+00   1.2000e+01
+   1.0000e+00   5.0000e+00   9.0000e+00   1.3000e+01
+   2.0000e+00   6.0000e+00   1.0000e+01   1.4000e+01
+   3.0000e+00   7.0000e+00   1.1000e+01   1.5000e+01
+>>> A[4]
+4.0
+>>> I = matrix([0, 5, 10, 15])
+>>> print A[I]      # the diagonal
+   0.0000e+00
+   5.0000e+00
+   1.0000e+01
+   1.5000e+01
+>>> I = [0,2];  J = [1,3]
+>>> print A[2*I+J]  # duplicate I and append J
+   0.0000e+00
+   2.0000e+00
+   0.0000e+00
+   2.0000e+00
+   1.0000e+00
+   3.0000e+00
+>>> I = matrix([0, 2]);  J =  matrix([1, 3])
+>>> print A[2*I+J]  # multiply I by 2 and add J
+   1.0000e+00
+   7.0000e+00
+>>> print A[4::4]   # get every fourth element skipping the first four  
+   4.0000e+00
+   8.0000e+00
+   1.2000e+01
+\end{verbatim}
+
+In two-argument indexing the arguments can be any combinations of the
+four types listed above.  The first argument indexes the rows of 
+the matrix and the second argument indexes the columns.  If both 
+indices are scalars, then a scalar is returned.  In all other cases, 
+a matrix is returned.  We continue the example.
+\begin{verbatim}
+>>> print A[:,1]
+   4.0000e+00
+   5.0000e+00
+   6.0000e+00
+   7.0000e+00
+>>> J = matrix([0, 2])
+>>> print A[J,J]
+   0.0000e+00   8.0000e+00
+   2.0000e+00   1.0000e+01
+>>> print A[:2, -2:]   
+   8.0000e+00   1.2000e+01
+   9.0000e+00   1.3000e+01
+\end{verbatim}
+
+Expressions of the form \code{\var{A}[\var{I}]} or 
+\code{\var{A}[\var{I},\var{J}]} can also appear on the lefthand side 
+of an assignment.   
+The righthand side must be a scalar (\ie, a number or a 1 by 1 dense
+matrix), a sequence of numbers, or a dense or sparse matrix. 
+If the righthand side is a scalar, it is interpreted as a 
+matrix with identical entries and the dimensions of the lefthand side.
+If the righthand side is a sequence of numbers (list, tuple, 
+\module{array} array, xrange object, \ldots) its values are 
+interpreted as the coefficients of the lefthand side in column-major 
+order.  If the righthand side is a matrix (\mtrx\ or \spmtrx), it must 
+have the same size as the lefthand side.  Sparse matrices are 
+converted to dense in the assignment.
+
+Indexed assignments are only allowed if they do not change the type of 
+the matrix.  For example, if \var{A} is a matrix with type \dtc, then 
+\code{\var{A}[\var{I}] = \var{B}} is only permitted if \var{B} is 
+an \intgr, a \flt, or a matrix of type \itc\ or \dtc.
+If \var{A} is an integer matrix, then \code{\var{A}[\var{I}] = \var{B}} 
+is only permitted if \var{B} is an \intgr\  or an integer matrix.
+
+The following example illlustrates indexed assignment.
+\begin{verbatim}
+>>> A = matrix(range(16), (4,4))
+>>> A[::2,::2] = matrix([[-1, -2], [-3, -4]])
+>>> print A
+  -1      4     -3      12
+   1      5      9      13
+  -2      6     -4      14
+   3      7      11     15
+>>> A[::5] += 1
+>>> print A
+   0      4     -3      12
+   1      6      9      13
+  -2      6     -3      14
+   3      7      11     16
+>>> A[0,:] = -1, 1, -1, 1
+>>> print A
+  -1      1     -1      1 
+   1      6      9      13
+  -2      6     -3      14
+   3      7      11     16
+>>> A[2:,2:] = xrange(4)
+>>> print A
+  -1      1     -1      1 
+   1      6      9      13
+  -2      6      0      2
+   3      7      1      3
+\end{verbatim}
+
+\section{Built-in Functions} \label{s-builtinfuncs}
+Many Python built-in functions and operations can be used with matrix 
+arguments.  We list some useful examples.
+
+\begin{funcdesc}{len}{x}
+Returns the product of the number of rows and the number of columns. 
+\end{funcdesc}
+
+\begin{funcdesc}{bool}{\optional{x}}
+Returns \False\ if \var{x} is empty (\ie, \code{len(\var{x})} is zero) 
+and \True\ otherwise.
+\end{funcdesc}
+
+\begin{funcdesc}{max}{x}
+Returns the maximum element of \var{x}.
+\end{funcdesc}
+
+\begin{funcdesc}{min}{x}
+Returns the minimum element of \var{x}.
+\end{funcdesc}
+
+\begin{funcdesc}{abs}{x}
+Returns a matrix with the absolute values of the elements of \var{x}.
+\end{funcdesc}
+
+\begin{funcdesc}{sum}{x\optional{, start=0.0}}
+Returns the sum of \var{start} and the elements of \var{x}.
+\end{funcdesc}
+
+Matrices can be used as  arguments to the \function{list()}, 
+\function{tuple()}, \function{zip()}, \function{map()}, and 
+\function{filter()} functions described in section 2.1 of the Python 
+Library Reference.  \code{list(\var{A})} and \code{tuple(\var{A})} 
+construct a list, respectively a tuple, from the elements of \var{A}.
+\code{zip(\var{A},\var{B},\ldots)} returns a list of tuples, 
+with the {\it i}th tuple containing the {\it i}th elements of \var{A}, 
+\var{B}, \ldots.
+
+\begin{verbatim}
+>>> from cvxopt.base import matrix
+>>> A = matrix([[-11., -5., -20.], [-6., -0., 7.]])
+>>> B = matrix(range(6), (3,2))
+>>> list(A)
+[-11.0, -5.0, -20.0, -6.0, 0.0, 7.0]
+>>> tuple(B)
+(0, 1, 2, 3, 4, 5)
+>>> zip(A,B)
+[(-11.0, 0), (-5.0, 1), (-20.0, 2), (-6.0, 3), (0.0, 4), (7.0, 5)]
+\end{verbatim}
+
+\code{map(\var{f},\var{A})}, where \var{f} is a function and \var{A} 
+is a matrix, returns a list constructed by applying \var{f} to each 
+element of \var{A}.  Multiple arguments can be provided, for example, 
+as in \code{map(\var{f},\var{A},\var{B})}, if \var{f} is a function 
+with two arguments.
+\begin{verbatim}
+>>> A = matrix([[5, -4, 10, -7], [-1, -5, -6, 2], [6, 1, 5, 2],  [-1, 2, -3, -7]])
+>>> B = matrix([[4,-15, 9, -14], [-4, -12, 1, -22], [-10, -9, 9, 12], [-9, -7,-11, -6]])
+>>> print matrix(map(max, A, B), (4,4))   # takes componentwise maximum
+   5     -1      6     -1
+  -4     -5      1      2
+   10     1      9     -3
+  -7      2      12    -6
+\end{verbatim}
+
+\code{filter(\var{f},\var{A})}, where \var{f} is a function and 
+\var{A} is a matrix, returns a list containing the elements of \var{A} 
+for which \var{f} is true.
+\begin{verbatim}
+>>> print filter(lambda x: x%2, A)         # list of odd elements in A
+[5, -7, -1, -5, 1, 5, -1, -3, -7]
+>>> print filter(lambda x: -2 < x < 3, A)  # list of elements between -2 and 3
+[-1, 2, 1, 2, -1, 2]
+\end{verbatim}
+
+It is also possible to iterate over matrix elements, as illustrated in
+the following example.
+\begin{verbatim}
+>>> A = matrix([[5, -3], [9, 11]])
+>>> for x in A: print max(x,0)
+...
+5
+0
+9
+11
+>>> [max(x,0) for x in A]
+[5, 0, 9, 11]
+\end{verbatim}
+
+The expression \samp{\var{x} in \var{A}} returns \True\ if an element 
+of \var{A} is equal to \var{x} and \False\ otherwise.
+
+\section{Other Matrix Functions} \label{s-otherfuncs}
+The following functions of dense matrices can be imported from 
+\module{cvxopt.base}.
+\begin{funcdesc}{sqrt}{x}
+The elementwise square root of \var{x}.  The result is returned 
+as a real matrix if \var{x} is an integer or real matrix and 
+as a complex matrix if \var{x} is a complex matrix.  Raises an 
+exception when \var{x} is an integer or real matrix with negative 
+elements.
+\end{funcdesc}
+
+\begin{funcdesc}{sin}{x}
+The sine function applied elementwise to \var{x}.  
+The result is returned as a real matrix if \var{x} is an integer
+or real matrix and as a complex matrix otherwise.  
+\end{funcdesc}
+
+\begin{funcdesc}{cos}{x}
+The cosine function applied elementwise to \var{x}.  
+The result is returned as a real matrix if \var{x} is an integer
+or real matrix and as a complex matrix otherwise.  
+\end{funcdesc}
+
+\begin{funcdesc}{exp}{x}
+The exponential function applied elementwise to \var{x}.  
+The result is returned as a real matrix if \var{x} is an integer 
+or real matrix and as a complex matrix otherwise.  
+\end{funcdesc}
+
+\begin{funcdesc}{log}{x}
+The natural logarithm applied elementwise to \var{x}.  
+The result is returned as a real matrix if \var{x} is an integer
+or real matrix and as a complex matrix otherwise.  
+Raises an exception when \var{x} is an integer or real matrix with 
+nonnegative elements, or a complex matrix with zero elements.
+\end{funcdesc}
+
+\begin{funcdesc}{mul}{x, y}
+The elementwise product of \var{x} and \var{y}.  
+The two matrices must have the same size and type.
+\end{funcdesc}
+
+\begin{funcdesc}{div}{x, y}
+The elementwise division of \var{x} by \var{y}.  
+The two matrices must have the same size and type.
+\end{funcdesc}
+
+
+\section{Randomly Generated Matrices} \label{s-random}
+The module \module{cvxopt.random} provides functions for generating
+random matrices.  Two types of random matrices are defined:
+matrices with normally distributed entries and matrices with uniformly 
+distributed entries.   
+
+The pseudo-random number generators used to 
+generate the random matrices are from the package described in the 
+references below.  
+\begin{seealso}
+\seelink{http://www.cs.wm.edu/\~{}va/software/park/park.html}
+{S. Park, Random Number Generators.}{}
+
+\seealso{S. Park, D. Geyer, Random Number Generators: Good Ones Are 
+Hard To Find,
+Communications of the ACM, October 1988.}
+\end{seealso}
+
+\begin{funcdesc}{normal}{nrows\optional{, ncols\optional{, 
+ mean\optional{, std}}}}
+Returns a type \dtc\ matrix of size \var{nrows} by 
+\var{ncols} with random elements chosen from a normal distribution 
+with mean \var{mean} and standard deviation \var{std}.
+The default values for the optional arguments are 
+\var{ncols}=1, \var{mean}=0.0, \var{std}=1.0.
+\end{funcdesc}
+
+\begin{funcdesc}{uniform}{nrows\optional{, ncols\optional{, 
+  a\optional{, b}}}}
+Returns a type \dtc\ matrix of size \var{nrows} by 
+\var{ncols} matrix with random elements, uniformly distributed 
+between \var{a} and \var{b}.
+The default values for the optional arguments are 
+\var{ncols}=1, \var{a}=0.0, \var{b}=1.0.
+\end{funcdesc}
+
+\begin{funcdesc}{getseed}{}
+Returns the current seed value (the state of the random number 
+generator).
+\end{funcdesc}
+
+\begin{funcdesc}{setseed}{\optional{value}}
+Sets the seed value.  \var{value} must be a nonnegative integer.
+If \var{value} is absent or equal to zero, the seed value is taken 
+from the system clock.  
+\end{funcdesc}
+
+\section{The NumPy Array Interface} \label{s-array-interface}
+
+The CVXOPT \mtrx\ object is compatible with the NumPy Array Interface, 
+which allows Python objects that represent multidimensional 
+arrays to exchange data using information stored in the 
+attribute \code{\_\_array\_struct\_\_}.  
+
+\begin{seealso}
+\seelink{http://numpy.scipy.org/array_interface.shtml}
+{NumPy Array Interface Specification}{}
+
+\seelink{http://numpy.scipy.org}{NumPy home page}{}
+\end{seealso}
+
+As already mentioned in section~\ref{s-creating-matrices},
+a two-dimensional array object (for example, a 2D \module{numarray} 
+array) can be converted to a \mtrx\ object by using the 
+\function{matrix()} constructor.
+Conversely, CVXOPT matrices can be used as array-like objects
+in \module{numarray}.  The following example illustrates the 
+compatibility of CVXOPT matrices and \module{numarray} arrays. 
+\begin{verbatim}
+>>> from cvxopt import matrix
+>>> a = matrix(range(6), (2,3), 'd')
+>>> print a
+   0.0000e+00   2.0000e+00   4.0000e+00
+   1.0000e+00   3.0000e+00   5.0000e+00
+>>> from numarray import array
+>>> b = array(a)
+>>> print b
+[[ 0.  2.  4.]
+ [ 1.  3.  5.]]
+>>> print a*b
+[[  0.   4.  16.]
+ [  1.   9.  25.]]
+\end{verbatim}
+In the last expression \code{a*b} is interpreted as a \module{numarray}
+multiplication (\ie, componentwise) even though one operand is a 
+\mtrx\ object.
+
+\section{Printing Options}
+The format used for printing dense matrices (and the sparse matrices 
+discussed in chapter~\ref{chap:spmatrix}) is controlled
+by the dictionary \member{cvxopt.base.print\_options}.  The dictionary 
+has three keys, \code{'iformat'}, \code{'dformat'}, \code{'zformat'} 
+that control, respectively, how integer, double and complex numbers are 
+printed.  The fields are C printf format strings with default 
+values \code{'5.4e'}\ for \dtc\ and \ztc\ matrices and \code{'5i'}\ for 
+\itc\ matrices.
+\begin{verbatim}
+>>> from cvxopt.base import matrix, print_options
+>>> print_options
+{'zformat': '5.4e', 'iformat': '5i', 'dformat': '5.4e'}
+>>> A = matrix([1., 2., 3.])
+>>> print A
+   1.0000e+00
+   2.0000e+00
+   3.0000e+00
+>>> print_options['dformat'] = 'f'
+>>> print A
+   1.000000
+   2.000000
+   3.000000
+>>> print_options['dformat'] = '5.2e'
+>>> print A
+   1.00e+00
+   2.00e+00
+   3.00e+00
+\end{verbatim}
diff --git a/doc/base_sparse.tex b/doc/base_sparse.tex
new file mode 100644
index 0000000..d0d7c6b
--- /dev/null
+++ b/doc/base_sparse.tex
@@ -0,0 +1,712 @@
+\chapter{Sparse Matrices (\module{cvxopt.base})}\label{chap:spmatrix}
+
+In this chapter we discuss the \spmtrx\ object defined in 
+\module{cvxopt.base}.
+
+\section{Creating Sparse Matrices} \label{s-creating-spmatrix}
+A general \spmtrx\ object can be thought of as a \emph{triplet 
+description} of a sparse matrix, \ie, a list of entries of the matrix, 
+with for each entry the value, row index, and column index.  
+Entries that are not included in the list are assumed to be zero.  
+For example, the sparse matrix
+\BEQ \label{e-sparse-A}
+ A = \left[ \begin{array}{rrrrr}
+  0 & 2 & 0 & 0 & 3 \\
+  2 & 0 & 0 & 0 & 0 \\
+ -1 & -2 & 0 & 4 & 0 \\
+  0 & 0 & 1 & 0 & 0 \end{array} \right]
+\EEQ
+has the triplet description 
+\[
+(2,1,0), \qquad (-1,2,0), \qquad (2,0,1), \qquad (-2,2,1), \qquad
+(1,3,2), \qquad (4,2,3), \qquad (3,0,4).
+\]
+The list may include entries with a zero value, so triplet
+descriptions are not necessarily unique.
+The list
+\[
+(2,1,0), \qquad (-1,2,0), \qquad (0,3,0), \qquad (2,0,1), \qquad 
+ (-2,2,1), \qquad (1,3,2), \qquad (4,2,3), \qquad (3,0,4)
+\]
+is another triplet description of the same matrix.
+
+An \spmtrx\ object corresponds to a particular triplet 
+description of a sparse matrix.  We will refer to the entries in
+the triplet description as the \emph{nonzero entries} of the object, 
+even though they may have a numerical value zero.
+
+Two functions are provided to create sparse matrices. 
+The first, \function{spmatrix()}, constructs a sparse matrix from 
+a triplet description. 
+\begin{funcdesc}{spmatrix}{x, I, J\optional{, size\optional{, tc}}}
+
+\var{I} and \var{J} are sequences of integers (lists, tuples, 
+\module{array} arrays, xrange objects, \ldots) or integer matrices 
+(\mtrx\ objects with typecode \itc), containing the row and column 
+indices of the nonzero entries.  
+The lengths of \var{I} and \var{J} must be  equal.  If they 
+are matrices, they are treated as lists of indices stored in 
+column-major order, \ie, as lists \code{list(\var{I})}, respectively, 
+\code{list(\var{J})}. 
+
+\var{size} is a tuple of nonnegative integers with the row and column 
+dimensions of the matrix.
+The \var{size} argument is only needed when creating a matrix with 
+a zero last row or last column.  If \var{size} is not specified, it 
+is determined from \var{I} and \var{J}:
+the default value for \code{\var{size}[0]} is \code{max(\var{I})+1} 
+if \var{I} is nonempty and zero otherwise.  
+The default value for \code{\var{size}[1]} is 
+\code{max(\var{J})+1} if \var{J} is nonempty and zero otherwise.
+
+\var{tc} is the typecode, \dtc\ or \ztc, for double and complex 
+matrices, respectively.   Integer sparse matrices are not implemented.
+
+\var{x} can be a number, a sequence of numbers, or a dense matrix.  
+This argument specifies the numerical values of the nonzero entries.
+\BIT
+\item If \var{x} is a number (Python \intgr, \flt\ or \cmplx), 
+a matrix is created with the sparsity pattern defined by \var{I} and 
+\var{J}, and nonzero entries initialized to the value of \var{x}.  
+The default value of \var{tc} is \dtc\ if \var{x} is \intgr\ or \flt,
+and \ztc\ if \var{x} is \cmplx.  
+
+The following code creates a 4 by 4 sparse identity matrix.
+\begin{verbatim}
+>>> from cvxopt.base import spmatrix
+>>> A = spmatrix(1.0, range(4), range(4))
+>>> print A  
+SIZE: (4,4)
+(0, 0)  1.0000e+00
+(1, 1)  1.0000e+00
+(2, 2)  1.0000e+00
+(3, 3)  1.0000e+00
+\end{verbatim}
+
+\item If \var{x} is a sequence of numbers, a sparse matrix is created 
+with the entries of \var{x} copied to the entries indexed by \var{I} 
+and \var{J}.  The list \var{x} must have the same length as \var{I} and 
+\var{J}.
+The default value of \var{tc} is determined from the elements of 
+\var{x}: 
+\dtc\ if \var{x} contains integers and floating-point numbers or
+if \var{x} is an empty list,
+and \ztc\ if \var{x} contains at least one complex number.
+
+As an example, the matrix~(\ref{e-sparse-A}) can be created as follows.
+\begin{verbatim}
+>>> A = spmatrix([2,-1,2,-2,1,4,3], [1,2,0,2,3,2,0], [0,0,1,1,2,3,4])
+>>> print A 
+SIZE: (4,5)
+(1, 0)  2.0000e+00
+(2, 0) -1.0000e+00
+(0, 1)  2.0000e+00
+(2, 1) -2.0000e+00
+(3, 2)  1.0000e+00
+(2, 3)  4.0000e+00
+(0, 4)  3.0000e+00
+\end{verbatim}
+
+\item If \var{x} is a dense matrix, a sparse matrix is created with 
+all the entries of \var{x} copied, in column-major order, to the 
+entries indexed by \var{I} and \var{J}.
+The matrix \var{x} must have the same length as \var{I} and \var{J}.
+The default value of \var{tc} is \dtc\ if \var{x} is an \itc\ or \dtc\
+matrix, and \ztc\ otherwise.
+\EIT
+
+If \var{I} and \var{J} contain repeated entries, the corresponding 
+values of the coefficients are added.
+\end{funcdesc}
+
+The function \function{sparse()} constructs a sparse matrix from
+a block-matrix description.
+   
+\begin{funcdesc}{sparse}{x\optional{, tc}}
+\var{tc} is the typecode, \dtc\ or \ztc, for double and complex 
+matrices, respectively.
+  
+\var{x} can be a \mtrx, \spmtrx, or a list of lists of matrices 
+(\mtrx\ or \spmtrx\ objects) and numbers (Python \intgr, \flt\ or 
+\cmplx). 
+\BIT
+\item If \var{x} is a \mtrx\ or \spmtrx\ object, then a sparse matrix 
+of the same size and the same numerical value is created. 
+Numerical zeros in \var{x} are treated as structural zeros and removed 
+from the triplet description of the new sparse matrix.
+
+\item If \var{x} is a list of lists of matrices (\mtrx\ or \spmtrx) 
+and numbers (Python \intgr, \flt\ or \cmplx) then each element of 
+\var{x} is interpreted as a (block-)column matrix stored in 
+colum-major order, and a block-matrix is constructed by juxtaposing
+the \code{len(\var{x})} block-columns
+(as in \function{matrix()}, see section~\ref{s-creating-matrices}). 
+Numerical zeros are removed from the triplet description of the new 
+matrix.  
+
+The following example shows how to construct a sparse block-matrix.
+\begin{verbatim}
+>>> from cvxopt.base import matrix, spmatrix, sparse
+>>> A = matrix([[1, 2, 0], [2, 1, 2], [0, 2, 1]])
+>>> B = spmatrix([], [], [], (3,3))
+>>> C = spmatrix([3, 4, 5], [0, 1, 2], [0, 1, 2])
+>>> print sparse([[A, B], [B, C]])
+SIZE: (6,6)
+(0, 0)  1.0000e+00
+(1, 0)  2.0000e+00
+(0, 1)  2.0000e+00
+(1, 1)  1.0000e+00
+(2, 1)  2.0000e+00
+(1, 2)  2.0000e+00
+(2, 2)  1.0000e+00
+(3, 3)  3.0000e+00
+(4, 4)  4.0000e+00
+(5, 5)  5.0000e+00
+\end{verbatim}
+
+A matrix with a single block-column can be represented by a single
+list.
+\begin{verbatim}
+>>> print sparse([A, C])
+SIZE: (6,3)
+(0, 0)  1.0000e+00
+(1, 0)  2.0000e+00
+(3, 0)  3.0000e+00
+(0, 1)  2.0000e+00
+(1, 1)  1.0000e+00
+(2, 1)  2.0000e+00
+(4, 1)  4.0000e+00
+(1, 2)  2.0000e+00
+(2, 2)  1.0000e+00
+(5, 2)  5.0000e+00
+\end{verbatim}
+\EIT
+
+\end{funcdesc}
+
+\section{Attributes and Methods}
+The following attributes and methods are defined for \spmtrx\ objects.
+
+\begin{memberdesc}[matrix]{V}
+A single-column dense matrix containing the numerical values of the 
+nonzero entries in column-major order.  Making an assignment to 
+the attribute is an efficient way of changing the values of the sparse 
+matrix, without changing the sparsity pattern.
+
+When the attribute \member{V} is read, a \emph{copy} of \member{V} is 
+returned, as a new dense matrix. 
+(This implies, for example, that an indexed assignment 
+\samp{A.V[I] = B} does not work, or at least 
+cannot be used to modify \var{A}.  Instead the attribute \code{V}\ 
+will be read and returned as a new matrix; then the elements of this 
+new matrix are modified.)
+\end{memberdesc} 
+
+\begin{memberdesc}[spmatrix]{I}
+A single-column integer matrix with the row indices of the entries in
+\code{V}.  A read-only attribute.
+\end{memberdesc} 
+
+\begin{memberdesc}[matrix]{J}
+A single-column integer matrix with the column indices of the entries
+in \code{V}.  A read-only attribute.
+\end{memberdesc} 
+
+\begin{memberdesc}[tuple]{size}
+A tuple with the dimensions of the matrix.  A read-only attribute.
+\end{memberdesc} 
+
+\begin{methoddesc}{trans}{}
+Returns the transpose of a sparse matrix as a new sparse matrix.
+One can also use \code{A.T} instead of \code{A.trans()}.
+\end{methoddesc}
+
+\begin{methoddesc}{ctrans}{}
+Returns the complex conjugate transpose of a sparse matrix as a 
+new sparse matrix.
+One can also use \code{A.H} instead of \code{A.ctrans()}. 
+\end{methoddesc}
+
+In the following example we take the elementwise square root of 
+the matrix
+\BEQ \label{e-spA-example}
+ A = \left[ \begin{array}{rrrrr}
+  0 & 2 & 0 & 0 & 3 \\
+  2 & 0 & 0 & 0 & 0 \\
+  1 & 2 & 0 & 4 & 0 \\
+  0 & 0 & 1 & 0 & 0 \end{array} \right]
+\EEQ
+\begin{verbatim}
+>>> from cvxopt.base import sqrt
+>>> A = spmatrix([2,1,2,2,1,3,4], [1,2,0,2,3,0,2], [0,0,1,1,2,3,3]) 
+>>> B = spmatrix(sqrt(A.V), A.I, A.J)
+>>> print B
+SIZE: (4,4)
+(1, 0)  1.4142e+00
+(2, 0)  1.0000e+00
+(0, 1)  1.4142e+00
+(2, 1)  1.4142e+00
+(3, 2)  1.0000e+00
+(0, 3)  1.7321e+00
+(2, 3)  2.0000e+00
+\end{verbatim}
+
+The next example below illustrates assignments to \member{V}.
+\begin{verbatim}
+>>> from cvxopt.base import spmatrix, matrix
+>>> A = spmatrix(range(5), [0,1,1,2,2], [0,0,1,1,2])
+>>> print A
+SIZE: (3,3)
+(0, 0)  0.0000e+00
+(1, 0)  1.0000e+00
+(1, 1)  2.0000e+00
+(2, 1)  3.0000e+00
+(2, 2)  4.0000e+00
+>>> B = spmatrix(A.V, A.J, A.I, (4,4))  # transpose and add a zero row and column
+>>> print B
+SIZE: (4,4)
+(0, 0)  0.0000e+00
+(0, 1)  1.0000e+00
+(1, 1)  2.0000e+00
+(1, 2)  3.0000e+00
+(2, 2)  4.0000e+00
+>>> print matrix(B)
+ 0.0000e+00   1.0000e+00   0.0000e+00   0.0000e+00
+ 0.0000e+00   2.0000e+00   3.0000e+00   0.0000e+00
+ 0.0000e+00   0.0000e+00   4.0000e+00   0.0000e+00
+ 0.0000e+00   0.0000e+00   0.0000e+00   0.0000e+00
+>>> B.V[:] = 1., 7., 8., 6., 4.   # assign new values to nonzero entries
+>>> print B
+SIZE: (4,4)
+(0, 0)  1.0000e+00
+(0, 1)  7.0000e+00
+(1, 1)  8.0000e+00
+(1, 2)  6.0000e+00
+(2, 2)  4.0000e+00
+>>> B.V += 1.0   # add 1 to the nonzero entries
+>>> print B
+SIZE: (4,4)
+(0, 0)  2.0000e+00
+(0, 1)  8.0000e+00
+(1, 1)  9.0000e+00
+(1, 2)  7.0000e+00
+(2, 2)  5.0000e+00
+\end{verbatim}
+
+The \member{V}, \member{I} and \member{J}  attributes can be used for 
+reading sparse matrices from or writing them to binary files.  
+Suppose we want to write the matrix \var{A} defined above to a binary 
+file.
+\begin{verbatim}
+>>> f = open('test.bin','w')
+>>> A.V.tofile(f)  
+>>> A.I.tofile(f) 
+>>> A.J.tofile(f)
+>>> f.close()
+\end{verbatim}
+A sparse matrix can be created from this file as follows.
+\begin{verbatim}
+>>> f = open('test.bin','r')
+>>> V = matrix(0.0, (5,1));  V.fromfile(f)  
+>>> I = matrix(0, (5,1));  I.fromfile(f)  
+>>> J = matrix(0, (5,1));  J.fromfile(f)  
+>>> B = spmatrix(V, I, J)
+>>> print B
+SIZE: (3,3)
+(0, 0)  0.0000e+00
+(1, 0)  1.0000e+00
+(1, 1)  2.0000e+00
+(2, 1)  3.0000e+00
+(2, 2)  4.0000e+00
+\end{verbatim}
+
+Note that the  \module{pickle} module provides a convenient alternative 
+to this method.
+
+\section{Arithmetic Operations} \label{s-spmatrix-arith}
+Most of the operations defined for dense \dtc\ and \ztc\ matrices
+(section~\ref{s-arithmetic}) are also defined for sparse matrices.
+In the following table, \var{A} is a sparse matrix,
+\var{B} is sparse or dense, and \var{c} is a scalar, defined as a
+Python number or a 1 by 1 dense matrix.
+
+\begin{center}
+\begin{tabular}{l|l}
+ Unary plus/minus & \code{+\var{A}}, \code{-\var{A}} \\
+ Addition & \code{\var{A}+\var{B}}, \code{\var{B}+\var{A}}, 
+   \code{\var{A}+\var{c}}, \code{\var{c}+\var{A}}\\
+ Subtraction & \code{\var{A}-\var{B}}, \code{\var{B}-\var{A}}, 
+    \code{\var{A}-\var{c}}, \code{\var{c}-\var{A}}\\
+ Matrix multiplication & \code{\var{A}*\var{B}}, 
+  \code{\var{B}*\var{A}} \\
+ Scalar multiplication and division & \code{\var{c}*\var{A}}, 
+   \code{\var{A}*\var{c}}, \code{\var{A}/\var{c}}
+ \end{tabular}
+\end{center}
+
+If \var{B} is a dense matrix, then the result of 
+\code{\var{A}+\var{B}}, \code{\var{B}+\var{A}}, \code{\var{A}-\var{B}}, 
+\code{\var{B}-\var{A}} is a dense  matrix.
+The typecode of the result is \dtc\ if \var{A} has typcode \dtc\ and 
+\var{B} has typecode \itc\ or \dtc,
+and it is \ztc\ if \var{A} and/or \var{B} have typecode \ztc.
+
+If \var{B} is a sparse matrix, then the result of
+\code{\var{A}+\var{B}}, \code{\var{B}+\var{A}}, 
+\code{\var{A}-\var{B}}, \code{\var{B}-\var{A}} is a sparse 
+matrix.  The typecode of the result is \dtc\ if \var{A} and \var{B}
+have typecode \dtc,  and \ztc\ otherwise.
+
+If \var{c} in \code{\var{A}+\var{c}}, \code{\var{A}-\var{c}}, 
+\code{\var{c}+\var{A}}, \code{\var{c}-\var{A}} is a number,
+then it is interpreted as a dense matrix with the same size as 
+\var{A}, typecode given by the type of \var{c}, and all entries equal 
+to \var{c}. 
+If \var{c} is a 1 by 1 dense matrix and the size of \var{A} is not 1 
+by 1, then \var{c}
+is interpreted as a dense matrix of the same size as \var{A},
+typecode given by the typecode of \var{c}, and all entries equal to 
+\code{\var{c}[0]}.
+
+The result of a matrix-matrix product \code{\var{A}*\var{B}} or 
+\code{\var{B}*\var{A}} is a dense matrix if \var{B} is dense, and sparse
+if \var{B} is sparse.   The matrix-matrix product is not allowed if 
+\var{B} is a dense \itc\ matrix.  
+
+If \var{c} is a number (Python \intgr\, \flt\ or \cmplx), then the 
+operations \code{\var{c}*\var{A}} and \code{\var{A}*\var{c}} define 
+scalar multiplication and return a sparse matrix.
+
+If \var{c} is a 1 by 1 dense matrix, then, if possible, the products 
+\code{\var{c}*\var{A}} and \code{\var{A}*\var{c}} are interpreted as 
+matrix-matrix products and a dense matrix is returned.  
+If the product cannot be interpreted as a matrix-matrix product
+(either because the dimensions of \var{A} are incompatible or because
+\var{c} has typecode \itc), then the product is interpreted as the 
+scalar multiplication with \code{\var{c}[0]} and a sparse matrix is 
+returned.
+
+The division \code{\var{A}/\var{c}} is interpreted as scalar 
+multiplication with \code{1.0/\var{c}} if \var{c} is a number, 
+or with  \code{1.0/\var{c}[0]} if \var{c} is a 1 by 1 dense matrix.
+
+The following in-place operations are defined for a sparse matrix 
+\var{A} if they do not change the dimensions or type of \var{A}.
+\begin{center}
+  \begin{tabular}{l|l}
+  In-place addition & \code{\var{A}+=\var{B}}, 
+    \code{\var{A}+=\var{c}} \\    
+  In-place subtraction & \code{\var{A}-=\var{B}}, 
+    \code{\var{A}-=\var{c}} \\    
+  In-place scalar multiplication and division & 
+    \code{\var{A}*=\var{c}}, \code{\var{A}/=\var{c}} 
+  \end{tabular}
+\end{center}
+
+For example, \samp{\var{A} += 1.0} is not allowed because the 
+operation \samp{\var{A} = \var{A} + 1.0} results in a dense matrix, 
+so it cannot be assigned to \var{A} without changing its type.
+
+In-place matrix-matrix products are not allowed.  (Except when
+\var{c} is a 1 by 1 dense matrix, in which case \code{\var{A}*=\var{c}} 
+is interpreted as a scalar product \code{\var{A}*=\var{c}[0]}.)
+
+As for dense operations, the in-place sparse operations do not return
+a new matrix but modify the existing object \var{A}.
+The restrictions on in-place operations follow the principle that once 
+a sparse matrix is created, its size and type cannot be modified.  
+The only attributes that can be modified are the sparsity pattern and 
+the numerical values of the nonzero elements.
+These attributes can be modified by in-place operations or by indexed 
+assignments.
+
+
+
+\section{Indexing and Slicing} 
+Sparse matrices can be indexed the same way as dense matrices 
+(see section~\ref{s-indexing} ).  
+
+\begin{verbatim}
+>>> from cvxopt.base import spmatrix
+>>> A = spmatrix([0,2,-1,2,-2,1], [0,1,2,0,2,1], [0,0,0,1,1,2]) 
+>>> print A[:,[0,1]]
+SIZE: (3,2)
+(0, 0)  0.0000e+00
+(1, 0)  2.0000e+00
+(2, 0) -1.0000e+00
+(0, 1)  2.0000e+00
+(2, 1) -2.0000e+00
+>>> B = spmatrix([0,2*1j,0,-2], [1,2,1,2], [0,0,1,1,])
+>>> print B[-2:,-2:]
+SIZE: (2,2)
+(0, 0)  0.0000e+00-j0.0000e+00
+(1, 0)  2.0000e+00-j0.0000e+00
+(0, 1)  0.0000e+00-j0.0000e+00
+(1, 1)  0.0000e+00-j2.0000e+00
+\end{verbatim}
+
+An indexed sparse matrix \code{\var{A}[\var{I}]} or 
+\code{\var{A}[\var{I},\var{J}]} can also be the target of an 
+assignment.  The righthand side of the assignment can be a scalar
+(a Python \intgr, \flt, or \cmplx,  or a 1 by 1 dense matrix),
+a sequence of numbers, or a sparse or dense matrix of 
+compatible dimensions. 
+If the righthand side is a scalar, it is treated as a dense matrix of 
+the same size as the lefthand side and with all its entries equal to 
+the scalar. 
+If the righthand side is a sequence of numbers, they are treated as
+the elements of a dense matrix in column-major order. 
+
+We continue the example above.
+\begin{verbatim}
+>>> C = spmatrix([10,-20,30], [0,2,1], [0,0,1])
+>>> A[:,0] = C[:,0]
+>>> print A
+SIZE: (3,3)
+(0, 0)  1.0000e+01
+(2, 0) -2.0000e+01
+(0, 1)  2.0000e+00
+(2, 1) -2.0000e+00
+(1, 2)  1.0000e+00
+>>> D = matrix(range(6), (3,2))
+>>> A[:,0] = D[:,0]
+>>> print A
+SIZE: (3,3)
+(0, 0)  0.0000e+00
+(1, 0)  1.0000e+00
+(2, 0)  2.0000e+00
+(0, 1)  2.0000e+00
+(2, 1) -2.0000e+00
+(1, 2)  1.0000e+00
+>>> A[:,0] = 1
+>>> print A
+SIZE: (3,3)
+(0, 0)  1.0000e+00
+(1, 0)  1.0000e+00
+(2, 0)  1.0000e+00
+(0, 1)  2.0000e+00
+(2, 1) -2.0000e+00
+(1, 2)  1.0000e+00
+>>> A[:,0] = 0
+>>> print A
+TYPE: (3,3)
+(0, 0)  0.0000e+00
+(1, 0)  0.0000e+00
+(2, 0)  0.0000e+00
+(0, 1)  2.0000e+00
+(2, 1) -2.0000e+00
+(1, 2)  1.0000e+00
+\end{verbatim}
+
+
+\section{Built-In Functions}
+
+The functions described in the table of section~\ref{s-builtinfuncs} 
+also work with sparse matrix arguments.  The difference is that for a 
+sparse matrix only the nonzero entries are considered. 
+
+\begin{funcdesc}{len}{x}
+If \var{x} is a \spmtrx, returns the number of nonzero entries in
+\var{x}.
+\end{funcdesc}
+
+\begin{funcdesc}{bool}{\optional{x}}
+If \var{x} is a \spmtrx, returns \False\ if \var{x} has at least one 
+nonzero entry; \False\ otherwise.
+\end{funcdesc}
+
+\begin{funcdesc}{max}{x}
+If \var{x} is a \spmtrx, returns the maximum nonzero entry of \var{x}.
+\end{funcdesc}
+
+\begin{funcdesc}{min}{x}
+If \var{x} is a \spmtrx, returns the minimum nonzero entry of \var{x}.
+\end{funcdesc}
+
+\begin{funcdesc}{abs}{x}
+If \var{x} is a \spmtrx, returns a sparse matrix with the absolute
+value of the elements of \var{x} and the same sparsity pattern.
+\end{funcdesc}
+
+\begin{funcdesc}{sum}{x\optional{, start=0.0}}
+If \var{x} is a \spmtrx, returns the sum of \var{start} and the 
+elements of \var{x}.
+\end{funcdesc}
+
+The functions \function{list()}, \function{tuple()}, \function{zip()}, 
+\function{map()}, \function{filter()} also take sparse matrix arguments.
+They work as for dense matrices, again with the difference that only 
+the nonzero entries are considered.
+
+In the following example we square the entries of the 
+matrix~(\ref{e-spA-example}). 
+
+\begin{verbatim}
+>>> A = spmatrix([2,1,2,2,1,3,4], [1,2,0,2,3,0,2], [0,0,1,1,2,3,3]) 
+>>> B = spmatrix(map(lambda x: x**2, A), A.I, A.J)
+>>> print B
+SIZE: (4,4)
+(1, 0)  4.0000e+00
+(2, 0)  1.0000e+00
+(0, 1)  4.0000e+00
+(2, 1)  4.0000e+00
+(3, 2)  1.0000e+00
+(0, 3)  9.0000e+00
+(2, 3)  1.6000e+01
+\end{verbatim}
+
+The expression \samp{\var{x} in \var{A}} returns \True\  if a nonzero
+entry of \var{A} is equal to \var{x} and \False\ otherwise.
+
+
+\section{Sparse BLAS Functions}
+The \module{cvxopt.base} module includes a few arithmetic functions 
+that extend functions from \module{cvxopt.blas} to sparse matrices.
+These functions are faster than the corresponding operations 
+implemented using the overloaded arithmetic described 
+in~section~\ref{s-spmatrix-arith}.
+They also work in-place, \ie, they modify their arguments without 
+creating new objects.
+
+
+\begin{funcdesc}{gemv}{A, x, y\optional{, trans='N'\optional{, 
+  alpha=1.0\optional{, beta=0.0}}}}
+Matrix-vector product with a general dense or sparse matrix:
+\[ 
+y := \alpha Ax + \beta y \quad (\mathrm{trans} = \mathrm{'N'}),
+  \qquad 
+y := \alpha A^T x + \beta y \quad (\mathrm{trans} = \mathrm{'T'}), 
+  \qquad
+y := \alpha A^H x + \beta y \quad (\mathrm{trans} = \mathrm{'C'}). 
+\]
+If \var{A} is a dense matrix, this is identical to 
+\function{blas.gemv()}.  If \var{A} is sparse, the result is the same 
+as when \function{blas.gemv()} is called with \code{matrix(A)} as 
+argument, however, without explicitly converting \var{A} to dense.
+\end{funcdesc}
+
+\begin{funcdesc}{symv}{A, x, y\optional{, uplo='L'\optional{, 
+alpha=1.0\optional{, beta=0.0}}}} 
+Matrix-vector product with a dense or sparse real symmetric matrix:
+\[
+   y := \alpha A x + \beta y.
+\]
+If \var{A} is a dense matrix, this is identical to 
+\function{blas.symv()}.  If \var{A} is sparse, the result is the same 
+as when \function{blas.symv()} is called with \code{matrix(A)} as 
+argument, however, without explicitly converting \var{A} to dense.
+\end{funcdesc}
+
+\begin{funcdesc}{gemm}{A, B, C\optional{, transA='N'\optional{, 
+transB='N'\optional{, alpha=1.0\optional{, beta=0.0\optional{, 
+partial=False}}}}}}
+Matrix-matrix product of two general sparse or dense matrices:
+\[
+  C := \alpha \op(A) \op(B) + \beta C 
+\]
+where
+\[
+\op(A) =  \left\{ \begin{array}{ll}
+ A & \mathrm{transA} = \mathrm{'N'} \\
+ A^T & \mathrm{transA} = \mathrm{'T'} \\
+ A^H & \mathrm{transA} = \mathrm{'C'} \end{array} \right.
+\qquad
+\op(B) =  \left\{ \begin{array}{ll}
+ B & \mathrm{transB} = \mathrm{'N'} \\
+ B^T & \mathrm{transB} = \mathrm{'T'} \\
+ B^H & \mathrm{transB} = \mathrm{'C'}. \end{array} \right.
+\]
+If \var{A}, \var{B} and \var{C} are dense matrices, this is 
+identical to \function{blas.gemm()}, described in section~\ref{s-blas3},
+and the argument \var{partial} is ignored.
+
+If \var{A} and/or \var{B} are sparse and \var{C} is dense, the result
+is the same as when \function{blas.gemm()} is called with
+\code{matrix(A)} and \code{matrix(B)} as arguments, without explicitly 
+converting  \var{A} and \var{B} to dense.
+The argument \var{partial} is ignored.
+
+If \var{C} is a sparse matrix, the matrix-matrix product in the
+definition of \function{blas.gemm()} is computed, but as a sparse 
+matrix.  
+If \var{partial} is \False, the result is stored in \var{C}, 
+and the sparsity pattern of \var{C} is  modified if necessary.
+If \var{partial} is \True, the operation only updates the nonzero
+elements in \var{C}, even if the sparsity pattern of \var{C} differs
+from that of the matrix product.  
+\end{funcdesc}
+
+\begin{funcdesc}{syrk}{A, C\optional{, uplo='L'\optional{, 
+trans='N'\optional{, alpha=1.0\optional{, beta=0.0\optional{, 
+partial=False}}}}}}
+Rank-{\it k} update of a sparse or dense real or complex symmetric
+matrix:
+\[
+ C := \alpha AA^T + \beta C \quad (\mathrm{trans} = \mathrm{'N'}), 
+ \qquad 
+ C := \alpha A^TA + \beta C \quad (\mathrm{trans} = \mathrm{'T'}), 
+\]
+If \var{A} and \var{C} are dense, this is identical to 
+\function{blas.syrk()}, described in section~\ref{s-blas3},
+and the argument \var{partial} is ignored.
+
+If \var{A} is sparse and \var{C} is dense, the result is the same as 
+when \function{blas.syrk()} is called with \code{matrix(A)} as 
+argument, without explicitly converting  \var{A} to dense.  
+The argument \var{partial} is ignored.
+
+If \var{C} is sparse, the product in the definition of 
+\function{blas.syrk()} is computed, but as a sparse matrix.  
+If \var{partial} is \False, the result is stored in \var{C}, 
+and the sparsity pattern of \var{C} is  modified if necessary.
+If \var{partial} is \True, the operation only updates the nonzero
+elements in \var{C}, even if the sparsity pattern of \var{C} differs
+from that of the matrix product.  
+\end{funcdesc}
+
+In the following example, we first compute 
+\[
+C =  A^TB, \qquad
+A = \left[ \begin{array}{ccc}
+0 & 1 & 0 \\ 1 & 0 & 1 \\ 0 & 1 & 0 \\ 1 & 0 & 0 \end{array}\right],
+\qquad
+B = \left[ \begin{array}{ccc}
+   0 & -1 & 0 \\ 2 & 0 & 2 \\ 0 & 3 & 0 \\ 2 & 0 & 0 
+   \end{array}\right].
+\]
+\begin{verbatim}
+>>> from cvxopt.base import spmatrix, gemm
+>>> A = spmatrix(1, [1,3,0,2,1], [0,0,1,1,2])
+>>> B = spmatrix([2,2,-1,3,2], [1,3,0,2,1], [0,0,1,1,2])
+>>> C = spmatrix([], [], [], size=(3,3))
+>>> gemm(A, B, C, transA='T')
+>>> print C
+SIZE: (3,3)
+(0, 0)  4.0000e+00
+(2, 0)  2.0000e+00
+(1, 1)  2.0000e+00
+(0, 2)  2.0000e+00
+(2, 2)  2.0000e+00
+\end{verbatim}
+Now suppose we want to replace {\it C} 
+\[
+C = A^TD, \qquad 
+D = \left[ \begin{array}{ccc}
+   0 & 1 & 0 \\ 3 & 0 & -2 \\ 0 & 1 & 0 \\ 4 & 0 & 0 
+   \end{array}\right].
+\]
+The new matrix has the same sparsity pattern as \var{C}, so we can 
+use \function{gemm()} with the \code{partial=True} option.
+This saves time in large sparse matrix multiplications when the 
+sparsity pattern of the result is known beforehand.
+\begin{verbatim}
+>>> D = spmatrix([3,4,1,1,-2], [1,3,0,2,1], [0,0,1,1,2])
+>>> gemm(A, D, C, transA='T', partial=True)
+>>> print C
+SIZE: (3,3)
+(0, 0)  7.0000e+00
+(2, 0)  3.0000e+00
+(1, 1)  2.0000e+00
+(0, 2) -2.0000e+00
+(2, 2) -2.0000e+00
+\end{verbatim}
diff --git a/doc/blas.tex b/doc/blas.tex
new file mode 100644
index 0000000..2d4531a
--- /dev/null
+++ b/doc/blas.tex
@@ -0,0 +1,755 @@
+\chapter{The BLAS Interface (\module{cvxopt.blas})}\label{chap:blas} 
+The \module{cvxopt.blas} module provides an interface to the 
+double-precision real and complex Basic Linear Algebra Subprograms 
+(BLAS).  The names and calling sequences of the Python functions in 
+the interface closely match the corresponding Fortran BLAS routines 
+(described in the references below) and their functionality is exactly 
+the same.  
+
+Many of the operations performed by the BLAS routines can be 
+implemented in a more straightforward way by using the matrix 
+arithmetic of section~\ref{s-arithmetic}, combined with the slicing 
+and indexing of section~\ref{s-indexing}.
+As an example, \samp{C = A*B} gives the same result as the BLAS
+call \samp{gemm(A,B,C)}.
+The BLAS interface offers two advantages.  First, some of the 
+functions it includes are not easily implemented using the basic 
+matrix arithmetic.  For example, BLAS includes functions that 
+efficiently exploit symmetry or triangular matrix structure.
+Second, there is a performance difference that can be significant for 
+large matrices.   Although our implementation of the basic matrix 
+arithmetic makes internal calls to BLAS, it also often requires 
+creating temporary matrices to store intermediate results.  
+The BLAS functions on the other hand always operate directly
+on their matrix arguments and never require any copying to temporary 
+matrices.  Thus they can be viewed as generalizations of the in-place 
+matrix addition and scalar multiplication of 
+section~\ref{s-arithmetic} to more complicated operations.
+
+\begin{seealso}
+\seetext{C. L. Lawson, R. J. Hanson, D. R. Kincaid, F. T. Krogh, 
+Basic Linear Algebra Subprograms for Fortran Use,
+ACM Transactions on Mathematical Software, 5(3), 309-323, 1975.}
+\seetext{J. J. Dongarra, J. Du Croz, S. Hammarling, R. J. Hanson,
+An Extended Set of Fortran Basic Linear Algebra Subprograms,
+ACM Transactions on Mathematical Software, 14(1), 1-17, 1988.}
+\seetext{J. J. Dongarra, J. Du Croz, S. Hammarling, I. Duff,
+A Set of Level 3 Basic Linear Algebra Subprograms,
+ACM Transactions on Mathematical Software, 16(1), 1-17, 1990.}
+\end{seealso}
+
+\section{Matrix Classes} \label{s-conventions}
+
+The BLAS exploit several types of matrix structure: symmetric, 
+Hermitian, triangular, and banded.   We represent all these matrix 
+classes by dense real or complex \mtrx\ objects, with additional 
+arguments that specify the structure.
+
+\begin{description}
+\item[Vector] 
+A real or complex {\it n}-vector is represented by a \mtrx\ of type 
+\dtc\ or \ztc\ and length {\it n}, with the entries of the vector 
+stored in column-major order. 
+
+\item[General matrix]
+A general real or complex {\it m} by {\it n} matrix is represented by 
+a real or complex \mtrx\ of size ({\it m}, {\it n}).
+
+\item[Symmetric matrix]
+A real or complex symmetric matrix of order {\it n} is represented
+by a real or complex \mtrx\ of size ({\it n}, {\it n}), and a character 
+argument \var{uplo} with two possible values:  
+\code{'L'} and \code{'U'}.
+If \var{uplo} is \code{'L'}, the lower triangular part of the
+symmetric matrix is stored; if \var{uplo} is \code{'U'}, the upper
+triangular part is stored.  A square \mtrx\ {\var X} of size 
+({\it n}, {\it n}) can therefore be used to represent the symmetric 
+matrices
+\BEAS
+&  \left[\begin{array}{ccccc}
+X[0,0]   & X[1,0]   & X[2,0]   & \cdots & X[n-1,0] \\
+X[1,0]   & X[1,1]   & X[2,1]   & \cdots & X[n-1,1] \\
+X[2,0]   & X[2,1]   & X[2,2]   & \cdots & X[n-1,2] \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots \\
+X[n-1,0] & X[n-1,1] & X[n-1,2] & \cdots & X[n-1,n-1]
+\end{array}\right] & \mbox{if uplo = 'L'}, \\
+& \left[\begin{array}{ccccc}
+X[0,0]   & X[0,1]   & X[0,2]   & \cdots & X[0,n-1] \\
+X[0,1]   & X[1,1]   & X[1,2]   & \cdots & X[1,n-1] \\
+X[0,2]   & X[1,2]   & X[2,2]   & \cdots & X[2,n-1] \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots \\
+X[0,n-1] & X[1,n-1] & X[2,n-1] & \cdots & X[n-1,n-1]
+\end{array}\right] & \mbox{if uplo = U'}. 
+\EEAS
+
+\item[Complex Hermitian matrix]
+A complex Hermitian matrix of order {\it n} is represented
+by a \mtrx\ of type \ztc\ and size ({\it n}, {\it n}), and
+a character argument \var{uplo} with the ame meaning as for symmetric 
+matrices.
+A complex \mtrx\ {\var X} of size ({\it n}, {\it n}) can 
+represent the Hermitian  matrices
+\BEAS
+&
+\left[\begin{array}{ccccc}
+\Re X[0,0]   & \bar X[1,0]   & \bar X[2,0]   & \cdots & \bar X[n-1,0] \\
+X[1,0]   & \Re X[1,1]   & \bar X[2,1]   & \cdots & \bar X[n-1,1] \\
+X[2,0]   & X[2,1]   & \Re X[2,2]   & \cdots & \bar X[n-1,2] \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots \\
+X[n-1,0] & X[n-1,1] & X[n-1,2] & \cdots & \Re X[n-1,n-1]
+\end{array}\right] & \mbox{if uplo = 'L'}, \\
+& \left[\begin{array}{ccccc}
+\Re X[0,0]   & X[0,1]   & X[0,2]   & \cdots & X[0,n-1] \\
+\bar X[0,1]   & \Re X[1,1]   & X[1,2]   & \cdots & X[1,n-1] \\
+\bar X[0,2]   & \bar X[1,2]   & \Re X[2,2]   & \cdots & X[2,n-1] \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots \\
+\bar X[0,n-1] & \bar X[1,n-1] & \bar X[2,n-1] & \cdots & \Re X[n-1,n-1]
+\end{array}\right] & \mbox{if uplo = 'U'}.
+\EEAS
+
+\item[Triangular matrix]
+A real or complex triangular matrix of order {\it n} is represented
+by a real or complex \mtrx\ of size ({\it n}, {\it n}), and two 
+character arguments: an argument \var{uplo} with possible values 
+\code{'L'} and \code{'U'} to distinguish between lower and upper 
+triangular matrices, and an argument \var{diag} with possible values 
+\code{'U'} and \code{'N'} to distinguish between unit and non-unit 
+triangular matrices.  A square \mtrx\ {\var X} of size 
+({\it n}, {\it n}) can represent the triangular matrices
+\BEAS
+& \left[\begin{array}{ccccc}
+X[0,0]   & 0        & 0        & \cdots & 0 \\
+X[1,0]   & X[1,1]   & 0        & \cdots & 0 \\
+X[2,0]   & X[2,1]   & X[2,2]   & \cdots & 0 \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots \\
+X[n-1,0] & X[n-1,1] & X[n-1,2] & \cdots & X[n-1,n-1]
+\end{array}\right] & \mbox{if uplo = 'L' and diag = 'N'}, \\
+& \left[\begin{array}{ccccc}
+1   & 0   & 0   & \cdots & 0 \\
+X[1,0]   & 1   & 0   & \cdots & 0 \\
+X[2,0]   & X[2,1]   & 1   & \cdots & 0 \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots \\
+X[n-1,0] & X[n-1,1] & X[n-1,2] & \cdots & 1
+\end{array}\right] & \mbox{if uplo = 'L' and diag = 'U'}, \\
+& \left[\begin{array}{ccccc}
+X[0,0]   & X[0,1]   & X[0,2]   & \cdots & X[0,n-1] \\
+0   & X[1,1]   & X[1,2]   & \cdots & X[1,n-1] \\
+0   & 0   & X[2,2]   & \cdots & X[2,n-1] \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots \\
+0 & 0 & 0 & \cdots & X[n-1,n-1]
+\end{array}\right] & \mbox{if uplo = 'U' and diag = 'N'}, \\
+& \left[\begin{array}{ccccc}
+1   & X[0,1]   & X[0,2]   & \cdots & X[0,n-1] \\
+0   & 1   & X[1,2]   & \cdots & X[1,n-1] \\
+0   & 0   & 1   & \cdots & X[2,n-1] \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots \\
+0 & 0 & 0 & \cdots & 1
+\end{array}\right] & \mbox{if uplo = 'U' and diag = 'U'}.
+\EEAS
+
+\item[General band matrix]
+A general real or complex {\it m} by {\it n} band matrix  with {\it kl}
+subdiagonals and {\it ku} superdiagonals is represented by a real or 
+complex \mtrx\ \var{X} of size ({\it kl+ku+1}, {\it n}), and the two 
+integers {\it m} and {\it kl}.   
+The diagonals of the band matrix are stored in the rows of \var{X}, 
+starting at the top diagonal, and shifted horizontally so that the 
+entries of the 
+{\it k}th column of the band matrix are stored in column {\it k} of 
+{\var X}.  A \mtrx\ {\var X} of size ({\it kl+ku+1}, {\it n}) therefore
+represents the {\it m} by {\it n} band matrix
+\[
+\left[ \begin{array}{ccccccc}
+X[k_u,0]     & X[k_u-1,1]     & X[k_u-2,2]     & \cdots & X[0,k_u] & 0               & \cdots \\
+X[k_u+1,0]   & X[k_u,1]       & X[k_u-1,2]     & \cdots & X[1,k_u] & X[0,k_u+1]   & \cdots \\
+X[k_u+2,0]   & X[k_u+1,1]     & X[k_u,2]       & \cdots & X[2,k_u] & X[1,k_u+1] & \cdots \\ 
+ \vdots      & \vdots         &  \vdots        & \ddots & \vdots   & \vdots          & \ddots  \\
+X[k_u+k_l,0] & X[k_u+k_l-1,1] & X[k_u+k_l-2,2] & \cdots &  &  & \\
+0            & X[k_u+k_l,1]   & X[k_u+k_l-1,2] & \cdots &  &  & \\
+\vdots       & \vdots         & \vdots         & \ddots &  &  & 
+\end{array}\right].
+\]
+
+\item[Symmetric band matrix]
+A real or complex symmetric band matrix of order {\it n} with {\it k}
+subdiagonals, is represented by a real or complex matrix \var{X} of 
+size ({\it k}+1, {\it n}), and an argument {\it uplo} to indicate 
+whether the subdiagonals ({\it uplo} is \code{'L'}) or superdiagonals 
+({\it uplo} is \code{'U'}) are stored.
+The {\it k}+1 diagonals are stored as rows of \var{X}, starting at the top 
+diagonal (\ie, the main diagonal if {\it uplo} is \code{'L'},  or
+the {\it k}th superdiagonal if {\it uplo} is \code{'U'}) and shifted
+horizontally so that the entries of the 
+{\it k}th column of the band matrix are stored in column {\it k} of 
+{\var X}.  A \mtrx\ {\it X} of size ({\it k}+1, {\it n}) can therefore
+represent the band matrices 
+\BEAS
+& \left[ \begin{array}{ccccccc}
+X[0,0] & X[1,0]   & X[2,0]   & \cdots & X[k,0]   & 0        & \cdots \\
+X[1,0] & X[0,1]   & X[1,1]   & \cdots & X[k-1,1] & X[k,1]   & \cdots \\
+X[2,0] & X[1,1]   & X[0,2]   & \cdots & X[k-2,2] & X[k-1,2] & \cdots \\
+\vdots & \vdots   &  \vdots  & \ddots & \vdots   & \vdots   & \ddots \\
+X[k,0] & X[k-1,1] & X[k-2,2] & \cdots &  &  & \\
+0      & X[k,1]   & X[k-1,2] & \cdots &  &  & \\
+\vdots & \vdots   & \vdots   & \ddots &  &  & 
+\end{array}\right] & \mbox{if uplo = 'L'}, \\
+& 
+\left[ \begin{array}{ccccccc}
+X[k,0]   & X[k-1,1] & X[k-2,2] & \cdots & X[0,k] & 0        & \cdots \\
+X[k-1,1] & X[k,1]   & X[k-1,2] & \cdots & X[1,k] & X[0,k+1] & \cdots \\
+X[k-2,2] & X[k-1,2] & X[k,2]   & \cdots & X[2,k] & X[1,k+1] & \cdots \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots & \vdots   & \ddots \\
+X[0,k]   & X[1,k]   & X[2,k]   & \cdots &  &  & \\
+0        & X[0,k+1] & X[1,k+1] & \cdots &  &  & \\
+\vdots   & \vdots   & \vdots   & \ddots &  &  & 
+\end{array}\right] & \mbox{if uplo='U'}.
+\EEAS
+
+\item[Hermitian  band matrix]
+A complex Hermitian band matrix of order {\it n} with {\it k} 
+subdiagonals is represented by a complex matrix of size 
+({\it k+1}, {\it n}) and an argument \var{uplo}.  
+A \mtrx\ {\it X} of size ({\it k}+1, {\it n}) can represent the band
+matrices 
+\BEAS
+& \left[ \begin{array}{ccccccc}
+\Re X[0,0] & \bar X[1,0]   & \bar X[2,0]   & \cdots & \bar X[k,0]   & 0        & \cdots \\
+X[1,0] & \Re X[0,1]   & \bar X[1,1]   & \cdots & \bar X[k-1,1] & \bar X[k,1]   & \cdots \\
+X[2,0] & X[1,1]   & \Re X[0,2]   & \cdots & \bar X[k-2,2] & \bar X[k-1,2] & \cdots \\
+\vdots & \vdots   &  \vdots  & \ddots & \vdots   & \vdots   & \ddots \\
+X[k,0] & X[k-1,1] & X[k-2,2] & \cdots &  &  & \\
+0      & X[k,1]   & X[k-1,2] & \cdots &  &  & \\
+\vdots & \vdots   & \vdots   & \ddots &  &  & 
+\end{array}\right] & \mbox{if uplo = 'L'}, \\
+& 
+\left[ \begin{array}{ccccccc}
+\Re X[k,0]   & X[k-1,1] & X[k-2,2] & \cdots & X[0,k] & 0        & \cdots \\
+\bar X[k-1,1] & \Re X[k,1]   & X[k-1,2] & \cdots & X[1,k] & X[0,k+1] & \cdots \\
+\bar X[k-2,2] & \bar X[k-1,2] & \Re X[k,2]   & \cdots & X[2,k] & X[1,k+1] & \cdots \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots & \vdots   & \ddots \\
+\bar X[0,k]   & \bar X[1,k]   & \bar X[2,k]   & \cdots &  &  & \\
+0        & \bar X[0,k+1] & \bar X[1,k+1] & \cdots &  &  & \\
+\vdots   & \vdots   & \vdots   & \ddots &  &  & 
+\end{array}\right] & \mbox{if uplo='U'}.
+\EEAS
+
+\item[Triangular band matrix]
+A triangular band matrix of order {\it n} with {\it k} subdiagonals or
+superdiagonals is represented by a real complex matrix of size 
+({\it k+1}, {\it n}) and two character arguments \var{uplo} and 
+\var{diag}.  
+A \mtrx\ {\it X} of size ({\it k}+1, {\it n}) can represent the band
+matrices 
+\BEAS
+& \left[ \begin{array}{cccc}
+X[0,0] & 0        & 0        & \cdots \\
+X[1,0] & X[0,1]   & 0        & \cdots  \\
+X[2,0] & X[1,1]   & X[0,2]   & \cdots \\
+\vdots & \vdots   & \vdots   & \ddots \\
+X[k,0] & X[k-1,1] & X[k-2,2] & \cdots \\
+0      & X[k,1]   & X[k-1,1] & \cdots \\
+\vdots & \vdots   & \vdots   & \ddots 
+\end{array}\right] & \mbox{if uplo = 'L' and diag = 'N'},  \\
+& \left[ \begin{array}{cccc}
+1      & 0        & 0        & \cdots \\
+X[1,0] & 1        & 0        & \cdots  \\
+X[2,0] & X[1,1]   & 1        & \cdots \\
+\vdots & \vdots   & \vdots   & \ddots \\
+X[k,0] & X[k-1,1] & X[k-2,2] & \cdots \\
+0      & X[k,1]   & X[k-1,2] & \cdots \\
+\vdots & \vdots   & \vdots   & \ddots 
+\end{array}\right] & \mbox{if uplo = 'L'  and diag = 'U'}, \\
+& \left[ \begin{array}{ccccccc}
+X[k,0] & X[k-1,1] & X[k-2,3] & \cdots & X[0,k]  & 0        & \cdots\\
+0      & X[k,1]   & X[k-1,2] & \cdots & X[1,k]  & X[0,k+1] & \cdots \\
+0      & 0        & X[k,2]   & \cdots & X[2,k]  & X[1,k+1] & \cdots \\
+\vdots & \vdots   &  \vdots  & \ddots & \vdots  & \vdots   & \ddots  
+\end{array}\right] & \mbox{if uplo = 'U' and diag = 'N'}, \\
+& \left[ \begin{array}{ccccccc}
+1      & X[k-1,1] & X[k-2,3] & \cdots & X[0,k]  & 0        & \cdots\\
+0      & 1        & X[k-1,2] & \cdots & X[1,k]  & X[0,k+1] & \cdots \\
+0      & 0        & 1        & \cdots & X[2,k]  & X[1,k+1] & \cdots \\
+\vdots & \vdots   &  \vdots  & \ddots & \vdots  & \vdots   & \ddots  
+\end{array}\right] & \mbox{if uplo = 'U' and diag = 'U'}.
+\EEAS
+\end{description}
+
+When discussing BLAS functions in the following sections we will
+omit several less important optional arguments that can 
+be used to select submatrices for in-place operations. 
+The complete specification is  documented in the docstrings of the 
+source code and the \program{pydoc} help program.
+
+\section{Level 1 BLAS} \label{s-blas1}
+The level 1 functions implement vector operations.  
+
+\begin{funcdesc}{scal}{alpha, x}
+Scales a vector by a constant: 
+\[ 
+x := \alpha x.
+\]
+If \var{x} is a real \mtrx, the scalar argument \var{alpha} must be a 
+Python \intgr\ or \flt.  If \var{x} is complex, \var{alpha} can be an 
+\intgr, \flt, or \cmplx.
+\end{funcdesc}
+
+\begin{funcdesc}{nrm2}{x}
+Euclidean norm of a vector:  returns 
+\[
+ \|x\|_2.
+\]  
+\end{funcdesc}
+
+\begin{funcdesc}{asum}{x}
+L-1 norm of a vector: returns 
+\[
+\|x\|_1 \quad \mbox{($x$ real)}, \qquad  
+\|\Re x\|_1 + \|\Im x\|_1 \quad \mbox{($x$ complex)}.
+\]
+\end{funcdesc}
+
+\begin{funcdesc}{iamax}{x}
+Returns 
+\[
+ \argmax_{k=0,\ldots,n-1} |x_k| \quad \mbox{($x$ real)}, \qquad
+ \argmax_{k=0,\ldots,n-1} |\Re x_k| + |\Im x_k| \quad 
+ \mbox{($x$ complex)}. 
+\]
+If more than one coefficient achieves the maximum, the index of the 
+first {\it k} is returned.  
+\end{funcdesc}
+
+\begin{funcdesc}{swap}{x, y}
+Interchanges two vectors:
+\[
+  x \leftrightarrow y.
+\]
+\var{x} and \var{y} are matrices of the same type (\dtc\ or \ztc).
+\end{funcdesc}
+
+\begin{funcdesc}{copy}{x, y}
+Copies a vector to another vector:
+\[
+ y := x.
+\]
+\var{x} and \var{y} are matrices of the same type (\dtc\ or \ztc).
+\end{funcdesc}
+
+\begin{funcdesc}{axpy}{x, y\optional{,alpha=1.0}}
+Constant times a vector plus a vector:  
+\[ 
+y := \alpha x + y.
+\]
+\var{x} and \var{y} are matrices of the same type (\dtc\ or \ztc).
+If \var{x} is real, the scalar argument \var{alpha} must be a Python 
+\intgr\ or \flt.  If \var{x} is complex, \var{alpha} can be an \intgr, 
+\flt, or \cmplx.  
+\end{funcdesc}
+
+\begin{funcdesc}{dot}{x, y}
+Returns 
+\[ 
+x^Hy. 
+\]  
+\var{x} and \var{y} are matrices of the same type (\dtc\ or \ztc).
+\end{funcdesc}
+
+\begin{funcdesc}{dotu}{x, y}
+Returns 
+\[ 
+x^Ty. 
+\]  
+\var{x} and \var{y} are matrices of the same type (\dtc\ or \ztc).
+\end{funcdesc}
+
+
+\section{Level 2 BLAS} \label{s-blas2}
+The level 2 functions implement matrix-vector products and 
+rank-1 and rank-2 matrix updates.
+Different types of matrix structure can be exploited using the 
+conventions of section~\ref{s-conventions}. 
+
+\begin{funcdesc}{gemv}{A, x, y\optional{, trans='N'\optional{, 
+alpha=1.0\optional{, beta=0.0}}}}
+Matrix-vector product with a general matrix:  
+\[ 
+y := \alpha Ax + \beta y \quad (\mathrm{trans} = \mathrm{'N'}),
+  \qquad 
+y := \alpha A^T x + \beta y \quad (\mathrm{trans} = \mathrm{'T'}), 
+  \qquad
+y := \alpha A^H x + \beta y \quad (\mathrm{trans} = \mathrm{'C'}). 
+\]
+The arguments \var{A}, \var{x} and {\var y} must have the same type 
+(\dtc\ or \ztc).  Complex values of \var{alpha} and \var{beta} are only
+allowed if \var{A} is complex. 
+\end{funcdesc}
+
+\begin{funcdesc}{symv}{A, x, y\optional{, uplo='L'\optional{, 
+alpha=1.0\optional{, beta=0.0}}}}
+Matrix-vector  product with a real symmetric matrix:  
+\[
+   y := \alpha A x + \beta y,
+\]
+where {\it A} is a real symmetric matrix.  
+The arguments \var{A}, \var{x} and {\var y} must have 
+type \dtc\ and \var{alpha} and \var{beta} must be real.
+\end{funcdesc}
+
+\begin{funcdesc}{hemv}{A, x, y\optional{, uplo='L'\optional{, 
+alpha=1.0\optional{, beta=0.0}}}}
+Matrix-vector  product with a real symmetric or complex Hermitian 
+matrix: 
+\[
+   y := \alpha A x + \beta y,
+\]
+where {\it A} is real symmetric or complex Hermitian.
+The arguments \var{A}, \var{x} and {\var y} must have the same
+type (\dtc\ or \ztc).  
+Complex values of \var{alpha} and \var{beta} are only
+allowed if \var{A} is complex. 
+\end{funcdesc}
+
+\begin{funcdesc}{trmv}{A, x\optional{, uplo='L'\optional{, 
+trans='N'\optional{, diag='N'}}}}
+Matrix-vector  product with a triangular matrix: 
+\[ 
+x := Ax \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+x := A^T x \quad (\mathrm{trans} = \mathrm{'T'}), \qquad
+x := A^H x \quad (\mathrm{trans} = \mathrm{'C'}), 
+\]
+where {\it A} is square and triangular.
+The arguments \var{A} and \var{x} must have the same type 
+(\dtc\ or \ztc).
+\end{funcdesc}
+
+\begin{funcdesc}{trsv}{A, x\optional{, uplo='L'\optional{, 
+trans='N'\optional{, diag='N'}}}}
+Solution of a nonsingular triangular set of linear equations:
+\[ 
+x := A^{-1}x \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+x := A^{-T}x \quad (\mathrm{trans} = \mathrm{'T'}), \qquad 
+x := A^{-H}x \quad (\mathrm{trans} = \mathrm{'C'}), 
+\]
+where {\it A} is square and triangular with nonzero diagonal 
+elements.  The arguments \var{A} and \var{x} must have the same type 
+(\dtc\ or \ztc).
+\end{funcdesc}
+
+\begin{funcdesc}{gbmv}{A, m, kl, x, y\optional{, trans='N'
+\optional{, alpha=1.0\optional{, beta=0.0}}}}
+Matrix-vector product with a general band matrix:
+\[ 
+y := \alpha Ax + \beta y \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+y := \alpha A^T x + \beta y \quad (\mathrm{trans} = \mathrm{'T'}), 
+\qquad 
+y := \alpha A^H x + \beta y \quad (\mathrm{trans} = \mathrm{'C'}),
+\]
+where  {\it A} is a rectangular band matrix with \var{m} rows and 
+\var{kl} subdiagonals.
+The arguments \var{A}, \var{x} and {\var y} must have the same
+type (\dtc\ or \ztc).
+Complex values of \var{alpha} and \var{beta} are only allowed if \var{A} is
+ complex.
+\end{funcdesc}
+
+\begin{funcdesc}{sbmv}{A, x, y\optional{, uplo='L'\optional{, 
+alpha=1.0\optional{, beta=0.0}}}}
+Matrix-vector  product with a real symmetric band matrix:
+\[
+ y := \alpha Ax + \beta y,
+\]
+where {\it A} is a real symmetric band matrix.
+The arguments \var{A}, \var{x} and {\var y} must have type \dtc\ and 
+\var{alpha} and \var{beta} must be real.
+\end{funcdesc}
+
+\begin{funcdesc}{hbmv}{A, x, y\optional{, uplo='L'\optional{, 
+alpha=1.0\optional{, beta=0.0}}}}
+Matrix-vector  product with a real symmetric or complex Hermitian 
+band matrix:
+\[
+ y := \alpha Ax + \beta y,
+\]
+where {\it A} is a real symmetric or complex Hermitian band matrix.
+The arguments \var{A}, \var{x} and {\var y} must have the same type
+(\dtc\ or \ztc).  
+Complex values of \var{alpha} and \var{beta} are only allowed if 
+\var{A} is complex. 
+\end{funcdesc}
+
+\begin{funcdesc}{tbmv}{A, x\optional{, uplo='L'\optional{, 
+trans\optional{, diag}}}}
+Matrix-vector  product with a triangular band matrix:
+\[
+x := Ax \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+x := A^T x \quad (\mathrm{trans} = \mathrm{'T'}), \qquad 
+x := A^H x \quad (\mathrm{trans} = \mathrm{'C'}). 
+\]
+The arguments \var{A} and \var{x} must have the same type 
+(\dtc\ or \ztc).  
+\end{funcdesc}
+
+\begin{funcdesc}{tbsv}{A, x\optional{, uplo='L'\optional{, 
+trans\optional{, diag}}}}
+Solution of a triangular banded set of linear equations:
+\[
+x := A^{-1}x \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+x := A^{-T} x \quad (\mathrm{trans} = \mathrm{'T'}), \qquad
+x := A^{-H} x \quad (\mathrm{trans} = \mathrm{'T'}), 
+\]
+where {\it A} is a triangular band matrix of with nonzero diagonal 
+elements.
+The arguments \var{A} and \var{x} must have the same type 
+(\dtc\ or \ztc).  
+\end{funcdesc}
+
+\begin{funcdesc}{ger}{x, y, A\optional{, alpha=1.0}}
+General rank-1 update:
+\[ 
+A := A + \alpha x y^H,
+\]
+where {\it A} is a general matrix.
+The arguments \var{A}, \var{x} and \var{y} must have the same type 
+(\dtc\ or \ztc).  
+Complex values of \var{alpha} are only allowed if \var{A} is complex.
+\end{funcdesc}
+
+\begin{funcdesc}{geru}{x, y, A\optional{, alpha=1.0}}
+General rank-1 update:
+\[ 
+A := A + \alpha x y^T, 
+\]
+where {\it A} is a general matrix.
+The arguments \var{A}, \var{x} and \var{y} must have the same type 
+(\dtc\ or \ztc).  
+Complex values of \var{alpha} are only allowed if \var{A} is complex.
+\end{funcdesc}
+
+\begin{funcdesc}{syr}{x, A\optional{, uplo='L'\optional{, alpha=1.0}}}
+Symmetric rank-1 update:
+\[
+ A := A + \alpha xx^T,
+\]
+where {\it A} is a real symmetric matrix.
+The arguments \var{A} and \var{x} must have type \dtc.  
+\var{alpha} must be a real number.
+\end{funcdesc}
+
+\begin{funcdesc}{her}{x, A\optional{, uplo='L'\optional{, alpha=1.0}}}
+Hermitian rank-1 update:
+\[
+ A := A + \alpha xx^H, 
+\]
+where {\it A} is a real symmetric or complex Hermitian matrix.
+The arguments \var{A} and \var{x} must have the same type 
+(\dtc\ or \ztc).  
+\var{alpha} must be a real number.
+\end{funcdesc}
+
+\begin{funcdesc}{syr2}{x, y, A\optional{, uplo='L'\optional{, 
+alpha=1.0}}}
+Symmetric rank-2  update:
+\[
+ A := A + \alpha (xy^T + yx^T),
+\]
+where {\it A} is a real symmetric matrix.
+The arguments \var{A}, \var{x} and \var{y} must have type \dtc.  
+\var{alpha} must be real.
+\end{funcdesc}
+
+\begin{funcdesc}{her2}{x, y, A\optional{, uplo='L'\optional{, 
+alpha=1.0}}}
+Symmetric rank-2  update:
+\[
+ A := A + \alpha xy^H + \bar \alpha yx^H,
+\]
+where {\it A} is a a real symmetric or complex Hermitian matrix.
+The arguments \var{A}, \var{x} and \var{y} must have the same type  
+(\dtc\ or \ztc).  
+Complex values of \var{alpha} are only allowed if \var{A} is complex.
+\end{funcdesc}
+
+As an example, the following code multiplies the tridiagonal matrix
+\[
+A = \left[\begin{array}{rrrr}
+  1 &  6 &  0 & 0 \\ 
+  2 & -4 &  3 & 0 \\ 
+  0 & -3 & -1 & 1 
+  \end{array}\right]
+\]
+with the vector {\it x} = (1,-1,2,-2).
+\begin{verbatim}
+>>> from cvxopt.base import matrix
+>>> from cvxopt.blas import gbmv
+>>> A = matrix([[0., 1., 2.],  [6., -4., -3.],  [3., -1., 0.],  [1., 0., 0.]])
+>>> x = matrix([1., -1., 2., -2.])
+>>> y = matrix(0., (3,1))
+>>> gbmv(A, 3, 1, x, y)
+>>> print y
+-5.0000e+00
+ 1.2000e+01
+-1.0000e+00
+\end{verbatim}
+
+The following example illustrates the use of \function{tbsv()}.
+\begin{verbatim}
+>>> from cvxopt.base import matrix
+>>> from cvxopt.blas import tbsv
+>>> A = matrix([-6., 5., -1., 2.], (1,4))
+>>> x = matrix(1.0, (4,1))
+>>> tbsv(A, x)  # x := diag(A)^{-1}*x
+>>> print x
+-1.6667e-01
+ 2.0000e-01
+-1.0000e+00
+ 5.0000e-01
+\end{verbatim}
+
+
+\section{Level 3 BLAS} \label{s-blas3}
+The level 3 BLAS include functions for matrix-matrix multiplication.
+
+\begin{funcdesc}{gemm}{A, B, C\optional{, transA='N'\optional{, 
+transB='N'\optional{, alpha=1.0\optional{, beta=0.0}}}}}
+Matrix-matrix product of two general matrices:  
+\[
+  C := \alpha \op(A) \op(B) + \beta C 
+\]
+where
+\[
+\op(A) =  \left\{ \begin{array}{ll}
+ A & \mathrm{transA} = \mathrm{'N'} \\
+ A^T & \mathrm{transA} = \mathrm{'T'} \\
+ A^H & \mathrm{transA} = \mathrm{'C'} \end{array} \right.
+\qquad
+\op(B) =  \left\{ \begin{array}{ll}
+ B & \mathrm{transB} = \mathrm{'N'} \\
+ B^T & \mathrm{transB} = \mathrm{'T'} \\
+ B^H & \mathrm{transB} = \mathrm{'C'}. \end{array} \right.
+\]
+The arguments \var{A}, \var{B} and \var{C} must have the same type 
+(\dtc\ or \ztc).
+Complex values of \var{alpha} and \var{beta} are only allowed 
+if \var{A} is complex.
+\end{funcdesc}
+
+\begin{funcdesc}{symm}{A, B, C\optional{, side='L'\optional{, 
+uplo='L'\optional{, alpha=1.0\optional{,  beta=0.0}}}}}
+Product of a real or complex symmetric matrix {\it A} and a general 
+matrix {\it B}:
+\[
+ C := \alpha AB + \beta C \quad (\mathrm{side} = \mathrm{'L'}), \qquad 
+ C := \alpha BA + \beta C \quad (\mathrm{side} = \mathrm{'R'}). 
+\]
+The arguments \var{A}, \var{B} and \var{C} must have the same type 
+(\dtc\ or \ztc).  Complex values of \var{alpha} and \var{beta} are 
+only allowed if \var{A} is complex.
+\end{funcdesc}
+
+\begin{funcdesc}{hemm}{A, B, C\optional{, side='L'\optional{, 
+uplo='L'\optional{, alpha=1.0\optional{,  beta=0.0}}}}}
+Product of a real symmetric or complex Hermitian matrix {\it A} and a 
+general matrix {\it B}:
+\[
+ C := \alpha AB + \beta C \quad (\mathrm{side} = \mathrm{'L'}), \qquad 
+ C := \alpha BA + \beta C \quad (\mathrm{side} = \mathrm{'R'}). 
+\]
+The arguments \var{A}, \var{B} and \var{C} must have the same type 
+(\dtc\ or \ztc).
+Complex values of \var{alpha} and \var{beta} are only allowed if 
+\var{A} is complex.
+\end{funcdesc}
+
+\begin{funcdesc}{trmm}{A, B\optional{, side='L'\optional{, 
+uplo='L'\optional{, transA='N'\optional{, diag='N'\optional{, 
+alpha=1.0}}}}}}
+Product of a triangular matrix {\it A} and a general matrix {\it B}:
+\[
+ B := \alpha\op(A)B \quad (\mathrm{side} = \mathrm{'L'}), \qquad 
+ B := \alpha B\op(A) \quad (\mathrm{side} = \mathrm{'R'}), \qquad 
+ \op(A) =  \left\{ \begin{array}{ll}
+ A & \mathrm{transA} = \mathrm{'N'} \\
+ A^T & \mathrm{transA} = \mathrm{'T'} \\
+ A^H & \mathrm{transA} = \mathrm{'C'}. \end{array} \right.
+\]
+The arguments \var{A} and \var{B} must have the same type (\dtc\ or 
+\ztc).   Complex values of \var{alpha} are only allowed if \var{A} is 
+complex.
+\end{funcdesc}
+
+\begin{funcdesc}{trsm}{A, B\optional{, side='L'\optional{, 
+uplo='L'\optional{, transA='N'\optional{, diag='N'\optional{, 
+alpha=1.0}}}}}}
+Solution of a nonsingular triangular system of equations:
+\[
+ B := \alpha \op(A)^{-1}B \quad (\mathrm{side} = \mathrm{'L'}), \qquad 
+ B := \alpha B\op(A)^{-1} \quad (\mathrm{side} = \mathrm{'R'}), \qquad 
+ \op(A) =  \left\{ \begin{array}{ll}
+ A & \mathrm{transA} = \mathrm{'N'} \\
+ A^T & \mathrm{transA} = \mathrm{'T'} \\
+ A^H & \mathrm{transA} = \mathrm{'C'}, \end{array} \right.
+\]
+where {\it A} is triangular and {\it B} is a general matrix.
+The arguments \var{A} and \var{B} must have the same type (\dtc\ or 
+\ztc).   Complex values of \var{alpha} are only allowed if \var{A} is 
+complex.
+\end{funcdesc}
+
+\begin{funcdesc}{syrk}{A, C\optional{, uplo='L'\optional{, 
+trans='N'\optional{, alpha=1.0\optional{, beta=0.0}}}}}
+Rank-{\it k} update of a real or complex symmetric matrix {\it C}:
+\[
+ C := \alpha AA^T + \beta C \quad (\mathrm{trans} = \mathrm{'N'}), 
+ \qquad 
+ C := \alpha A^TA + \beta C \quad (\mathrm{trans} = \mathrm{'T'}), 
+\]
+where {\it A} is a general matrix.
+The arguments \var{A} and \var{C} must have the same type (\dtc\ or 
+\ztc).  Complex values of \var{alpha} and \var{beta} are only allowed 
+if \var{A} is complex.
+\end{funcdesc}
+
+\begin{funcdesc}{herk}{A, C\optional{, uplo='L'\optional{, 
+trans='N'\optional{, alpha=1.0\optional{, beta=0.0}}}}}
+Rank-{\it k} update of a real symmetric or complex Hermitian matrix
+{\it C}:
+\[
+ C := \alpha AA^H + \beta C \quad (\mathrm{trans} = \mathrm{'N'}), 
+ \qquad 
+ C := \alpha A^HA + \beta C \quad (\mathrm{trans} = \mathrm{'C'}),
+\]
+where {\it A} is a general matrix.
+The arguments \var{A} and \var{C} must have the same type (\dtc\ or
+\ztc).  \var{alpha} and \var{beta} must be real.
+\end{funcdesc}
+
+\begin{funcdesc}{syr2k}{A, B, C\optional{, uplo='L'\optional{, 
+trans='N'\optional{, alpha=1.0\optional{, beta=0.0}}}}}
+Rank-{\it 2k} update of a real or complex symmetric matrix {\it C}:
+\[
+ C := \alpha (AB^T + BA^T) + \beta C \quad 
+  (\mathrm{trans} = \mathrm{'N'}), \qquad 
+ C := \alpha (A^TB + B^TA) + \beta C \quad 
+  (\mathrm{trans} = \mathrm{'T'}). 
+\]
+{\it A} and {\it B} are general real or complex matrices.
+The arguments \var{A}, \var{B} and \var{C} must have the same
+type.  Complex values of \var{alpha} and \var{beta} are only 
+allowed if \var{A} is complex.
+\end{funcdesc}
+
+\begin{funcdesc}{her2k}{A, B, C\optional{, uplo='L'\optional{, 
+trans='N'\optional{, alpha=1.0\optional{ beta=0.0}}}}}
+Rank-{\it 2k} update of a real symmetric or complex Hermitian matrix
+{\it C}:
+\[
+ C := \alpha AB^H + \bar \alpha BA^H + \beta C \quad 
+  (\mathrm{trans} = \mathrm{'N'}), \qquad 
+ C := \alpha A^HB + \bar\alpha B^HA + \beta C \quad 
+  (\mathrm{trans} = \mathrm{'C'}), 
+\]
+where {\it A} and {\it B} are general matrices.
+The arguments \var{A}, \var{B} and \var{C} must have the same type 
+(\dtc\ or \ztc).  Complex values of \var{alpha} are only allowed if 
+\var{A} is complex.  \var{beta} must be real.
+\end{funcdesc}
diff --git a/doc/c-api.tex b/doc/c-api.tex
new file mode 100644
index 0000000..a836b51
--- /dev/null
+++ b/doc/c-api.tex
@@ -0,0 +1,194 @@
+\chapter{C API}\label{chap:c-api}
+The API can be used to extend CVXOPT with interfaces to 
+external C routines and libraries. 
+A C program that creates or manipulates the dense or sparse matrix
+objects defined in \module{cvxopt.base} must include the 
+\file{cvxopt.h} header file in the \file{src} directory of the 
+distribution.
+
+Before the C-API can be used in an extension module it must be
+initialized by calling the macro \cfunction{import\_cvxopt}. 
+As an example
+we show the module initialization from the \module{cvxopt.blas} module,
+which itself uses the API:
+\begin{verbatim}
+PyMODINIT_FUNC initblas(void)
+{
+  PyObject *m;
+
+  m = Py_InitModule3("cvxopt.blas", blas_functions, blas__doc__);
+
+  if (import_cvxopt() < 0)
+    return;
+}
+\end{verbatim}
+  
+
+\section{Dense Matrices}
+As can be seen from the header file \file{cvxopt.h}, a \mtrx\ is
+essentially a  structure with four fields.
+The fields \cdata{nrows} and \cdata{ncols} are two integers that 
+specify the dimensions.
+The \cdata{id} field controls the type of the matrix and can have 
+values \constant{DOUBLE}, \constant{INT} and \constant{COMPLEX}. 
+The \cdata{buffer} field is an array that contains the matrix elements 
+stored contiguously in column-major order. 
+
+The following C functions can be used to create matrices.
+\begin{cfuncdesc}{matrix*}{Matrix\_New}{int nrows, int ncols, int id}
+Returns a \mtrx\ object of type \var{id} with \var{nrows} rows
+and \var{ncols} columns. The elements of the matrix are uninitialized.
+\end{cfuncdesc}
+
+\begin{cfuncdesc}{matrix*}{Matrix\_NewFromMatrix}{matrix *src, int id}
+Returns a copy of the matrix \var{src} converted to type \var{id}. 
+The following type conversions are allowed: \itc\ to \dtc,
+\itc\ to \ztc\ and \dtc\  to \ztc.
+\end{cfuncdesc}
+
+\begin{cfuncdesc}{matrix*}{Matrix\_NewFromSequence}{PyListObject *x, int id}
+Creates a matrix of type \var{id} from the Python sequence type \var{x}. The
+returned matrix has size \code{(len(\var{x}),1)}.  
+The size can be changed by modifying the \member{nrows} and 
+\member{ncols} fields of the returned matrix.
+\end{cfuncdesc}
+
+To illustrate the creation and manipulation of dense matrices (as well
+as the Python C API), we show the code for the \function{uniform()} 
+function from \module{cvxopt.random} described in 
+section~\ref{s-random}.
+\begin{verbatim}
+PyObject * uniform(PyObject *self, PyObject *args, PyObject *kwrds) 
+{
+  matrix *obj;
+  int i, nrows, ncols = 1;
+  double a = 0, b = 1;
+  char *kwlist[] = {"nrows", "ncols", "a", "b", NULL};
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "i|idd", kwlist, 
+          &nrows, &ncols, &a, &b)) return NULL;
+  
+  if ((nrows<0) || (ncols<0)) {
+    PyErr_SetString(PyExc_TypeError, "dimensions must be non-negative");
+    return NULL;
+  }
+  
+  if (!(obj = Matrix_New(nrows, ncols, DOUBLE)))
+    return PyErr_NoMemory();
+  
+  for (i = 0; i < nrows*ncols; i++)
+    MAT_BUFD(obj)[i] = Uniform(a,b);
+  
+  return (PyObject *)obj;
+}
+\end{verbatim}
+
+\section{Sparse Matrices}
+Sparse matrices are stored in compressed column storage (CCS) 
+format.   For a general  \var{nrows} by \var{ncols} sparse matrix with 
+\var{nnz} nonzero entries this means the following.  The sparsity
+pattern and the nonzero values are stored in three fields:
+\begin{description}
+\item[values:] A \dtc\ or \ztc\ matrix of size \code{(\var{nnz},1)} 
+ with the nonzero entries of the matrix stored columnwise.  
+\item[rowind:] An array of integers of length \var{nnz} containing the
+row indices of the nonzero entries, stored in the same order as 
+\var{values}.
+\item[colptr:] An array of integers of length \code{\var{ncols}+1} with
+for each column of the matrix the index of the first element in 
+\var{values} from that column.  More precisely, 
+\code{\var{colptr}[0]} is \code{0}, and for 
+\code{\var{k} = 0, 1, \ldots, \var{ncols}-1},
+\code{\var{colptr}[k+1]} is equal to \code{\var{colptr}[k]} plus the 
+number of nonzeros in column \var{k} of the matrix.
+Thus, \code{\var{colptr}[\var{ncols}]} is equal to \var{nnz}, the 
+number of nonzero entries.
+\end{description}
+
+For example, for the matrix
+\[ 
+A=\left [\begin{array}{cccc}
+    1 & 0 & 0 & 5\\
+    2 & 0 & 4 & 0\\
+    0 & 0 & 0 & 6\\
+    3 & 0 & 0 & 0
+\end{array}\right]
+\] 
+the elements of \var{values}, \var{rowind} and \var{colptr} are:
+\begin{quote}
+  \var{values}: 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, \qquad  
+  \var{rowind}: 0, 1,3, 1, 0, 2, \qquad 
+  \var{colptr}: 0, 3, 3, 4, 6.
+\end{quote}
+It is crucial that for each column the row indices in \var{rowind} are
+sorted; the equivalent representation 
+\begin{quote}
+  \var{values}: 3.0, 2.0, 1.0, 4.0, 5.0, 6.0, \qquad  
+  \var{rowind}: 3, 1, 0, 1, 0, 2, \qquad 
+  \var{colptr}: 0, 3, 3, 4, 6
+\end{quote}
+is not allowed (and will likely cause the program to crash).
+
+The \cdata{nzmax} field specifies the number of non-zero elements the
+matrix can store.  It is equal to the length of \var{rowind} and 
+\var{values}; this number can be larger that 
+\code{\var{colptr}[\var{nrows}]}, but never less. 
+This field makes it possible to preallocate a certain amount of 
+memory to avoid reallocations if the matrix is constructed
+sequentially by filling in elements. 
+In general the \var{nzmax} field can safely be ignored, however, since 
+it will always be adjusted automatically as the number of non-zero 
+elements grows.
+
+The \cdata{id} field controls the type of the matrix and can have 
+values \constant{DOUBLE} and \constant{COMPLEX}. 
+
+Sparse matrices are created using the following functions from the API. 
+\begin{cfuncdesc}{spmatrix*}{SpMatrix\_New}{int nrows, int ncols, int
+    nzmax, int id} 
+  Returns a sparse zero matrix with \var{nrows} rows and
+  \var{ncols} columns. \var{nzmax} is the number of elements that will
+  be allocated (the length of the \var{values} and \var{rowind}
+  fields).  
+\end{cfuncdesc}
+
+\begin{cfuncdesc}{spmatrix*}{SpMatrix\_NewFromMatrix}{spmatrix *src, int
+    id}
+  Returns a copy the sparse matrix \var{src}. 
+\end{cfuncdesc}
+
+\begin{cfuncdesc}{spmatrix*}{SpMatrix\_NewFromIJV}{matrix *I, matrix *J, 
+    matrix *V, int nrows, int ncols, int nzmax, int id}
+  Creates a sparse matrix with \var{nrows} rows and \var{ncols}
+  columns from a triplet description. \var{I} and \var{J}
+  must be integer matrices and \var{V} either a double or complex matrix,
+  or \constant{NULL}. If \var{V} is \constant{NULL} the values of the 
+  entries in the matrix are undefined, otherwise they are
+  specified by \var{V}.  Repeated entries in \var{V} are summed. 
+  The number of allocated elements is given by \var{nzmax}, which is 
+  adjusted if it is smaller than the required amount. 
+\end{cfuncdesc}
+
+We illustrate use of the sparse matrix class by listing the source
+code for the \method{real()} method, which returns the real part of
+a sparse matrix: 
+
+\begin{verbatim}
+static PyObject * spmatrix_real(spmatrix *self) {
+
+  if (SP_ID(self) != COMPLEX) 
+    return (PyObject *)SpMatrix_NewFromMatrix(self, 0, SP_ID(self));
+  
+  spmatrix *ret = SpMatrix_New(SP_NROWS(self), SP_NCOLS(self), 
+      SP_NNZ(self), DOUBLE);
+  if (!ret) return PyErr_NoMemory();
+
+  int i;
+  for (i=0; i < SP_NNZ(self); i++) 
+    SP_VALD(ret)[i] = creal(SP_VALZ(self)[i]);
+  
+  memcpy(SP_COL(ret), SP_COL(self), (SP_NCOLS(self)+1)*sizeof(int_t));
+  memcpy(SP_ROW(ret), SP_ROW(self), SP_NNZ(self)*sizeof(int_t));
+  return (PyObject *)ret;
+}
+\end{verbatim}
diff --git a/doc/cvxopt.tex b/doc/cvxopt.tex
new file mode 100644
index 0000000..f0d4888
--- /dev/null
+++ b/doc/cvxopt.tex
@@ -0,0 +1,121 @@
+\documentclass{manual}
+\usepackage{graphicx}
+
+\def\BIT{\begin{itemize}}
+\def\EIT{\end{itemize}}
+\def\BEQ{\begin{equation}}
+\def\EEQ{\end{equation}}
+\def\reals{{\mbox{\bf R}}}
+\def\complex{{\mbox{\bf C}}}
+\newcommand{\eg}{{\em e.g.}}
+\newcommand{\ie}{{\em i.e.}}
+\newcommand{\BEA}{\begin{eqnarray}}
+\newcommand{\EEA}{\end{eqnarray}}
+\newcommand{\BEAS}{\begin{eqnarray*}}
+\newcommand{\EEAS}{\end{eqnarray*}}
+\newcommand{\Rank}{\mathop{\bf rank}}
+\newcommand{\Tr}{\mathop{\bf tr}}
+\newcommand{\lse}{\mathop{\bf lse}}
+\newcommand{\diag}{\mbox{\bf diag}\,}
+\newcommand{\ones}{{\bf 1}}
+\newcommand{\argmax}{\mathop{\rm argmax}}
+\newcommand{\symm}{{\mbox{\bf S}}}  
+\newcommand{\op}{\mathop{\mathrm{op}}}
+
+% constants
+\newcommand{\dtc}{\code{'d'}}
+\newcommand{\itc}{\code{'i'}}
+\newcommand{\ztc}{\code{'z'}}
+\newcommand{\None}{\code{None}}
+\newcommand{\True}{\code{True}}
+\newcommand{\False}{\code{False}}
+
+% types
+\newcommand{\flt}{\pytype{float}}
+\newcommand{\chr}{\pytype{char}}
+\newcommand{\intgr}{\pytype{integer}}
+\newcommand{\cmplx}{\pytype{complex}}
+\newcommand{\mtrx}{\class{matrix}}
+\newcommand{\spmtrx}{\class{spmatrix}}
+
+%\makeindex     
+
+\title{CVXOPT: A Python Package for Convex Optimization}
+\author{Joachim Dahl \& Lieven Vandenberghe \\
+{\tt joachim at kom.aau.dk}, {\tt vandenbe at ee.ucla.edu}}
+\date{February 6, 2007}
+\release{0.8.2}
+
+\begin{document}
+\maketitle
+
+\chapter*{Copyright and License}
+Copyright \copyright{2004-2007} J. Dahl \& L. Vandenberghe. 
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the 
+\ulink{GNU General Public License}{http://www.gnu.org/copyleft/gpl.html}
+as published by 
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+\ulink{GNU General Public License}{http://www.gnu.org/copyleft/gpl.html}
+for more details.
+
+\hrule
+The CVXOPT distribution includes source code for the following 
+software libraries.
+\BIT
+\item Part of the SuiteSparse suite of sparse matrix algorithms, 
+ including:
+\BIT
+\item AMD Version 2.0.  Copyright (c) 2006 by Timothy A.\ Davis, 
+ Patrick R.\ Amestoy, and Iain S.\ Duff.  
+\item CHOLMOD Version 1.4.  
+ Copyright (c) 2005-2006 by University of Florida, Timothy A. Davis 
+ and W. Hager.
+\item COLAMD version 2.6.  Copyright (c) 1998-2006 by Timothy A.\ Davis.
+\item UMFPACK Version 5.0.2. 
+ Copyright (c) 1995-2006 by Timothy A.\  Davis.
+\EIT
+
+These packages are licensed under the terms of the 
+\ulink{GNU Lesser General Public License}
+{http://www.gnu.org/copyleft/lesser.html} (UMFPACK, parts of CHOLMOD,
+AMD, COLAMD) and the \ulink{GNU General Public License}
+{http://www.gnu.org/copyleft/gpl.html} (parts of CHOLMOD).
+For details, consult the README files in the source directories or 
+the website listed below.
+
+\begin{quote}
+Availability: \ulink{www.cise.ufl.edu/research/sparse}
+{http://www.cise.ufl.edu/research/sparse}.
+\end{quote}
+
+\item RNGS Random Number Generation --- Multiple Streams 
+(Sep. 22, 1998) by Steve Park \& Dave Geyer.
+
+\begin{quote}
+Availability: \ulink{www.cs.wm.edu/\~{}va/software/park/park.html}
+{http://www.cs.wm.edu/\~{}va/software/park/park.html}.
+\end{quote}
+
+\EIT
+
+\tableofcontents
+
+\input{intro}
+\input{base}
+\input{blas}
+\input{lapack}
+\input{fftw}
+\input{base_sparse}
+\input{spsolvers}
+\input{solvers}
+\input{modeling}
+\input{c-api}
+\input{cvxopt.ind}
+\end{document}
diff --git a/doc/cvxopt/about.html b/doc/cvxopt/about.html
new file mode 100644
index 0000000..5295a32
--- /dev/null
+++ b/doc/cvxopt/about.html
@@ -0,0 +1,114 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="prev" href="genindex.html" />
+<link rel="parent" href="cvxopt.html" />
+<meta name='aesop' content='information' />
+<title>About this document ...</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="Index"
+  href="genindex.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="genindex.html">Index</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0014000000000000000000">
+About this document ...</A>
+</H1>
+ <strong>CVXOPT: A Python Package for Convex Optimization</strong>,
+February 6, 2007, Release 0.8.2
+<p> This document was generated using the <a
+    href="http://saftsack.fs.uni-bayreuth.de/~latex2ht/">
+    <strong>LaTeX</strong>2<tt>HTML</tt></a> translator.
+</p>
+
+<p> <a
+    href="http://saftsack.fs.uni-bayreuth.de/~latex2ht/">
+    <strong>LaTeX</strong>2<tt>HTML</tt></a> is Copyright ©
+  1993, 1994, 1995, 1996, 1997, <a
+    href="http://cbl.leeds.ac.uk/nikos/personal.html">Nikos
+    Drakos</a>, Computer Based Learning Unit, University of
+  Leeds, and Copyright © 1997, 1998, <a
+    href="http://www.maths.mq.edu.au/~ross/">Ross
+    Moore</a>, Mathematics Department, Macquarie University,
+  Sydney.
+</p>
+
+<p> The application of <a
+    href="http://saftsack.fs.uni-bayreuth.de/~latex2ht/">
+    <strong>LaTeX</strong>2<tt>HTML</tt></a> to the Python
+  documentation has been heavily tailored by Fred L. Drake,
+  Jr.  Original navigation icons were contributed by Christopher
+  Petrilli.
+</p>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="Index"
+  href="genindex.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="genindex.html">Index</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/blank.gif b/doc/cvxopt/blank.gif
new file mode 100644
index 0000000..2e31f4e
Binary files /dev/null and b/doc/cvxopt/blank.gif differ
diff --git a/doc/cvxopt/c-fftw.html b/doc/cvxopt/c-fftw.html
new file mode 100644
index 0000000..15dc1a3
--- /dev/null
+++ b/doc/cvxopt/c-fftw.html
@@ -0,0 +1,130 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node33.html" />
+<link rel="prev" href="node19.html" />
+<link rel="parent" href="cvxopt.html" />
+<link rel="next" href="node30.html" />
+<meta name='aesop' content='information' />
+<title>5. Discrete Transforms (cvxopt.fftw)</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.9 Example: Analytic Centering"
+  href="node28.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="5.1 Discrete Fourier Transform"
+  href="node30.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node28.html">4.9 Example: Analytic Centering</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node30.html">5.1 Discrete Fourier Transform</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION007000000000000000000"></A> <A NAME="c-fftw"></A>
+<BR>
+5. Discrete Transforms (<tt class="module">cvxopt.fftw</tt>)
+</H1>
+
+<P>
+The <tt class="module">cvxopt.fftw</tt> module is an interface to the FFTW library
+and contains routines for discrete Fourier, cosine, and sine 
+transforms.  This module is optional, and only installed when 
+the FFTW library is made available during the CVXOPT installation.
+
+<P>
+<div class="seealso">
+  <p class="heading">See Also:</p>
+
+<dl compact="compact" class="seeurl">
+    <dt><a href='http://www.fftw.org'
+        >FFTW3 code, documentation, copyright and
+license.</a></dt>
+    <dd></dd>
+  </dl>
+</div>
+
+<P>
+
+<p><br /></p><hr class='online-navigation' />
+<div class='online-navigation'>
+<!--Table of Child-Links-->
+<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></a>
+
+<UL CLASS="ChildLinks">
+<LI><A href="node30.html">5.1 Discrete Fourier Transform</a>
+<LI><A href="node31.html">5.2 Discrete Cosine Transform</a>
+<LI><A href="node32.html">5.3 Discrete Sine Transform</a>
+</ul>
+<!--End of Table of Child-Links-->
+</div>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.9 Example: Analytic Centering"
+  href="node28.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="5.1 Discrete Fourier Transform"
+  href="node30.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node28.html">4.9 Example: Analytic Centering</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node30.html">5.1 Discrete Fourier Transform</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/c-spsolvers.html b/doc/cvxopt/c-spsolvers.html
new file mode 100644
index 0000000..78756ac
--- /dev/null
+++ b/doc/cvxopt/c-spsolvers.html
@@ -0,0 +1,136 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node45.html" />
+<link rel="prev" href="node33.html" />
+<link rel="parent" href="cvxopt.html" />
+<link rel="next" href="s-orderings.html" />
+<meta name='aesop' content='information' />
+<title>7. Sparse Linear Equation Solvers</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="6.6 Sparse BLAS Functions"
+  href="node39.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="7.1 Matrix Orderings (cvxopt.amd)"
+  href="s-orderings.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node39.html">6.6 Sparse BLAS Functions</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-orderings.html">7.1 Matrix Orderings (cvxopt.amd)</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION009000000000000000000"></A> <A NAME="c-spsolvers"></A>
+<BR>
+7. Sparse Linear Equation Solvers
+</H1>
+In this section we describe routines for solving sparse sets of linear 
+equations.
+
+<P>
+A real symmetric or complex Hermitian sparse matrix is stored as
+an <tt class="class">spmatrix</tt> object <var>X</var>  of size (<I>n</I>, <I>n</I>) and an 
+additional character argument <code>uplo</code> with possible values 
+<code>'L'</code> and <code>'U'</code>.  
+If <code>uplo</code> is <code>'L'</code>, the lower triangular part
+of <var>X</var> contains the lower triangular part of the
+symmetric or Hermitian matrix, and the upper triangular matrix
+of <var>X</var> is ignored.
+If <code>uplo</code> is <code>'U'</code>, the upper triangular part
+of <var>X</var> contains the upper triangular part of the
+matrix, and the lower triangular matrix of <var>X</var> is ignored.
+
+<P>
+A general sparse square matrix of order <I>n</I> is represented by an
+<tt class="class">spmatrix</tt> object of size (<I>n</I>, <I>n</I>).
+
+<P>
+Dense matrices, which appear as righthand sides of equations, are 
+stored using the same conventions as in the BLAS and LAPACK modules.
+
+<P>
+
+<p><br /></p><hr class='online-navigation' />
+<div class='online-navigation'>
+<!--Table of Child-Links-->
+<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></a>
+
+<UL CLASS="ChildLinks">
+<LI><A href="s-orderings.html">7.1 Matrix Orderings (<tt class="module">cvxopt.amd</tt>)</a>
+<LI><A href="s-umfpack.html">7.2 General Linear Equations (<tt class="module">cvxopt.umfpack</tt>)</a>
+<LI><A href="s-cholmod.html">7.3 Positive Definite Linear Equations (<tt class="module">cvxopt.cholmod</tt>)</a>
+<LI><A href="e-covsel.html">7.4 Example: Covariance Selection</a>
+</ul>
+<!--End of Table of Child-Links-->
+</div>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="6.6 Sparse BLAS Functions"
+  href="node39.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="7.1 Matrix Orderings (cvxopt.amd)"
+  href="s-orderings.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node39.html">6.6 Sparse BLAS Functions</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-orderings.html">7.1 Matrix Orderings (cvxopt.amd)</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/contents.gif b/doc/cvxopt/contents.gif
new file mode 100644
index 0000000..6d299c4
Binary files /dev/null and b/doc/cvxopt/contents.gif differ
diff --git a/doc/cvxopt/contents.html b/doc/cvxopt/contents.html
new file mode 100644
index 0000000..d54f9a2
--- /dev/null
+++ b/doc/cvxopt/contents.html
@@ -0,0 +1,179 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node3.html" />
+<link rel="prev" href="node1.html" />
+<link rel="parent" href="cvxopt.html" />
+<link rel="next" href="node3.html" />
+<meta name='aesop' content='information' />
+<title>Contents</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="Copyright and License"
+  href="node1.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="1. Introduction"
+  href="node3.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node1.html">Copyright and License</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node3.html">1. Introduction</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+<BR><h2><A NAME="SECTION002000000000000000000">
+Contents</A>
+</h2>
+<!--Table of Contents-->
+
+<UL CLASS="TofC">
+<LI><A href="node3.html">1. Introduction</a>
+<LI><A href="node4.html">2. Dense Matrices (cvxopt.base)</a>
+<UL>
+<LI><A href="s-creating-matrices.html">2.1 Creating Matrices</a>
+<LI><A href="node6.html">2.2 Attributes and Methods</a>
+<LI><A href="s-arithmetic.html">2.3 Arithmetic Operations</a>
+<LI><A href="s-indexing.html">2.4 Indexing and Slicing</a>
+<LI><A href="s-builtinfuncs.html">2.5 Built-in Functions</a>
+<LI><A href="s-otherfuncs.html">2.6 Other Matrix Functions</a>
+<LI><A href="s-random.html">2.7 Randomly Generated Matrices</a>
+<LI><A href="s-array-interface.html">2.8 The NumPy Array Interface</a>
+<LI><A href="node13.html">2.9 Printing Options</a>
+</ul>
+<LI><A href="node14.html">3. The BLAS Interface (cvxopt.blas)</a>
+<UL>
+<LI><A href="s-conventions.html">3.1 Matrix Classes</a>
+<LI><A href="s-blas1.html">3.2 Level 1 BLAS</a>
+<LI><A href="s-blas2.html">3.3 Level 2 BLAS</a>
+<LI><A href="s-blas3.html">3.4 Level 3 BLAS</a>
+</ul>
+<LI><A href="node19.html">4. The LAPACK Interface (cvxopt.lapack)</a>
+<UL>
+<LI><A href="node20.html">4.1 General Linear Equations</a>
+<LI><A href="e-kkt-example.html">4.2 Positive Definite Linear Equations</a>
+<LI><A href="node22.html">4.3 Symmetric and Hermitian Linear Equations</a>
+<LI><A href="node23.html">4.4 Triangular Linear Equations</a>
+<LI><A href="node24.html">4.5 Least-Squares and Least-Norm Problems</a>
+<LI><A href="node25.html">4.6 Symmetric and Hermitian Eigenvalue Decomposition</a>
+<LI><A href="e-gevd.html">4.7 Generalized Symmetric Definite Eigenproblems</a>
+<LI><A href="node27.html">4.8 Singular Value Decomposition</a>
+<LI><A href="node28.html">4.9 Example: Analytic Centering</a>
+</ul>
+<LI><A href="c-fftw.html">5. Discrete Transforms (cvxopt.fftw)</a>
+<UL>
+<LI><A href="node30.html">5.1 Discrete Fourier Transform</a>
+<LI><A href="node31.html">5.2 Discrete Cosine Transform</a>
+<LI><A href="node32.html">5.3 Discrete Sine Transform</a>
+</ul>
+<LI><A href="node33.html">6. Sparse Matrices (cvxopt.base)</a>
+<UL>
+<LI><A href="s-creating-spmatrix.html">6.1 Creating Sparse Matrices</a>
+<LI><A href="e-spA-example.html">6.2 Attributes and Methods</a>
+<LI><A href="s-spmatrix-arith.html">6.3 Arithmetic Operations</a>
+<LI><A href="node37.html">6.4 Indexing and Slicing</a>
+<LI><A href="node38.html">6.5 Built-In Functions</a>
+<LI><A href="node39.html">6.6 Sparse BLAS Functions</a>
+</ul>
+<LI><A href="c-spsolvers.html">7. Sparse Linear Equation Solvers</a>
+<UL>
+<LI><A href="s-orderings.html">7.1 Matrix Orderings (cvxopt.amd)</a>
+<LI><A href="s-umfpack.html">7.2 General Linear Equations (cvxopt.umfpack)</a>
+<LI><A href="s-cholmod.html">7.3 Positive Definite Linear Equations (cvxopt.cholmod)</a>
+<LI><A href="e-covsel.html">7.4 Example: Covariance Selection</a>
+</ul>
+<LI><A href="node45.html">8. Optimization Routines (cvxopt.solvers)</a>
+<UL>
+<LI><A href="s-lpsolver.html">8.1 Linear Programming</a>
+<LI><A href="node47.html">8.2 Quadratic Programming</a>
+<LI><A href="node48.html">8.3 Geometric Programming</a>
+<LI><A href="s-sdpsolver.html">8.4 Semidefinite Programming</a>
+<LI><A href="e-nlcp.html">8.5 Nonlinear Convex Programming</a>
+<LI><A href="node51.html">8.6 Exploiting Structure in LPs and SDPs</a>
+<LI><A href="node52.html">8.7 Exploiting Structure in Nonlinear Convex Programs</a>
+<LI><A href="s-external.html">8.8 Optional Solvers</a>
+<LI><A href="s-parameters.html">8.9 Algorithm Parameters</a>
+</ul>
+<LI><A href="node55.html">9. Modeling (cvxopt.modeling)</a>
+<UL>
+<LI><A href="s-variables.html">9.1 Variables</a>
+<LI><A href="s-functions.html">9.2 Functions</a>
+<LI><A href="node58.html">9.3 Constraints</a>
+<LI><A href="s-lp.html">9.4 Optimization Problems</a>
+<LI><A href="node60.html">9.5 Examples</a>
+</ul>
+<LI><A href="node61.html">10. C API</a>
+<UL>
+<LI><A href="node62.html">10.1 Dense Matrices</a>
+<LI><A href="node63.html">10.2 Sparse Matrices</a>
+</ul>
+<LI><A href="genindex.html">Index</a>
+</ul>
+<!--End of Table of Contents-->
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="Copyright and License"
+  href="node1.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="1. Introduction"
+  href="node3.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node1.html">Copyright and License</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node3.html">1. Introduction</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/cvxopt.css b/doc/cvxopt/cvxopt.css
new file mode 100644
index 0000000..06a613c
--- /dev/null
+++ b/doc/cvxopt/cvxopt.css
@@ -0,0 +1,243 @@
+/*
+ * The first part of this is the standard CSS generated by LaTeX2HTML,
+ * with the "empty" declarations removed.
+ */
+
+/* Century Schoolbook font is very similar to Computer Modern Math: cmmi */
+.math                   { font-family: "Century Schoolbook", serif; }
+.math i                 { font-family: "Century Schoolbook", serif;
+                          font-weight: bold }
+.boldmath               { font-family: "Century Schoolbook", serif;
+                          font-weight: bold }
+
+/*
+ * Implement both fixed-size and relative sizes.
+ *
+ * I think these can be safely removed, as it doesn't appear that
+ * LaTeX2HTML ever generates these, even though these are carried
+ * over from the LaTeX2HTML stylesheet.
+ */
+small.xtiny             { font-size : xx-small; }
+small.tiny              { font-size : x-small; }
+small.scriptsize        { font-size : smaller; }
+small.footnotesize      { font-size : small; }
+big.xlarge              { font-size : large; }
+big.xxlarge             { font-size : x-large; }
+big.huge                { font-size : larger; }
+big.xhuge               { font-size : xx-large; }
+
+/*
+ * Document-specific styles come next;
+ * these are added for the Python documentation.
+ *
+ * Note that the size specifications for the H* elements are because
+ * Netscape on Solaris otherwise doesn't get it right; they all end up
+ * the normal text size.
+ */
+
+body                    { color: #000000;
+                          background-color: #ffffff; }
+
+a:link:active           { color: #ff0000; }
+a:link:hover            { background-color: #bbeeff; }
+a:visited:hover         { background-color: #bbeeff; }
+a:visited               { color: #551a8b; }
+a:link                  { color: #0000bb; }
+
+h1, h2, h3, h4, h5, h6  { font-family: avantgarde, sans-serif;
+                          font-weight: bold; }
+h1                      { font-size: 180%; }
+h2                      { font-size: 150%; }
+h3, h4                  { font-size: 120%; }
+
+/* These are section titles used in navigation links, so make sure we
+ * match the section header font here, even it not the weight.
+ */
+.sectref                { font-family: avantgarde, sans-serif; }
+/* And the label before the titles in navigation: */
+.navlabel               { font-size: 85%; }
+
+
+/* LaTeX2HTML insists on inserting <br> elements into headers which
+ * are marked with \label.  This little bit of CSS magic ensures that
+ * these elements don't cause spurious whitespace to be added.
+ */
+h1>br, h2>br, h3>br,
+h4>br, h5>br, h6>br     { display: none; }
+
+code, tt                { font-family: "lucida typewriter", lucidatypewriter,
+                                       monospace; }
+var                     { font-family: times, serif;
+                          font-style: italic;
+                          font-weight: normal; }
+
+.Unix                   { font-variant: small-caps; }
+
+.typelabel              { font-family: lucida, sans-serif; }
+
+.navigation td          { background-color: #99ccff;
+                          font-weight: bold;
+                          font-family: avantgarde, sans-serif;
+                          font-size: 110%; }
+
+div.warning             { background-color: #fffaf0;
+                          border: thin solid black;
+                          padding: 1em;
+                          margin-left: 2em;
+                          margin-right: 2em; }
+
+div.warning .label      { font-family: sans-serif;
+                          font-size: 110%;
+                          margin-right: 0.5em; }
+
+div.note                { background-color: #fffaf0;
+                          border: thin solid black;
+                          padding: 1em;
+                          margin-left: 2em;
+                          margin-right: 2em; }
+
+div.note .label         { margin-right: 0.5em;
+                          font-family: sans-serif; }
+
+address                 { font-size: 80%; }
+.release-info           { font-style: italic;
+                          font-size: 80%; }
+
+.titlegraphic           { vertical-align: top; }
+
+.verbatim pre           { color: #00008b;
+                          font-family: "lucida typewriter", lucidatypewriter,
+                                       monospace;
+                          font-size: 90%; }
+.verbatim               { margin-left: 2em; }
+.verbatim .footer       { padding: 0.05in;
+                          font-size: 85%;
+                          background-color: #99ccff;
+                          margin-right: 0.5in; }
+
+.grammar                { background-color: #99ccff;
+                          margin-right: 0.5in;
+                          padding: 0.05in; }
+.grammar-footer         { padding: 0.05in;
+                          font-size: 85%; }
+.grammartoken           { font-family: "lucida typewriter", lucidatypewriter,
+                                       monospace; }
+
+.productions                  { background-color: #bbeeff; }
+.productions a:active         { color: #ff0000; }
+.productions a:link:hover     { background-color: #99ccff; }
+.productions a:visited:hover  { background-color: #99ccff; }
+.productions a:visited        { color: #551a8b; }
+.productions a:link           { color: #0000bb; }
+.productions table            { vertical-align: baseline;
+                                empty-cells: show; }
+.productions > table td,
+.productions > table th       { padding: 2px; }
+.productions > table td:first-child,
+.productions > table td:last-child {
+                                font-family: "lucida typewriter",
+                                             lucidatypewriter,
+                                             monospace;
+                                }
+/* same as the second selector above, but expressed differently for Opera */
+.productions > table td:first-child + td + td {
+                                font-family: "lucida typewriter",
+                                             lucidatypewriter,
+                                             monospace;
+                                vertical-align: baseline;
+                                }
+.productions > table td:first-child + td {
+                                padding-left: 1em;
+                                padding-right: 1em;
+                                }
+.productions > table tr       { vertical-align: baseline; }
+
+.email                  { font-family: avantgarde, sans-serif; }
+.mailheader             { font-family: avantgarde, sans-serif; }
+.mimetype               { font-family: avantgarde, sans-serif; }
+.newsgroup              { font-family: avantgarde, sans-serif; }
+.url                    { font-family: avantgarde, sans-serif; }
+.file                   { font-family: avantgarde, sans-serif; }
+.guilabel               { font-family: avantgarde, sans-serif; }
+
+.realtable              { border-collapse: collapse;
+                          border-color: black;
+                          border-style: solid;
+                          border-width: 0px 0px 2px 0px;
+                          empty-cells: show;
+                          margin-left: auto;
+                          margin-right: auto;
+                          padding-left: 0.4em;
+                          padding-right: 0.4em;
+                          }
+.realtable tbody        { vertical-align: baseline; }
+.realtable tfoot        { display: table-footer-group; }
+.realtable thead        { background-color: #99ccff;
+                          border-width: 0px 0px 2px 1px;
+                          display: table-header-group;
+                          font-family: avantgarde, sans-serif;
+                          font-weight: bold;
+                          vertical-align: baseline;
+                          }
+.realtable thead :first-child {
+                          border-width: 0px 0px 2px 0px;
+                          }
+.realtable thead th     { border-width: 0px 0px 2px 1px }
+.realtable td,
+.realtable th           { border-color: black;
+                          border-style: solid;
+                          border-width: 0px 0px 1px 1px;
+                          padding-left: 0.4em;
+                          padding-right: 0.4em;
+                          }
+.realtable td:first-child,
+.realtable th:first-child {
+                          border-left-width: 0px;
+                          vertical-align: baseline;
+                          }
+.center                 { text-align: center; }
+.left                   { text-align: left; }
+.right                  { text-align: right; }
+
+.refcount-info          { font-style: italic; }
+.refcount-info .value   { font-weight: bold;
+                          color: #006600; }
+
+/*
+ * Some decoration for the "See also:" blocks, in part inspired by some of
+ * the styling on Lars Marius Garshol's XSA pages.
+ * (The blue in the navigation bars is #99CCFF.)
+ */
+.seealso                { background-color: #fffaf0;
+                          border: thin solid black;
+                          padding: 0pt 1em 4pt 1em; }
+
+.seealso > .heading     { font-size: 110%;
+                          font-weight: bold; }
+
+/*
+ * Class 'availability' is used for module availability statements at
+ * the top of modules.
+ */
+.availability .platform { font-weight: bold; }
+
+
+/*
+ * Additional styles for the distutils package.
+ */
+.du-command             { font-family: monospace; }
+.du-option              { font-family: avantgarde, sans-serif; }
+.du-filevar             { font-family: avantgarde, sans-serif;
+                          font-style: italic; }
+.du-xxx:before          { content: "** ";
+                          font-weight: bold; }
+.du-xxx:after           { content: " **";
+                          font-weight: bold; }
+
+
+/*
+ * Some specialization for printed output.
+ */
+ at media print {
+  .online-navigation    { display: none; }
+  }
diff --git a/doc/cvxopt/cvxopt.html b/doc/cvxopt/cvxopt.html
new file mode 100644
index 0000000..a77b0dd
--- /dev/null
+++ b/doc/cvxopt/cvxopt.html
@@ -0,0 +1,183 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node1.html" />
+<meta name='aesop' content='information' />
+<title>CVXOPT: A Python Package for Convex Optimization</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></td>
+<td class='online-navigation'><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></td>
+<td class='online-navigation'><a rel="next" title="Copyright and License"
+  href="node1.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node1.html">Copyright and License</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<div class="titlepage">
+<div class='center'>
+<h1>CVXOPT: A Python Package for Convex Optimization</h1>
+<p><b><font size="+2">Joachim Dahl & Lieven Vandenberghe</font></b></p>
+<p><i><TT>joachim at kom.aau.dk</TT>, <TT>vandenbe at ee.ucla.edu</TT></i></p>
+<p><strong>Release 0.8.2</strong><br />
+<strong>February 6, 2007</strong></p>
+<p></p>
+</div>
+</div>
+
+<P>
+
+<p><br /></p><hr class='online-navigation' />
+<div class='online-navigation'>
+<!--Table of Child-Links-->
+<A NAME="CHILD_LINKS"></a>
+
+<UL CLASS="ChildLinks">
+<LI><A href="node1.html">Copyright and License</a>
+<LI><A href="contents.html">Contents</a>
+<LI><A href="node3.html">1. Introduction</a>
+<LI><A href="node4.html">2. Dense Matrices (<tt class="module">cvxopt.base</tt>)</a>
+<UL>
+<LI><A href="s-creating-matrices.html">2.1 Creating Matrices</a>
+<LI><A href="node6.html">2.2 Attributes and Methods</a>
+<LI><A href="s-arithmetic.html">2.3 Arithmetic Operations</a>
+<LI><A href="s-indexing.html">2.4 Indexing and Slicing</a>
+<LI><A href="s-builtinfuncs.html">2.5 Built-in Functions</a>
+<LI><A href="s-otherfuncs.html">2.6 Other Matrix Functions</a>
+<LI><A href="s-random.html">2.7 Randomly Generated Matrices</a>
+<LI><A href="s-array-interface.html">2.8 The NumPy Array Interface</a>
+<LI><A href="node13.html">2.9 Printing Options</a>
+</ul>
+<LI><A href="node14.html">3. The BLAS Interface (<tt class="module">cvxopt.blas</tt>)</a>
+<UL>
+<LI><A href="s-conventions.html">3.1 Matrix Classes</a>
+<LI><A href="s-blas1.html">3.2 Level 1 BLAS</a>
+<LI><A href="s-blas2.html">3.3 Level 2 BLAS</a>
+<LI><A href="s-blas3.html">3.4 Level 3 BLAS</a>
+</ul>
+<LI><A href="node19.html">4. The LAPACK Interface (<tt class="module">cvxopt.lapack</tt>)</a>
+<UL>
+<LI><A href="node20.html">4.1 General Linear Equations</a>
+<LI><A href="e-kkt-example.html">4.2 Positive Definite Linear Equations</a>
+<LI><A href="node22.html">4.3 Symmetric and Hermitian Linear Equations</a>
+<LI><A href="node23.html">4.4 Triangular Linear Equations</a>
+<LI><A href="node24.html">4.5 Least-Squares and Least-Norm Problems</a>
+<LI><A href="node25.html">4.6 Symmetric and Hermitian Eigenvalue Decomposition</a>
+<LI><A href="e-gevd.html">4.7 Generalized Symmetric Definite Eigenproblems</a>
+<LI><A href="node27.html">4.8 Singular Value Decomposition</a>
+<LI><A href="node28.html">4.9 Example: Analytic Centering</a>
+</ul>
+<LI><A href="c-fftw.html">5. Discrete Transforms (<tt class="module">cvxopt.fftw</tt>)</a>
+<UL>
+<LI><A href="node30.html">5.1 Discrete Fourier Transform</a>
+<LI><A href="node31.html">5.2 Discrete Cosine Transform</a>
+<LI><A href="node32.html">5.3 Discrete Sine Transform</a>
+</ul>
+<LI><A href="node33.html">6. Sparse Matrices (<tt class="module">cvxopt.base</tt>)</a>
+<UL>
+<LI><A href="s-creating-spmatrix.html">6.1 Creating Sparse Matrices</a>
+<LI><A href="e-spA-example.html">6.2 Attributes and Methods</a>
+<LI><A href="s-spmatrix-arith.html">6.3 Arithmetic Operations</a>
+<LI><A href="node37.html">6.4 Indexing and Slicing</a>
+<LI><A href="node38.html">6.5 Built-In Functions</a>
+<LI><A href="node39.html">6.6 Sparse BLAS Functions</a>
+</ul>
+<LI><A href="c-spsolvers.html">7. Sparse Linear Equation Solvers</a>
+<UL>
+<LI><A href="s-orderings.html">7.1 Matrix Orderings (<tt class="module">cvxopt.amd</tt>)</a>
+<LI><A href="s-umfpack.html">7.2 General Linear Equations (<tt class="module">cvxopt.umfpack</tt>)</a>
+<LI><A href="s-cholmod.html">7.3 Positive Definite Linear Equations (<tt class="module">cvxopt.cholmod</tt>)</a>
+<LI><A href="e-covsel.html">7.4 Example: Covariance Selection</a>
+</ul>
+<LI><A href="node45.html">8. Optimization Routines (<tt class="module">cvxopt.solvers</tt>)</a>
+<UL>
+<LI><A href="s-lpsolver.html">8.1 Linear Programming</a>
+<LI><A href="node47.html">8.2 Quadratic Programming</a>
+<LI><A href="node48.html">8.3 Geometric Programming</a>
+<LI><A href="s-sdpsolver.html">8.4 Semidefinite Programming</a>
+<LI><A href="e-nlcp.html">8.5 Nonlinear Convex Programming</a>
+<LI><A href="node51.html">8.6 Exploiting Structure in LPs and SDPs</a>
+<LI><A href="node52.html">8.7 Exploiting Structure in Nonlinear Convex Programs</a>
+<LI><A href="s-external.html">8.8 Optional Solvers</a>
+<LI><A href="s-parameters.html">8.9 Algorithm Parameters</a>
+</ul>
+<LI><A href="node55.html">9. Modeling (<tt class="module">cvxopt.modeling</tt>)</a>
+<UL>
+<LI><A href="s-variables.html">9.1 Variables</a>
+<LI><A href="s-functions.html">9.2 Functions</a>
+<LI><A href="node58.html">9.3 Constraints</a>
+<LI><A href="s-lp.html">9.4 Optimization Problems</a>
+<LI><A href="node60.html">9.5 Examples</a>
+</ul>
+<LI><A href="node61.html">10. C API</a>
+<UL>
+<LI><A href="node62.html">10.1 Dense Matrices</a>
+<LI><A href="node63.html">10.2 Sparse Matrices</a>
+</ul>
+<LI><A href="genindex.html">Index</a>
+<LI><A href="about.html">About this document ...</a>
+</ul>
+<!--End of Table of Child-Links-->
+</div>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></td>
+<td class='online-navigation'><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></td>
+<td class='online-navigation'><a rel="next" title="Copyright and License"
+  href="node1.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node1.html">Copyright and License</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/e-covsel.html b/doc/cvxopt/e-covsel.html
new file mode 100644
index 0000000..e04b892
--- /dev/null
+++ b/doc/cvxopt/e-covsel.html
@@ -0,0 +1,320 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="prev" href="s-cholmod.html" />
+<link rel="parent" href="c-spsolvers.html" />
+<link rel="next" href="node45.html" />
+<meta name='aesop' content='information' />
+<title>7.4 Example: Covariance Selection</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="7.3 Positive Definite Linear"
+  href="s-cholmod.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="7. Sparse Linear Equation"
+  href="c-spsolvers.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-cholmod.html">7.3 Positive Definite Linear</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="c-spsolvers.html">7. Sparse Linear Equation</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION009400000000000000000">
+7.4 Example: Covariance Selection</A>
+</H1>
+This example illustrates the use of the routines for sparse Cholesky 
+factorization.  We consider the problem 
+<BR>
+<DIV ALIGN="RIGHT" CLASS="mathdisplay">
+
+<!-- MATH
+ \begin{equation}
+\begin{array}{ll}
+ \mbox{minimize} & -\log\det K + \mathop{\bf tr}(KY)\\
+ \mbox{subject to} & K_{ij}=0,\quad (i,j) \not \in S.
+ \end{array}
+\end{equation}
+ -->
+<A NAME="e-covsel"></A>
+<TABLE WIDTH="100%" ALIGN="CENTER">
+<TR VALIGN="MIDDLE"><TD></TD><TD ALIGN="CENTER" NOWRAP><A NAME="e-covsel"></A><IMG
+ WIDTH="227" HEIGHT="45" BORDER="0"
+ SRC="img104.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & -\log\det K + \mathop{...
+...box{subject to} & K_{ij}=0,\quad (i,j) \not \in S.
+\end{array}\end{displaymath}"></TD>
+<TD CLASS="eqno" WIDTH=10 ALIGN="RIGHT">
+(7.5)</TD></TR>
+</TABLE>
+<BR CLEAR="ALL"></DIV><P></P>
+The optimization variable is a symmetric matrix <I>K</I> of order <I>n</I>
+and the domain of the problem is the set of positive definite matrices.
+The matrix <SPAN CLASS="MATH"><IMG
+ WIDTH="17" HEIGHT="14" ALIGN="BOTTOM" BORDER="0"
+ SRC="img105.gif"
+ ALT="$Y$"></SPAN> and the index set  <SPAN CLASS="MATH"><IMG
+ WIDTH="15" HEIGHT="14" ALIGN="BOTTOM" BORDER="0"
+ SRC="img106.gif"
+ ALT="$S$"></SPAN> are given.  We assume that all 
+the diagonal positions are included in <SPAN CLASS="MATH"><IMG
+ WIDTH="15" HEIGHT="14" ALIGN="BOTTOM" BORDER="0"
+ SRC="img106.gif"
+ ALT="$S$"></SPAN>.
+This problem arises in maximum likelihood estimation of the covariance
+matrix of a zero-mean normal distribution, with constraints 
+that specify that pairs of variables are conditionally independent.
+
+<P>
+We can express <I>K</I> as
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+K(x) = E_1\mbox{\bf diag}\,(x)E_2^T+E_2\mbox{\bf diag}\,(x)E_1^T
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="265" HEIGHT="28" BORDER="0"
+ SRC="img107.gif"
+ ALT="\begin{displaymath}
+K(x) = E_1\mbox{\bf diag}\,(x)E_2^T+E_2\mbox{\bf diag}\,(x)E_1^T
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>x</I> are the nonzero elements in the lower triangular part
+of <I>K</I>, with the diagonal elements scaled by 1/2,
+and
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+E_1 = \left[ \begin{array}{cccc}
+  e_{i_1} & e_{i_2} & \cdots & e_{i_q} \end{array}\right], \qquad
+ E_2 = \left[ \begin{array}{cccc}
+  e_{j_1} & e_{j_2} & \cdots & e_{j_q} \end{array}\right],
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="436" HEIGHT="30" BORDER="0"
+ SRC="img108.gif"
+ ALT="\begin{displaymath}
+E_1 = \left[ \begin{array}{cccc}
+e_{i_1} & e_{i_2} & \cdot...
+...cc}
+e_{j_1} & e_{j_2} & \cdots & e_{j_q} \end{array}\right],
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where (<I>i_k</I>, <I>j_k</I>) are the positions of the nonzero 
+entries in the lower-triangular part of <I>K</I>.
+With this notation, we can solve problem (<A HREF="#e-covsel">7.5</A>) by solving
+the unconstrained problem
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+   \mbox{minimize} & f(x) = -\log\det K(x) + \mathop{\bf tr}(K(x)Y).
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="325" HEIGHT="30" BORDER="0"
+ SRC="img109.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & f(x) = -\log\det K(x) + \mathop{\bf tr}(K(x)Y).
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+The code below implements Newton's method with a backtracking line
+search.  The gradient and Hessian of the objective function are given 
+by
+<P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{eqnarray*}
+\nabla f(x) 
+&=& 2 \mbox{\bf diag}\,( E_1^T (Y - K(x)^{-1}) E_2)) \\
+&=& 2\mbox{\bf diag}\,(Y_{IJ} - \left(K(x)^{-1}\right)_{IJ})\\
+\nabla^2 f(x) & = & 
+ 2 (E_1^T K(x)^{-1} E_1) \circ (E_2^T K(x)^{-1} E_2) 
+   + 2 (E_1^T K(x)^{-1} E_2) \circ (E_2^T K(x)^{-1} E_1) \\
+&=& 2 \left(K(x)^{-1}\right)_{II} \circ 
+      \left(K(x)^{-1}\right)_{JJ}
+   +2 \left(K(x)^{-1}\right)_{IJ} \circ 
+      \left(K(x)^{-1}\right)_{JI},
+\end{eqnarray*}
+ -->
+<IMG
+ WIDTH="588" HEIGHT="105" BORDER="0"
+ SRC="img110.gif"
+ ALT="\begin{eqnarray*}
+\nabla f(x)
+&=& 2 \mbox{\bf diag}\,( E_1^T (Y - K(x)^{-1}) E_...
+...\left(K(x)^{-1}\right)_{IJ} \circ
+\left(K(x)^{-1}\right)_{JI},
+\end{eqnarray*}"></DIV>
+<BR CLEAR="ALL"><P></P>
+<BR CLEAR="ALL"><P></P>
+where <code>o</code> denotes Hadamard product.
+
+<P>
+<div class="verbatim"><pre>
+from cvxopt.base import matrix, spmatrix, log, mul
+from cvxopt import blas, lapack, amd, cholmod
+
+def covsel(Y):
+    """
+    Returns the solution of
+
+         minimize    -logdet K + Tr(KY)
+         subject to  K_{ij}=0,  (i,j) not in indices listed in I,J.
+
+    Y is a symmetric sparse matrix with nonzero diagonal elements.
+    I = Y.I,  J = Y.J.
+    """
+
+    I, J = Y.I, Y.J
+    n, m = Y.size[0], len(I) 
+    N = I + J*n         # non-zero positions for one-argument indexing 
+    D = [k for k in xrange(m) if I[k]==J[k]]  # position of diagonal elements
+
+    # starting point: symmetric identity with nonzero pattern I,J
+    K = spmatrix(0, I, J) 
+    K[::n+1] = 1
+
+    # Kn is used in the line search
+    Kn = spmatrix(0, I, J)
+
+    # symbolic factorization of K 
+    F = cholmod.symbolic(K)
+
+    # Kinv will be the inverse of K
+    Kinv = matrix(0.0, (n,n))
+    
+    for iters in xrange(100):
+
+        # numeric factorization of K
+        cholmod.numeric(K, F)
+        d = cholmod.diag(F)
+
+        # compute Kinv by solving K*X = I 
+        Kinv[:] = 0
+        Kinv[::n+1] = 1
+        cholmod.solve(F, Kinv)
+
+        # solve Newton system
+        grad = 2*(Y.V - Kinv[N])
+        hess = 2*(mul(Kinv[I,J],Kinv[J,I]) + mul(Kinv[I,I],Kinv[J,J]))
+        v = -grad
+        lapack.posv(hess,v) 
+        
+        # stopping criterion
+        sqntdecr = -blas.dot(grad,v) 
+        print "Newton decrement squared:%- 7.5e" %sqntdecr
+        if (sqntdecr < 1e-12):
+            print "number of iterations: ", iters+1 
+            break
+
+        # line search
+        dx = +v
+        dx[D] *= 2      # scale the diagonal elems        
+        f = -2.0 * sum(log(d))    # f = -log det K
+        s = 1
+        for lsiter in xrange(50):
+            Kn.V = K.V + s*dx
+            try: 
+                cholmod.numeric(Kn, F)
+            except ArithmeticError:
+                s *= 0.5
+            else:
+                d = cholmod.diag(F)
+                fn = -2.0 * sum(log(d)) + 2*s*blas.dot(v,Y.V)
+                if (fn < f - 0.01*s*sqntdecr): 
+                     break
+                s *= 0.5
+            
+        K.V = Kn.V
+
+    return K
+</pre></div>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="7.3 Positive Definite Linear"
+  href="s-cholmod.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="7. Sparse Linear Equation"
+  href="c-spsolvers.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-cholmod.html">7.3 Positive Definite Linear</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="c-spsolvers.html">7. Sparse Linear Equation</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/e-gevd.html b/doc/cvxopt/e-gevd.html
new file mode 100644
index 0000000..3a0aec5
--- /dev/null
+++ b/doc/cvxopt/e-gevd.html
@@ -0,0 +1,185 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node27.html" />
+<link rel="prev" href="node25.html" />
+<link rel="parent" href="node19.html" />
+<link rel="next" href="node27.html" />
+<meta name='aesop' content='information' />
+<title>4.7 Generalized Symmetric Definite Eigenproblems</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.6 Symmetric and Hermitian"
+  href="node25.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.8 Singular Value Decomposition"
+  href="node27.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node25.html">4.6 Symmetric and Hermitian</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node27.html">4.8 Singular Value Decomposition</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION006700000000000000000">
+4.7 Generalized Symmetric Definite Eigenproblems</A>
+</H1>
+Three types of generalized eigenvalue problems can be solved:
+<BR>
+<DIV ALIGN="RIGHT" CLASS="mathdisplay">
+
+<!-- MATH
+ \begin{equation}
+AZ = BZ\mbox{\bf diag}\,(\lambda)\quad \mbox{(type 1)}, \qquad 
+ ABZ = Z\mbox{\bf diag}\,(\lambda) \quad \mbox{(type 2)}, \qquad 
+ BAZ = Z\mbox{\bf diag}\,(\lambda) \quad \mbox{(type 3)},
+\end{equation}
+ -->
+<A NAME="e-gevd"></A>
+<TABLE WIDTH="100%" ALIGN="CENTER">
+<TR VALIGN="MIDDLE"><TD></TD><TD ALIGN="CENTER" NOWRAP><A NAME="e-gevd"></A><IMG
+ WIDTH="649" HEIGHT="28" BORDER="0"
+ SRC="img66.gif"
+ ALT="\begin{displaymath}
+AZ = BZ\mbox{\bf diag}\,(\lambda)\quad \mbox{(type 1)}, \qq...
+...ad
+BAZ = Z\mbox{\bf diag}\,(\lambda) \quad \mbox{(type 3)},
+\end{displaymath}"></TD>
+<TD CLASS="eqno" WIDTH=10 ALIGN="RIGHT">
+(4.2)</TD></TR>
+</TABLE>
+<BR CLEAR="ALL"></DIV><P></P>
+with <SPAN CLASS="MATH"><IMG
+ WIDTH="16" HEIGHT="14" ALIGN="BOTTOM" BORDER="0"
+ SRC="img53.gif"
+ ALT="$A$"></SPAN> and <SPAN CLASS="MATH"><IMG
+ WIDTH="17" HEIGHT="14" ALIGN="BOTTOM" BORDER="0"
+ SRC="img67.gif"
+ ALT="$B$"></SPAN> real symmetric or complex Hermitian, and <SPAN CLASS="MATH"><IMG
+ WIDTH="17" HEIGHT="14" ALIGN="BOTTOM" BORDER="0"
+ SRC="img67.gif"
+ ALT="$B$"></SPAN> positive 
+definite.
+The matrix of eigenvectors is normalized as follows:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+Z^H BZ = I \quad \mbox{(types 1 and 2)}, \qquad 
+ Z^H B^{-1}Z = I \quad \mbox{(type 3)}.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="392" HEIGHT="27" BORDER="0"
+ SRC="img68.gif"
+ ALT="\begin{displaymath}
+Z^H BZ = I \quad \mbox{(types 1 and 2)}, \qquad
+Z^H B^{-1}Z = I \quad \mbox{(type 3)}.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-105' xml:id='l2h-105' class="function">sygv</tt></b>(</nobr></td>
+  <td><var>A, B, W</var><big>[</big><var>, itype=1</var><big>[</big><var>, 
+jobz='N'</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves the generalized eigenproblem (<A HREF="#e-gevd">4.2</A>) for real symmetric 
+matrices of order <I>n</I>, stored in real matrices <var>A</var> and <var>B</var>.
+<var>itype</var> is an integer with possible values 1, 2, 3, and specifies
+the type of eigenproblem.
+<var>W</var> is a real matrix of length at least <I>n</I>.
+On exit, it contains the eigenvalues in ascending order.
+On exit, <var>B</var> contains the Cholesky factor of <I>B</I>.
+If <var>jobz</var> is <code>'V'</code>, the eigenvectors are computed
+and returned in <var>A</var>.
+If <var>jobz</var> is <code>'N'</code>, the eigenvectors are not returned and the 
+contents of <var>A</var> are destroyed.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-106' xml:id='l2h-106' class="function">hegv</tt></b>(</nobr></td>
+  <td><var>A, B, W</var><big>[</big><var>, itype=1</var><big>[</big><var>, 
+jobz='N'</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Generalized eigenvalue problem (<A HREF="#e-gevd">4.2</A>) of real symmetric or 
+complex Hermitian matrix of order <var>n</var>.
+The calling sequence is identical to <tt class="function">sygv()</tt>,
+except that <var>A</var> and <var>B</var> can be real or complex.
+</dl>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.6 Symmetric and Hermitian"
+  href="node25.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.8 Singular Value Decomposition"
+  href="node27.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node25.html">4.6 Symmetric and Hermitian</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node27.html">4.8 Singular Value Decomposition</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/e-kkt-example.html b/doc/cvxopt/e-kkt-example.html
new file mode 100644
index 0000000..fc331e5
--- /dev/null
+++ b/doc/cvxopt/e-kkt-example.html
@@ -0,0 +1,483 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node22.html" />
+<link rel="prev" href="node20.html" />
+<link rel="parent" href="node19.html" />
+<link rel="next" href="node22.html" />
+<meta name='aesop' content='information' />
+<title>4.2 Positive Definite Linear Equations</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.1 General Linear Equations"
+  href="node20.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.3 Symmetric and Hermitian"
+  href="node22.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node20.html">4.1 General Linear Equations</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node22.html">4.3 Symmetric and Hermitian</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION006200000000000000000">
+4.2 Positive Definite Linear Equations</A>
+</H1>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-72' xml:id='l2h-72' class="function">posv</tt></b>(</nobr></td>
+  <td><var>A, B</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A X = B,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="64" HEIGHT="27" BORDER="0"
+ SRC="img41.gif"
+ ALT="\begin{displaymath}
+A X = B,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is a real symmetric or complex Hermitian positive 
+definite matrix.
+On exit, <var>B</var> is replaced by the solution, and <var>A</var> is 
+overwritten with the Cholesky factor.
+The matrices <var>A</var> and <var>B</var> must have the same type (<code>'d'</code> or 
+<code>'z'</code>).
+Raises an <code>ArithmeticError</code> if the matrix is not positive definite.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-73' xml:id='l2h-73' class="function">potrf</tt></b>(</nobr></td>
+  <td><var>A</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Cholesky factorization 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A = LL^T \qquad \mbox{or} \qquad A = LL^H
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="207" HEIGHT="24" BORDER="0"
+ SRC="img46.gif"
+ ALT="\begin{displaymath}
+A = LL^T \qquad \mbox{or} \qquad A = LL^H
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+of a positive definite real symmetric or complex Hermitian matrix
+<I>A</I>.  On exit, the lower triangular part of <var>A</var> 
+(if <var>uplo</var> is <code>'L'</code>) or the upper triangular part 
+(if <var>uplo</var> is <code>'U'</code>) is overwritten with the Cholesky factor 
+or its (conjugate) transpose.
+Raises an <code>ArithmeticError</code> if the matrix is not positive definite.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-74' xml:id='l2h-74' class="function">potrs</tt></b>(</nobr></td>
+  <td><var>A, B</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves a set of linear equations
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+AX=B
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="60" HEIGHT="24" BORDER="0"
+ SRC="img47.gif"
+ ALT="\begin{displaymath}
+AX=B
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+with a positive 
+definite real symmetric or complex Hermitian matrix,
+given the Cholesky factorization computed by 
+<tt class="function">posv()</tt> or <tt class="function">potrf()</tt>.
+On entry, <var>A</var> contains the triangular factor, as computed by
+<tt class="function">posv()</tt> or <tt class="function">potrf()</tt>.  On exit, <var>B</var> is replaced 
+by the solution.
+<var>B</var> must have the same type as <var>A</var>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-75' xml:id='l2h-75' class="function">potri</tt></b>(</nobr></td>
+  <td><var>A</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd> 
+Computes the inverse of a positive definite matrix.
+On entry, <var>A</var> contains the Cholesky factorization computed 
+by <tt class="function">potrf()</tt> or <tt class="function">posv()</tt>. On exit, it contains
+the inverse.
+</dl>
+
+<P>
+As an example, we use <tt class="function">posv()</tt> to solve the linear system
+<BR>
+<DIV ALIGN="RIGHT" CLASS="mathdisplay">
+
+<!-- MATH
+ \begin{equation}
+\left[ \begin{array}{cc}
+ -\mbox{\bf diag}\,(d)^2  & A \\
+ A^T  & 0 \end{array} \right]
+ \left[ \begin{array}{c} x_1 \\x_2 \end{array} \right]
+ = \left[ \begin{array}{c} b_1 \\b_2 \end{array} \right]
+\end{equation}
+ -->
+<A NAME="e-kkt-example"></A>
+<TABLE WIDTH="100%" ALIGN="CENTER">
+<TR VALIGN="MIDDLE"><TD></TD><TD ALIGN="CENTER" NOWRAP><A NAME="e-kkt-example"></A><IMG
+ WIDTH="244" HEIGHT="45" BORDER="0"
+ SRC="img48.gif"
+ ALT="\begin{displaymath}
+\left[ \begin{array}{cc}
+-\mbox{\bf diag}\,(d)^2 & A \\
+...
+...ght]
+= \left[ \begin{array}{c} b_1 \\ b_2 \end{array} \right]
+\end{displaymath}"></TD>
+<TD CLASS="eqno" WIDTH=10 ALIGN="RIGHT">
+(4.1)</TD></TR>
+</TABLE>
+<BR CLEAR="ALL"></DIV><P></P>
+by block-elimination. 
+We first pick a random problem.
+<div class="verbatim"><pre>
+>>> from cvxopt.base import matrix, div
+>>> from cvxopt.random import normal, uniform
+>>> from cvxopt.blas import syrk, gemv
+>>> from cvxopt.lapack import posv
+>>> m, n = 100, 50  
+>>> A = normal(m,n)
+>>> b1, b2 = normal(m), normal(n)
+>>> d = uniform(m)
+</pre></div>
+We then solve the equations 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A^T \mbox{\bf diag}\,(d)^{-2}A x_2 = b_2 + A^T \mbox{\bf diag}\,(d)^{-2} b_1, \qquad
+ \mbox{\bf diag}\,(d)^2 x_1 = Ax_2 - b_1.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="481" HEIGHT="28" BORDER="0"
+ SRC="img49.gif"
+ ALT="\begin{displaymath}
+A^T \mbox{\bf diag}\,(d)^{-2}A x_2 = b_2 + A^T \mbox{\bf di...
+...(d)^{-2} b_1, \qquad
+\mbox{\bf diag}\,(d)^2 x_1 = Ax_2 - b_1.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+<div class="verbatim"><pre>
+>>> Asc = div(A, d[:, n*[0]])                # Asc := diag(d)^{-1}*A
+>>> B = matrix(0.0, (n,n))
+>>> syrk(Asc, B, trans='T')                  # B := Asc^T * Asc = A^T * diag(d)^{-2} * A
+>>> x1 = div(b1, d)                          # x1 := diag(d)^{-1}*b1
+>>> x2 = +b2
+>>> gemv(Asc, x1, x2, trans='T', beta=1.0)   # x2 := x2 + Asc^T*x1 = b2 + A^T*diag(d)^{-2}*b1 
+>>> posv(B, x2)                              # x2 := B^{-1}*x2 = B^{-1}*(b2 + A^T*diag(d)^{-2}*b1)
+>>> gemv(Asc, x2, x1, beta=-1.0)             # x1 := Asc*x2 - x1 = diag(d)^{-1} * (A*x2 - b1)
+>>> x1 = div(x1, d)                          # x1 := diag(d)^{-1}*x1 = diag(d)^{-2} * (A*x2 - b1)
+</pre></div>
+
+<P>
+There are separate routines for equations with positive definite band 
+matrices.
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-76' xml:id='l2h-76' class="function">pbsv</tt></b>(</nobr></td>
+  <td><var>A, B</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+AX=B
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="60" HEIGHT="24" BORDER="0"
+ SRC="img47.gif"
+ ALT="\begin{displaymath}
+AX=B
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is a real symmetric or complex Hermitian positive definite
+band matrix.  On entry, the diagonals of <I>A</I> are stored in <var>A</var>, 
+using the BLAS format for symmetric or Hermitian band matrices
+(see section <A href="s-conventions.html#s-conventions">3.1</A>).  On exit, <var>B</var> is replaced by the
+solution, and <var>A</var> is overwritten with the Cholesky factor (in the
+BLAS format for triangular band matrices).  The matrices <var>A</var> and 
+<var>B</var> must have the same type (<code>'d'</code> or <code>'z'</code>).
+Raises an <code>ArithmeticError</code> if the matrix is not positive definite.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-77' xml:id='l2h-77' class="function">pbtrf</tt></b>(</nobr></td>
+  <td><var>A</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Cholesky factorization 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A = LL^T \qquad \mbox{or} \qquad A = LL^H
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="207" HEIGHT="24" BORDER="0"
+ SRC="img46.gif"
+ ALT="\begin{displaymath}
+A = LL^T \qquad \mbox{or} \qquad A = LL^H
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+of a positive definite real symmetric or complex Hermitian band matrix
+<I>A</I>.  On entry, the diagonals of <I>A</I> are stored in <var>A</var>, 
+using the BLAS format for symmetric or Hermitian band matrices.
+On exit, <var>A</var> contains the Cholesky factor, in the BLAS format
+for triangular band matrices.
+Raises an <code>ArithmeticError</code> if the matrix is not positive definite.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-78' xml:id='l2h-78' class="function">pbtrs</tt></b>(</nobr></td>
+  <td><var>A, B</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves a set of linear equations
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+AX=B
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="60" HEIGHT="24" BORDER="0"
+ SRC="img47.gif"
+ ALT="\begin{displaymath}
+AX=B
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+with a positive definite real symmetric or complex Hermitian band matrix,
+given the Cholesky factorization computed by <tt class="function">pbsv()</tt> or 
+<tt class="function">pbtrf()</tt>.
+On entry, <var>A</var> contains the triangular factor, as computed by
+<tt class="function">pbsv()</tt> or <tt class="function">pbtrf()</tt>.  On exit, <var>B</var> is replaced 
+by the solution.  <var>B</var> must have the same type as <var>A</var>.
+</dl>
+
+<P>
+The following functions are useful for tridiagonal systems.
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-79' xml:id='l2h-79' class="function">ptsv</tt></b>(</nobr></td>
+  <td><var>d, e, B</var>)</td></tr></table></dt>
+<dd>
+Solves
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A X = B,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="64" HEIGHT="27" BORDER="0"
+ SRC="img41.gif"
+ ALT="\begin{displaymath}
+A X = B,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is an <I>n</I> by <I>n</I> real symmetric or complex 
+Hermitian tridiagonal matrix, with diagonal <var>d</var> (a <code>'d'</code> matrix of 
+length <I>n</I>) and subdiagonal <var>e</var> (a <code>'d'</code> or <code>'z'</code> matrix of length 
+<I>n</I>-1).
+The arguments <var>e</var> and <var>B</var> must have the same type.  
+On exit <var>d</var> contains the diagonal elements of <I>D</I> in 
+the LDL<SPAN CLASS="MATH"><IMG
+ WIDTH="14" HEIGHT="18" ALIGN="BOTTOM" BORDER="0"
+ SRC="img50.gif"
+ ALT="${}\mathrm{^T}$"></SPAN> or LDL<SPAN CLASS="MATH"><IMG
+ WIDTH="14" HEIGHT="18" ALIGN="BOTTOM" BORDER="0"
+ SRC="img51.gif"
+ ALT="${}\mathrm{^H}$"></SPAN> factorization 
+of <I>A</I>, and <var>e</var> contains the subdiagonal elements of the unit 
+lower bidiagonal matrix <I>L</I>.  
+<var>B</var> is overwritten with the solution <I>X</I>.  
+Raises an <code>ArithmeticError</code> if the matrix is singular.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-80' xml:id='l2h-80' class="function">pttrf</tt></b>(</nobr></td>
+  <td><var>d, e</var>)</td></tr></table></dt>
+<dd>
+LDL<SPAN CLASS="MATH"><IMG
+ WIDTH="14" HEIGHT="18" ALIGN="BOTTOM" BORDER="0"
+ SRC="img50.gif"
+ ALT="${}\mathrm{^T}$"></SPAN> or LDL<SPAN CLASS="MATH"><IMG
+ WIDTH="14" HEIGHT="18" ALIGN="BOTTOM" BORDER="0"
+ SRC="img51.gif"
+ ALT="${}\mathrm{^H}$"></SPAN> factorization of an <I>n</I> by 
+<I>n</I> real symmetric or complex Hermitian tridiagonal matrix <I>A</I>.
+On entry, the argument <var>d</var> is a <code>'d'</code> matrix with the diagonal elements
+of <I>A</I>.  The argument <var>e</var> is <code>'d'</code> or <code>'z'</code> matrix with
+the subdiagonal elements of <I>A</I>.
+On exit <var>d</var> contains the diagonal elements of <I>D</I>, and <var>e</var> 
+contains the subdiagonal elements of the unit lower bidiagonal matrix 
+<I>L</I>.  Raises an <code>ArithmeticError</code> if the matrix is singular.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-81' xml:id='l2h-81' class="function">gttrs</tt></b>(</nobr></td>
+  <td><var>d, e, B</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves a set of linear equations 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+AX=B
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="60" HEIGHT="24" BORDER="0"
+ SRC="img47.gif"
+ ALT="\begin{displaymath}
+AX=B
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is an <I>n</I> by <I>n</I> real symmetric or complex
+Hermitian tridiagonal matrix, given its LDL<SPAN CLASS="MATH"><IMG
+ WIDTH="14" HEIGHT="18" ALIGN="BOTTOM" BORDER="0"
+ SRC="img50.gif"
+ ALT="${}\mathrm{^T}$"></SPAN> or 
+LDL<SPAN CLASS="MATH"><IMG
+ WIDTH="14" HEIGHT="18" ALIGN="BOTTOM" BORDER="0"
+ SRC="img51.gif"
+ ALT="${}\mathrm{^H}$"></SPAN> factorization.
+The argument <var>d</var> is the diagonal of the diagonal matrix <I>D</I>.
+The argument <var>uplo</var> only matters for complex matrices.
+If <var>uplo</var> is <code>'L'</code>, then <var>e</var> contains the subdiagonal 
+elements of the unit bidiagonal matrix <I>L</I>.
+If <var>uplo</var> is <code>'U'</code>, then <var>e</var> contains the complex
+conjugates of the elements of the unit bidiagonal matrix <I>L</I>.
+On exit, <var>B</var> is overwritten with the solution <I>X</I>. 
+<var>B</var> must have the same type as <var>e</var>.
+</dl>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.1 General Linear Equations"
+  href="node20.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.3 Symmetric and Hermitian"
+  href="node22.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node20.html">4.1 General Linear Equations</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node22.html">4.3 Symmetric and Hermitian</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/e-nlcp.html b/doc/cvxopt/e-nlcp.html
new file mode 100644
index 0000000..1daee5b
--- /dev/null
+++ b/doc/cvxopt/e-nlcp.html
@@ -0,0 +1,594 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node51.html" />
+<link rel="prev" href="s-sdpsolver.html" />
+<link rel="parent" href="node45.html" />
+<link rel="next" href="node51.html" />
+<meta name='aesop' content='information' />
+<title>8.5 Nonlinear Convex Programming</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.4 Semidefinite Programming"
+  href="s-sdpsolver.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.6 Exploiting Structure in"
+  href="node51.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-sdpsolver.html">8.4 Semidefinite Programming</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node51.html">8.6 Exploiting Structure in</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0010500000000000000000">
+8.5 Nonlinear Convex Programming</A>
+</H1>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-149' xml:id='l2h-149' class="function">cp</tt></b>(</nobr></td>
+  <td><var>F</var><big>[</big><var>, G, h</var><big>[</big><var>, A, b</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves an optimization problem
+<BR>
+<DIV ALIGN="RIGHT" CLASS="mathdisplay">
+
+<!-- MATH
+ \begin{equation}
+\begin{array}{ll}
+ \mbox{minimize} & f_0(x) \\
+ \mbox{subject to} & f_k(x) \leq 0, \quad k=1,\ldots,m \\
+  & G x \preceq h  \\
+  & A x = b,
+ \end{array}
+\end{equation}
+ -->
+<A NAME="e-nlcp"></A>
+<TABLE WIDTH="100%" ALIGN="CENTER">
+<TR VALIGN="MIDDLE"><TD></TD><TD ALIGN="CENTER" NOWRAP><A NAME="e-nlcp"></A><IMG
+ WIDTH="254" HEIGHT="83" BORDER="0"
+ SRC="img138.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & f_0(x) \\
+\mbox{subj...
+... k=1,\ldots,m \\
+& G x \preceq h \\
+& A x = b,
+\end{array}\end{displaymath}"></TD>
+<TD CLASS="eqno" WIDTH=10 ALIGN="RIGHT">
+(8.3)</TD></TR>
+</TABLE>
+<BR CLEAR="ALL"></DIV><P></P>
+with <!-- MATH
+ $f=(f_0,\ldots,f_m)$
+ -->
+<SPAN CLASS="MATH"><IMG
+ WIDTH="117" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
+ SRC="img139.gif"
+ ALT="$f=(f_0,\ldots,f_m)$"></SPAN> convex and twice differentiable.
+
+<P>
+<var>F</var> is a function that evaluates the objective and nonlinear 
+constraint functions.  It must handle the following calling sequences.
+
+<P>
+
+<UL>
+<LI><code>F()</code> returns a tuple (<var>m</var>, <var>x0</var>), where <var>m</var> is 
+ the number of nonlinear constraints and <var>x0</var> is a point in the 
+ domain of <I>f</I>.  <var>x0</var> is a dense real matrix of size 
+ (<var>n</var>,1).
+
+<P>
+</LI>
+<LI><code>F(x)</code>, with <var>x</var> a dense real matrix of size 
+ (<var>n</var>,1), returns a tuple (<var>f</var>, <var>Df</var>).  
+ <var>f</var> is a dense real matrix of size (<var>m</var>+1,1), with 
+ <code><var>f</var>[<var>k</var>]</code> equal to <I>f_k(x)</I>. 
+ (If <I>m</I> is zero, <var>f</var> can also be returned as a number.)
+ <var>Df</var> is a dense or sparse real matrix of size (<var>m</var>+1,<var>n</var>) 
+ with <code><var>Df</var>[<var>k</var>,:]</code> equal to the transpose of the gradient
+ of <I>f_k</I> at <I>x</I>.
+ If <var>x</var> is not in the domain of <I>f</I>, <code>F(x)</code> returns 
+ <code>None</code> or a tuple (<code>None</code>,<code>None</code>).
+
+<P>
+</LI>
+<LI><code>F(x,z)</code>, with <var>x</var> a dense real matrix of size 
+ (<var>n</var>,1) and <var>z</var> a positive dense real matrix of size 
+ (<var>m</var>+1,1) returns a tuple (<var>f</var>, <var>Df</var>, <var>H</var>).  
+ <var>f</var> and <var>Df</var> are defined as above.  
+ <var>H</var> is a square dense or sparse real matrix of size 
+ (<I>n</I>, <I>n</I>), whose lower triangular part contains the lower 
+ triangular part of
+ <BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+z_0 \nabla^2f_0(x) + z_1 \nabla^2f_1(x) + \cdots + z_m \nabla^2f_m(x).
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="303" HEIGHT="28" BORDER="0"
+ SRC="img140.gif"
+ ALT="\begin{displaymath}
+z_0 \nabla^2f_0(x) + z_1 \nabla^2f_1(x) + \cdots + z_m \nabla^2f_m(x).
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+If <var>F</var> is called with two arguments, it can be assumed that 
+ <var>x</var> is in the domain of <I>f</I>.
+</LI>
+</UL>
+
+<P>
+<var>G</var> and <var>A</var> are dense or sparse real matrices with <var>n</var> 
+columns.  Their default values are matrices of size (0,<var>n</var>).
+<var>h</var> and <var>b</var> are dense real matrices with one column, and the 
+same number of rows as <var>G</var> and <var>A</var>, respectively.
+Their default values are matrices of size (0,1).
+
+<P>
+<tt class="function">cp()</tt> returns a dictionary with keys <code>'status'</code>, 
+<code>'x'</code>, <code>'snl'</code>, <code>'sl'</code>, <code>'y'</code>, <code>'znl'</code>, 
+<code>'zl'</code>. 
+The possible values of the <code>'status'</code> key are:
+<DL>
+<DT><STRONG><code>'optimal'</code></STRONG></DT>
+<DD>In this case the 
+<code>'x'</code> entry of the dictionary is the primal optimal solution,
+  the <code>'snl'</code> and <code>'sl'</code> entries are the corresponding
+ slacks in the nonlinear and linear inequality constraints, and the 
+<code>'znl'</code>, <code>'zl'</code> and <code>'y'</code> entries are the optimal 
+values of the dual variables associated with the nonlinear 
+inequalities, the linear inequalities, and the linear equality 
+constraints.  These vectors approximately satisfy the Karush-
+Kuhn-Tucker (KKT) conditions
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\nabla f_0(x) +  D\tilde f(x)^T z_\mathrm{nl} + 
+ G^T z_\mathrm{l} + A^T y = 0, \qquad
+\tilde f(x) + s_\mathrm{nl} = 0, \quad k=1,\ldots,m, \qquad
+ Gx + s_\mathrm{l} = h, \qquad
+ Ax = b,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="701" HEIGHT="28" BORDER="0"
+ SRC="img141.gif"
+ ALT="\begin{displaymath}
+\nabla f_0(x) + D\tilde f(x)^T z_\mathrm{nl} +
+G^T z_\mat...
+... k=1,\ldots,m, \qquad
+Gx + s_\mathrm{l} = h, \qquad
+Ax = b,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <!-- MATH
+ $\tilde f = (f_1,\ldots, f_m)$
+ -->
+<SPAN CLASS="MATH"><IMG
+ WIDTH="117" HEIGHT="38" ALIGN="MIDDLE" BORDER="0"
+ SRC="img142.gif"
+ ALT="$\tilde f = (f_1,\ldots, f_m)$"></SPAN>,
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+s_\mathrm{nl}\succeq 0, \qquad s_\mathrm{l}\succeq 0, \qquad 
+z_\mathrm{nl} \succeq 0, \qquad z_\mathrm{l} \succeq 0, \qquad
+s_\mathrm{nl}^T z_\mathrm{nl} +  s_\mathrm{l}^T z_\mathrm{l} = 0.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="453" HEIGHT="28" BORDER="0"
+ SRC="img125.gif"
+ ALT="\begin{displaymath}
+s_\mathrm{nl}\succeq 0, \qquad s_\mathrm{l}\succeq 0, \qquad...
+...\mathrm{nl}^T z_\mathrm{nl} + s_\mathrm{l}^T z_\mathrm{l} = 0.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+</DD>
+<DT><STRONG><code>'unknown'</code></STRONG></DT>
+<DD>This indicates that the algorithm reached
+the maximum number of iterations before a solution was found.
+The <code>'x'</code>, <code>'snl'</code>, <code>'sl'</code>, 
+<code>'y'</code>, <code>'znl'</code> and <code>'zl'</code> entries are <code>None</code>. 
+</DD>
+</DL>
+
+<P>
+</dl>
+
+<P>
+<DL>
+<DT><STRONG>Example: equality constrained analytic centering</STRONG></DT>
+<DD><P>
+The equality constrained analytic centering problem is defined as
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+ \mbox{minimize} & -\sum_{i=1}^m \log x_i \\
+ \mbox{subject to} & Ax = b. 
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="169" HEIGHT="45" BORDER="0"
+ SRC="img143.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & -\sum_{i=1}^m \log x_i \\
+\mbox{subject to} & Ax = b.
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+The function <tt class="function">acent()</tt> defined  below solves the problem, 
+assumping it is solvable.
+
+<P>
+<div class="verbatim"><pre>
+from cvxopt import solvers 
+from cvxopt.base import matrix, spmatrix, log
+
+def acent(A, b):
+    m, n = A.size
+    def F(x=None, z=None):
+        if x is None: return 0, matrix(1.0, (n,1))
+        if min(x) <= 0.0: return None
+        f = -sum(log(x))
+        Df = -(x**-1).T 
+        if z is None: return f, Df
+        H = z[0] * spmatrix(x**-2, range(n), range(n))
+        return f, Df, H
+    return solvers.cp(F, A=A, b=b)['x']
+</pre></div>
+
+<P>
+</DD>
+<DT><STRONG>Example: robust least-squares</STRONG></DT>
+<DD><P>
+The function <tt class="function">robls()</tt> defined below solves the unconstrained 
+problem
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} &  \sum_{k=1}^m \phi((Ax-b)_k), 
+\end{array} \qquad \mbox{where} \quad A \in{\mbox{\bf R}}^{m\times n}, \quad
+\phi(u) = \sqrt{\rho + u^2}.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="519" HEIGHT="30" BORDER="0"
+ SRC="img144.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & \sum_{k=1}^m \phi((Ax-b)...
+...{\mbox{\bf R}}^{m\times n}, \quad
+\phi(u) = \sqrt{\rho + u^2}.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+<div class="verbatim"><pre>
+from cvxopt import solvers 
+from cvxopt.base import matrix, spmatrix, sqrt, div
+
+def robls(A, b, rho): 
+    m, n = A.size
+    def F(x=None, z=None):
+        if x is None: return 0, matrix(0.0, (n,1))
+        y = A*x-b
+        w = sqrt(rho + y**2)
+        f = sum(w)
+        Df = div(y, w).T * A 
+        if z is None: return f, Df 
+        H = A.T * spmatrix(z[0]*rho*(w**-3), range(m), range(m)) * A
+        return f, Df, H
+    return solvers.cp(F)['x']
+</pre></div>
+
+<P>
+</DD>
+<DT><STRONG>Example: floor planning</STRONG></DT>
+<DD><P>
+This example is the floor planning problem of section 8.8.2 in the book 
+<em class="citetitle"><a
+ href="http://www.stanford.edu/~boyd/cvxbook"
+ title="Convex Optimization"
+ >Convex Optimization</a></em>: 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+ \mbox{minimize} & W + H \\
+ \mbox{subject to} & A_{\mathrm{min}, k}/h_k - w_k \leq 0, 
+        \quad k=1,\ldots, 5  \\
+   &  x_1 \geq 0, \quad x_2 \geq 0,  \quad x_4 \geq 0 \\
+   & x_1 + w_1 + \rho \leq x_3, \quad x_2 + w_2 + \rho \leq x_3, \quad 
+     x_3 + w_3 + \rho \leq x_5, \quad x_4 + w_4 + \rho \leq x_5, \quad
+     x_5 + w_5 \leq W \\
+   & y_2 \geq 0,  \quad y_3 \geq 0, \quad y_5 \geq 0  \\
+   & y_2 + h_2 + \rho \leq y_1, \quad y_1 + h_1 + \rho \leq y_4, \quad 
+     y_3 + h_3 + \rho \leq y_4, \quad y_4 + h_4 \leq H, \quad
+     y_5 + h_5 \leq H \\
+   & h_k/\gamma \leq w_k \leq \gamma h_k, \quad k=1,\ldots,5.
+\end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="740" HEIGHT="140" BORDER="0"
+ SRC="img145.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & W + H \\
+\mbox{subjec...
+...gamma \leq w_k \leq \gamma h_k, \quad k=1,\ldots,5.
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+This problem has 22 variables 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+W, \qquad H, \qquad x\in{\mbox{\bf R}}^5, \qquad y\in{\mbox{\bf R}}^5, \qquad
+w\in{\mbox{\bf R}}^5, \qquad h\in{\mbox{\bf R}}^5,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="417" HEIGHT="27" BORDER="0"
+ SRC="img146.gif"
+ ALT="\begin{displaymath}
+W, \qquad H, \qquad x\in{\mbox{\bf R}}^5, \qquad y\in{\mbox{...
+...}^5, \qquad
+w\in{\mbox{\bf R}}^5, \qquad h\in{\mbox{\bf R}}^5,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+5 nonlinear inequality constraints, and 26 linear inequality 
+constraints.  The code belows defines a function
+<tt class="function">floorplan()</tt> that solves the problem by calling
+<tt class="function">cp()</tt>,  then applies it to  4 instances, and creates 
+a figure.
+
+<P>
+<div class="verbatim"><pre>
+import pylab
+from cvxopt import solvers
+from cvxopt.base import matrix, spmatrix, mul, div
+
+def floorplan(Amin):
+
+    #     minimize    W+H
+    #     subject to  Amink / hk <= wk, k = 1,..., 5 
+    #                 x1 >= 0,  x2 >= 0, x4 >= 0
+    #                 x1 + w1 + rho <= x3  
+    #                 x2 + w2 + rho <= x3 
+    #                 x3 + w3 + rho <= x5  
+    #                 x4 + w4 + rho <= x5
+    #                 x5 + w5 <= W
+    #                 y2 >= 0,  y3 >= 0,  y5 >= 0 
+    #                 y2 + h2 + rho <= y1 
+    #                 y1 + h1 + rho <= y4 
+    #                 y3 + h3 + rho <= y4
+    #                 y4 + h4 <= H  
+    #                 y5 + h5 <= H
+    #                 hk/gamma <= wk <= gamma*hk,  k = 1, ..., 5
+    #
+    # 22 Variables W, H, x (5), y (5), w (5), h (5).
+    #
+    # W, H:  scalars; bounding box width and height
+    # x, y:  5-vectors; coordinates of bottom left corners of blocks
+    # w, h:  5-vectors; widths and heigths of the 5 blocks
+
+    rho, gamma = 1.0, 5.0   # min spacing, min aspect ratio
+
+    # The objective is to minimize W + H.  There are five nonlinear 
+    # constraints 
+    #
+    #     -wk + Amink / hk <= 0,  k = 1, ..., 5
+
+    def F(x=None, z=None):
+        if x is None:  return 5, matrix(17*[0.0] + 5*[1.0])
+        if min(x[17:]) <= 0.0:  return None 
+        f = matrix(0.0, (6,1))
+        f[0] = x[0] + x[1]  
+        f[1:] = -x[12:17] + div(Amin, x[17:]) 
+        Df = matrix(0.0, (6,22))
+        Df[0, [0,1]] = 1.0
+        Df[1:,12:17] = spmatrix(-1.0, range(5), range(5))
+        Df[1:,17:] = spmatrix(-div(Amin, x[17:]**2), range(5), range(5))
+        if z is None: return f, Df
+        H = spmatrix( 2.0* mul(z[1:], div(Amin, x[17::]**3)), range(17,22), range(17,22) )
+        return f, Df, H
+
+    G = matrix(0.0, (26,22)) 
+    h = matrix(0.0, (26,1))
+    G[0,2] = -1.0                                       # -x1 <= 0
+    G[1,3] = -1.0                                       # -x2 <= 0 
+    G[2,5] = -1.0                                       # -x4 <= 0
+    G[3, [2, 4, 12]], h[3] = [1.0, -1.0, 1.0], -rho     # x1 - x3 + w1 <= -rho 
+    G[4, [3, 4, 13]], h[4] = [1.0, -1.0, 1.0], -rho     # x2 - x3 + w2 <= -rho 
+    G[5, [4, 6, 14]], h[5] = [1.0, -1.0, 1.0], -rho     # x3 - x5 + w3 <= -rho 
+    G[6, [5, 6, 15]], h[6] = [1.0, -1.0, 1.0], -rho     # x4 - x5 + w4 <= -rho 
+    G[7, [0, 6, 16]] = -1.0, 1.0, 1.0                   # -W + x5 + w5 <= 0
+    G[8,8] = -1.0                                       # -y2 <= 0 
+    G[9,9] = -1.0                                       # -y3 <= 0 
+    G[10,11] = -1.0                                     # -y5 <= 0 
+    G[11, [7, 8, 18]], h[11] = [-1.0, 1.0, 1.0], -rho   # -y1 + y2 + h2 <= -rho 
+    G[12, [7, 10, 17]], h[12] = [1.0, -1.0, 1.0], -rho  #  y1 - y4 + h1 <= -rho 
+    G[13, [9, 10, 19]], h[13] = [1.0, -1.0, 1.0], -rho  #  y3 - y4 + h3 <= -rho 
+    G[14, [1, 10, 20]] = -1.0, 1.0, 1.0                 # -H + y4 + h4 <= 0  
+    G[15, [1, 11, 21]] = -1.0, 1.0, 1.0                 # -H + y5 + h5 <= 0
+    G[16, [12, 17]] = -1.0, 1.0/gamma                   # -w1 + h1/gamma <= 0 
+    G[17, [12, 17]] = 1.0, -gamma                       #  w1 - gamma * h1 <= 0
+    G[18, [13, 18]] = -1.0, 1.0/gamma                   # -w2 + h2/gamma <= 0 
+    G[19, [13, 18]] = 1.0, -gamma                       #  w2 - gamma * h2 <= 0
+    G[20, [14, 18]] = -1.0, 1.0/gamma                   # -w3 + h3/gamma <= 0  
+    G[21, [14, 19]] = 1.0, -gamma                       #  w3 - gamma * h3 <= 0
+    G[22, [15, 19]] = -1.0, 1.0/gamma                   # -w4  + h4/gamma <= 0 
+    G[23, [15, 20]] = 1.0, -gamma                       #  w4 - gamma * h4 <= 0
+    G[24, [16, 21]] = -1.0, 1.0/gamma                   # -w5 + h5/gamma <= 0 
+    G[25, [16, 21]] = 1.0, -gamma                       #  w5 - gamma * h5 <= 0.0
+
+    # solve and return W, H, x, y, w, h 
+    sol = solvers.cp(F, G, h)  
+    return  sol['x'][0], sol['x'][1], sol['x'][2:7], sol['x'][7:12], sol['x'][12:17], sol['x'][17:] 
+
+pylab.figure(facecolor='w')
+pylab.subplot(221)
+Amin = matrix([100., 100., 100., 100., 100.])
+W, H, x, y, w, h =  floorplan(Amin)
+for k in xrange(5):
+    pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], 
+               [y[k], y[k]+h[k], y[k]+h[k], y[k]], '#D0D0D0')
+    pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1))
+pylab.axis([-1.0, 26, -1.0, 26])
+pylab.xticks([])
+pylab.yticks([])
+
+pylab.subplot(222)
+Amin = matrix([20., 50., 80., 150., 200.])
+W, H, x, y, w, h =  floorplan(Amin)
+for k in xrange(5):
+    pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], 
+               [y[k], y[k]+h[k], y[k]+h[k], y[k]], '#D0D0D0')
+    pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1))
+pylab.axis([-1.0, 26, -1.0, 26])
+pylab.xticks([])
+pylab.yticks([])
+
+pylab.subplot(223)
+Amin = matrix([180., 80., 80., 80., 80.])
+W, H, x, y, w, h =  floorplan(Amin)
+for k in xrange(5):
+    pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], 
+               [y[k], y[k]+h[k], y[k]+h[k], y[k]],'#D0D0D0')
+    pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1))
+pylab.axis([-1.0, 26, -1.0, 26])
+pylab.xticks([])
+pylab.yticks([])
+
+pylab.subplot(224)
+Amin = matrix([20., 150., 20., 200., 110.])
+W, H, x, y, w, h =  floorplan(Amin)
+for k in xrange(5):
+    pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], 
+               [y[k], y[k]+h[k], y[k]+h[k], y[k]],'#D0D0D0')
+    pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1))
+pylab.axis([-1.0, 26, -1.0, 26])
+pylab.xticks([])
+pylab.yticks([])
+
+pylab.show()
+</pre></div>
+
+<P>
+<DIV ALIGN="CENTER">
+<IMG
+ WIDTH="680" HEIGHT="511" ALIGN="BOTTOM" BORDER="0"
+ SRC="img147.gif"
+ ALT="\includegraphics[width=15cm]{figures/floorplan.eps}">
+
+</DIV>
+</DD>
+</DL>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.4 Semidefinite Programming"
+  href="s-sdpsolver.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.6 Exploiting Structure in"
+  href="node51.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-sdpsolver.html">8.4 Semidefinite Programming</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node51.html">8.6 Exploiting Structure in</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/e-spA-example.html b/doc/cvxopt/e-spA-example.html
new file mode 100644
index 0000000..ff5554d
--- /dev/null
+++ b/doc/cvxopt/e-spA-example.html
@@ -0,0 +1,278 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="s-spmatrix-arith.html" />
+<link rel="prev" href="s-creating-spmatrix.html" />
+<link rel="parent" href="node33.html" />
+<link rel="next" href="s-spmatrix-arith.html" />
+<meta name='aesop' content='information' />
+<title>6.2 Attributes and Methods</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="6.1 Creating Sparse Matrices"
+  href="s-creating-spmatrix.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="6. Sparse Matrices (cvxopt.base)"
+  href="node33.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="6.3 Arithmetic Operations"
+  href="s-spmatrix-arith.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-creating-spmatrix.html">6.1 Creating Sparse Matrices</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node33.html">6. Sparse Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-spmatrix-arith.html">6.3 Arithmetic Operations</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION008200000000000000000">
+6.2 Attributes and Methods</A>
+</H1>
+The following attributes and methods are defined for <tt class="class">spmatrix</tt> objects.
+
+<P>
+<dl><dt><b><tt id='l2h-117' xml:id='l2h-117' class="member">V</tt></b></dt>
+<dd>
+A single-column dense matrix containing the numerical values of the 
+nonzero entries in column-major order.  Making an assignment to 
+the attribute is an efficient way of changing the values of the sparse 
+matrix, without changing the sparsity pattern.
+
+<P>
+When the attribute <tt class="member">V</tt> is read, a <em>copy</em> of <tt class="member">V</tt> is 
+returned, as a new dense matrix. 
+(This implies, for example, that an indexed assignment 
+"<tt class="samp">A.V[I] = B</tt>" does not work, or at least 
+cannot be used to modify <var>A</var>.  Instead the attribute <code>V</code> 
+will be read and returned as a new matrix; then the elements of this 
+new matrix are modified.)
+</dl> 
+
+<P>
+<dl><dt><b><tt id='l2h-118' xml:id='l2h-118' class="member">I</tt></b></dt>
+<dd>
+A single-column integer matrix with the row indices of the entries in
+<code>V</code>.  A read-only attribute.
+</dl> 
+
+<P>
+<dl><dt><b><tt id='l2h-119' xml:id='l2h-119' class="member">J</tt></b></dt>
+<dd>
+A single-column integer matrix with the column indices of the entries
+in <code>V</code>.  A read-only attribute.
+</dl> 
+
+<P>
+<dl><dt><b><tt id='l2h-120' xml:id='l2h-120' class="member">size</tt></b></dt>
+<dd>
+A tuple with the dimensions of the matrix.  A read-only attribute.
+</dl> 
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-121' xml:id='l2h-121' class="method">trans</tt></b>(</nobr></td>
+  <td><var></var>)</td></tr></table></dt>
+<dd>
+Returns the transpose of a sparse matrix as a new sparse matrix.
+One can also use <code>A.T</code> instead of <code>A.trans()</code>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-122' xml:id='l2h-122' class="method">ctrans</tt></b>(</nobr></td>
+  <td><var></var>)</td></tr></table></dt>
+<dd>
+Returns the complex conjugate transpose of a sparse matrix as a 
+new sparse matrix.
+One can also use <code>A.H</code> instead of <code>A.ctrans()</code>. 
+</dl>
+
+<P>
+In the following example we take the elementwise square root of 
+the matrix
+<BR>
+<DIV ALIGN="RIGHT" CLASS="mathdisplay">
+
+<!-- MATH
+ \begin{equation}
+A = \left[ \begin{array}{rrrrr}
+  0 & 2 & 0 & 0 & 3 \\
+  2 & 0 & 0 & 0 & 0 \\
+  1 & 2 & 0 & 4 & 0 \\
+  0 & 0 & 1 & 0 & 0 \end{array} \right]
+\end{equation}
+ -->
+<A NAME="e-spA-example"></A>
+<TABLE WIDTH="100%" ALIGN="CENTER">
+<TR VALIGN="MIDDLE"><TD></TD><TD ALIGN="CENTER" NOWRAP><A NAME="e-spA-example"></A><IMG
+ WIDTH="168" HEIGHT="83" BORDER="0"
+ SRC="img81.gif"
+ ALT="\begin{displaymath}
+A = \left[ \begin{array}{rrrrr}
+0 & 2 & 0 & 0 & 3 \\
+2 &...
+...
+1 & 2 & 0 & 4 & 0 \\
+0 & 0 & 1 & 0 & 0 \end{array} \right]
+\end{displaymath}"></TD>
+<TD CLASS="eqno" WIDTH=10 ALIGN="RIGHT">
+(6.2)</TD></TR>
+</TABLE>
+<BR CLEAR="ALL"></DIV><P></P>
+<div class="verbatim"><pre>
+>>> from cvxopt.base import sqrt
+>>> A = spmatrix([2,1,2,2,1,3,4], [1,2,0,2,3,0,2], [0,0,1,1,2,3,3]) 
+>>> B = spmatrix(sqrt(A.V), A.I, A.J)
+>>> print B
+SIZE: (4,4)
+(1, 0)  1.4142e+00
+(2, 0)  1.0000e+00
+(0, 1)  1.4142e+00
+(2, 1)  1.4142e+00
+(3, 2)  1.0000e+00
+(0, 3)  1.7321e+00
+(2, 3)  2.0000e+00
+</pre></div>
+
+<P>
+The next example below illustrates assignments to <tt class="member">V</tt>.
+<div class="verbatim"><pre>
+>>> from cvxopt.base import spmatrix, matrix
+>>> A = spmatrix(range(5), [0,1,1,2,2], [0,0,1,1,2])
+>>> print A
+SIZE: (3,3)
+(0, 0)  0.0000e+00
+(1, 0)  1.0000e+00
+(1, 1)  2.0000e+00
+(2, 1)  3.0000e+00
+(2, 2)  4.0000e+00
+>>> B = spmatrix(A.V, A.J, A.I, (4,4))  # transpose and add a zero row and column
+>>> print B
+SIZE: (4,4)
+(0, 0)  0.0000e+00
+(0, 1)  1.0000e+00
+(1, 1)  2.0000e+00
+(1, 2)  3.0000e+00
+(2, 2)  4.0000e+00
+>>> print matrix(B)
+ 0.0000e+00   1.0000e+00   0.0000e+00   0.0000e+00
+ 0.0000e+00   2.0000e+00   3.0000e+00   0.0000e+00
+ 0.0000e+00   0.0000e+00   4.0000e+00   0.0000e+00
+ 0.0000e+00   0.0000e+00   0.0000e+00   0.0000e+00
+>>> B.V[:] = 1., 7., 8., 6., 4.   # assign new values to nonzero entries
+>>> print B
+SIZE: (4,4)
+(0, 0)  1.0000e+00
+(0, 1)  7.0000e+00
+(1, 1)  8.0000e+00
+(1, 2)  6.0000e+00
+(2, 2)  4.0000e+00
+>>> B.V += 1.0   # add 1 to the nonzero entries
+>>> print B
+SIZE: (4,4)
+(0, 0)  2.0000e+00
+(0, 1)  8.0000e+00
+(1, 1)  9.0000e+00
+(1, 2)  7.0000e+00
+(2, 2)  5.0000e+00
+</pre></div>
+
+<P>
+The <tt class="member">V</tt>, <tt class="member">I</tt> and <tt class="member">J</tt>  attributes can be used for 
+reading sparse matrices from or writing them to binary files.  
+Suppose we want to write the matrix <var>A</var> defined above to a binary 
+file.
+<div class="verbatim"><pre>
+>>> f = open('test.bin','w')
+>>> A.V.tofile(f)  
+>>> A.I.tofile(f) 
+>>> A.J.tofile(f)
+>>> f.close()
+</pre></div>
+A sparse matrix can be created from this file as follows.
+<div class="verbatim"><pre>
+>>> f = open('test.bin','r')
+>>> V = matrix(0.0, (5,1));  V.fromfile(f)  
+>>> I = matrix(0, (5,1));  I.fromfile(f)  
+>>> J = matrix(0, (5,1));  J.fromfile(f)  
+>>> B = spmatrix(V, I, J)
+>>> print B
+SIZE: (3,3)
+(0, 0)  0.0000e+00
+(1, 0)  1.0000e+00
+(1, 1)  2.0000e+00
+(2, 1)  3.0000e+00
+(2, 2)  4.0000e+00
+</pre></div>
+
+<P>
+Note that the  <tt class="module">pickle</tt> module provides a convenient alternative 
+to this method.
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="6.1 Creating Sparse Matrices"
+  href="s-creating-spmatrix.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="6. Sparse Matrices (cvxopt.base)"
+  href="node33.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="6.3 Arithmetic Operations"
+  href="s-spmatrix-arith.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-creating-spmatrix.html">6.1 Creating Sparse Matrices</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node33.html">6. Sparse Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-spmatrix-arith.html">6.3 Arithmetic Operations</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/genindex.html b/doc/cvxopt/genindex.html
new file mode 100644
index 0000000..cbca7d5
--- /dev/null
+++ b/doc/cvxopt/genindex.html
@@ -0,0 +1,539 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="about.html" />
+<link rel="prev" href="node61.html" />
+<link rel="parent" href="cvxopt.html" />
+<link rel="next" href="about.html" />
+<meta name='aesop' content='information' />
+<title>Index</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="10.2 Sparse Matrices"
+  href="node63.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="About this document ..."
+  href="about.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node63.html">10.2 Sparse Matrices</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="about.html">About this document ...</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+<br />
+
+<h2><A NAME="SECTION0013000000000000000000">
+Index</A>
+</h2><hr /><center>
+<b><a href="#letter-Symbols">Symbols</a></b> |
+<b><a href="#letter-a">a</a></b> |
+<b><a href="#letter-b">b</a></b> |
+<b><a href="#letter-c">c</a></b> |
+<b><a href="#letter-d">d</a></b> |
+<b><a href="#letter-e">e</a></b> |
+<b><a href="#letter-f">f</a></b> |
+<b><a href="#letter-g">g</a></b> |
+<b><a href="#letter-h">h</a></b> |
+<b><a href="#letter-i">i</a></b> |
+<b><a href="#letter-j">j</a></b> |
+<b><a href="#letter-l">l</a></b> |
+<b><a href="#letter-m">m</a></b> |
+<b><a href="#letter-n">n</a></b> |
+<b><a href="#letter-o">o</a></b> |
+<b><a href="#letter-p">p</a></b> |
+<b><a href="#letter-q">q</a></b> |
+<b><a href="#letter-r">r</a></b> |
+<b><a href="#letter-s">s</a></b> |
+<b><a href="#letter-t">t</a></b> |
+<b><a href="#letter-u">u</a></b> |
+<b><a href="#letter-v">v</a></b></center>
+
+<hr />
+<h2 id="letter-Symbols">Symbols</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="node6.html#l2h-8">\_\_array\_struct\_\_ (PyCObject attribute)</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-a">A</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-builtinfuncs.html#l2h-15">abs()</a>,
+    <a href="node38.html#l2h-127">[Link]</a>
+<dt><a href="s-lp.html#l2h-170">addconstraint() (lp method)</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-blas1.html#l2h-30">asum()</a>
+<dt><a href="s-blas1.html#l2h-34">axpy()</a>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-b">B</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-builtinfuncs.html#l2h-12">bool()</a>,
+    <a href="node38.html#l2h-124">[Link]</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-c">C</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="node51.html#l2h-150">conelp()</a>
+<dt><a href="s-lp.html#l2h-166">constraints() (lp method)</a>
+<dt><a href="s-blas1.html#l2h-33">copy()</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-otherfuncs.html#l2h-19">cos()</a>
+<dt><a href="e-nlcp.html#l2h-149">cp()</a>
+<dt><a href="node6.html#l2h-5">ctrans()</a>,
+    <a href="e-spA-example.html#l2h-122">[Link]</a>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-d">D</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="node31.html#l2h-111">dct()</a>
+<dt><a href="s-lp.html#l2h-169">delconstraint() (lp method)</a>
+<dt><a href="node30.html#l2h-109">dft()</a>
+<dt><a href="s-cholmod.html#l2h-144">diag()</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-otherfuncs.html#l2h-23">div()</a>
+<dt><a href="s-blas1.html#l2h-35">dot()</a>,
+    <a href="s-functions.html#l2h-158">[Link]</a>
+<dt><a href="s-blas1.html#l2h-36">dotu()</a>
+<dt><a href="node32.html#l2h-113">dst()</a>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-e">E</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-lp.html#l2h-168">equalities() (lp method)</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-otherfuncs.html#l2h-20">exp()</a>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-f">F</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="node6.html#l2h-10">fromfile()</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-lp.html#l2h-173">fromfile() (lp method)</a>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-g">G</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-blas2.html#l2h-42">gbmv()</a>
+<dt><a href="node20.html#l2h-66">gbsv()</a>
+<dt><a href="node20.html#l2h-67">gbtrf()</a>
+<dt><a href="node20.html#l2h-68">gbtrs()</a>
+<dt><a href="node24.html#l2h-93">gels()</a>
+<dt><a href="s-blas3.html#l2h-53">gemm()</a>,
+    <a href="node39.html#l2h-131">[Link]</a>
+<dt><a href="s-blas2.html#l2h-37">gemv()</a>,
+    <a href="node39.html#l2h-129">[Link]</a>
+<dt><a href="node24.html#l2h-94">geqrf()</a>
+<dt><a href="s-blas2.html#l2h-47">ger()</a>
+<dt><a href="s-blas2.html#l2h-48">geru()</a>
+<dt><a href="node27.html#l2h-108">gesdd()</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+<dt><a href="node20.html#l2h-62">gesv()</a>
+<dt><a href="node27.html#l2h-107">gesvd()</a>
+<dt><a href="node20.html#l2h-63">getrf()</a>
+<dt><a href="node20.html#l2h-65">getri()</a>
+<dt><a href="node20.html#l2h-64">getrs()</a>
+<dt><a href="s-random.html#l2h-26">getseed()</a>
+<dt><a href="node48.html#l2h-147">gp()</a>
+<dt><a href="node20.html#l2h-69">gtsv()</a>
+<dt><a href="node20.html#l2h-70">gttrf()</a>
+<dt><a href="e-kkt-example.html#l2h-81">gttrs()</a>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-h">H</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-blas2.html#l2h-44">hbmv()</a>
+<dt><a href="node25.html#l2h-101">heev()</a>
+<dt><a href="node25.html#l2h-102">heevd()</a>
+<dt><a href="node25.html#l2h-104">heevr()</a>
+<dt><a href="node25.html#l2h-103">heevx()</a>
+<dt><a href="e-gevd.html#l2h-106">hegv()</a>
+<dt><a href="s-blas3.html#l2h-55">hemm()</a>
+<dt><a href="s-blas2.html#l2h-39">hemv()</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-blas2.html#l2h-50">her()</a>
+<dt><a href="s-blas2.html#l2h-52">her2()</a>
+<dt><a href="s-blas3.html#l2h-61">her2k()</a>
+<dt><a href="s-blas3.html#l2h-59">herk()</a>
+<dt><a href="node22.html#l2h-86">hesv()</a>
+<dt><a href="node22.html#l2h-87">hetrf()</a>
+<dt><a href="node22.html#l2h-89">hetri()</a>
+<dt><a href="node22.html#l2h-88">hetrs()</a>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-i">I</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="e-spA-example.html#l2h-118">I (spmatrix attribute)</a>
+<dt><a href="s-blas1.html#l2h-31">iamax()</a>
+<dt><a href="node31.html#l2h-112">idct()</a>
+<dt><a href="node30.html#l2h-110">idft()</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+<dt><a href="node32.html#l2h-114">idst()</a>
+<dt><a href="node6.html#l2h-7">imag()</a>
+<dt><a href="s-lp.html#l2h-167">inequalities() (lp method)</a>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-j">J</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="e-spA-example.html#l2h-119">J (matrix attribute)</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-l">L</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-builtinfuncs.html#l2h-11">len()</a>,
+    <a href="node38.html#l2h-123">[Link]</a>
+<dt><a href="s-umfpack.html#l2h-134">linsolve()</a>,
+    <a href="s-cholmod.html#l2h-138">[Link]</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-otherfuncs.html#l2h-21">log()</a>
+<dt><a href="s-lpsolver.html#l2h-145">lp()</a>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-m">M</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-creating-matrices.html#l2h-1">matrix()</a>
+<dt><a href="node62.html#l2h-174">Matrix\_New()</a>
+<dt><a href="node62.html#l2h-175">Matrix\_NewFromMatrix()</a>
+<dt><a href="node62.html#l2h-176">Matrix\_NewFromSequence()</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-builtinfuncs.html#l2h-13">max()</a>,
+    <a href="node38.html#l2h-125">[Link]</a>
+<dt><a href="s-builtinfuncs.html#l2h-14">min()</a>,
+    <a href="node38.html#l2h-126">[Link]</a>
+<dt><a href="s-otherfuncs.html#l2h-22">mul()</a>
+<dt><a href="node58.html#l2h-161">multiplier (constraint attribute)</a>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-n">N</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="node58.html#l2h-162">name (constraint attribute)</a>
+<dt><a href="s-variables.html#l2h-153">name (variable attribute)</a>
+<dt><a href="node52.html#l2h-151">nlcp()</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-random.html#l2h-24">normal()</a>
+<dt><a href="s-blas1.html#l2h-29">nrm2()</a>
+<dt><a href="s-umfpack.html#l2h-136">numeric()</a>,
+    <a href="s-cholmod.html#l2h-141">[Link]</a>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-o">O</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-lp.html#l2h-164">objective (op attribute)</a>
+<dt><a href="s-lp.html#l2h-163">op (class in )</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-orderings.html#l2h-133">order()</a>
+<dt><a href="node24.html#l2h-95">ormqr()</a>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-p">P</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="e-kkt-example.html#l2h-76">pbsv()</a>
+<dt><a href="e-kkt-example.html#l2h-77">pbtrf()</a>
+<dt><a href="e-kkt-example.html#l2h-78">pbtrs()</a>
+<dt><a href="e-kkt-example.html#l2h-72">posv()</a>
+<dt><a href="e-kkt-example.html#l2h-73">potrf()</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+<dt><a href="e-kkt-example.html#l2h-75">potri()</a>
+<dt><a href="e-kkt-example.html#l2h-74">potrs()</a>
+<dt><a href="e-kkt-example.html#l2h-79">ptsv()</a>
+<dt><a href="e-kkt-example.html#l2h-80">pttrf()</a>
+<dt><a href="node20.html#l2h-71">pttrs()</a>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-q">Q</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="node47.html#l2h-146">qp()</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-r">R</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="node6.html#l2h-6">real()</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-s">S</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-blas2.html#l2h-43">sbmv()</a>
+<dt><a href="s-blas1.html#l2h-28">scal()</a>
+<dt><a href="s-sdpsolver.html#l2h-148">sdp()</a>
+<dt><a href="s-random.html#l2h-27">setseed()</a>
+<dt><a href="s-otherfuncs.html#l2h-18">sin()</a>
+<dt><a href="node6.html#l2h-2">size (tuple attribute)</a>,
+    <a href="e-spA-example.html#l2h-120">[Link]</a>
+<dt><a href="s-umfpack.html#l2h-137">solve()</a>,
+    <a href="s-cholmod.html#l2h-142">[Link]</a>
+<dt><a href="s-lp.html#l2h-171">solve() (op method)</a>
+<dt><a href="s-creating-spmatrix.html#l2h-116">sparse()</a>
+<dt><a href="s-cholmod.html#l2h-139">splinsolve()</a>
+<dt><a href="s-creating-spmatrix.html#l2h-115">spmatrix()</a>
+<dt><a href="node63.html#l2h-177">SpMatrix\_New()</a>
+<dt><a href="node63.html#l2h-179">SpMatrix\_NewFromIJV()</a>
+<dt><a href="node63.html#l2h-178">SpMatrix\_NewFromMatrix()</a>
+<dt><a href="s-cholmod.html#l2h-143">spsolve()</a>
+<dt><a href="s-otherfuncs.html#l2h-17">sqrt()</a>
+<dt><a href="s-builtinfuncs.html#l2h-16">sum()</a>,
+    <a href="node38.html#l2h-128">[Link]</a>,
+    <a href="s-functions.html#l2h-157">[Link]</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-blas1.html#l2h-32">swap()</a>
+<dt><a href="node25.html#l2h-97">syev()</a>
+<dt><a href="node25.html#l2h-98">syevd()</a>
+<dt><a href="node25.html#l2h-100">syevr()</a>
+<dt><a href="node25.html#l2h-99">syevx()</a>
+<dt><a href="e-gevd.html#l2h-105">sygv()</a>
+<dt><a href="s-umfpack.html#l2h-135">symbolic()</a>,
+    <a href="s-cholmod.html#l2h-140">[Link]</a>
+<dt><a href="s-blas3.html#l2h-54">symm()</a>
+<dt><a href="s-blas2.html#l2h-38">symv()</a>,
+    <a href="node39.html#l2h-130">[Link]</a>
+<dt><a href="s-blas2.html#l2h-49">syr()</a>
+<dt><a href="s-blas2.html#l2h-51">syr2()</a>
+<dt><a href="s-blas3.html#l2h-60">syr2k()</a>
+<dt><a href="s-blas3.html#l2h-58">syrk()</a>,
+    <a href="node39.html#l2h-132">[Link]</a>
+<dt><a href="node22.html#l2h-82">sysv()</a>
+<dt><a href="node22.html#l2h-83">sytrf()</a>
+<dt><a href="node22.html#l2h-85">sytri()</a>
+<dt><a href="node22.html#l2h-84">sytrs()</a>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-t">T</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-blas2.html#l2h-45">tbmv()</a>
+<dt><a href="s-blas2.html#l2h-46">tbsv()</a>
+<dt><a href="node23.html#l2h-92">tbtrs()</a>
+<dt><a href="node6.html#l2h-9">tofile()</a>
+<dt><a href="s-lp.html#l2h-172">tofile() (op method)</a>
+<dt><a href="node6.html#l2h-4">trans()</a>,
+    <a href="e-spA-example.html#l2h-121">[Link]</a>
+<dt><a href="s-blas3.html#l2h-56">trmm()</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-blas2.html#l2h-40">trmv()</a>
+<dt><a href="s-blas3.html#l2h-57">trsm()</a>
+<dt><a href="s-blas2.html#l2h-41">trsv()</a>
+<dt><a href="node23.html#l2h-91">trtri()</a>
+<dt><a href="node23.html#l2h-90">trtrs()</a>
+<dt><a href="node58.html#l2h-159">type() (constraint method)</a>
+<dt><a href="node6.html#l2h-3">typecode (char attribute)</a>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-u">U</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-random.html#l2h-25">uniform()</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+<dt><a href="node24.html#l2h-96">unmqr()</a>
+</dl>
+</td>
+</tr></table>
+<hr />
+<h2 id="letter-v">V</h2>
+
+<table width="100%"><tr valign="top"><td width="50%">
+<dl compact='compact'>
+<dt><a href="e-spA-example.html#l2h-117">V (matrix attribute)</a>
+<dt><a href="node58.html#l2h-160">value() (constraint method)</a>
+<dt><a href="s-variables.html#l2h-154">value (variable attribute)</a>
+<dt><a href="s-functions.html#l2h-156">value() (variable method)</a>
+</dl>
+</td><td width="50%">
+<dl compact='compact'>
+<dt><a href="s-variables.html#l2h-152">variable (class in )</a>
+<dt><a href="s-lp.html#l2h-165">variables() (lp method)</a>
+<dt><a href="s-functions.html#l2h-155">variables() (variable method)</a>
+</dl>
+</td>
+</tr></table>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="10.2 Sparse Matrices"
+  href="node63.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="About this document ..."
+  href="about.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node63.html">10.2 Sparse Matrices</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="about.html">About this document ...</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/img1.gif b/doc/cvxopt/img1.gif
new file mode 100644
index 0000000..53d7971
Binary files /dev/null and b/doc/cvxopt/img1.gif differ
diff --git a/doc/cvxopt/img10.gif b/doc/cvxopt/img10.gif
new file mode 100644
index 0000000..12d11a4
Binary files /dev/null and b/doc/cvxopt/img10.gif differ
diff --git a/doc/cvxopt/img100.gif b/doc/cvxopt/img100.gif
new file mode 100644
index 0000000..c134195
Binary files /dev/null and b/doc/cvxopt/img100.gif differ
diff --git a/doc/cvxopt/img101.gif b/doc/cvxopt/img101.gif
new file mode 100644
index 0000000..549115f
Binary files /dev/null and b/doc/cvxopt/img101.gif differ
diff --git a/doc/cvxopt/img102.gif b/doc/cvxopt/img102.gif
new file mode 100644
index 0000000..ab2fa96
Binary files /dev/null and b/doc/cvxopt/img102.gif differ
diff --git a/doc/cvxopt/img103.gif b/doc/cvxopt/img103.gif
new file mode 100644
index 0000000..845d722
Binary files /dev/null and b/doc/cvxopt/img103.gif differ
diff --git a/doc/cvxopt/img104.gif b/doc/cvxopt/img104.gif
new file mode 100644
index 0000000..9511d86
Binary files /dev/null and b/doc/cvxopt/img104.gif differ
diff --git a/doc/cvxopt/img105.gif b/doc/cvxopt/img105.gif
new file mode 100644
index 0000000..df02e06
Binary files /dev/null and b/doc/cvxopt/img105.gif differ
diff --git a/doc/cvxopt/img106.gif b/doc/cvxopt/img106.gif
new file mode 100644
index 0000000..71a86ee
Binary files /dev/null and b/doc/cvxopt/img106.gif differ
diff --git a/doc/cvxopt/img107.gif b/doc/cvxopt/img107.gif
new file mode 100644
index 0000000..ea1daa6
Binary files /dev/null and b/doc/cvxopt/img107.gif differ
diff --git a/doc/cvxopt/img108.gif b/doc/cvxopt/img108.gif
new file mode 100644
index 0000000..df927cc
Binary files /dev/null and b/doc/cvxopt/img108.gif differ
diff --git a/doc/cvxopt/img109.gif b/doc/cvxopt/img109.gif
new file mode 100644
index 0000000..2932787
Binary files /dev/null and b/doc/cvxopt/img109.gif differ
diff --git a/doc/cvxopt/img11.gif b/doc/cvxopt/img11.gif
new file mode 100644
index 0000000..30abc1f
Binary files /dev/null and b/doc/cvxopt/img11.gif differ
diff --git a/doc/cvxopt/img110.gif b/doc/cvxopt/img110.gif
new file mode 100644
index 0000000..fe6e960
Binary files /dev/null and b/doc/cvxopt/img110.gif differ
diff --git a/doc/cvxopt/img111.gif b/doc/cvxopt/img111.gif
new file mode 100644
index 0000000..c5df7d2
Binary files /dev/null and b/doc/cvxopt/img111.gif differ
diff --git a/doc/cvxopt/img112.gif b/doc/cvxopt/img112.gif
new file mode 100644
index 0000000..d999ca9
Binary files /dev/null and b/doc/cvxopt/img112.gif differ
diff --git a/doc/cvxopt/img113.gif b/doc/cvxopt/img113.gif
new file mode 100644
index 0000000..6c499b1
Binary files /dev/null and b/doc/cvxopt/img113.gif differ
diff --git a/doc/cvxopt/img114.gif b/doc/cvxopt/img114.gif
new file mode 100644
index 0000000..4473873
Binary files /dev/null and b/doc/cvxopt/img114.gif differ
diff --git a/doc/cvxopt/img115.gif b/doc/cvxopt/img115.gif
new file mode 100644
index 0000000..69d03ed
Binary files /dev/null and b/doc/cvxopt/img115.gif differ
diff --git a/doc/cvxopt/img116.gif b/doc/cvxopt/img116.gif
new file mode 100644
index 0000000..a7834b3
Binary files /dev/null and b/doc/cvxopt/img116.gif differ
diff --git a/doc/cvxopt/img117.gif b/doc/cvxopt/img117.gif
new file mode 100644
index 0000000..a7f1897
Binary files /dev/null and b/doc/cvxopt/img117.gif differ
diff --git a/doc/cvxopt/img118.gif b/doc/cvxopt/img118.gif
new file mode 100644
index 0000000..55450d3
Binary files /dev/null and b/doc/cvxopt/img118.gif differ
diff --git a/doc/cvxopt/img119.gif b/doc/cvxopt/img119.gif
new file mode 100644
index 0000000..c841027
Binary files /dev/null and b/doc/cvxopt/img119.gif differ
diff --git a/doc/cvxopt/img12.gif b/doc/cvxopt/img12.gif
new file mode 100644
index 0000000..ff12e45
Binary files /dev/null and b/doc/cvxopt/img12.gif differ
diff --git a/doc/cvxopt/img120.gif b/doc/cvxopt/img120.gif
new file mode 100644
index 0000000..290b602
Binary files /dev/null and b/doc/cvxopt/img120.gif differ
diff --git a/doc/cvxopt/img121.gif b/doc/cvxopt/img121.gif
new file mode 100644
index 0000000..d613bb5
Binary files /dev/null and b/doc/cvxopt/img121.gif differ
diff --git a/doc/cvxopt/img122.gif b/doc/cvxopt/img122.gif
new file mode 100644
index 0000000..b95f1b6
Binary files /dev/null and b/doc/cvxopt/img122.gif differ
diff --git a/doc/cvxopt/img123.gif b/doc/cvxopt/img123.gif
new file mode 100644
index 0000000..6fbe986
Binary files /dev/null and b/doc/cvxopt/img123.gif differ
diff --git a/doc/cvxopt/img124.gif b/doc/cvxopt/img124.gif
new file mode 100644
index 0000000..9f77105
Binary files /dev/null and b/doc/cvxopt/img124.gif differ
diff --git a/doc/cvxopt/img125.gif b/doc/cvxopt/img125.gif
new file mode 100644
index 0000000..a6a9ff9
Binary files /dev/null and b/doc/cvxopt/img125.gif differ
diff --git a/doc/cvxopt/img126.gif b/doc/cvxopt/img126.gif
new file mode 100644
index 0000000..1b76714
Binary files /dev/null and b/doc/cvxopt/img126.gif differ
diff --git a/doc/cvxopt/img127.gif b/doc/cvxopt/img127.gif
new file mode 100644
index 0000000..96e0bc8
Binary files /dev/null and b/doc/cvxopt/img127.gif differ
diff --git a/doc/cvxopt/img128.gif b/doc/cvxopt/img128.gif
new file mode 100644
index 0000000..2ef9f91
Binary files /dev/null and b/doc/cvxopt/img128.gif differ
diff --git a/doc/cvxopt/img129.gif b/doc/cvxopt/img129.gif
new file mode 100644
index 0000000..0414453
Binary files /dev/null and b/doc/cvxopt/img129.gif differ
diff --git a/doc/cvxopt/img13.gif b/doc/cvxopt/img13.gif
new file mode 100644
index 0000000..9236bb3
Binary files /dev/null and b/doc/cvxopt/img13.gif differ
diff --git a/doc/cvxopt/img130.gif b/doc/cvxopt/img130.gif
new file mode 100644
index 0000000..89f009e
Binary files /dev/null and b/doc/cvxopt/img130.gif differ
diff --git a/doc/cvxopt/img131.gif b/doc/cvxopt/img131.gif
new file mode 100644
index 0000000..d9a43ea
Binary files /dev/null and b/doc/cvxopt/img131.gif differ
diff --git a/doc/cvxopt/img132.gif b/doc/cvxopt/img132.gif
new file mode 100644
index 0000000..225bdd4
Binary files /dev/null and b/doc/cvxopt/img132.gif differ
diff --git a/doc/cvxopt/img133.gif b/doc/cvxopt/img133.gif
new file mode 100644
index 0000000..3cf04fb
Binary files /dev/null and b/doc/cvxopt/img133.gif differ
diff --git a/doc/cvxopt/img134.gif b/doc/cvxopt/img134.gif
new file mode 100644
index 0000000..9654e8c
Binary files /dev/null and b/doc/cvxopt/img134.gif differ
diff --git a/doc/cvxopt/img135.gif b/doc/cvxopt/img135.gif
new file mode 100644
index 0000000..5c508f5
Binary files /dev/null and b/doc/cvxopt/img135.gif differ
diff --git a/doc/cvxopt/img136.gif b/doc/cvxopt/img136.gif
new file mode 100644
index 0000000..7609df3
Binary files /dev/null and b/doc/cvxopt/img136.gif differ
diff --git a/doc/cvxopt/img137.gif b/doc/cvxopt/img137.gif
new file mode 100644
index 0000000..0547846
Binary files /dev/null and b/doc/cvxopt/img137.gif differ
diff --git a/doc/cvxopt/img138.gif b/doc/cvxopt/img138.gif
new file mode 100644
index 0000000..2a8098d
Binary files /dev/null and b/doc/cvxopt/img138.gif differ
diff --git a/doc/cvxopt/img139.gif b/doc/cvxopt/img139.gif
new file mode 100644
index 0000000..3ed1191
Binary files /dev/null and b/doc/cvxopt/img139.gif differ
diff --git a/doc/cvxopt/img14.gif b/doc/cvxopt/img14.gif
new file mode 100644
index 0000000..e740592
Binary files /dev/null and b/doc/cvxopt/img14.gif differ
diff --git a/doc/cvxopt/img140.gif b/doc/cvxopt/img140.gif
new file mode 100644
index 0000000..7fe3cb9
Binary files /dev/null and b/doc/cvxopt/img140.gif differ
diff --git a/doc/cvxopt/img141.gif b/doc/cvxopt/img141.gif
new file mode 100644
index 0000000..89130db
Binary files /dev/null and b/doc/cvxopt/img141.gif differ
diff --git a/doc/cvxopt/img142.gif b/doc/cvxopt/img142.gif
new file mode 100644
index 0000000..b2865e8
Binary files /dev/null and b/doc/cvxopt/img142.gif differ
diff --git a/doc/cvxopt/img143.gif b/doc/cvxopt/img143.gif
new file mode 100644
index 0000000..d193090
Binary files /dev/null and b/doc/cvxopt/img143.gif differ
diff --git a/doc/cvxopt/img144.gif b/doc/cvxopt/img144.gif
new file mode 100644
index 0000000..bdb0788
Binary files /dev/null and b/doc/cvxopt/img144.gif differ
diff --git a/doc/cvxopt/img145.gif b/doc/cvxopt/img145.gif
new file mode 100644
index 0000000..ca98f98
Binary files /dev/null and b/doc/cvxopt/img145.gif differ
diff --git a/doc/cvxopt/img146.gif b/doc/cvxopt/img146.gif
new file mode 100644
index 0000000..93bde6e
Binary files /dev/null and b/doc/cvxopt/img146.gif differ
diff --git a/doc/cvxopt/img147.gif b/doc/cvxopt/img147.gif
new file mode 100644
index 0000000..70766b4
Binary files /dev/null and b/doc/cvxopt/img147.gif differ
diff --git a/doc/cvxopt/img148.gif b/doc/cvxopt/img148.gif
new file mode 100644
index 0000000..0f83e30
Binary files /dev/null and b/doc/cvxopt/img148.gif differ
diff --git a/doc/cvxopt/img149.gif b/doc/cvxopt/img149.gif
new file mode 100644
index 0000000..808dfca
Binary files /dev/null and b/doc/cvxopt/img149.gif differ
diff --git a/doc/cvxopt/img15.gif b/doc/cvxopt/img15.gif
new file mode 100644
index 0000000..f7349df
Binary files /dev/null and b/doc/cvxopt/img15.gif differ
diff --git a/doc/cvxopt/img150.gif b/doc/cvxopt/img150.gif
new file mode 100644
index 0000000..2eb398f
Binary files /dev/null and b/doc/cvxopt/img150.gif differ
diff --git a/doc/cvxopt/img151.gif b/doc/cvxopt/img151.gif
new file mode 100644
index 0000000..9e6a2f6
Binary files /dev/null and b/doc/cvxopt/img151.gif differ
diff --git a/doc/cvxopt/img152.gif b/doc/cvxopt/img152.gif
new file mode 100644
index 0000000..4a6a6e1
Binary files /dev/null and b/doc/cvxopt/img152.gif differ
diff --git a/doc/cvxopt/img153.gif b/doc/cvxopt/img153.gif
new file mode 100644
index 0000000..51e5739
Binary files /dev/null and b/doc/cvxopt/img153.gif differ
diff --git a/doc/cvxopt/img154.gif b/doc/cvxopt/img154.gif
new file mode 100644
index 0000000..03869c3
Binary files /dev/null and b/doc/cvxopt/img154.gif differ
diff --git a/doc/cvxopt/img155.gif b/doc/cvxopt/img155.gif
new file mode 100644
index 0000000..b8ed0de
Binary files /dev/null and b/doc/cvxopt/img155.gif differ
diff --git a/doc/cvxopt/img156.gif b/doc/cvxopt/img156.gif
new file mode 100644
index 0000000..f7f8a0b
Binary files /dev/null and b/doc/cvxopt/img156.gif differ
diff --git a/doc/cvxopt/img157.gif b/doc/cvxopt/img157.gif
new file mode 100644
index 0000000..ec6f938
Binary files /dev/null and b/doc/cvxopt/img157.gif differ
diff --git a/doc/cvxopt/img158.gif b/doc/cvxopt/img158.gif
new file mode 100644
index 0000000..25ea937
Binary files /dev/null and b/doc/cvxopt/img158.gif differ
diff --git a/doc/cvxopt/img159.gif b/doc/cvxopt/img159.gif
new file mode 100644
index 0000000..3217c6e
Binary files /dev/null and b/doc/cvxopt/img159.gif differ
diff --git a/doc/cvxopt/img16.gif b/doc/cvxopt/img16.gif
new file mode 100644
index 0000000..42d03cc
Binary files /dev/null and b/doc/cvxopt/img16.gif differ
diff --git a/doc/cvxopt/img160.gif b/doc/cvxopt/img160.gif
new file mode 100644
index 0000000..6a506ee
Binary files /dev/null and b/doc/cvxopt/img160.gif differ
diff --git a/doc/cvxopt/img161.gif b/doc/cvxopt/img161.gif
new file mode 100644
index 0000000..419fc46
Binary files /dev/null and b/doc/cvxopt/img161.gif differ
diff --git a/doc/cvxopt/img162.gif b/doc/cvxopt/img162.gif
new file mode 100644
index 0000000..e5a14a9
Binary files /dev/null and b/doc/cvxopt/img162.gif differ
diff --git a/doc/cvxopt/img163.gif b/doc/cvxopt/img163.gif
new file mode 100644
index 0000000..c537ea2
Binary files /dev/null and b/doc/cvxopt/img163.gif differ
diff --git a/doc/cvxopt/img164.gif b/doc/cvxopt/img164.gif
new file mode 100644
index 0000000..9297eea
Binary files /dev/null and b/doc/cvxopt/img164.gif differ
diff --git a/doc/cvxopt/img165.gif b/doc/cvxopt/img165.gif
new file mode 100644
index 0000000..5fb7051
Binary files /dev/null and b/doc/cvxopt/img165.gif differ
diff --git a/doc/cvxopt/img166.gif b/doc/cvxopt/img166.gif
new file mode 100644
index 0000000..12ca978
Binary files /dev/null and b/doc/cvxopt/img166.gif differ
diff --git a/doc/cvxopt/img167.gif b/doc/cvxopt/img167.gif
new file mode 100644
index 0000000..8eacb97
Binary files /dev/null and b/doc/cvxopt/img167.gif differ
diff --git a/doc/cvxopt/img168.gif b/doc/cvxopt/img168.gif
new file mode 100644
index 0000000..a9b4ee6
Binary files /dev/null and b/doc/cvxopt/img168.gif differ
diff --git a/doc/cvxopt/img169.gif b/doc/cvxopt/img169.gif
new file mode 100644
index 0000000..38891a0
Binary files /dev/null and b/doc/cvxopt/img169.gif differ
diff --git a/doc/cvxopt/img17.gif b/doc/cvxopt/img17.gif
new file mode 100644
index 0000000..fde7a8c
Binary files /dev/null and b/doc/cvxopt/img17.gif differ
diff --git a/doc/cvxopt/img170.gif b/doc/cvxopt/img170.gif
new file mode 100644
index 0000000..657cc09
Binary files /dev/null and b/doc/cvxopt/img170.gif differ
diff --git a/doc/cvxopt/img171.gif b/doc/cvxopt/img171.gif
new file mode 100644
index 0000000..308398a
Binary files /dev/null and b/doc/cvxopt/img171.gif differ
diff --git a/doc/cvxopt/img172.gif b/doc/cvxopt/img172.gif
new file mode 100644
index 0000000..d224c91
Binary files /dev/null and b/doc/cvxopt/img172.gif differ
diff --git a/doc/cvxopt/img173.gif b/doc/cvxopt/img173.gif
new file mode 100644
index 0000000..b1210e4
Binary files /dev/null and b/doc/cvxopt/img173.gif differ
diff --git a/doc/cvxopt/img174.gif b/doc/cvxopt/img174.gif
new file mode 100644
index 0000000..fc10348
Binary files /dev/null and b/doc/cvxopt/img174.gif differ
diff --git a/doc/cvxopt/img175.gif b/doc/cvxopt/img175.gif
new file mode 100644
index 0000000..a406e65
Binary files /dev/null and b/doc/cvxopt/img175.gif differ
diff --git a/doc/cvxopt/img176.gif b/doc/cvxopt/img176.gif
new file mode 100644
index 0000000..9e0cb0e
Binary files /dev/null and b/doc/cvxopt/img176.gif differ
diff --git a/doc/cvxopt/img177.gif b/doc/cvxopt/img177.gif
new file mode 100644
index 0000000..c883847
Binary files /dev/null and b/doc/cvxopt/img177.gif differ
diff --git a/doc/cvxopt/img178.gif b/doc/cvxopt/img178.gif
new file mode 100644
index 0000000..c504faa
Binary files /dev/null and b/doc/cvxopt/img178.gif differ
diff --git a/doc/cvxopt/img179.gif b/doc/cvxopt/img179.gif
new file mode 100644
index 0000000..b253d09
Binary files /dev/null and b/doc/cvxopt/img179.gif differ
diff --git a/doc/cvxopt/img18.gif b/doc/cvxopt/img18.gif
new file mode 100644
index 0000000..5172cf0
Binary files /dev/null and b/doc/cvxopt/img18.gif differ
diff --git a/doc/cvxopt/img180.gif b/doc/cvxopt/img180.gif
new file mode 100644
index 0000000..a36019d
Binary files /dev/null and b/doc/cvxopt/img180.gif differ
diff --git a/doc/cvxopt/img181.gif b/doc/cvxopt/img181.gif
new file mode 100644
index 0000000..9b80cf2
Binary files /dev/null and b/doc/cvxopt/img181.gif differ
diff --git a/doc/cvxopt/img182.gif b/doc/cvxopt/img182.gif
new file mode 100644
index 0000000..1fecb9a
Binary files /dev/null and b/doc/cvxopt/img182.gif differ
diff --git a/doc/cvxopt/img183.gif b/doc/cvxopt/img183.gif
new file mode 100644
index 0000000..77c7176
Binary files /dev/null and b/doc/cvxopt/img183.gif differ
diff --git a/doc/cvxopt/img184.gif b/doc/cvxopt/img184.gif
new file mode 100644
index 0000000..21fc3cf
Binary files /dev/null and b/doc/cvxopt/img184.gif differ
diff --git a/doc/cvxopt/img185.gif b/doc/cvxopt/img185.gif
new file mode 100644
index 0000000..d4a8b36
Binary files /dev/null and b/doc/cvxopt/img185.gif differ
diff --git a/doc/cvxopt/img19.gif b/doc/cvxopt/img19.gif
new file mode 100644
index 0000000..83acb21
Binary files /dev/null and b/doc/cvxopt/img19.gif differ
diff --git a/doc/cvxopt/img2.gif b/doc/cvxopt/img2.gif
new file mode 100644
index 0000000..5ccd9a9
Binary files /dev/null and b/doc/cvxopt/img2.gif differ
diff --git a/doc/cvxopt/img20.gif b/doc/cvxopt/img20.gif
new file mode 100644
index 0000000..b76cc84
Binary files /dev/null and b/doc/cvxopt/img20.gif differ
diff --git a/doc/cvxopt/img21.gif b/doc/cvxopt/img21.gif
new file mode 100644
index 0000000..a7fbafe
Binary files /dev/null and b/doc/cvxopt/img21.gif differ
diff --git a/doc/cvxopt/img22.gif b/doc/cvxopt/img22.gif
new file mode 100644
index 0000000..e4a074d
Binary files /dev/null and b/doc/cvxopt/img22.gif differ
diff --git a/doc/cvxopt/img23.gif b/doc/cvxopt/img23.gif
new file mode 100644
index 0000000..869ba46
Binary files /dev/null and b/doc/cvxopt/img23.gif differ
diff --git a/doc/cvxopt/img24.gif b/doc/cvxopt/img24.gif
new file mode 100644
index 0000000..4a87e49
Binary files /dev/null and b/doc/cvxopt/img24.gif differ
diff --git a/doc/cvxopt/img25.gif b/doc/cvxopt/img25.gif
new file mode 100644
index 0000000..a95ac23
Binary files /dev/null and b/doc/cvxopt/img25.gif differ
diff --git a/doc/cvxopt/img26.gif b/doc/cvxopt/img26.gif
new file mode 100644
index 0000000..de46221
Binary files /dev/null and b/doc/cvxopt/img26.gif differ
diff --git a/doc/cvxopt/img27.gif b/doc/cvxopt/img27.gif
new file mode 100644
index 0000000..5943e9e
Binary files /dev/null and b/doc/cvxopt/img27.gif differ
diff --git a/doc/cvxopt/img28.gif b/doc/cvxopt/img28.gif
new file mode 100644
index 0000000..755a6f8
Binary files /dev/null and b/doc/cvxopt/img28.gif differ
diff --git a/doc/cvxopt/img29.gif b/doc/cvxopt/img29.gif
new file mode 100644
index 0000000..8b4855d
Binary files /dev/null and b/doc/cvxopt/img29.gif differ
diff --git a/doc/cvxopt/img3.gif b/doc/cvxopt/img3.gif
new file mode 100644
index 0000000..4658dfc
Binary files /dev/null and b/doc/cvxopt/img3.gif differ
diff --git a/doc/cvxopt/img30.gif b/doc/cvxopt/img30.gif
new file mode 100644
index 0000000..e9724f7
Binary files /dev/null and b/doc/cvxopt/img30.gif differ
diff --git a/doc/cvxopt/img31.gif b/doc/cvxopt/img31.gif
new file mode 100644
index 0000000..e9031f9
Binary files /dev/null and b/doc/cvxopt/img31.gif differ
diff --git a/doc/cvxopt/img32.gif b/doc/cvxopt/img32.gif
new file mode 100644
index 0000000..8adae6b
Binary files /dev/null and b/doc/cvxopt/img32.gif differ
diff --git a/doc/cvxopt/img33.gif b/doc/cvxopt/img33.gif
new file mode 100644
index 0000000..8cce0a5
Binary files /dev/null and b/doc/cvxopt/img33.gif differ
diff --git a/doc/cvxopt/img34.gif b/doc/cvxopt/img34.gif
new file mode 100644
index 0000000..8ceaecb
Binary files /dev/null and b/doc/cvxopt/img34.gif differ
diff --git a/doc/cvxopt/img35.gif b/doc/cvxopt/img35.gif
new file mode 100644
index 0000000..e4f124c
Binary files /dev/null and b/doc/cvxopt/img35.gif differ
diff --git a/doc/cvxopt/img36.gif b/doc/cvxopt/img36.gif
new file mode 100644
index 0000000..8383eb1
Binary files /dev/null and b/doc/cvxopt/img36.gif differ
diff --git a/doc/cvxopt/img37.gif b/doc/cvxopt/img37.gif
new file mode 100644
index 0000000..7e3998e
Binary files /dev/null and b/doc/cvxopt/img37.gif differ
diff --git a/doc/cvxopt/img38.gif b/doc/cvxopt/img38.gif
new file mode 100644
index 0000000..9ceac38
Binary files /dev/null and b/doc/cvxopt/img38.gif differ
diff --git a/doc/cvxopt/img39.gif b/doc/cvxopt/img39.gif
new file mode 100644
index 0000000..0b1097c
Binary files /dev/null and b/doc/cvxopt/img39.gif differ
diff --git a/doc/cvxopt/img4.gif b/doc/cvxopt/img4.gif
new file mode 100644
index 0000000..336eb93
Binary files /dev/null and b/doc/cvxopt/img4.gif differ
diff --git a/doc/cvxopt/img40.gif b/doc/cvxopt/img40.gif
new file mode 100644
index 0000000..1f214d1
Binary files /dev/null and b/doc/cvxopt/img40.gif differ
diff --git a/doc/cvxopt/img41.gif b/doc/cvxopt/img41.gif
new file mode 100644
index 0000000..d7cd418
Binary files /dev/null and b/doc/cvxopt/img41.gif differ
diff --git a/doc/cvxopt/img42.gif b/doc/cvxopt/img42.gif
new file mode 100644
index 0000000..2ef863d
Binary files /dev/null and b/doc/cvxopt/img42.gif differ
diff --git a/doc/cvxopt/img43.gif b/doc/cvxopt/img43.gif
new file mode 100644
index 0000000..c151b85
Binary files /dev/null and b/doc/cvxopt/img43.gif differ
diff --git a/doc/cvxopt/img44.gif b/doc/cvxopt/img44.gif
new file mode 100644
index 0000000..a06fbb3
Binary files /dev/null and b/doc/cvxopt/img44.gif differ
diff --git a/doc/cvxopt/img45.gif b/doc/cvxopt/img45.gif
new file mode 100644
index 0000000..104f95d
Binary files /dev/null and b/doc/cvxopt/img45.gif differ
diff --git a/doc/cvxopt/img46.gif b/doc/cvxopt/img46.gif
new file mode 100644
index 0000000..8f2f340
Binary files /dev/null and b/doc/cvxopt/img46.gif differ
diff --git a/doc/cvxopt/img47.gif b/doc/cvxopt/img47.gif
new file mode 100644
index 0000000..64562fb
Binary files /dev/null and b/doc/cvxopt/img47.gif differ
diff --git a/doc/cvxopt/img48.gif b/doc/cvxopt/img48.gif
new file mode 100644
index 0000000..ada3ec8
Binary files /dev/null and b/doc/cvxopt/img48.gif differ
diff --git a/doc/cvxopt/img49.gif b/doc/cvxopt/img49.gif
new file mode 100644
index 0000000..f4d7a24
Binary files /dev/null and b/doc/cvxopt/img49.gif differ
diff --git a/doc/cvxopt/img5.gif b/doc/cvxopt/img5.gif
new file mode 100644
index 0000000..926b471
Binary files /dev/null and b/doc/cvxopt/img5.gif differ
diff --git a/doc/cvxopt/img50.gif b/doc/cvxopt/img50.gif
new file mode 100644
index 0000000..1f214d1
Binary files /dev/null and b/doc/cvxopt/img50.gif differ
diff --git a/doc/cvxopt/img51.gif b/doc/cvxopt/img51.gif
new file mode 100644
index 0000000..d6482df
Binary files /dev/null and b/doc/cvxopt/img51.gif differ
diff --git a/doc/cvxopt/img52.gif b/doc/cvxopt/img52.gif
new file mode 100644
index 0000000..3ee43a8
Binary files /dev/null and b/doc/cvxopt/img52.gif differ
diff --git a/doc/cvxopt/img53.gif b/doc/cvxopt/img53.gif
new file mode 100644
index 0000000..5fb538e
Binary files /dev/null and b/doc/cvxopt/img53.gif differ
diff --git a/doc/cvxopt/img54.gif b/doc/cvxopt/img54.gif
new file mode 100644
index 0000000..bca9bdf
Binary files /dev/null and b/doc/cvxopt/img54.gif differ
diff --git a/doc/cvxopt/img55.gif b/doc/cvxopt/img55.gif
new file mode 100644
index 0000000..532c14b
Binary files /dev/null and b/doc/cvxopt/img55.gif differ
diff --git a/doc/cvxopt/img56.gif b/doc/cvxopt/img56.gif
new file mode 100644
index 0000000..c9b0585
Binary files /dev/null and b/doc/cvxopt/img56.gif differ
diff --git a/doc/cvxopt/img57.gif b/doc/cvxopt/img57.gif
new file mode 100644
index 0000000..0c801de
Binary files /dev/null and b/doc/cvxopt/img57.gif differ
diff --git a/doc/cvxopt/img58.gif b/doc/cvxopt/img58.gif
new file mode 100644
index 0000000..d4cf0ce
Binary files /dev/null and b/doc/cvxopt/img58.gif differ
diff --git a/doc/cvxopt/img59.gif b/doc/cvxopt/img59.gif
new file mode 100644
index 0000000..921f4d3
Binary files /dev/null and b/doc/cvxopt/img59.gif differ
diff --git a/doc/cvxopt/img6.gif b/doc/cvxopt/img6.gif
new file mode 100644
index 0000000..d7c2eba
Binary files /dev/null and b/doc/cvxopt/img6.gif differ
diff --git a/doc/cvxopt/img60.gif b/doc/cvxopt/img60.gif
new file mode 100644
index 0000000..c87e807
Binary files /dev/null and b/doc/cvxopt/img60.gif differ
diff --git a/doc/cvxopt/img61.gif b/doc/cvxopt/img61.gif
new file mode 100644
index 0000000..88725ec
Binary files /dev/null and b/doc/cvxopt/img61.gif differ
diff --git a/doc/cvxopt/img62.gif b/doc/cvxopt/img62.gif
new file mode 100644
index 0000000..f22c502
Binary files /dev/null and b/doc/cvxopt/img62.gif differ
diff --git a/doc/cvxopt/img63.gif b/doc/cvxopt/img63.gif
new file mode 100644
index 0000000..e11ed23
Binary files /dev/null and b/doc/cvxopt/img63.gif differ
diff --git a/doc/cvxopt/img64.gif b/doc/cvxopt/img64.gif
new file mode 100644
index 0000000..bd8f8e3
Binary files /dev/null and b/doc/cvxopt/img64.gif differ
diff --git a/doc/cvxopt/img65.gif b/doc/cvxopt/img65.gif
new file mode 100644
index 0000000..f25e88c
Binary files /dev/null and b/doc/cvxopt/img65.gif differ
diff --git a/doc/cvxopt/img66.gif b/doc/cvxopt/img66.gif
new file mode 100644
index 0000000..48d7696
Binary files /dev/null and b/doc/cvxopt/img66.gif differ
diff --git a/doc/cvxopt/img67.gif b/doc/cvxopt/img67.gif
new file mode 100644
index 0000000..9415389
Binary files /dev/null and b/doc/cvxopt/img67.gif differ
diff --git a/doc/cvxopt/img68.gif b/doc/cvxopt/img68.gif
new file mode 100644
index 0000000..e242bd5
Binary files /dev/null and b/doc/cvxopt/img68.gif differ
diff --git a/doc/cvxopt/img69.gif b/doc/cvxopt/img69.gif
new file mode 100644
index 0000000..cd1b5e7
Binary files /dev/null and b/doc/cvxopt/img69.gif differ
diff --git a/doc/cvxopt/img7.gif b/doc/cvxopt/img7.gif
new file mode 100644
index 0000000..419da7e
Binary files /dev/null and b/doc/cvxopt/img7.gif differ
diff --git a/doc/cvxopt/img70.gif b/doc/cvxopt/img70.gif
new file mode 100644
index 0000000..a1897df
Binary files /dev/null and b/doc/cvxopt/img70.gif differ
diff --git a/doc/cvxopt/img71.gif b/doc/cvxopt/img71.gif
new file mode 100644
index 0000000..f1c73f2
Binary files /dev/null and b/doc/cvxopt/img71.gif differ
diff --git a/doc/cvxopt/img72.gif b/doc/cvxopt/img72.gif
new file mode 100644
index 0000000..fdcb389
Binary files /dev/null and b/doc/cvxopt/img72.gif differ
diff --git a/doc/cvxopt/img73.gif b/doc/cvxopt/img73.gif
new file mode 100644
index 0000000..651d539
Binary files /dev/null and b/doc/cvxopt/img73.gif differ
diff --git a/doc/cvxopt/img74.gif b/doc/cvxopt/img74.gif
new file mode 100644
index 0000000..391ce1d
Binary files /dev/null and b/doc/cvxopt/img74.gif differ
diff --git a/doc/cvxopt/img75.gif b/doc/cvxopt/img75.gif
new file mode 100644
index 0000000..77617fe
Binary files /dev/null and b/doc/cvxopt/img75.gif differ
diff --git a/doc/cvxopt/img76.gif b/doc/cvxopt/img76.gif
new file mode 100644
index 0000000..dfb375e
Binary files /dev/null and b/doc/cvxopt/img76.gif differ
diff --git a/doc/cvxopt/img77.gif b/doc/cvxopt/img77.gif
new file mode 100644
index 0000000..8f32f43
Binary files /dev/null and b/doc/cvxopt/img77.gif differ
diff --git a/doc/cvxopt/img78.gif b/doc/cvxopt/img78.gif
new file mode 100644
index 0000000..67bab1f
Binary files /dev/null and b/doc/cvxopt/img78.gif differ
diff --git a/doc/cvxopt/img79.gif b/doc/cvxopt/img79.gif
new file mode 100644
index 0000000..a8066ae
Binary files /dev/null and b/doc/cvxopt/img79.gif differ
diff --git a/doc/cvxopt/img8.gif b/doc/cvxopt/img8.gif
new file mode 100644
index 0000000..d658ad3
Binary files /dev/null and b/doc/cvxopt/img8.gif differ
diff --git a/doc/cvxopt/img80.gif b/doc/cvxopt/img80.gif
new file mode 100644
index 0000000..4f164b9
Binary files /dev/null and b/doc/cvxopt/img80.gif differ
diff --git a/doc/cvxopt/img81.gif b/doc/cvxopt/img81.gif
new file mode 100644
index 0000000..506a57b
Binary files /dev/null and b/doc/cvxopt/img81.gif differ
diff --git a/doc/cvxopt/img82.gif b/doc/cvxopt/img82.gif
new file mode 100644
index 0000000..d76ccca
Binary files /dev/null and b/doc/cvxopt/img82.gif differ
diff --git a/doc/cvxopt/img83.gif b/doc/cvxopt/img83.gif
new file mode 100644
index 0000000..6d1f129
Binary files /dev/null and b/doc/cvxopt/img83.gif differ
diff --git a/doc/cvxopt/img84.gif b/doc/cvxopt/img84.gif
new file mode 100644
index 0000000..c030743
Binary files /dev/null and b/doc/cvxopt/img84.gif differ
diff --git a/doc/cvxopt/img85.gif b/doc/cvxopt/img85.gif
new file mode 100644
index 0000000..035ed92
Binary files /dev/null and b/doc/cvxopt/img85.gif differ
diff --git a/doc/cvxopt/img86.gif b/doc/cvxopt/img86.gif
new file mode 100644
index 0000000..33f88a8
Binary files /dev/null and b/doc/cvxopt/img86.gif differ
diff --git a/doc/cvxopt/img87.gif b/doc/cvxopt/img87.gif
new file mode 100644
index 0000000..9a372fe
Binary files /dev/null and b/doc/cvxopt/img87.gif differ
diff --git a/doc/cvxopt/img88.gif b/doc/cvxopt/img88.gif
new file mode 100644
index 0000000..440d45e
Binary files /dev/null and b/doc/cvxopt/img88.gif differ
diff --git a/doc/cvxopt/img89.gif b/doc/cvxopt/img89.gif
new file mode 100644
index 0000000..d6482df
Binary files /dev/null and b/doc/cvxopt/img89.gif differ
diff --git a/doc/cvxopt/img9.gif b/doc/cvxopt/img9.gif
new file mode 100644
index 0000000..b04d887
Binary files /dev/null and b/doc/cvxopt/img9.gif differ
diff --git a/doc/cvxopt/img90.gif b/doc/cvxopt/img90.gif
new file mode 100644
index 0000000..ad2760e
Binary files /dev/null and b/doc/cvxopt/img90.gif differ
diff --git a/doc/cvxopt/img91.gif b/doc/cvxopt/img91.gif
new file mode 100644
index 0000000..c066982
Binary files /dev/null and b/doc/cvxopt/img91.gif differ
diff --git a/doc/cvxopt/img92.gif b/doc/cvxopt/img92.gif
new file mode 100644
index 0000000..50f90b6
Binary files /dev/null and b/doc/cvxopt/img92.gif differ
diff --git a/doc/cvxopt/img93.gif b/doc/cvxopt/img93.gif
new file mode 100644
index 0000000..cc86cfc
Binary files /dev/null and b/doc/cvxopt/img93.gif differ
diff --git a/doc/cvxopt/img94.gif b/doc/cvxopt/img94.gif
new file mode 100644
index 0000000..d1b9578
Binary files /dev/null and b/doc/cvxopt/img94.gif differ
diff --git a/doc/cvxopt/img95.gif b/doc/cvxopt/img95.gif
new file mode 100644
index 0000000..5fef4b8
Binary files /dev/null and b/doc/cvxopt/img95.gif differ
diff --git a/doc/cvxopt/img96.gif b/doc/cvxopt/img96.gif
new file mode 100644
index 0000000..10d320e
Binary files /dev/null and b/doc/cvxopt/img96.gif differ
diff --git a/doc/cvxopt/img97.gif b/doc/cvxopt/img97.gif
new file mode 100644
index 0000000..ec52434
Binary files /dev/null and b/doc/cvxopt/img97.gif differ
diff --git a/doc/cvxopt/img98.gif b/doc/cvxopt/img98.gif
new file mode 100644
index 0000000..2ded839
Binary files /dev/null and b/doc/cvxopt/img98.gif differ
diff --git a/doc/cvxopt/img99.gif b/doc/cvxopt/img99.gif
new file mode 100644
index 0000000..dce022e
Binary files /dev/null and b/doc/cvxopt/img99.gif differ
diff --git a/doc/cvxopt/index.gif b/doc/cvxopt/index.gif
new file mode 100644
index 0000000..32eecfb
Binary files /dev/null and b/doc/cvxopt/index.gif differ
diff --git a/doc/cvxopt/index.html b/doc/cvxopt/index.html
new file mode 100644
index 0000000..a77b0dd
--- /dev/null
+++ b/doc/cvxopt/index.html
@@ -0,0 +1,183 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node1.html" />
+<meta name='aesop' content='information' />
+<title>CVXOPT: A Python Package for Convex Optimization</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></td>
+<td class='online-navigation'><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></td>
+<td class='online-navigation'><a rel="next" title="Copyright and License"
+  href="node1.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node1.html">Copyright and License</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<div class="titlepage">
+<div class='center'>
+<h1>CVXOPT: A Python Package for Convex Optimization</h1>
+<p><b><font size="+2">Joachim Dahl & Lieven Vandenberghe</font></b></p>
+<p><i><TT>joachim at kom.aau.dk</TT>, <TT>vandenbe at ee.ucla.edu</TT></i></p>
+<p><strong>Release 0.8.2</strong><br />
+<strong>February 6, 2007</strong></p>
+<p></p>
+</div>
+</div>
+
+<P>
+
+<p><br /></p><hr class='online-navigation' />
+<div class='online-navigation'>
+<!--Table of Child-Links-->
+<A NAME="CHILD_LINKS"></a>
+
+<UL CLASS="ChildLinks">
+<LI><A href="node1.html">Copyright and License</a>
+<LI><A href="contents.html">Contents</a>
+<LI><A href="node3.html">1. Introduction</a>
+<LI><A href="node4.html">2. Dense Matrices (<tt class="module">cvxopt.base</tt>)</a>
+<UL>
+<LI><A href="s-creating-matrices.html">2.1 Creating Matrices</a>
+<LI><A href="node6.html">2.2 Attributes and Methods</a>
+<LI><A href="s-arithmetic.html">2.3 Arithmetic Operations</a>
+<LI><A href="s-indexing.html">2.4 Indexing and Slicing</a>
+<LI><A href="s-builtinfuncs.html">2.5 Built-in Functions</a>
+<LI><A href="s-otherfuncs.html">2.6 Other Matrix Functions</a>
+<LI><A href="s-random.html">2.7 Randomly Generated Matrices</a>
+<LI><A href="s-array-interface.html">2.8 The NumPy Array Interface</a>
+<LI><A href="node13.html">2.9 Printing Options</a>
+</ul>
+<LI><A href="node14.html">3. The BLAS Interface (<tt class="module">cvxopt.blas</tt>)</a>
+<UL>
+<LI><A href="s-conventions.html">3.1 Matrix Classes</a>
+<LI><A href="s-blas1.html">3.2 Level 1 BLAS</a>
+<LI><A href="s-blas2.html">3.3 Level 2 BLAS</a>
+<LI><A href="s-blas3.html">3.4 Level 3 BLAS</a>
+</ul>
+<LI><A href="node19.html">4. The LAPACK Interface (<tt class="module">cvxopt.lapack</tt>)</a>
+<UL>
+<LI><A href="node20.html">4.1 General Linear Equations</a>
+<LI><A href="e-kkt-example.html">4.2 Positive Definite Linear Equations</a>
+<LI><A href="node22.html">4.3 Symmetric and Hermitian Linear Equations</a>
+<LI><A href="node23.html">4.4 Triangular Linear Equations</a>
+<LI><A href="node24.html">4.5 Least-Squares and Least-Norm Problems</a>
+<LI><A href="node25.html">4.6 Symmetric and Hermitian Eigenvalue Decomposition</a>
+<LI><A href="e-gevd.html">4.7 Generalized Symmetric Definite Eigenproblems</a>
+<LI><A href="node27.html">4.8 Singular Value Decomposition</a>
+<LI><A href="node28.html">4.9 Example: Analytic Centering</a>
+</ul>
+<LI><A href="c-fftw.html">5. Discrete Transforms (<tt class="module">cvxopt.fftw</tt>)</a>
+<UL>
+<LI><A href="node30.html">5.1 Discrete Fourier Transform</a>
+<LI><A href="node31.html">5.2 Discrete Cosine Transform</a>
+<LI><A href="node32.html">5.3 Discrete Sine Transform</a>
+</ul>
+<LI><A href="node33.html">6. Sparse Matrices (<tt class="module">cvxopt.base</tt>)</a>
+<UL>
+<LI><A href="s-creating-spmatrix.html">6.1 Creating Sparse Matrices</a>
+<LI><A href="e-spA-example.html">6.2 Attributes and Methods</a>
+<LI><A href="s-spmatrix-arith.html">6.3 Arithmetic Operations</a>
+<LI><A href="node37.html">6.4 Indexing and Slicing</a>
+<LI><A href="node38.html">6.5 Built-In Functions</a>
+<LI><A href="node39.html">6.6 Sparse BLAS Functions</a>
+</ul>
+<LI><A href="c-spsolvers.html">7. Sparse Linear Equation Solvers</a>
+<UL>
+<LI><A href="s-orderings.html">7.1 Matrix Orderings (<tt class="module">cvxopt.amd</tt>)</a>
+<LI><A href="s-umfpack.html">7.2 General Linear Equations (<tt class="module">cvxopt.umfpack</tt>)</a>
+<LI><A href="s-cholmod.html">7.3 Positive Definite Linear Equations (<tt class="module">cvxopt.cholmod</tt>)</a>
+<LI><A href="e-covsel.html">7.4 Example: Covariance Selection</a>
+</ul>
+<LI><A href="node45.html">8. Optimization Routines (<tt class="module">cvxopt.solvers</tt>)</a>
+<UL>
+<LI><A href="s-lpsolver.html">8.1 Linear Programming</a>
+<LI><A href="node47.html">8.2 Quadratic Programming</a>
+<LI><A href="node48.html">8.3 Geometric Programming</a>
+<LI><A href="s-sdpsolver.html">8.4 Semidefinite Programming</a>
+<LI><A href="e-nlcp.html">8.5 Nonlinear Convex Programming</a>
+<LI><A href="node51.html">8.6 Exploiting Structure in LPs and SDPs</a>
+<LI><A href="node52.html">8.7 Exploiting Structure in Nonlinear Convex Programs</a>
+<LI><A href="s-external.html">8.8 Optional Solvers</a>
+<LI><A href="s-parameters.html">8.9 Algorithm Parameters</a>
+</ul>
+<LI><A href="node55.html">9. Modeling (<tt class="module">cvxopt.modeling</tt>)</a>
+<UL>
+<LI><A href="s-variables.html">9.1 Variables</a>
+<LI><A href="s-functions.html">9.2 Functions</a>
+<LI><A href="node58.html">9.3 Constraints</a>
+<LI><A href="s-lp.html">9.4 Optimization Problems</a>
+<LI><A href="node60.html">9.5 Examples</a>
+</ul>
+<LI><A href="node61.html">10. C API</a>
+<UL>
+<LI><A href="node62.html">10.1 Dense Matrices</a>
+<LI><A href="node63.html">10.2 Sparse Matrices</a>
+</ul>
+<LI><A href="genindex.html">Index</a>
+<LI><A href="about.html">About this document ...</a>
+</ul>
+<!--End of Table of Child-Links-->
+</div>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></td>
+<td class='online-navigation'><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></td>
+<td class='online-navigation'><a rel="next" title="Copyright and License"
+  href="node1.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node1.html">Copyright and License</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/modules.gif b/doc/cvxopt/modules.gif
new file mode 100644
index 0000000..f5860b6
Binary files /dev/null and b/doc/cvxopt/modules.gif differ
diff --git a/doc/cvxopt/next.gif b/doc/cvxopt/next.gif
new file mode 100644
index 0000000..5dcaff8
Binary files /dev/null and b/doc/cvxopt/next.gif differ
diff --git a/doc/cvxopt/node1.html b/doc/cvxopt/node1.html
new file mode 100644
index 0000000..a70fe3a
--- /dev/null
+++ b/doc/cvxopt/node1.html
@@ -0,0 +1,171 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="contents.html" />
+<link rel="prev" href="cvxopt.html" />
+<link rel="parent" href="cvxopt.html" />
+<link rel="next" href="contents.html" />
+<meta name='aesop' content='information' />
+<title>Copyright and License</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="Contents"
+  href="contents.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="contents.html">Contents</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION001000000000000000000">
+Copyright and License</A>
+</H1>
+Copyright ©2004-2007 J. Dahl & L. Vandenberghe. 
+
+<P>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the 
+<a class="ulink" href="http://www.gnu.org/copyleft/gpl.html"
+  >GNU General Public License</a>
+as published by 
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+<P>
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+<a class="ulink" href="http://www.gnu.org/copyleft/gpl.html"
+  >GNU General Public License</a>
+for more details.
+
+<P>
+<HR>The CVXOPT distribution includes source code for the following 
+software libraries.
+
+<UL>
+<LI>Part of the SuiteSparse suite of sparse matrix algorithms, 
+ including:
+
+<UL>
+<LI>AMD Version 2.0.  Copyright (c) 2006 by Timothy A. Davis, 
+ Patrick R. Amestoy, and Iain S. Duff.  
+</LI>
+<LI>CHOLMOD Version 1.4.  
+ Copyright (c) 2005-2006 by University of Florida, Timothy A. Davis 
+ and W. Hager.
+</LI>
+<LI>COLAMD version 2.6.  Copyright (c) 1998-2006 by Timothy A. Davis.
+</LI>
+<LI>UMFPACK Version 5.0.2. 
+ Copyright (c) 1995-2006 by Timothy A.  Davis.
+</LI>
+</UL>
+
+<P>
+These packages are licensed under the terms of the 
+<a class="ulink" href="http://www.gnu.org/copyleft/lesser.html"
+  >GNU Lesser General Public License</a> (UMFPACK, parts of CHOLMOD,
+AMD, COLAMD) and the <a class="ulink" href="http://www.gnu.org/copyleft/gpl.html"
+  >GNU General Public License</a> (parts of CHOLMOD).
+For details, consult the README files in the source directories or 
+the website listed below.
+
+<P>
+<BLOCKQUOTE>
+Availability: <a class="ulink" href="http://www.cise.ufl.edu/research/sparse"
+  >www.cise.ufl.edu/research/sparse</a>.
+
+</BLOCKQUOTE>
+
+<P>
+</LI>
+<LI>RNGS Random Number Generation -- Multiple Streams 
+(Sep. 22, 1998) by Steve Park & Dave Geyer.
+
+<P>
+<BLOCKQUOTE>
+Availability: <a class="ulink" href="http://www.cs.wm.edu/~va/software/park/park.html"
+  >www.cs.wm.edu/~va/software/park/park.html</a>.
+
+</BLOCKQUOTE>
+
+<P>
+</LI>
+</UL>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="Contents"
+  href="contents.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="contents.html">Contents</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node13.html b/doc/cvxopt/node13.html
new file mode 100644
index 0000000..d1978b0
--- /dev/null
+++ b/doc/cvxopt/node13.html
@@ -0,0 +1,123 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="prev" href="s-array-interface.html" />
+<link rel="parent" href="node4.html" />
+<link rel="next" href="node14.html" />
+<meta name='aesop' content='information' />
+<title>2.9 Printing Options</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.8 The NumPy Array"
+  href="s-array-interface.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="3. The BLAS Interface"
+  href="node14.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-array-interface.html">2.8 The NumPy Array</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node14.html">3. The BLAS Interface</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION004900000000000000000">
+2.9 Printing Options</A>
+</H1>
+The format used for printing dense matrices (and the sparse matrices 
+discussed in chapter <A HREF="node33.html#chap:spmatrix">6</A>) is controlled
+by the dictionary <tt class="member">cvxopt.base.print_options</tt>.  The dictionary 
+has three keys, <code>'iformat'</code>, <code>'dformat'</code>, <code>'zformat'</code> 
+that control, respectively, how integer, double and complex numbers are 
+printed.  The fields are C printf format strings with default 
+values <code>'5.4e'</code> for <code>'d'</code> and <code>'z'</code> matrices and <code>'5i'</code> for 
+<code>'i'</code> matrices.
+<div class="verbatim"><pre>
+>>> from cvxopt.base import matrix, print_options
+>>> print_options
+{'zformat': '5.4e', 'iformat': '5i', 'dformat': '5.4e'}
+>>> A = matrix([1., 2., 3.])
+>>> print A
+   1.0000e+00
+   2.0000e+00
+   3.0000e+00
+>>> print_options['dformat'] = 'f'
+>>> print A
+   1.000000
+   2.000000
+   3.000000
+>>> print_options['dformat'] = '5.2e'
+>>> print A
+   1.00e+00
+   2.00e+00
+   3.00e+00
+</pre></div>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.8 The NumPy Array"
+  href="s-array-interface.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="3. The BLAS Interface"
+  href="node14.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-array-interface.html">2.8 The NumPy Array</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node14.html">3. The BLAS Interface</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node14.html b/doc/cvxopt/node14.html
new file mode 100644
index 0000000..9f5bbe9
--- /dev/null
+++ b/doc/cvxopt/node14.html
@@ -0,0 +1,155 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node19.html" />
+<link rel="prev" href="node4.html" />
+<link rel="parent" href="cvxopt.html" />
+<link rel="next" href="s-conventions.html" />
+<meta name='aesop' content='information' />
+<title>3. The BLAS Interface (cvxopt.blas)</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.9 Printing Options"
+  href="node13.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="3.1 Matrix Classes"
+  href="s-conventions.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node13.html">2.9 Printing Options</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-conventions.html">3.1 Matrix Classes</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION005000000000000000000"></A><A NAME="chap:blas"></A>
+<BR>
+3. The BLAS Interface (<tt class="module">cvxopt.blas</tt>)
+</H1> 
+The <tt class="module">cvxopt.blas</tt> module provides an interface to the 
+double-precision real and complex Basic Linear Algebra Subprograms 
+(BLAS).  The names and calling sequences of the Python functions in 
+the interface closely match the corresponding Fortran BLAS routines 
+(described in the references below) and their functionality is exactly 
+the same.  
+
+<P>
+Many of the operations performed by the BLAS routines can be 
+implemented in a more straightforward way by using the matrix 
+arithmetic of section <A href="s-arithmetic.html#s-arithmetic">2.3</A>, combined with the slicing 
+and indexing of section <A href="s-indexing.html#s-indexing">2.4</A>.
+As an example, "<tt class="samp">C = A*B</tt>" gives the same result as the BLAS
+call "<tt class="samp">gemm(A,B,C)</tt>".
+The BLAS interface offers two advantages.  First, some of the 
+functions it includes are not easily implemented using the basic 
+matrix arithmetic.  For example, BLAS includes functions that 
+efficiently exploit symmetry or triangular matrix structure.
+Second, there is a performance difference that can be significant for 
+large matrices.   Although our implementation of the basic matrix 
+arithmetic makes internal calls to BLAS, it also often requires 
+creating temporary matrices to store intermediate results.  
+The BLAS functions on the other hand always operate directly
+on their matrix arguments and never require any copying to temporary 
+matrices.  Thus they can be viewed as generalizations of the in-place 
+matrix addition and scalar multiplication of 
+section <A href="s-arithmetic.html#s-arithmetic">2.3</A> to more complicated operations.
+
+<P>
+<div class="seealso">
+  <p class="heading">See Also:</p>
+
+<div class="seetext"><p>C. L. Lawson, R. J. Hanson, D. R. Kincaid, F. T. Krogh, 
+Basic Linear Algebra Subprograms for Fortran Use,
+ACM Transactions on Mathematical Software, 5(3), 309-323, 1975.</p></div>
+<div class="seetext"><p>J. J. Dongarra, J. Du Croz, S. Hammarling, R. J. Hanson,
+An Extended Set of Fortran Basic Linear Algebra Subprograms,
+ACM Transactions on Mathematical Software, 14(1), 1-17, 1988.</p></div>
+<div class="seetext"><p>J. J. Dongarra, J. Du Croz, S. Hammarling, I. Duff,
+A Set of Level 3 Basic Linear Algebra Subprograms,
+ACM Transactions on Mathematical Software, 16(1), 1-17, 1990.</p></div>
+</div>
+
+<P>
+
+<p><br /></p><hr class='online-navigation' />
+<div class='online-navigation'>
+<!--Table of Child-Links-->
+<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></a>
+
+<UL CLASS="ChildLinks">
+<LI><A href="s-conventions.html">3.1 Matrix Classes</a>
+<LI><A href="s-blas1.html">3.2 Level 1 BLAS</a>
+<LI><A href="s-blas2.html">3.3 Level 2 BLAS</a>
+<LI><A href="s-blas3.html">3.4 Level 3 BLAS</a>
+</ul>
+<!--End of Table of Child-Links-->
+</div>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.9 Printing Options"
+  href="node13.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="3.1 Matrix Classes"
+  href="s-conventions.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node13.html">2.9 Printing Options</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-conventions.html">3.1 Matrix Classes</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node19.html b/doc/cvxopt/node19.html
new file mode 100644
index 0000000..0bf402f
--- /dev/null
+++ b/doc/cvxopt/node19.html
@@ -0,0 +1,154 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="c-fftw.html" />
+<link rel="prev" href="node14.html" />
+<link rel="parent" href="cvxopt.html" />
+<link rel="next" href="node20.html" />
+<meta name='aesop' content='information' />
+<title>4. The LAPACK Interface (cvxopt.lapack)</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="3.4 Level 3 BLAS"
+  href="s-blas3.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.1 General Linear Equations"
+  href="node20.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-blas3.html">3.4 Level 3 BLAS</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node20.html">4.1 General Linear Equations</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION006000000000000000000"></A>
+<A NAME="chap:lapack"></A>
+<BR>
+4. The LAPACK Interface (<tt class="module">cvxopt.lapack</tt>)
+</H1>
+
+<P>
+The module <tt class="module">cvxopt.lapack</tt> includes functions for 
+solving dense sets of linear equations, for the corresponding matrix 
+factorizations (LU, Cholesky, LDL<SPAN CLASS="MATH"><IMG
+ WIDTH="14" HEIGHT="18" ALIGN="BOTTOM" BORDER="0"
+ SRC="img40.gif"
+ ALT="$\mathrm{{}^T}$"></SPAN>),
+for solving least-squares and least-norm problems, for QR 
+factorization, for symmetric eigenvalue problems and for singular 
+value decomposition.  
+
+<P>
+In this chapter we briefly describe the Python calling sequences.
+For further details on the underlying LAPACK functions we refer to the 
+LAPACK Users' Guide and manual pages.  
+
+<P>
+The BLAS conventional storage scheme of section <A href="s-conventions.html#s-conventions">3.1</A> is 
+used. As in the previous chapter, we omit from the function definitions
+less important arguments that are useful for selecting submatrices. 
+The complete definitions are documented in the docstrings in the 
+source code.
+
+<P>
+<div class="seealso">
+  <p class="heading">See Also:</p>
+
+<dl compact="compact" class="seeurl">
+    <dt><a href='http://www.netlib.org/lapack/lug/lapack_lug.html'
+        >LAPACK 
+Users' Guide, Third Edition, SIAM, 1999.</a></dt>
+    <dd></dd>
+  </dl> 
+</div>
+
+<P>
+
+<p><br /></p><hr class='online-navigation' />
+<div class='online-navigation'>
+<!--Table of Child-Links-->
+<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></a>
+
+<UL CLASS="ChildLinks">
+<LI><A href="node20.html">4.1 General Linear Equations</a>
+<LI><A href="e-kkt-example.html">4.2 Positive Definite Linear Equations</a>
+<LI><A href="node22.html">4.3 Symmetric and Hermitian Linear Equations</a>
+<LI><A href="node23.html">4.4 Triangular Linear Equations</a>
+<LI><A href="node24.html">4.5 Least-Squares and Least-Norm Problems</a>
+<LI><A href="node25.html">4.6 Symmetric and Hermitian Eigenvalue Decomposition</a>
+<LI><A href="e-gevd.html">4.7 Generalized Symmetric Definite Eigenproblems</a>
+<LI><A href="node27.html">4.8 Singular Value Decomposition</a>
+<LI><A href="node28.html">4.9 Example: Analytic Centering</a>
+</ul>
+<!--End of Table of Child-Links-->
+</div>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="3.4 Level 3 BLAS"
+  href="s-blas3.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.1 General Linear Equations"
+  href="node20.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-blas3.html">3.4 Level 3 BLAS</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node20.html">4.1 General Linear Equations</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node20.html b/doc/cvxopt/node20.html
new file mode 100644
index 0000000..346c10a
--- /dev/null
+++ b/doc/cvxopt/node20.html
@@ -0,0 +1,539 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="e-kkt-example.html" />
+<link rel="prev" href="node19.html" />
+<link rel="parent" href="node19.html" />
+<link rel="next" href="e-kkt-example.html" />
+<meta name='aesop' content='information' />
+<title>4.1 General Linear Equations</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4. The LAPACK Interface"
+  href="node19.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.2 Positive Definite Linear"
+  href="e-kkt-example.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="e-kkt-example.html">4.2 Positive Definite Linear</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION006100000000000000000">
+4.1 General Linear Equations</A>
+</H1>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-62' xml:id='l2h-62' class="function">gesv</tt></b>(</nobr></td>
+  <td><var>A, B</var><big>[</big><var>, ipiv=None</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A X = B,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="64" HEIGHT="27" BORDER="0"
+ SRC="img41.gif"
+ ALT="\begin{displaymath}
+A X = B,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> and <I>B</I> are real or complex matrices, with <I>A</I>
+square and nonsingular.  On exit, <var>B</var> is replaced by the solution.  
+The arguments <var>A</var> and <var>B</var> must have the same type (<code>'d'</code> or
+<code>'z'</code>).  
+The optional argument <var>ipiv</var> is an integer matrix of length at 
+least <var>n</var>.  
+If <var>ipiv</var> is provided, then <tt class="function">gesv()</tt> solves the system, 
+replaces <var>A</var> with its triangular factors, and returns the 
+permutation matrix in <var>ipiv</var>.
+If <var>ipiv</var> is not specified, then <tt class="function">gesv()</tt> solves the
+system but does not return the LU factorization and does not 
+modify <var>A</var>.  
+For example,
+<div class="verbatim"><pre>
+>>> gesv(A, B)
+</pre></div>
+solves the system without modifying <var>A</var> and returns the solution 
+in <var>B</var>.
+<div class="verbatim"><pre>
+>>> gesv(A, B, ipiv)
+</pre></div>
+returns the solution in <var>B</var> and also returns the details of the 
+LU factorization in <var>A</var> and <var>ipiv</var>.
+
+<P>
+Raises an <code>ArithmeticError</code> if the matrix is singular.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-63' xml:id='l2h-63' class="function">getrf</tt></b>(</nobr></td>
+  <td><var>A, ipiv</var>)</td></tr></table></dt>
+<dd>
+LU factorization of a general, possibly rectangular, real or
+complex matrix,  
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A = PLU
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="68" HEIGHT="24" BORDER="0"
+ SRC="img42.gif"
+ ALT="\begin{displaymath}
+A = PLU
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is <var>m</var> by <var>n</var>.
+The argument <var>ipiv</var> is an integer matrix of length at least
+min{<var>m</var>, <var>n</var>}.
+On exit, the lower triangular part of <var>A</var> is replaced by <I>L</I>,
+the upper triangular part by <I>U</I>, and the permutation matrix is 
+returned in <var>ipiv</var>.
+Raises an <code>ArithmeticError</code> if the matrix is not full rank.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-64' xml:id='l2h-64' class="function">getrs</tt></b>(</nobr></td>
+  <td><var>A, ipiv, B</var><big>[</big><var>, trans='N'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves a general set of linear equations
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+AX=B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+ A^TX=B \quad (\mathrm{trans} = \mathrm{'T'}), \qquad 
+ A^HX=B \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="601" HEIGHT="28" BORDER="0"
+ SRC="img43.gif"
+ ALT="\begin{displaymath}
+AX=B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+A^TX=B ...
+...'T'}), \qquad
+A^HX=B \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+given the LU factorization computed by <tt class="function">gesv()</tt> or 
+<tt class="function">getrf()</tt>.
+On entry, <var>A</var> and <var>ipiv</var> must contain the factorization
+as computed by <tt class="function">gesv()</tt> or <tt class="function">getrf()</tt>.  
+On exit, <var>B</var> is overwritten with the solution. 
+<var>B</var> must have the same type as <var>A</var>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-65' xml:id='l2h-65' class="function">getri</tt></b>(</nobr></td>
+  <td><var>A, ipiv</var>)</td></tr></table></dt>
+<dd>
+Computes the inverse of a matrix.
+On entry, <var>A</var> and <var>ipiv</var> must contain the factorization
+as computed by <tt class="function">gesv()</tt> or <tt class="function">getrf()</tt>.  On exit, 
+<var>A</var> contains the inverse.
+</dl>
+
+<P>
+In the following example we compute
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+x = (A^{-1} + A^{-T})b
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="129" HEIGHT="28" BORDER="0"
+ SRC="img44.gif"
+ ALT="\begin{displaymath}
+x = (A^{-1} + A^{-T})b
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+for randomly generated problem data, factoring the coefficient matrix 
+once.
+<div class="verbatim"><pre>
+>>> from cvxopt.base import matrix
+>>> from cvxopt.random import normal
+>>> from cvxopt.lapack import gesv, getrs
+>>> n = 10
+>>> A = normal(n,n)
+>>> b = normal(n)
+>>> ipiv = matrix(0, (n,1))
+>>> x = +b
+>>> gesv(A, x, ipiv)               # x = A^{-1}*b 
+>>> x2 = +b
+>>> getrs(A, ipiv, x2, trans='T')  # x2 = A^{-T}*b
+>>> x += x2
+</pre></div>
+
+<P>
+Separate functions are provided for equations with band matrices.
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-66' xml:id='l2h-66' class="function">gbsv</tt></b>(</nobr></td>
+  <td><var>A, kl, B</var><big>[</big><var>, ipiv=None</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A X = B,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="64" HEIGHT="27" BORDER="0"
+ SRC="img41.gif"
+ ALT="\begin{displaymath}
+A X = B,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> and <I>B</I> are real or complex matrices, with <I>A</I>
+<I>n</I> by <I>n</I> and banded with <var>kl</var> subdiagonals.  
+The arguments <var>A</var> and <var>B</var> must have the same type (<code>'d'</code> or
+<code>'z'</code>).  
+
+<P>
+The optional argument <var>ipiv</var> is an integer matrix of length at least
+<I>n</I>.
+If <var>ipiv</var> is provided, then <var>A</var> must have 
+2<var>kl</var> + <var>ku</var> + 1 rows.  On entry the diagonals of <I>A</I> are
+stored in rows <var>kl</var> + 1 to 2<var>kl</var> + <var>ku</var> +1 of the <var>A</var>, using
+the BLAS format for general band matrices (see section <A href="s-conventions.html#s-conventions">3.1</A>).
+On exit, the factorization is returned in <var>A</var> and <var>ipiv</var>.
+
+<P>
+If <var>ipiv</var> is not provided, then <var>A</var> must have <var>kl</var> + <var>ku</var> + 
+1 rows.  On entry the diagonals of <I>A</I> are stored in the rows of 
+<var>A</var>, following the standard format for general band matrices. 
+In this case, <tt class="function">gbsv()</tt> does not modify <var>A</var> on exit and does
+not return the factorization.
+
+<P>
+On exit, <var>B</var> is replaced by the solution <I>X</I>.  
+Raises an <code>ArithmeticError</code> if the matrix is singular.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-67' xml:id='l2h-67' class="function">gbtrf</tt></b>(</nobr></td>
+  <td><var>A, m, kl, ipiv</var>)</td></tr></table></dt>
+<dd>
+LU factorization of a general <I>m</I> by <I>n</I> real or complex band 
+matrix with <var>kl</var> subdiagonals.
+The matrix is stored using the BLAS format for general band matrices
+(see section <A href="s-conventions.html#s-conventions">3.1</A>), by providing the 
+diagonals (stored as rows of a <var>ku</var> + <var>kl</var> + 1 by <I>n</I> matrix),
+the number of rows <var>m</var>, and the number of subdiagonals <var>kl</var>.
+The argument <var>ipiv</var> is an integer matrix of length at least
+min{<I>m</I>, <I>n</I>}.
+On exit, <var>A</var> and <var>ipiv</var> contain the details of the factorization.
+Raises an <code>ArithmeticError</code> if the matrix is not full rank.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-68' xml:id='l2h-68' class="function">gbtrs</tt></b>(</nobr></td>
+  <td><var>A, kl, ipiv, B</var><big>[</big><var>, trans='N'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves a set of linear equations 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+AX=B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+ A^TX=B \quad (\mathrm{trans} = \mathrm{'T'}), \qquad 
+ A^HX=B \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="601" HEIGHT="28" BORDER="0"
+ SRC="img43.gif"
+ ALT="\begin{displaymath}
+AX=B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+A^TX=B ...
+...'T'}), \qquad
+A^HX=B \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+with <I>A</I> a general band matrix with <var>kl</var> subdiagonals, given the 
+LU factorization computed by <tt class="function">gbsv()</tt> or <tt class="function">gbtrf()</tt>.
+On entry, <var>A</var> and <var>ipiv</var> must contain the factorization
+as computed by <tt class="function">gbsv()</tt> or <tt class="function">gbtrf()</tt>.  
+On exit, <var>B</var> is overwritten with the solution. 
+<var>B</var> must have the same type as <var>A</var>.
+</dl>
+
+<P>
+As an example, we solve a linear equation with
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A = \left[ \begin{array}{cccc}
+ 1 & 2 & 0 & 0 \\
+ 3 & 4 & 5 & 0 \\
+ 6 & 7 & 8 & 9 \\
+ 0 & 10 & 11 & 12 
+ \end{array}\right], \qquad  x = \left[\begin{array}{c} 1 \\1 \\1 \\1
+ \end{array}\right].
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="297" HEIGHT="83" BORDER="0"
+ SRC="img45.gif"
+ ALT="\begin{displaymath}
+A = \left[ \begin{array}{cccc}
+1 & 2 & 0 & 0 \\
+3 & 4 & ...
+...= \left[\begin{array}{c} 1 \\ 1 \\ 1 \\ 1
+\end{array}\right].
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+<div class="verbatim"><pre>
+>>> from cvxopt.base import matrix
+>>> from cvxopt.lapack import gbsv, gbtrf, gbtrs
+>>> n, kl, ku = 4, 2, 1
+>>> A = matrix([[0., 1., 3., 6.], [2., 4., 7., 10.], [5., 8., 11., 0.], [9., 12., 0., 0.]])
+>>> x = matrix(1.0, (4,1))
+>>> gbsv(A, kl, x)
+>>> print x
+   7.1429e-02
+   4.6429e-01
+  -2.1429e-01
+  -1.0714e-01
+</pre></div>
+The code below illustrates how one can reuse the factorization returned
+by <tt class="function">gbsv()</tt>. 
+<div class="verbatim"><pre>
+>>> Ac = matrix(0.0, (2*kl+ku+1,n))
+>>> Ac[kl:,:] = A
+>>> ipiv = matrix(0, (n,1))
+>>> x = matrix(1.0, (4,1))
+>>> gbsv(Ac, kl, x, ipiv)                 # solves A*x = 1
+>>> print x                 
+   7.1429e-02
+   4.6429e-01
+  -2.1429e-01
+  -1.0714e-01
+>>> x = matrix(1.0, (4,1))
+>>> gbtrs(Ac, kl, ipiv, x, trans='T')     # solve A^T*x = 1
+>>> print x
+   7.1429e-02
+   2.3810e-02
+   1.4286e-01
+  -2.3810e-02
+</pre></div>
+An alternative method uses <tt class="function">getrf()</tt> for the factorization.
+<div class="verbatim"><pre>
+>>> Ac[kl:,:] = A
+>>> gbtrf(Ac, n, kl, ipiv)                 
+>>> x = matrix(1.0, (4,1))
+>>> gbtrs(Ac, kl, ipiv, x)                # solve A^T*x = 1
+>>> print x                 
+   7.1429e-02
+   4.6429e-01
+  -2.1429e-01
+  -1.0714e-01
+>>> x = matrix(1.0, (4,1))
+>>> gbtrs(Ac, kl, ipiv, x, trans='T')     # solve A^T*x = 1
+>>> print x
+   7.1429e-02
+   2.3810e-02
+   1.4286e-01
+  -2.3810e-02
+</pre></div>
+
+<P>
+The following functions can be used for tridiagonal matrices They use a 
+simpler matrix format, that stores the diagonals in three separate 
+vectors.
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-69' xml:id='l2h-69' class="function">gtsv</tt></b>(</nobr></td>
+  <td><var>dl, d, du, B)</var>)</td></tr></table></dt>
+<dd>
+Solves
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A X = B,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="64" HEIGHT="27" BORDER="0"
+ SRC="img41.gif"
+ ALT="\begin{displaymath}
+A X = B,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is an <I>n</I> by <I>n</I> tridiagonal matrix, 
+with subdiagonal <var>dl</var> (a matrix of length <I>n</I>-1), 
+diagonal <var>d</var> (a matrix of length <I>n</I>), and superdiagonal 
+<var>du</var> (a matrix of length <I>n</I>-1).  
+The four arguments must have the same type (<code>'d'</code> or <code>'z'</code>).
+On exit <var>dl</var>, <var>d</var>, <var>du</var> are overwritten with the details of 
+the LU factorization of <I>A</I>, and <var>B</var> is overwritten with the 
+solution <I>X</I>.  
+Raises an <code>ArithmeticError</code> if the matrix is singular.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-70' xml:id='l2h-70' class="function">gttrf</tt></b>(</nobr></td>
+  <td><var>dl, d, du, du2, ipiv</var>)</td></tr></table></dt>
+<dd>
+LU factorization of an <I>n</I> by <I>n</I> tridiagonal matrix with
+subdiagonal <var>dl</var>, diagonal <var>d</var> and superdiagonal <var>du</var>.
+<var>dl</var>, <var>d</var> and <var>du</var> must have the same type.
+<var>du2</var> is a matrix of length <I>n</I>-2, and of the same type as 
+<var>dl</var>.
+<var>ipiv</var> is an <code>'i'</code> matrix of length <I>n</I>.
+On exit, the five arguments contain the details of the factorization.
+Raises an <code>ArithmeticError</code> if the matrix is singular.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-71' xml:id='l2h-71' class="function">pttrs</tt></b>(</nobr></td>
+  <td><var>dl, d, du, du2, ipiv, B</var><big>[</big><var>, trans='N'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves a set of linear equations 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+AX=B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+ A^TX=B \quad (\mathrm{trans} = \mathrm{'T'}), \qquad 
+ A^HX=B \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="601" HEIGHT="28" BORDER="0"
+ SRC="img43.gif"
+ ALT="\begin{displaymath}
+AX=B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+A^TX=B ...
+...'T'}), \qquad
+A^HX=B \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is an <I>n</I> by <I>n</I> tridiagonal matrix.
+The arguments <var>dl</var>, <var>d</var>, <var>du</var>, <var>du2</var> and <var>ipiv</var>
+contain the details of the LU factorization as returned by 
+<tt class="function">gttrf()</tt>.
+On exit, <var>B</var> is overwritten with the solution <I>X</I>. 
+<var>B</var> must have the same type as <var>dl</var>.
+</dl>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4. The LAPACK Interface"
+  href="node19.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.2 Positive Definite Linear"
+  href="e-kkt-example.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="e-kkt-example.html">4.2 Positive Definite Linear</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node22.html b/doc/cvxopt/node22.html
new file mode 100644
index 0000000..6c293d9
--- /dev/null
+++ b/doc/cvxopt/node22.html
@@ -0,0 +1,338 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node23.html" />
+<link rel="prev" href="e-kkt-example.html" />
+<link rel="parent" href="node19.html" />
+<link rel="next" href="node23.html" />
+<meta name='aesop' content='information' />
+<title>4.3 Symmetric and Hermitian Linear Equations</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.2 Positive Definite Linear"
+  href="e-kkt-example.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.4 Triangular Linear Equations"
+  href="node23.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="e-kkt-example.html">4.2 Positive Definite Linear</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node23.html">4.4 Triangular Linear Equations</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION006300000000000000000">
+4.3 Symmetric and Hermitian Linear Equations</A>
+</H1>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-82' xml:id='l2h-82' class="function">sysv</tt></b>(</nobr></td>
+  <td><var>A, B</var><big>[</big><var>, ipiv=None</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+AX=B
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="60" HEIGHT="24" BORDER="0"
+ SRC="img47.gif"
+ ALT="\begin{displaymath}
+AX=B
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is a real or complex symmetric matrix  of order <I>n</I>.
+On exit, <var>B</var> is replaced by the solution.  
+The matrices <var>A</var> and <var>B</var> must have the same type (<code>'d'</code> or 
+<code>'z'</code>).
+The optional argument <var>ipiv</var> is an integer matrix of length at 
+least equal to <I>n</I>.
+If <var>ipiv</var> is provided, <tt class="function">sysv()</tt> solves the system and 
+returns the factorization in <var>A</var> and <var>ipiv</var>.
+If <var>ipiv</var> is not specified, <tt class="function">sysv()</tt> solves the
+system but does not return the factorization and does not modify 
+<var>A</var>.
+Raises an <code>ArithmeticError</code> if the matrix is singular.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-83' xml:id='l2h-83' class="function">sytrf</tt></b>(</nobr></td>
+  <td><var>A, ipiv</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+LDL<SPAN CLASS="MATH"><IMG
+ WIDTH="14" HEIGHT="18" ALIGN="BOTTOM" BORDER="0"
+ SRC="img50.gif"
+ ALT="${}\mathrm{^T}$"></SPAN> factorization 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+PAP^T = LDL^T
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="112" HEIGHT="24" BORDER="0"
+ SRC="img52.gif"
+ ALT="\begin{displaymath}
+PAP^T = LDL^T
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+of a real or complex symmetric matrix <SPAN CLASS="MATH"><IMG
+ WIDTH="16" HEIGHT="14" ALIGN="BOTTOM" BORDER="0"
+ SRC="img53.gif"
+ ALT="$A$"></SPAN> of order <I>n</I>.
+<var>ipiv</var> is an <code>'i'</code> matrix of length at least <I>n</I>.
+On exit, <var>A</var> and <var>ipiv</var> contain the factorization.
+Raises an <code>ArithmeticError</code> if the matrix is singular.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-84' xml:id='l2h-84' class="function">sytrs</tt></b>(</nobr></td>
+  <td><var>A, ipiv, B</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A X = B
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="60" HEIGHT="24" BORDER="0"
+ SRC="img47.gif"
+ ALT="\begin{displaymath}
+AX=B
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+given the LDL<SPAN CLASS="MATH"><IMG
+ WIDTH="14" HEIGHT="18" ALIGN="BOTTOM" BORDER="0"
+ SRC="img50.gif"
+ ALT="${}\mathrm{^T}$"></SPAN> factorization computed by 
+<tt class="function">sytrf()</tt> or <tt class="function">sysv()</tt>. <var>B</var> must have the same
+type as <var>A</var>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-85' xml:id='l2h-85' class="function">sytri</tt></b>(</nobr></td>
+  <td><var>A, ipiv</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Computes the inverse of a real or complex symmetric matrix.
+On entry, <var>A</var> and <var>ipiv</var> contain the LDL<SPAN CLASS="MATH"><IMG
+ WIDTH="14" HEIGHT="18" ALIGN="BOTTOM" BORDER="0"
+ SRC="img50.gif"
+ ALT="${}\mathrm{^T}$"></SPAN> 
+factorization computed by <tt class="function">sytrf()</tt> or <tt class="function">sysv()</tt>. 
+On exit, <var>A</var> contains the inverse.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-86' xml:id='l2h-86' class="function">hesv</tt></b>(</nobr></td>
+  <td><var>A, B</var><big>[</big><var>, ipiv=<code>None</code></var><big>[</big><var>, uplo='L'</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A X = B
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="60" HEIGHT="24" BORDER="0"
+ SRC="img47.gif"
+ ALT="\begin{displaymath}
+AX=B
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is a real symmetric or complex Hermitian of order <I>n</I>.
+On exit, <var>B</var> is replaced by the solution.
+The matrices <var>A</var> and <var>B</var> must have the same type (<code>'d'</code> or 
+<code>'z'</code>).
+The optional argument <var>ipiv</var> is an integer matrix of length at 
+least <var>n</var>.  
+If <var>ipiv</var> is provided, then <tt class="function">hesv()</tt> solves the system and 
+returns the factorization in <var>A</var> and <var>ipiv</var>.
+If <var>ipiv</var> is not specified, then <tt class="function">hesv()</tt> solves the
+system but does not return the factorization and does not modify 
+<var>A</var>.
+Raises an <code>ArithmeticError</code> if the matrix is singular.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-87' xml:id='l2h-87' class="function">hetrf</tt></b>(</nobr></td>
+  <td><var>A, ipiv</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+LDL<SPAN CLASS="MATH"><IMG
+ WIDTH="14" HEIGHT="18" ALIGN="BOTTOM" BORDER="0"
+ SRC="img51.gif"
+ ALT="${}\mathrm{^H}$"></SPAN> factorization 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+PAP^T = LDL^H
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="115" HEIGHT="24" BORDER="0"
+ SRC="img54.gif"
+ ALT="\begin{displaymath}
+PAP^T = LDL^H
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+of a real symmetric or complex Hermitian matrix of order <I>n</I>.
+<var>ipiv</var> is an <code>'i'</code> matrix of length at least <var>n</var>.
+On exit, <var>A</var> and <var>ipiv</var> contain the factorization.
+Raises an <code>ArithmeticError</code> if the matrix is singular.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-88' xml:id='l2h-88' class="function">hetrs</tt></b>(</nobr></td>
+  <td><var>A, ipiv, B</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A X = B
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="60" HEIGHT="24" BORDER="0"
+ SRC="img47.gif"
+ ALT="\begin{displaymath}
+AX=B
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+given the LDL<SPAN CLASS="MATH"><IMG
+ WIDTH="14" HEIGHT="18" ALIGN="BOTTOM" BORDER="0"
+ SRC="img51.gif"
+ ALT="${}\mathrm{^H}$"></SPAN> factorization computed by 
+<tt class="function">hetrf()</tt> or <tt class="function">hesv()</tt>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-89' xml:id='l2h-89' class="function">hetri</tt></b>(</nobr></td>
+  <td><var>A, ipiv</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Computes the inverse of a real symmetric or complex Hermitian  matrix.
+On entry, <var>A</var> and <var>ipiv</var> contain the LDL<SPAN CLASS="MATH"><IMG
+ WIDTH="14" HEIGHT="18" ALIGN="BOTTOM" BORDER="0"
+ SRC="img51.gif"
+ ALT="${}\mathrm{^H}$"></SPAN> 
+factorization computed by <tt class="function">hetrf()</tt> or <tt class="function">hesv()</tt>. 
+On exit, <var>A</var> contains the inverse.
+</dl>
+
+<P>
+As an example we solve the KKT system (<A href="e-kkt-example.html#e-kkt-example">4.1</A>).
+<div class="verbatim"><pre>
+>>> from cvxopt.lapack import sysv
+>>> K = matrix(0.0, (m+n,m+n))
+>>> K[: (m+n)*m : m+n+1] = -d**2
+>>> K[:m, m:] = A
+>>> x = matrix(0.0, (m+n,1))
+>>> x[:m], x[m:] = b1, b2
+>>> sysv(K, x, uplo='U')
+</pre></div>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.2 Positive Definite Linear"
+  href="e-kkt-example.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.4 Triangular Linear Equations"
+  href="node23.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="e-kkt-example.html">4.2 Positive Definite Linear</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node23.html">4.4 Triangular Linear Equations</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node23.html b/doc/cvxopt/node23.html
new file mode 100644
index 0000000..8a0d840
--- /dev/null
+++ b/doc/cvxopt/node23.html
@@ -0,0 +1,182 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node24.html" />
+<link rel="prev" href="node22.html" />
+<link rel="parent" href="node19.html" />
+<link rel="next" href="node24.html" />
+<meta name='aesop' content='information' />
+<title>4.4 Triangular Linear Equations</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.3 Symmetric and Hermitian"
+  href="node22.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.5 Least-Squares and Least-Norm"
+  href="node24.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node22.html">4.3 Symmetric and Hermitian</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node24.html">4.5 Least-Squares and Least-Norm</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION006400000000000000000">
+4.4 Triangular Linear Equations</A>
+</H1>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-90' xml:id='l2h-90' class="function">trtrs</tt></b>(</nobr></td>
+  <td><var>A, B</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+trans='N'</var><big>[</big><var>, diag='N'</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves a triangular set of equations
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+AX=B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+ A^TX=B \quad (\mathrm{trans} = \mathrm{'T'}), \qquad 
+ A^HX=B \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="601" HEIGHT="28" BORDER="0"
+ SRC="img43.gif"
+ ALT="\begin{displaymath}
+AX=B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+A^TX=B ...
+...'T'}), \qquad
+A^HX=B \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is real or complex and triangular of order <I>n</I>, 
+and <var>B</var> is a matrix with <I>n</I> rows.
+<var>A</var> and <var>B</var> are matrices with the same type (<code>'d'</code> or <code>'z'</code>).
+<tt class="function">trtrs()</tt> is similar to <tt class="function">blas.trsm()</tt>, except
+that it raises an <code>ArithmeticError</code> if a diagonal element of 
+<var>A</var> is zero (whereas <tt class="function">blas.trsm()</tt> returns <code>inf</code>
+values).
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-91' xml:id='l2h-91' class="function">trtri</tt></b>(</nobr></td>
+  <td><var>A</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, diag='N'</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Computes the inverse of a real or complex triangular matrix <I>A</I>.  
+On exit, <var>A</var> contains the inverse.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-92' xml:id='l2h-92' class="function">tbtrs</tt></b>(</nobr></td>
+  <td><var>A, B</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+trans='T'</var><big>[</big><var>,diag='N'</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves a triangular set of equations
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+AX=B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+ A^TX=B \quad (\mathrm{trans} = \mathrm{'T'}), \qquad 
+ A^HX=B \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="601" HEIGHT="28" BORDER="0"
+ SRC="img43.gif"
+ ALT="\begin{displaymath}
+AX=B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+A^TX=B ...
+...'T'}), \qquad
+A^HX=B \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is real or complex triangular band matrix of order <I>n</I>, 
+and <var>B</var> is a matrix with <I>n</I> rows.
+The diagonals of <I>A</I> are stored in <var>A</var> using the BLAS conventions 
+for triangular band matrices. 
+<var>A</var> and <var>B</var> are matrices with the same type (<code>'d'</code> or <code>'z'</code>).
+On exit, <var>B</var> is replaced by the solution <I>X</I>.
+</dl>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.3 Symmetric and Hermitian"
+  href="node22.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.5 Least-Squares and Least-Norm"
+  href="node24.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node22.html">4.3 Symmetric and Hermitian</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node24.html">4.5 Least-Squares and Least-Norm</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node24.html b/doc/cvxopt/node24.html
new file mode 100644
index 0000000..912244e
--- /dev/null
+++ b/doc/cvxopt/node24.html
@@ -0,0 +1,402 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node25.html" />
+<link rel="prev" href="node23.html" />
+<link rel="parent" href="node19.html" />
+<link rel="next" href="node25.html" />
+<meta name='aesop' content='information' />
+<title>4.5 Least-Squares and Least-Norm Problems</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.4 Triangular Linear Equations"
+  href="node23.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.6 Symmetric and Hermitian"
+  href="node25.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node23.html">4.4 Triangular Linear Equations</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node25.html">4.6 Symmetric and Hermitian</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION006500000000000000000">
+4.5 Least-Squares and Least-Norm Problems</A>
+</H1>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-93' xml:id='l2h-93' class="function">gels</tt></b>(</nobr></td>
+  <td><var>A, B</var><big>[</big><var>, trans='N'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves least-squares and least-norm problems with a full rank 
+<I>m</I> by <I>n</I> matrix <I>A</I>.
+
+<P>
+
+<OL>
+<LI><var>trans</var> is <code>'N'</code>.  If <I>m</I> is greater than or equal
+to <I>n</I>, <tt class="function">gels()</tt> solves the least-squares problem
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll} 
+ \mbox{minimize} & \|AX-B\|_F.
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="165" HEIGHT="30" BORDER="0"
+ SRC="img55.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & \Vert AX-B\Vert _F.
+\end{array}
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+If <I>m</I> is less than or equal to <I>n</I>, <tt class="function">gels()</tt> solves 
+the least-norm problem
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll} 
+ \mbox{minimize} & \|X\|_F \\
+ \mbox{subject to} & AX = B.
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="141" HEIGHT="45" BORDER="0"
+ SRC="img56.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & \Vert X\Vert _F \\
+\mbox{subject to} & AX = B.
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+</LI>
+<LI><var>trans</var> is <code>'T'</code> or <code>'C'</code> and <var>A</var> and <var>B</var>
+are real.  If <I>m</I> is greater than or equal to <I>n</I>,
+<tt class="function">gels()</tt> solves the least-norm problem
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll} 
+ \mbox{minimize} & \|X\|_F \\
+ \mbox{subject to} & A^TX=B.
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="151" HEIGHT="45" BORDER="0"
+ SRC="img57.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & \Vert X\Vert _F \\
+\mbox{subject to} & A^TX=B.
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+If <I>m</I> is less than or equal to <I>n</I>, <tt class="function">gels()</tt> solves 
+the least-squares problem
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll} 
+ \mbox{minimize} & \|A^TX-B\|_F.
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="175" HEIGHT="30" BORDER="0"
+ SRC="img58.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & \Vert A^TX-B\Vert _F.
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+</LI>
+<LI><var>trans</var> is <code>'C'</code> and <var>A</var> and <var>B</var>
+are complex. If <I>m</I> is greater than or equal to <I>n</I>, 
+<tt class="function">gels()</tt> solves the least-norm problem
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll} 
+ \mbox{minimize} & \|X\|_F \\
+ \mbox{subject to} & A^HX=B.
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="153" HEIGHT="45" BORDER="0"
+ SRC="img59.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & \Vert X\Vert _F \\
+\mbox{subject to} & A^HX=B.
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+If <I>m</I> is less than or equal to <I>n</I>, <tt class="function">gels()</tt> solves 
+the least-squares problem
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll} 
+ \mbox{minimize} & \|A^HX-B\|_F.
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="177" HEIGHT="30" BORDER="0"
+ SRC="img60.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & \Vert A^HX-B\Vert _F.
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+</LI>
+</OL>
+<var>A</var> and <var>B</var> must have the same typecode (<code>'d'</code> or <code>'z'</code>).
+<var>trans</var> = <code>'T'</code> is not allowed if <var>A</var> is complex.
+On exit, the solution <I>X</I> is stored as the leading submatrix 
+of <var>B</var>.
+The array <var>A</var> is overwritten with details of the QR or the LQ 
+factorization of <I>A</I>.
+Note that <tt class="function">gels()</tt> does not check whether <SPAN CLASS="MATH"><IMG
+ WIDTH="16" HEIGHT="14" ALIGN="BOTTOM" BORDER="0"
+ SRC="img53.gif"
+ ALT="$A$"></SPAN> is full rank.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-94' xml:id='l2h-94' class="function">geqrf</tt></b>(</nobr></td>
+  <td><var>A, tau</var>)</td></tr></table></dt>
+<dd>
+QR factorization of a real or complex matrix <var>A</var>:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A = Q R.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="61" HEIGHT="27" BORDER="0"
+ SRC="img61.gif"
+ ALT="\begin{displaymath}
+A = Q R.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+If <var>A</var> is <I>m</I> by <I>n</I>, then <I>Q</I> is <I>m</I> by <I>m</I> 
+and orthogonal/unitary, and <var>R</var> is <I>m</I> by <I>n</I>
+and upper triangular (if <var>m</var> is greater than or equal to <var>n</var>), 
+or upper trapezoidal (if <var>m</var> is less than or equal to <var>n</var>).  
+<var>tau</var>  is a matrix of the same type as <var>A</var> and of length at 
+least min{<var>m</var>, <var>n</var>}.
+On exit, <I>R</I> is stored in the upper triangular part of <var>A</var>.
+The matrix <I>Q</I> is stored as a product of min{<var>m</var>, <var>n</var>}
+elementary reflectors in the first min{<var>m</var>, <var>n</var>} columns 
+of <var>A</var> and in <var>tau</var>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-95' xml:id='l2h-95' class="function">ormqr</tt></b>(</nobr></td>
+  <td><var>A, tau, C</var><big>[</big><var>, side='L'</var><big>[</big><var>, 
+trans='N'</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Product with a real orthogonal matrix:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+C := \mathop{\mathrm{op}}(Q)C \quad (\mathrm{side} = \mathrm{'L'}), \qquad 
+ C := C\mathop{\mathrm{op}}(Q) \quad (\mathrm{side} = \mathrm{'R'}), \qquad 
+ \mathop{\mathrm{op}}(Q) =  \left\{ \begin{array}{ll}
+ Q & \mathrm{trans} = \mathrm{'N'} \\
+ Q^T & \mathrm{trans} = \mathrm{'T'},
+\end{array}\right.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="658" HEIGHT="45" BORDER="0"
+ SRC="img62.gif"
+ ALT="\begin{displaymath}
+C := \mathop{\mathrm{op}}(Q)C \quad (\mathrm{side} = \mathr...
+...} \\
+Q^T & \mathrm{trans} = \mathrm{'T'},
+\end{array}\right.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>Q</I> is square and orthogonal.  
+<I>Q</I> is stored in <var>A</var> and <var>tau</var> as a product 
+of min{<var>A</var>.<tt class="member">size</tt>[0], <var>A</var>.<tt class="member">size</tt>[1]} 
+elementary reflectors, as computed by <tt class="function">geqrf()</tt>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-96' xml:id='l2h-96' class="function">unmqr</tt></b>(</nobr></td>
+  <td><var>A, tau, C</var><big>[</big><var>, side='L'</var><big>[</big><var>, 
+trans='N'</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Product with a real orthogonal or complex unitary matrix:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+C := \mathop{\mathrm{op}}(Q)C \quad (\mathrm{side} = \mathrm{'L'}), \qquad 
+ C := C\mathop{\mathrm{op}}(Q) \quad (\mathrm{side} = \mathrm{'R'}), \qquad 
+ \mathop{\mathrm{op}}(Q) =  \left\{ \begin{array}{ll}
+ Q & \mathrm{trans} = \mathrm{'N'} \\
+ Q^T & \mathrm{trans} = \mathrm{'T'} \\
+ Q^H & \mathrm{trans} = \mathrm{'C'},
+\end{array}\right.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="662" HEIGHT="64" BORDER="0"
+ SRC="img63.gif"
+ ALT="\begin{displaymath}
+C := \mathop{\mathrm{op}}(Q)C \quad (\mathrm{side} = \mathr...
+...} \\
+Q^H & \mathrm{trans} = \mathrm{'C'},
+\end{array}\right.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+<I>Q</I> is square and orthogonal or unitary.  
+<I>Q</I> is stored in <var>A</var> and <var>tau</var> as a product of 
+min{<var>A</var>.<tt class="member">size</tt>[0], <var>A</var>.<tt class="member">size</tt>[1]} 
+elementary reflectors, as computed by <tt class="function">geqrf()</tt>.
+The arrays <var>A</var>, <var>tau</var> and <var>C</var> must have the same type.
+<code><var>trans</var> = 'T'</code> is only allowed if the typecode is <code>'d'</code>.
+</dl>
+
+<P>
+In the following example, we solve a least-squares problem 
+by a direct call to <tt class="function">gels()</tt>, and by separate calls to 
+<tt class="function">geqrf()</tt>, <tt class="function">ormqr()</tt>, and <tt class="function">trtrs()</tt>.
+<div class="verbatim"><pre>
+>>> from cvxopt import random, blas, lapack
+>>> from cvxopt.base import matrix
+>>> m, n = 10, 5
+>>> A, b = random.normal(m,n), random.normal(m,1)
+>>> x1 = +b
+>>> lapack.gels(+A, x1)                  # x1[:n] minimizes ||A*x1[:n] - b||_2
+>>> tau = matrix(0.0, (n,1)) 
+>>> lapack.geqrf(A, tau)                 # A = [Q1, Q2] * [R1; 0]
+>>> x2 = +b
+>>> lapack.ormqr(A, tau, x2, trans='T')  # x2 := [Q1, Q2]' * b
+>>> lapack.trtrs(A[:n,:], x2, uplo='U')  # x2[:n] := R1^{-1}*x2[:n]
+>>> blas.nrm2(x1[:n] - x2[:n])
+3.0050798580569307e-16
+</pre></div>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.4 Triangular Linear Equations"
+  href="node23.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.6 Symmetric and Hermitian"
+  href="node25.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node23.html">4.4 Triangular Linear Equations</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node25.html">4.6 Symmetric and Hermitian</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node25.html b/doc/cvxopt/node25.html
new file mode 100644
index 0000000..ccfc5d4
--- /dev/null
+++ b/doc/cvxopt/node25.html
@@ -0,0 +1,257 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="e-gevd.html" />
+<link rel="prev" href="node24.html" />
+<link rel="parent" href="node19.html" />
+<link rel="next" href="e-gevd.html" />
+<meta name='aesop' content='information' />
+<title>4.6 Symmetric and Hermitian Eigenvalue Decomposition</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.5 Least-Squares and Least-Norm"
+  href="node24.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.7 Generalized Symmetric Definite"
+  href="e-gevd.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node24.html">4.5 Least-Squares and Least-Norm</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="e-gevd.html">4.7 Generalized Symmetric Definite</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION006600000000000000000">
+4.6 Symmetric and Hermitian Eigenvalue Decomposition</A>
+</H1>
+The first four routines compute all or selected  eigenvalues and 
+eigenvectors of a real symmetric matrix <SPAN CLASS="MATH"><IMG
+ WIDTH="16" HEIGHT="14" ALIGN="BOTTOM" BORDER="0"
+ SRC="img53.gif"
+ ALT="$A$"></SPAN>:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A = V\mbox{\bf diag}\,(\lambda)V^T,\qquad  V^TV = I.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="229" HEIGHT="28" BORDER="0"
+ SRC="img64.gif"
+ ALT="\begin{displaymath}
+A = V\mbox{\bf diag}\,(\lambda)V^T,\qquad V^TV = I.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-97' xml:id='l2h-97' class="function">syev</tt></b>(</nobr></td>
+  <td><var>A, W</var><big>[</big><var>, jobz='N'</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Eigenvalue decomposition of a real symmetric matrix of order <I>n</I>.
+<var>W</var> is a real matrix of length at least <I>n</I>.
+On exit, <var>W</var> contains the eigenvalues in ascending order.
+If <var>jobz</var> is <code>'V'</code>, the eigenvectors are also computed
+and returned in <var>A</var>.
+If <var>jobz</var> is <code>'N'</code>, the eigenvectors are not returned and the 
+contents of <var>A</var> are destroyed.
+Raises an <code>ArithmeticError</code> if the eigenvalue decomposition fails.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-98' xml:id='l2h-98' class="function">syevd</tt></b>(</nobr></td>
+  <td><var>A, W</var><big>[</big><var>, jobz='N'</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+This is an alternative to <tt class="function">syev()</tt>, based on a different
+algorithm.  It is faster on large problems, but also uses more memory.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-99' xml:id='l2h-99' class="function">syevx</tt></b>(</nobr></td>
+  <td><var>A, W</var><big>[</big><var>, jobz='N'</var><big>[</big><var>, 
+range='A'</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, vl=0.0, vu=0.0</var><big>[</big><var>, 
+il=1, iu=1</var><big>[</big><var>, Z=<code>None</code></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Computes selected eigenvalues and eigenvectors of a real symmetric 
+matrix <var>A</var> of order <I>n</I>.
+
+<P>
+<var>W</var> is a real matrix of length at least <var>n</var>.
+On exit, <var>W</var> contains the eigenvalues in ascending order.
+If <var>range</var> is <code>'A'</code>, all the eigenvalues are computed.
+If <var>range</var> is <code>'I'</code>, eigenvalues <var>il</var> through <var>iu</var>
+are computed, where <var>1</var> <code><=</code> <var>il</var> <code><=</code> <var>iu</var> 
+<code><=</code> <var>n</var>. 
+If <var>range</var> is <code>'V'</code>, the eigenvalues in the interval 
+<code>(<var>vl</var>,<var>vu</var>]</code> are computed. 
+
+<P>
+If <var>jobz</var> is <code>'V'</code>, the (normalized) eigenvectors are 
+computed, and returned in <var>Z</var>.  If <var>jobz</var> is <code>'N'</code>, the 
+eigenvectors are not computed.  In both cases, the contents of <var>A</var> 
+are destroyed on exit.
+<var>Z</var> is optional (and not referenced) if <var>jobz</var> is <code>'N'</code>.
+It is required if <var>jobz</var> is <code>'V'</code> and must have at least
+<var>n</var> columns if <var>range</var> is <code>'A'</code> or <code>'V'</code> and  at
+least <code><var>iu</var>-<var>il</var>+1</code> columns if <var>range</var> is <code>'I'</code>.
+
+<P>
+<tt class="function">syevx()</tt> returns the number of computed eigenvalues.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-100' xml:id='l2h-100' class="function">syevr</tt></b>(</nobr></td>
+  <td><var>A, W</var><big>[</big><var>, jobz='N'</var><big>[</big><var>, 
+range='A'</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, vl=0.0, vu=0.0</var><big>[</big><var>, 
+il=1, iu=n</var><big>[</big><var>, Z=<code>None</code></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+This is an alternative to <tt class="function">syevx()</tt>. 
+<tt class="function">syevr()</tt> is the most recent LAPACK routine for symmetric 
+eigenvalue problems, and expected to supersede the three other 
+routines in future releases.
+</dl>
+
+<P>
+The next four routines can be used to compute eigenvalues and 
+eigenvectors for complex Hermitian matrices:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A = V\mbox{\bf diag}\,(\lambda)V^H,\qquad  V^HV = I.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="233" HEIGHT="28" BORDER="0"
+ SRC="img65.gif"
+ ALT="\begin{displaymath}
+A = V\mbox{\bf diag}\,(\lambda)V^H,\qquad V^HV = I.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+For real symmetric matrices they are identical to the corresponding
+<tt class="function">syev_()</tt> routines.
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-101' xml:id='l2h-101' class="function">heev</tt></b>(</nobr></td>
+  <td><var>A, W</var><big>[</big><var>, jobz='N'</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Eigenvalue decomposition of a real symmetric or complex Hermitian
+matrix of order <I>n</I>.
+The calling sequence is identical to <tt class="function">syev()</tt>, except that 
+<var>A</var> can be real or complex.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-102' xml:id='l2h-102' class="function">heevd</tt></b>(</nobr></td>
+  <td><var>A, W</var><big>[</big><var>, jobz='N'</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+This is an alternative to <tt class="function">heev()</tt>. 
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-103' xml:id='l2h-103' class="function">heevx</tt></b>(</nobr></td>
+  <td><var>A, W</var><big>[</big><var>, jobz='N'</var><big>[</big><var>, 
+range='A'</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, vl=0.0, vu=0.0 </var><big>[</big><var>, 
+il=1, iu=n</var><big>[</big><var>, Z=<code>None</code></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Computes selected eigenvalues and eigenvectors of a real symmetric 
+or complex Hermitian matrix of order <I>n</I>.
+The calling sequence is identical to <tt class="function">syevx()</tt>,
+except that <var>A</var> can be real or complex.
+<var>Z</var> must have the same type as <var>A</var>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-104' xml:id='l2h-104' class="function">heevr</tt></b>(</nobr></td>
+  <td><var>A, W</var><big>[</big><var>, jobz='N'</var><big>[</big><var>, 
+range='A'</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, vl=0.0, vu=0.0</var><big>[</big><var>, 
+il=1, iu=n</var><big>[</big><var>, Z=<code>None</code></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+This is an alternative to <tt class="function">heevx()</tt>. 
+</dl>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.5 Least-Squares and Least-Norm"
+  href="node24.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.7 Generalized Symmetric Definite"
+  href="e-gevd.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node24.html">4.5 Least-Squares and Least-Norm</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="e-gevd.html">4.7 Generalized Symmetric Definite</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node27.html b/doc/cvxopt/node27.html
new file mode 100644
index 0000000..7310e3d
--- /dev/null
+++ b/doc/cvxopt/node27.html
@@ -0,0 +1,217 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node28.html" />
+<link rel="prev" href="e-gevd.html" />
+<link rel="parent" href="node19.html" />
+<link rel="next" href="node28.html" />
+<meta name='aesop' content='information' />
+<title>4.8 Singular Value Decomposition</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.7 Generalized Symmetric Definite"
+  href="e-gevd.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.9 Example: Analytic Centering"
+  href="node28.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="e-gevd.html">4.7 Generalized Symmetric Definite</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node28.html">4.9 Example: Analytic Centering</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION006800000000000000000">
+4.8 Singular Value Decomposition</A>
+</H1>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-107' xml:id='l2h-107' class="function">gesvd</tt></b>(</nobr></td>
+  <td><var>A, S</var><big>[</big><var>, jobu='N'</var><big>[</big><var>, 
+jobvt='N'</var><big>[</big><var>, U=<code>None</code></var><big>[</big><var>, Vt=<code>None</code></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Singular value decomposition 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A = U \Sigma V^T, \qquad A = U \Sigma V^H
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="200" HEIGHT="27" BORDER="0"
+ SRC="img69.gif"
+ ALT="\begin{displaymath}
+A = U \Sigma V^T, \qquad A = U \Sigma V^H
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+of a real or complex <I>m</I> by <I>n</I> matrix <var>A</var>.
+
+<P>
+<var>S</var> is a real matrix of length at least min{<I>m</I>, <I>n</I>}.
+On exit, its first  min{<I>m</I>, <I>n</I>} elements are the 
+singular values in descending order.
+
+<P>
+The argument <var>jobu</var> controls how many left singular vectors are
+computed.  The possible values are <code>'N'</code>, <code>'A'</code>, <code>'S'</code> 
+and <code>'O'</code>. 
+If <var>jobu</var> is <code>'N'</code>, no left singular vectors are 
+computed.
+If <var>jobu</var> is <code>'A'</code>, all left singular vectors are computed 
+and returned as columns of <var>U</var>.
+If <var>jobu</var> is <code>'S'</code>, the first min{<I>m</I>,<I>n</I>} left 
+singular vectors are computed and returned as columns of <var>U</var>.
+If <var>jobu</var> is <code>'O'</code>, the first min{<I>m</I>,<I>n</I>} left 
+singular vectors are computed and returned as columns of <var>A</var>.
+The argument <var>U</var> is <code>None</code> (if <var>jobu</var> is <code>'N'</code>
+or <code>'A'</code>) or a matrix of the same type as <var>A</var>.
+
+<P>
+The argument <var>jobvt</var> controls how many right singular vectors are
+computed.  The possible values are <code>'N'</code>, <code>'A'</code>, <code>'S'</code> 
+and <code>'O'</code>. 
+If <var>jobvt</var> is <code>'N'</code>, no right singular vectors are 
+computed.  If <var>jobvt</var> is <code>'A'</code>, all right singular vectors 
+are computed and returned as rows of <var>Vt</var>.
+If <var>jobvt</var> is <code>'S'</code>, the first min{<I>m</I>,<I>n</I>} right 
+singular vectors are computed and their (conjugate) transposes are
+returned as rows of <var>Vt</var>.
+If <var>jobvt</var> is <code>'O'</code>, the first min{<I>m</I>, <I>n</I>} right 
+singular vectors are computed and their (conjugate) transposes 
+are returned as rows of <var>A</var>.
+Note that the (conjugate) transposes of the right singular vectors 
+(<EM>i.e.</EM>, the matrix <SPAN CLASS="MATH"><IMG
+ WIDTH="29" HEIGHT="16" ALIGN="BOTTOM" BORDER="0"
+ SRC="img70.gif"
+ ALT="$V^H$"></SPAN>) are returned in <var>Vt</var> or <var>A</var>.
+The argument <var>Vt</var> can be <code>None</code> (if <var>jobvt</var> is <code>'N'</code>
+or <code>'A'</code>) or a matrix of the same type as <var>A</var>.
+
+<P>
+On exit, the contents of <var>A</var> are destroyed.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-108' xml:id='l2h-108' class="function">gesdd</tt></b>(</nobr></td>
+  <td><var>A, S</var><big>[</big><var>, jobz='N'</var><big>[</big><var>, 
+U=<code>None</code></var><big>[</big><var>, Vt=<code>None</code></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd> 
+Singular value decomposition of a real or complex <I>m</I> by <I>n</I> 
+matrix <var>A</var>.  This function is based on a divide-and-conquer 
+algorithm and is faster than <tt class="function">gesvd()</tt>.
+
+<P>
+<var>S</var> is a real matrix of length at least min{<I>m</I>, <I>n</I>}.
+On exit, its first min{<I>m</I>, <I>n</I>} elements are the 
+singular values in descending order.
+
+<P>
+The argument <var>jobz</var> controls how many singular vectors are
+computed.  The possible values are <code>'N'</code>, <code>'A'</code>, <code>'S'</code> 
+and <code>'O'</code>. 
+If <var>jobz</var> is <code>'N'</code>, no singular vectors are computed.
+If <var>jobz</var> is <code>'A'</code>, all <I>m</I> left singular vectors are 
+computed and returned as columns of <var>U</var> and all <I>n</I> right 
+singular vectors are computed and returned as rows of <var>Vt</var>.
+If <var>jobz</var> is <code>'S'</code>, the first min{<I>m</I>, <I>n</I>} left 
+and right singular vectors are computed and returned as columns of 
+<var>U</var> and rows of <var>Vt</var>.
+If <var>jobz</var> is <code>'O'</code> and <I>m</I> is greater than or equal
+to <I>n</I>, the first <I>n</I> left singular vectors are returned as
+columns of <var>A</var> and the <I>n</I> right singular vectors are returned
+as rows of <var>Vt</var>.  If <var>jobz</var> is <code>'O'</code> and <I>m</I> is less 
+than <I>n</I>, the <I>m</I> left singular vectors are returned as columns
+of <var>U</var> and the first <I>m</I> right singular vectors are returned 
+as rows of <var>A</var>.  
+Note that the (conjugate) transposes of the right singular vectors 
+are returned in <var>Vt</var> or <var>A</var>.
+
+<P>
+The argument <var>U</var> can be <code>None</code> (if <var>jobz</var> is <code>'N'</code>
+or <code>'A'</code> of <var>jobz</var> is <code>'O'</code> and <I>m</I> is greater than
+or equal to  <I>n</I>)  or a matrix of the same type as <var>A</var>.
+The argument <var>Vt</var> can be <code>None</code> (if <var>jobz</var> is <code>'N'</code>
+or <code>'A'</code> or <var>jobz</var> is <code>'O'</code> and <I>m</I> is less than
+<I>n</I>) or a matrix of the same type as <var>A</var>.
+
+<P>
+On exit, the contents of <var>A</var> are destroyed.
+</dl>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.7 Generalized Symmetric Definite"
+  href="e-gevd.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4.9 Example: Analytic Centering"
+  href="node28.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="e-gevd.html">4.7 Generalized Symmetric Definite</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node28.html">4.9 Example: Analytic Centering</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node28.html b/doc/cvxopt/node28.html
new file mode 100644
index 0000000..228afa8
--- /dev/null
+++ b/doc/cvxopt/node28.html
@@ -0,0 +1,197 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="prev" href="node27.html" />
+<link rel="parent" href="node19.html" />
+<link rel="next" href="c-fftw.html" />
+<meta name='aesop' content='information' />
+<title>4.9 Example: Analytic Centering</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.8 Singular Value Decomposition"
+  href="node27.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="5. Discrete Transforms (cvxopt.fftw)"
+  href="c-fftw.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node27.html">4.8 Singular Value Decomposition</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="c-fftw.html">5. Discrete Transforms (cvxopt.fftw)</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION006900000000000000000">
+4.9 Example: Analytic Centering</A>
+</H1>
+The analytic centering problem is defined as
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+  \mbox{minimize} & -\sum_{i=1}^m \log(b_i-a_i^Tx).
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="227" HEIGHT="30" BORDER="0"
+ SRC="img71.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & -\sum_{i=1}^m \log(b_i-a_i^Tx).
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+In the code below we solve the problem using Newton's method.
+At each iteration the Newton direction is computed by solving 
+a positive definite set of linear equations
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A^T \mbox{\bf diag}\,(b-Ax)^{-2} A v = -\mbox{\bf diag}\,(b-Ax)^{-1}{\bf 1}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="301" HEIGHT="28" BORDER="0"
+ SRC="img72.gif"
+ ALT="\begin{displaymath}
+A^T \mbox{\bf diag}\,(b-Ax)^{-2} A v = -\mbox{\bf diag}\,(b-Ax)^{-1}{\bf 1}
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+(where <I>A</I> has rows <SPAN CLASS="MATH"><IMG
+ WIDTH="22" HEIGHT="35" ALIGN="MIDDLE" BORDER="0"
+ SRC="img73.gif"
+ ALT="$a_i^T$"></SPAN>), and a suitable step size is determined 
+by a backtracking line search.
+
+<P>
+We use the level-3 BLAS function <tt class="function">syrk()</tt> to form the Hessian 
+matrix and the LAPACK function <tt class="function">posv()</tt> to solving the Newton
+system.   The code can be further optimized by replacing the 
+matrix-vector products with the level-2 BLAS function <tt class="function">gemv()</tt>.
+
+<P>
+<div class="verbatim"><pre>
+from cvxopt.base import matrix, log, mul, div
+from cvxopt import blas, lapack, random
+from math import sqrt
+
+def acent(A,b):
+    """  
+    Returns the analytic center of A*x <= b.
+    We assume that b > 0 and the feasible set is bounded.
+    """
+
+    MAXITERS = 100
+    ALPHA = 0.01
+    BETA = 0.5
+    TOL = 1e-8
+
+    m, n = A.size
+    x = matrix(0.0, (n,1))
+    H = matrix(0.0, (n,n))
+    g = matrix(0.0, (n,1))
+
+    for iter in xrange(MAXITERS):
+        
+        # Gradient is g = A^T * (1./(b-A*x)).
+        d = (b-A*x)**-1
+        g = A.T * d
+
+        # Hessian is H = A^T * diag(d)^2 * A.
+        Asc = mul( d[:,n*[0]], A )
+        blas.syrk(Asc, H, trans='T')
+
+        # Newton step is v = -H^-1 * g.
+        v = -g
+        lapack.posv(H, v)
+
+        # Terminate if Newton decrement is less than TOL.
+	lam = blas.dot(g, v)
+        if sqrt(-lam) < TOL: return x
+
+        # Backtracking line search.
+        y = mul(A*v, d)
+	step = 1.0
+        while 1-step*max(y) < 0: step *= BETA 
+	while True:
+            if -sum(log(1-step*y)) < ALPHA*step*lam: break
+	    step *= BETA
+        x += step*v
+</pre></div>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="4.8 Singular Value Decomposition"
+  href="node27.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="4. The LAPACK Interface"
+  href="node19.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="5. Discrete Transforms (cvxopt.fftw)"
+  href="c-fftw.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node27.html">4.8 Singular Value Decomposition</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node19.html">4. The LAPACK Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="c-fftw.html">5. Discrete Transforms (cvxopt.fftw)</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node3.html b/doc/cvxopt/node3.html
new file mode 100644
index 0000000..5b81eef
--- /dev/null
+++ b/doc/cvxopt/node3.html
@@ -0,0 +1,176 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node4.html" />
+<link rel="prev" href="contents.html" />
+<link rel="parent" href="cvxopt.html" />
+<link rel="next" href="node4.html" />
+<meta name='aesop' content='information' />
+<title>1. Introduction</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="Contents"
+  href="contents.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="contents.html">Contents</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION003000000000000000000"></A><A NAME="chap:intro"></A>
+<BR>
+1. Introduction
+</H1>
+
+<P>
+CVXOPT is a free software package for convex optimization based on
+the Python programming language.
+It can be used with the interactive Python interpreter, 
+on the command line by executing Python scripts, or integrated in 
+other software via Python extension modules.
+Its main purpose is to make the development of software for convex 
+optimization applications straightforward by building on Python's 
+extensive standard library and on the strengths of Python as a 
+high-level programming language.  
+
+<P>
+Release 0.8.2 of CVXOPT includes routines for basic linear algebra 
+calculations, 
+interfaces to efficient libraries for solving dense and sparse linear 
+equations, 
+convex optimization solvers written in Python,
+interfaces to a few other optimization libraries, 
+and a modeling tool for piecewise-linear convex optimization problems.
+These components are organized in different modules.  
+<DL>
+<DT><STRONG><tt class="module">cvxopt.base</tt></STRONG></DT>
+<DD>This module defines a Python type
+ <tt class="class">matrix</tt> for storing and manipulating dense matrices, 
+ a Python type <tt class="class">spmatrix</tt> for storing and manipulating sparse 
+ matrices, and routines for sparse matrix-vector and matrix-matrix 
+ multiplication (see chapters <A HREF="node4.html#chap:matrix">2</A> 
+ and <A HREF="node33.html#chap:spmatrix">6</A>).
+</DD>
+<DT><STRONG><tt class="module">cvxopt.random</tt></STRONG></DT>
+<DD>Routines for generating random matrices 
+ with uniformly or normally distributed entries 
+ (see section <A href="s-random.html#s-random">2.7</A>).
+</DD>
+<DT><STRONG><tt class="module">cvxopt.blas</tt></STRONG></DT>
+<DD>Interface to most of the double-precision 
+ real and complex BLAS (chapter <A HREF="node14.html#chap:blas">3</A>).
+</DD>
+<DT><STRONG><tt class="module">cvxopt.lapack</tt></STRONG></DT>
+<DD>Interface to the dense double-precision 
+ real and complex linear equation solvers and eigenvalue routines 
+ from LAPACK (chapter <A HREF="node19.html#chap:lapack">4</A>).
+</DD>
+<DT><STRONG><tt class="module">cvxopt.fftw</tt></STRONG></DT>
+<DD>An optional interface to the 
+ discrete transform routines from FFTW (section <A href="c-fftw.html#c-fftw">5</A>). 
+</DD>
+<DT><STRONG><tt class="module">cvxopt.amd</tt></STRONG></DT>
+<DD>Interface to the approximate minimum degree
+ ordering routine from AMD (chapter <A href="s-orderings.html#s-orderings">7.1</A>).
+</DD>
+<DT><STRONG><tt class="module">cvxopt.umfpack</tt></STRONG></DT>
+<DD>Interface to the sparse LU solver 
+ from UMFPACK (section <A href="s-umfpack.html#s-umfpack">7.2</A>).
+</DD>
+<DT><STRONG><tt class="module">cvxopt.cholmod</tt></STRONG></DT>
+<DD>Interface to the sparse Cholesky 
+ solver from CHOLMOD (section <A href="s-cholmod.html#s-cholmod">7.3</A>).
+</DD>
+<DT><STRONG><tt class="module">cvxopt.solvers</tt></STRONG></DT>
+<DD>Convex optimization routines
+ and optional interfaces to solvers from GLPK, MOSEK and DSDP5
+ (chapter <A HREF="node45.html#chap:solvers">8</A>).
+</DD>
+<DT><STRONG><tt class="module">cvxopt.modeling</tt></STRONG></DT>
+<DD>Routines for specifying and solving 
+ linear programs and convex optimization problems with piecewise-linear 
+ cost and constraint functions (chapter <A HREF="node55.html#chap:modeling">9</A>).
+</DD>
+<DT><STRONG><tt class="module">cvxopt.info</tt></STRONG></DT>
+<DD>Defines a string <code>version</code> with
+ the version number of the CVXOPT installation and a function 
+ <tt class="function">license()</tt> that prints the CVXOPT license.  
+</DD>
+</DL>
+The modules are described in detail in this manual and in the 
+on-line Python help facility <b class="program">pydoc</b>.  Several example scripts 
+are included in the distribution. 
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="Contents"
+  href="contents.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="contents.html">Contents</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node30.html b/doc/cvxopt/node30.html
new file mode 100644
index 0000000..42733a5
--- /dev/null
+++ b/doc/cvxopt/node30.html
@@ -0,0 +1,154 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node31.html" />
+<link rel="prev" href="c-fftw.html" />
+<link rel="parent" href="c-fftw.html" />
+<link rel="next" href="node31.html" />
+<meta name='aesop' content='information' />
+<title>5.1 Discrete Fourier Transform</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="5. Discrete Transforms (cvxopt.fftw)"
+  href="c-fftw.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="5. Discrete Transforms (cvxopt.fftw)"
+  href="c-fftw.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="5.2 Discrete Cosine Transform"
+  href="node31.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="c-fftw.html">5. Discrete Transforms (cvxopt.fftw)</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="c-fftw.html">5. Discrete Transforms (cvxopt.fftw)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node31.html">5.2 Discrete Cosine Transform</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION007100000000000000000">
+5.1 Discrete Fourier Transform</A>
+</H1> 
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-109' xml:id='l2h-109' class="function">dft</tt></b>(</nobr></td>
+  <td><var>X</var>)</td></tr></table></dt>
+<dd>
+Replaces the columns of a dense complex matrix with their discrete 
+Fourier transforms:  if <var>X</var> has <I>n</I> rows,
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+X[k,:] := \sum_{j=0}^{n-1} e^{-2\pi j k \sqrt{-1}/n} X[j,:],
+ \qquad k=0,\ldots,n-1.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="375" HEIGHT="58" BORDER="0"
+ SRC="img74.gif"
+ ALT="\begin{displaymath}
+X[k,:] := \sum_{j=0}^{n-1} e^{-2\pi j k \sqrt{-1}/n} X[j,:],
+\qquad k=0,\ldots,n-1.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-110' xml:id='l2h-110' class="function">idft</tt></b>(</nobr></td>
+  <td><var>X</var>)</td></tr></table></dt>
+<dd>
+Replaces the columns of a dense complex matrix with their inverse 
+discrete Fourier transforms: if <var>X</var> has <I>n</I> rows,
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+X[k,:] := 
+ \frac{1}{n} \sum_{j=0}^{n-1} e^{2\pi j k \sqrt{-1}/n} X[j,:],
+  \qquad k=0,\ldots,n-1.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="382" HEIGHT="58" BORDER="0"
+ SRC="img75.gif"
+ ALT="\begin{displaymath}
+X[k,:] :=
+\frac{1}{n} \sum_{j=0}^{n-1} e^{2\pi j k \sqrt{-1}/n} X[j,:],
+\qquad k=0,\ldots,n-1.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+</dl>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="5. Discrete Transforms (cvxopt.fftw)"
+  href="c-fftw.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="5. Discrete Transforms (cvxopt.fftw)"
+  href="c-fftw.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="5.2 Discrete Cosine Transform"
+  href="node31.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="c-fftw.html">5. Discrete Transforms (cvxopt.fftw)</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="c-fftw.html">5. Discrete Transforms (cvxopt.fftw)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node31.html">5.2 Discrete Cosine Transform</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node31.html b/doc/cvxopt/node31.html
new file mode 100644
index 0000000..3cf96da
--- /dev/null
+++ b/doc/cvxopt/node31.html
@@ -0,0 +1,149 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node32.html" />
+<link rel="prev" href="node30.html" />
+<link rel="parent" href="c-fftw.html" />
+<link rel="next" href="node32.html" />
+<meta name='aesop' content='information' />
+<title>5.2 Discrete Cosine Transform</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="5.1 Discrete Fourier Transform"
+  href="node30.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="5. Discrete Transforms (cvxopt.fftw)"
+  href="c-fftw.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="5.3 Discrete Sine Transform"
+  href="node32.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node30.html">5.1 Discrete Fourier Transform</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="c-fftw.html">5. Discrete Transforms (cvxopt.fftw)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node32.html">5.3 Discrete Sine Transform</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION007200000000000000000">
+5.2 Discrete Cosine Transform</A>
+</H1> 
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-111' xml:id='l2h-111' class="function">dct</tt></b>(</nobr></td>
+  <td><var>X</var><big>[</big><var>, type=2</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Replaces the columns of a dense real matrix with their discrete
+cosine transforms.  The second argument, an integer between 1 and 4,
+denotes the type of transform (DCT-I, DCT-II, DCT-III, DCT-IV).
+The DCT-I transform requires that the row dimension of <var>X</var> is at 
+least 2.
+These transforms are defined as follows 
+(for a matrix with <I>n</I> rows).
+<P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{eqnarray*}
+\mbox{DCT-I:} \qquad
+ X[k,:]  & := & X[0,:] + (-1)^k X[n-1,:] + 
+ 2 \sum_{j=1}^{n-2} X[j,:] \cos(\pi j k /(n-1)), 
+ \qquad k=0,\ldots,n-1.\\
+\mbox{DCT-II:} \qquad
+ X[k,:]  & := & 2 \sum_{j=0}^{n-1} X[j,:] \cos(\pi(j+1/2)k/n), 
+ \qquad k=0,\ldots,n-1.\\
+\mbox{DCT-III:} \qquad
+ X[k,:]  & := & X[0,:] + 2 \sum_{j=1}^{n-1} X[j,:] \cos(\pi j(k+1/2)/n),
+ \qquad k=0,\ldots,n-1.\\
+\mbox{DCT-IV:} \qquad
+ X[k,:]  & := & 2 \sum_{j=0}^{n-1} X[j,:] \cos(\pi (j+1/2)(k+1/2)/n), 
+ \qquad k=0,\ldots,n-1.
+\end{eqnarray*}
+ -->
+<IMG
+ WIDTH="724" HEIGHT="230" BORDER="0"
+ SRC="img76.gif"
+ ALT="\begin{eqnarray*}
+\mbox{DCT-I:} \qquad
+X[k,:] & := & X[0,:] + (-1)^k X[n-1,:] +...
+...n-1} X[j,:] \cos(\pi (j+1/2)(k+1/2)/n),
+\qquad k=0,\ldots,n-1.
+\end{eqnarray*}"></DIV>
+<BR CLEAR="ALL"><P></P>
+<BR CLEAR="ALL"><P></P>
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-112' xml:id='l2h-112' class="function">idct</tt></b>(</nobr></td>
+  <td><var>X</var><big>[</big><var>, type=2</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Replaces the columns of a dense real matrix with the inverses
+of the discrete cosine transforms defined above.  
+</dl>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="5.1 Discrete Fourier Transform"
+  href="node30.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="5. Discrete Transforms (cvxopt.fftw)"
+  href="c-fftw.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="5.3 Discrete Sine Transform"
+  href="node32.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node30.html">5.1 Discrete Fourier Transform</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="c-fftw.html">5. Discrete Transforms (cvxopt.fftw)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node32.html">5.3 Discrete Sine Transform</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node32.html b/doc/cvxopt/node32.html
new file mode 100644
index 0000000..5ffc866
--- /dev/null
+++ b/doc/cvxopt/node32.html
@@ -0,0 +1,146 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="prev" href="node31.html" />
+<link rel="parent" href="c-fftw.html" />
+<link rel="next" href="node33.html" />
+<meta name='aesop' content='information' />
+<title>5.3 Discrete Sine Transform</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="5.2 Discrete Cosine Transform"
+  href="node31.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="5. Discrete Transforms (cvxopt.fftw)"
+  href="c-fftw.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="6. Sparse Matrices (cvxopt.base)"
+  href="node33.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node31.html">5.2 Discrete Cosine Transform</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="c-fftw.html">5. Discrete Transforms (cvxopt.fftw)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node33.html">6. Sparse Matrices (cvxopt.base)</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION007300000000000000000">
+5.3 Discrete Sine Transform</A>
+</H1> 
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-113' xml:id='l2h-113' class="function">dst</tt></b>(</nobr></td>
+  <td><var>X</var><big>[</big><var>, type=1</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Replaces the columns of a dense real matrix with their discrete
+sine transforms.  The second argument, an integer between 1 and 4,
+denotes the type of transform (DST-I, DST-II, DST-III, DST-IV).
+These transforms are defined as follows 
+(for a matrix with <I>n</I> rows).
+<P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{eqnarray*}
+\mbox{DST-I:} \qquad
+ X[k,:] & := & 
+ 2 \sum_{j=0}^{n-1} X[j,:] \sin(\pi(j+1)(k+1)/(n+1)), 
+ \qquad k=0,\ldots,n-1.\\
+\mbox{DST-II:} \qquad
+ X[k,:]  & := & 2 \sum_{j=0}^{n-1} X[j,:] \sin(\pi(j+1/2)(k+1)/n), 
+ \qquad k=0,\ldots,n-1.\\
+\mbox{DST-III:} \qquad
+ X[k,:]  & := & (-1)^k X[n-1,:] + 2 \sum_{j=0}^{n-2} 
+ X[j,:] \sin(\pi(j+1)(k+1/2)/n), 
+ \qquad k=0,\ldots,n-1. \\
+\mbox{DST-IV:} \qquad
+ X[k,:]  & := & 2 \sum_{j=0}^{n-1} X[j,:] \sin(\pi (j+1/2)(k+1/2)/n), 
+ \qquad k=0,\ldots,n-1.
+\end{eqnarray*}
+ -->
+<IMG
+ WIDTH="714" HEIGHT="230" BORDER="0"
+ SRC="img77.gif"
+ ALT="\begin{eqnarray*}
+\mbox{DST-I:} \qquad
+X[k,:] & := &
+2 \sum_{j=0}^{n-1} X[j,:...
+...n-1} X[j,:] \sin(\pi (j+1/2)(k+1/2)/n),
+\qquad k=0,\ldots,n-1.
+\end{eqnarray*}"></DIV>
+<BR CLEAR="ALL"><P></P>
+<BR CLEAR="ALL"><P></P>
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-114' xml:id='l2h-114' class="function">idst</tt></b>(</nobr></td>
+  <td><var>X</var><big>[</big><var>, type=1</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Replaces the columns of a dense real matrix with the inverses
+of the discrete sine transforms defined above.  
+</dl>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="5.2 Discrete Cosine Transform"
+  href="node31.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="5. Discrete Transforms (cvxopt.fftw)"
+  href="c-fftw.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="6. Sparse Matrices (cvxopt.base)"
+  href="node33.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node31.html">5.2 Discrete Cosine Transform</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="c-fftw.html">5. Discrete Transforms (cvxopt.fftw)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node33.html">6. Sparse Matrices (cvxopt.base)</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node33.html b/doc/cvxopt/node33.html
new file mode 100644
index 0000000..af1fdbb
--- /dev/null
+++ b/doc/cvxopt/node33.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="c-spsolvers.html" />
+<link rel="prev" href="c-fftw.html" />
+<link rel="parent" href="cvxopt.html" />
+<link rel="next" href="s-creating-spmatrix.html" />
+<meta name='aesop' content='information' />
+<title>6. Sparse Matrices (cvxopt.base)</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="5.3 Discrete Sine Transform"
+  href="node32.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="6.1 Creating Sparse Matrices"
+  href="s-creating-spmatrix.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node32.html">5.3 Discrete Sine Transform</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-creating-spmatrix.html">6.1 Creating Sparse Matrices</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION008000000000000000000"></A><A NAME="chap:spmatrix"></A>
+<BR>
+6. Sparse Matrices (<tt class="module">cvxopt.base</tt>)
+</H1>
+
+<P>
+In this chapter we discuss the <tt class="class">spmatrix</tt> object defined in 
+<tt class="module">cvxopt.base</tt>.
+
+<P>
+
+<p><br /></p><hr class='online-navigation' />
+<div class='online-navigation'>
+<!--Table of Child-Links-->
+<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></a>
+
+<UL CLASS="ChildLinks">
+<LI><A href="s-creating-spmatrix.html">6.1 Creating Sparse Matrices</a>
+<LI><A href="e-spA-example.html">6.2 Attributes and Methods</a>
+<LI><A href="s-spmatrix-arith.html">6.3 Arithmetic Operations</a>
+<LI><A href="node37.html">6.4 Indexing and Slicing</a>
+<LI><A href="node38.html">6.5 Built-In Functions</a>
+<LI><A href="node39.html">6.6 Sparse BLAS Functions</a>
+</ul>
+<!--End of Table of Child-Links-->
+</div>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="5.3 Discrete Sine Transform"
+  href="node32.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="6.1 Creating Sparse Matrices"
+  href="s-creating-spmatrix.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node32.html">5.3 Discrete Sine Transform</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-creating-spmatrix.html">6.1 Creating Sparse Matrices</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node37.html b/doc/cvxopt/node37.html
new file mode 100644
index 0000000..514cf1a
--- /dev/null
+++ b/doc/cvxopt/node37.html
@@ -0,0 +1,175 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node38.html" />
+<link rel="prev" href="s-spmatrix-arith.html" />
+<link rel="parent" href="node33.html" />
+<link rel="next" href="node38.html" />
+<meta name='aesop' content='information' />
+<title>6.4 Indexing and Slicing</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="6.3 Arithmetic Operations"
+  href="s-spmatrix-arith.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="6. Sparse Matrices (cvxopt.base)"
+  href="node33.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="6.5 Built-In Functions"
+  href="node38.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-spmatrix-arith.html">6.3 Arithmetic Operations</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node33.html">6. Sparse Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node38.html">6.5 Built-In Functions</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION008400000000000000000">
+6.4 Indexing and Slicing</A>
+</H1> 
+Sparse matrices can be indexed the same way as dense matrices 
+(see section <A href="s-indexing.html#s-indexing">2.4</A> ).  
+
+<P>
+<div class="verbatim"><pre>
+>>> from cvxopt.base import spmatrix
+>>> A = spmatrix([0,2,-1,2,-2,1], [0,1,2,0,2,1], [0,0,0,1,1,2]) 
+>>> print A[:,[0,1]]
+SIZE: (3,2)
+(0, 0)  0.0000e+00
+(1, 0)  2.0000e+00
+(2, 0) -1.0000e+00
+(0, 1)  2.0000e+00
+(2, 1) -2.0000e+00
+>>> B = spmatrix([0,2*1j,0,-2], [1,2,1,2], [0,0,1,1,])
+>>> print B[-2:,-2:]
+SIZE: (2,2)
+(0, 0)  0.0000e+00-j0.0000e+00
+(1, 0)  2.0000e+00-j0.0000e+00
+(0, 1)  0.0000e+00-j0.0000e+00
+(1, 1)  0.0000e+00-j2.0000e+00
+</pre></div>
+
+<P>
+An indexed sparse matrix <code><var>A</var>[<var>I</var>]</code> or 
+<code><var>A</var>[<var>I</var>,<var>J</var>]</code> can also be the target of an 
+assignment.  The righthand side of the assignment can be a scalar
+(a Python integer, float, or complex,  or a 1 by 1 dense matrix),
+a sequence of numbers, or a sparse or dense matrix of 
+compatible dimensions. 
+If the righthand side is a scalar, it is treated as a dense matrix of 
+the same size as the lefthand side and with all its entries equal to 
+the scalar. 
+If the righthand side is a sequence of numbers, they are treated as
+the elements of a dense matrix in column-major order. 
+
+<P>
+We continue the example above.
+<div class="verbatim"><pre>
+>>> C = spmatrix([10,-20,30], [0,2,1], [0,0,1])
+>>> A[:,0] = C[:,0]
+>>> print A
+SIZE: (3,3)
+(0, 0)  1.0000e+01
+(2, 0) -2.0000e+01
+(0, 1)  2.0000e+00
+(2, 1) -2.0000e+00
+(1, 2)  1.0000e+00
+>>> D = matrix(range(6), (3,2))
+>>> A[:,0] = D[:,0]
+>>> print A
+SIZE: (3,3)
+(0, 0)  0.0000e+00
+(1, 0)  1.0000e+00
+(2, 0)  2.0000e+00
+(0, 1)  2.0000e+00
+(2, 1) -2.0000e+00
+(1, 2)  1.0000e+00
+>>> A[:,0] = 1
+>>> print A
+SIZE: (3,3)
+(0, 0)  1.0000e+00
+(1, 0)  1.0000e+00
+(2, 0)  1.0000e+00
+(0, 1)  2.0000e+00
+(2, 1) -2.0000e+00
+(1, 2)  1.0000e+00
+>>> A[:,0] = 0
+>>> print A
+TYPE: (3,3)
+(0, 0)  0.0000e+00
+(1, 0)  0.0000e+00
+(2, 0)  0.0000e+00
+(0, 1)  2.0000e+00
+(2, 1) -2.0000e+00
+(1, 2)  1.0000e+00
+</pre></div>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="6.3 Arithmetic Operations"
+  href="s-spmatrix-arith.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="6. Sparse Matrices (cvxopt.base)"
+  href="node33.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="6.5 Built-In Functions"
+  href="node38.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-spmatrix-arith.html">6.3 Arithmetic Operations</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node33.html">6. Sparse Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node38.html">6.5 Built-In Functions</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node38.html b/doc/cvxopt/node38.html
new file mode 100644
index 0000000..6bb25d6
--- /dev/null
+++ b/doc/cvxopt/node38.html
@@ -0,0 +1,184 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node39.html" />
+<link rel="prev" href="node37.html" />
+<link rel="parent" href="node33.html" />
+<link rel="next" href="node39.html" />
+<meta name='aesop' content='information' />
+<title>6.5 Built-In Functions</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="6.4 Indexing and Slicing"
+  href="node37.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="6. Sparse Matrices (cvxopt.base)"
+  href="node33.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="6.6 Sparse BLAS Functions"
+  href="node39.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node37.html">6.4 Indexing and Slicing</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node33.html">6. Sparse Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node39.html">6.6 Sparse BLAS Functions</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION008500000000000000000">
+6.5 Built-In Functions</A>
+</H1>
+
+<P>
+The functions described in the table of section <A href="s-builtinfuncs.html#s-builtinfuncs">2.5</A> 
+also work with sparse matrix arguments.  The difference is that for a 
+sparse matrix only the nonzero entries are considered. 
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-123' xml:id='l2h-123' class="function">len</tt></b>(</nobr></td>
+  <td><var>x</var>)</td></tr></table></dt>
+<dd>
+If <var>x</var> is a <tt class="class">spmatrix</tt>, returns the number of nonzero entries in
+<var>x</var>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-124' xml:id='l2h-124' class="function">bool</tt></b>(</nobr></td>
+  <td><var></var><big>[</big><var>x</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+If <var>x</var> is a <tt class="class">spmatrix</tt>, returns <code>False</code> if <var>x</var> has at least one 
+nonzero entry; <code>False</code> otherwise.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-125' xml:id='l2h-125' class="function">max</tt></b>(</nobr></td>
+  <td><var>x</var>)</td></tr></table></dt>
+<dd>
+If <var>x</var> is a <tt class="class">spmatrix</tt>, returns the maximum nonzero entry of <var>x</var>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-126' xml:id='l2h-126' class="function">min</tt></b>(</nobr></td>
+  <td><var>x</var>)</td></tr></table></dt>
+<dd>
+If <var>x</var> is a <tt class="class">spmatrix</tt>, returns the minimum nonzero entry of <var>x</var>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-127' xml:id='l2h-127' class="function">abs</tt></b>(</nobr></td>
+  <td><var>x</var>)</td></tr></table></dt>
+<dd>
+If <var>x</var> is a <tt class="class">spmatrix</tt>, returns a sparse matrix with the absolute
+value of the elements of <var>x</var> and the same sparsity pattern.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-128' xml:id='l2h-128' class="function">sum</tt></b>(</nobr></td>
+  <td><var>x</var><big>[</big><var>, start=0.0</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+If <var>x</var> is a <tt class="class">spmatrix</tt>, returns the sum of <var>start</var> and the 
+elements of <var>x</var>.
+</dl>
+
+<P>
+The functions <tt class="function">list()</tt>, <tt class="function">tuple()</tt>, <tt class="function">zip()</tt>, 
+<tt class="function">map()</tt>, <tt class="function">filter()</tt> also take sparse matrix arguments.
+They work as for dense matrices, again with the difference that only 
+the nonzero entries are considered.
+
+<P>
+In the following example we square the entries of the 
+matrix (<A href="e-spA-example.html#e-spA-example">6.2</A>). 
+
+<P>
+<div class="verbatim"><pre>
+>>> A = spmatrix([2,1,2,2,1,3,4], [1,2,0,2,3,0,2], [0,0,1,1,2,3,3]) 
+>>> B = spmatrix(map(lambda x: x**2, A), A.I, A.J)
+>>> print B
+SIZE: (4,4)
+(1, 0)  4.0000e+00
+(2, 0)  1.0000e+00
+(0, 1)  4.0000e+00
+(2, 1)  4.0000e+00
+(3, 2)  1.0000e+00
+(0, 3)  9.0000e+00
+(2, 3)  1.6000e+01
+</pre></div>
+
+<P>
+The expression "<tt class="samp"><var>x</var> in <var>A</var></tt>" returns <code>True</code>  if a nonzero
+entry of <var>A</var> is equal to <var>x</var> and <code>False</code> otherwise.
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="6.4 Indexing and Slicing"
+  href="node37.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="6. Sparse Matrices (cvxopt.base)"
+  href="node33.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="6.6 Sparse BLAS Functions"
+  href="node39.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node37.html">6.4 Indexing and Slicing</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node33.html">6. Sparse Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node39.html">6.6 Sparse BLAS Functions</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node39.html b/doc/cvxopt/node39.html
new file mode 100644
index 0000000..e7fa0de
--- /dev/null
+++ b/doc/cvxopt/node39.html
@@ -0,0 +1,375 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="prev" href="node38.html" />
+<link rel="parent" href="node33.html" />
+<link rel="next" href="c-spsolvers.html" />
+<meta name='aesop' content='information' />
+<title>6.6 Sparse BLAS Functions</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="6.5 Built-In Functions"
+  href="node38.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="6. Sparse Matrices (cvxopt.base)"
+  href="node33.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="7. Sparse Linear Equation"
+  href="c-spsolvers.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node38.html">6.5 Built-In Functions</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node33.html">6. Sparse Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="c-spsolvers.html">7. Sparse Linear Equation</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION008600000000000000000">
+6.6 Sparse BLAS Functions</A>
+</H1>
+The <tt class="module">cvxopt.base</tt> module includes a few arithmetic functions 
+that extend functions from <tt class="module">cvxopt.blas</tt> to sparse matrices.
+These functions are faster than the corresponding operations 
+implemented using the overloaded arithmetic described 
+in section <A href="s-spmatrix-arith.html#s-spmatrix-arith">6.3</A>.
+They also work in-place, <EM>i.e.</EM>, they modify their arguments without 
+creating new objects.
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-129' xml:id='l2h-129' class="function">gemv</tt></b>(</nobr></td>
+  <td><var>A, x, y</var><big>[</big><var>, trans='N'</var><big>[</big><var>, 
+  alpha=1.0</var><big>[</big><var>, beta=0.0</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Matrix-vector product with a general dense or sparse matrix:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+y := \alpha Ax + \beta y \quad (\mathrm{trans} = \mathrm{'N'}),
+  \qquad 
+y := \alpha A^T x + \beta y \quad (\mathrm{trans} = \mathrm{'T'}), 
+  \qquad
+y := \alpha A^H x + \beta y \quad (\mathrm{trans} = \mathrm{'C'}).
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="707" HEIGHT="28" BORDER="0"
+ SRC="img17.gif"
+ ALT="\begin{displaymath}
+y := \alpha Ax + \beta y \quad (\mathrm{trans} = \mathrm{'N'...
+...\alpha A^H x + \beta y \quad (\mathrm{trans} = \mathrm{'C'}).
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+If <var>A</var> is a dense matrix, this is identical to 
+<tt class="function">blas.gemv()</tt>.  If <var>A</var> is sparse, the result is the same 
+as when <tt class="function">blas.gemv()</tt> is called with <code>matrix(A)</code> as 
+argument, however, without explicitly converting <var>A</var> to dense.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-130' xml:id='l2h-130' class="function">symv</tt></b>(</nobr></td>
+  <td><var>A, x, y</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+alpha=1.0</var><big>[</big><var>, beta=0.0</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd> 
+Matrix-vector product with a dense or sparse real symmetric matrix:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+y := \alpha A x + \beta y.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="106" HEIGHT="27" BORDER="0"
+ SRC="img82.gif"
+ ALT="\begin{displaymath}
+y := \alpha A x + \beta y.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+If <var>A</var> is a dense matrix, this is identical to 
+<tt class="function">blas.symv()</tt>.  If <var>A</var> is sparse, the result is the same 
+as when <tt class="function">blas.symv()</tt> is called with <code>matrix(A)</code> as 
+argument, however, without explicitly converting <var>A</var> to dense.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-131' xml:id='l2h-131' class="function">gemm</tt></b>(</nobr></td>
+  <td><var>A, B, C</var><big>[</big><var>, transA='N'</var><big>[</big><var>, 
+transB='N'</var><big>[</big><var>, alpha=1.0</var><big>[</big><var>, beta=0.0</var><big>[</big><var>, 
+partial=False</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Matrix-matrix product of two general sparse or dense matrices:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+C := \alpha \mathop{\mathrm{op}}(A) \mathop{\mathrm{op}}(B) + \beta C
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="177" HEIGHT="28" BORDER="0"
+ SRC="img31.gif"
+ ALT="\begin{displaymath}
+C := \alpha \mathop{\mathrm{op}}(A) \mathop{\mathrm{op}}(B) + \beta C
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\mathop{\mathrm{op}}(A) =  \left\{ \begin{array}{ll}
+ A & \mathrm{transA} = \mathrm{'N'} \\
+ A^T & \mathrm{transA} = \mathrm{'T'} \\
+ A^H & \mathrm{transA} = \mathrm{'C'} \end{array} \right.
+\qquad
+\mathop{\mathrm{op}}(B) =  \left\{ \begin{array}{ll}
+ B & \mathrm{transB} = \mathrm{'N'} \\
+ B^T & \mathrm{transB} = \mathrm{'T'} \\
+ B^H & \mathrm{transB} = \mathrm{'C'}. \end{array} \right.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="474" HEIGHT="64" BORDER="0"
+ SRC="img32.gif"
+ ALT="\begin{displaymath}
+\mathop{\mathrm{op}}(A) = \left\{ \begin{array}{ll}
+A & \ma...
+...\\
+B^H & \mathrm{transB} = \mathrm{'C'}. \end{array} \right.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+If <var>A</var>, <var>B</var> and <var>C</var> are dense matrices, this is 
+identical to <tt class="function">blas.gemm()</tt>, described in section <A href="s-blas3.html#s-blas3">3.4</A>,
+and the argument <var>partial</var> is ignored.
+
+<P>
+If <var>A</var> and/or <var>B</var> are sparse and <var>C</var> is dense, the result
+is the same as when <tt class="function">blas.gemm()</tt> is called with
+<code>matrix(A)</code> and <code>matrix(B)</code> as arguments, without explicitly 
+converting  <var>A</var> and <var>B</var> to dense.
+The argument <var>partial</var> is ignored.
+
+<P>
+If <var>C</var> is a sparse matrix, the matrix-matrix product in the
+definition of <tt class="function">blas.gemm()</tt> is computed, but as a sparse 
+matrix.  
+If <var>partial</var> is <code>False</code>, the result is stored in <var>C</var>, 
+and the sparsity pattern of <var>C</var> is  modified if necessary.
+If <var>partial</var> is <code>True</code>, the operation only updates the nonzero
+elements in <var>C</var>, even if the sparsity pattern of <var>C</var> differs
+from that of the matrix product.  
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-132' xml:id='l2h-132' class="function">syrk</tt></b>(</nobr></td>
+  <td><var>A, C</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+trans='N'</var><big>[</big><var>, alpha=1.0</var><big>[</big><var>, beta=0.0</var><big>[</big><var>, 
+partial=False</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Rank-<I>k</I> update of a sparse or dense real or complex symmetric
+matrix:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+C := \alpha AA^T + \beta C \quad (\mathrm{trans} = \mathrm{'N'}), 
+ \qquad 
+ C := \alpha A^TA + \beta C \quad (\mathrm{trans} = \mathrm{'T'}),
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="501" HEIGHT="28" BORDER="0"
+ SRC="img36.gif"
+ ALT="\begin{displaymath}
+C := \alpha AA^T + \beta C \quad (\mathrm{trans} = \mathrm{...
+... \alpha A^TA + \beta C \quad (\mathrm{trans} = \mathrm{'T'}),
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+If <var>A</var> and <var>C</var> are dense, this is identical to 
+<tt class="function">blas.syrk()</tt>, described in section <A href="s-blas3.html#s-blas3">3.4</A>,
+and the argument <var>partial</var> is ignored.
+
+<P>
+If <var>A</var> is sparse and <var>C</var> is dense, the result is the same as 
+when <tt class="function">blas.syrk()</tt> is called with <code>matrix(A)</code> as 
+argument, without explicitly converting  <var>A</var> to dense.  
+The argument <var>partial</var> is ignored.
+
+<P>
+If <var>C</var> is sparse, the product in the definition of 
+<tt class="function">blas.syrk()</tt> is computed, but as a sparse matrix.  
+If <var>partial</var> is <code>False</code>, the result is stored in <var>C</var>, 
+and the sparsity pattern of <var>C</var> is  modified if necessary.
+If <var>partial</var> is <code>True</code>, the operation only updates the nonzero
+elements in <var>C</var>, even if the sparsity pattern of <var>C</var> differs
+from that of the matrix product.  
+</dl>
+
+<P>
+In the following example, we first compute 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+C =  A^TB, \qquad
+A = \left[ \begin{array}{ccc}
+0 & 1 & 0 \\1 & 0 & 1 \\0 & 1 & 0 \\1 & 0 & 0 \end{array}\right],
+\qquad
+B = \left[ \begin{array}{ccc}
+   0 & -1 & 0 \\2 & 0 & 2 \\0 & 3 & 0 \\2 & 0 & 0 
+   \end{array}\right].
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="418" HEIGHT="83" BORDER="0"
+ SRC="img83.gif"
+ ALT="\begin{displaymath}
+C = A^TB, \qquad
+A = \left[ \begin{array}{ccc}
+0 & 1 & 0 \\ ...
+...0 \\ 2 & 0 & 2 \\ 0 & 3 & 0 \\ 2 & 0 & 0
+\end{array}\right].
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+<div class="verbatim"><pre>
+>>> from cvxopt.base import spmatrix, gemm
+>>> A = spmatrix(1, [1,3,0,2,1], [0,0,1,1,2])
+>>> B = spmatrix([2,2,-1,3,2], [1,3,0,2,1], [0,0,1,1,2])
+>>> C = spmatrix([], [], [], size=(3,3))
+>>> gemm(A, B, C, transA='T')
+>>> print C
+SIZE: (3,3)
+(0, 0)  4.0000e+00
+(2, 0)  2.0000e+00
+(1, 1)  2.0000e+00
+(0, 2)  2.0000e+00
+(2, 2)  2.0000e+00
+</pre></div>
+Now suppose we want to replace <I>C</I> 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+C = A^TD, \qquad 
+D = \left[ \begin{array}{ccc}
+   0 & 1 & 0 \\3 & 0 & -2 \\0 & 1 & 0 \\4 & 0 & 0 
+   \end{array}\right].
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="252" HEIGHT="83" BORDER="0"
+ SRC="img84.gif"
+ ALT="\begin{displaymath}
+C = A^TD, \qquad
+D = \left[ \begin{array}{ccc}
+0 & 1 & 0 \\ 3 & 0 & -2 \\ 0 & 1 & 0 \\ 4 & 0 & 0
+\end{array}\right].
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+The new matrix has the same sparsity pattern as <var>C</var>, so we can 
+use <tt class="function">gemm()</tt> with the <code>partial=True</code> option.
+This saves time in large sparse matrix multiplications when the 
+sparsity pattern of the result is known beforehand.
+<div class="verbatim"><pre>
+>>> D = spmatrix([3,4,1,1,-2], [1,3,0,2,1], [0,0,1,1,2])
+>>> gemm(A, D, C, transA='T', partial=True)
+>>> print C
+SIZE: (3,3)
+(0, 0)  7.0000e+00
+(2, 0)  3.0000e+00
+(1, 1)  2.0000e+00
+(0, 2) -2.0000e+00
+(2, 2) -2.0000e+00
+</pre></div>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="6.5 Built-In Functions"
+  href="node38.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="6. Sparse Matrices (cvxopt.base)"
+  href="node33.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="7. Sparse Linear Equation"
+  href="c-spsolvers.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node38.html">6.5 Built-In Functions</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node33.html">6. Sparse Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="c-spsolvers.html">7. Sparse Linear Equation</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node4.html b/doc/cvxopt/node4.html
new file mode 100644
index 0000000..28ff426
--- /dev/null
+++ b/doc/cvxopt/node4.html
@@ -0,0 +1,124 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node14.html" />
+<link rel="prev" href="node3.html" />
+<link rel="parent" href="cvxopt.html" />
+<link rel="next" href="s-creating-matrices.html" />
+<meta name='aesop' content='information' />
+<title>2. Dense Matrices (cvxopt.base)</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="1. Introduction"
+  href="node3.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.1 Creating Matrices"
+  href="s-creating-matrices.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node3.html">1. Introduction</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-creating-matrices.html">2.1 Creating Matrices</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION004000000000000000000"></A><A NAME="chap:matrix"></A>
+<BR>
+2. Dense Matrices (<tt class="module">cvxopt.base</tt>)
+</H1>
+
+<P>
+The <tt class="module">cvxopt.base</tt> module defines two new Python types: 
+<tt class="class">matrix</tt> objects, used for dense matrix computations, and 
+<tt class="class">spmatrix</tt> objects, used for sparse matrix computations.
+In this chapter we describe the dense <tt class="class">matrix</tt> object.
+
+<P>
+
+<p><br /></p><hr class='online-navigation' />
+<div class='online-navigation'>
+<!--Table of Child-Links-->
+<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></a>
+
+<UL CLASS="ChildLinks">
+<LI><A href="s-creating-matrices.html">2.1 Creating Matrices</a>
+<LI><A href="node6.html">2.2 Attributes and Methods</a>
+<LI><A href="s-arithmetic.html">2.3 Arithmetic Operations</a>
+<LI><A href="s-indexing.html">2.4 Indexing and Slicing</a>
+<LI><A href="s-builtinfuncs.html">2.5 Built-in Functions</a>
+<LI><A href="s-otherfuncs.html">2.6 Other Matrix Functions</a>
+<LI><A href="s-random.html">2.7 Randomly Generated Matrices</a>
+<LI><A href="s-array-interface.html">2.8 The NumPy Array Interface</a>
+<LI><A href="node13.html">2.9 Printing Options</a>
+</ul>
+<!--End of Table of Child-Links-->
+</div>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="1. Introduction"
+  href="node3.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.1 Creating Matrices"
+  href="s-creating-matrices.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node3.html">1. Introduction</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-creating-matrices.html">2.1 Creating Matrices</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node45.html b/doc/cvxopt/node45.html
new file mode 100644
index 0000000..039732e
--- /dev/null
+++ b/doc/cvxopt/node45.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node55.html" />
+<link rel="prev" href="c-spsolvers.html" />
+<link rel="parent" href="cvxopt.html" />
+<link rel="next" href="s-lpsolver.html" />
+<meta name='aesop' content='information' />
+<title>8. Optimization Routines (cvxopt.solvers)</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="7.4 Example: Covariance Selection"
+  href="e-covsel.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.1 Linear Programming"
+  href="s-lpsolver.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="e-covsel.html">7.4 Example: Covariance Selection</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-lpsolver.html">8.1 Linear Programming</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0010000000000000000000"></A>
+<A NAME="chap:solvers"></A>
+<BR>
+8. Optimization Routines (<tt class="module">cvxopt.solvers</tt>)
+</H1>
+
+<P>
+
+<p><br /></p><hr class='online-navigation' />
+<div class='online-navigation'>
+<!--Table of Child-Links-->
+<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></a>
+
+<UL CLASS="ChildLinks">
+<LI><A href="s-lpsolver.html">8.1 Linear Programming</a>
+<LI><A href="node47.html">8.2 Quadratic Programming</a>
+<LI><A href="node48.html">8.3 Geometric Programming</a>
+<LI><A href="s-sdpsolver.html">8.4 Semidefinite Programming</a>
+<LI><A href="e-nlcp.html">8.5 Nonlinear Convex Programming</a>
+<LI><A href="node51.html">8.6 Exploiting Structure in LPs and SDPs</a>
+<LI><A href="node52.html">8.7 Exploiting Structure in Nonlinear Convex Programs</a>
+<LI><A href="s-external.html">8.8 Optional Solvers</a>
+<LI><A href="s-parameters.html">8.9 Algorithm Parameters</a>
+</ul>
+<!--End of Table of Child-Links-->
+</div>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="7.4 Example: Covariance Selection"
+  href="e-covsel.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.1 Linear Programming"
+  href="s-lpsolver.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="e-covsel.html">7.4 Example: Covariance Selection</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-lpsolver.html">8.1 Linear Programming</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node47.html b/doc/cvxopt/node47.html
new file mode 100644
index 0000000..a8b49f2
--- /dev/null
+++ b/doc/cvxopt/node47.html
@@ -0,0 +1,341 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node48.html" />
+<link rel="prev" href="s-lpsolver.html" />
+<link rel="parent" href="node45.html" />
+<link rel="next" href="node48.html" />
+<meta name='aesop' content='information' />
+<title>8.2 Quadratic Programming</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.1 Linear Programming"
+  href="s-lpsolver.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.3 Geometric Programming"
+  href="node48.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-lpsolver.html">8.1 Linear Programming</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node48.html">8.3 Geometric Programming</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0010200000000000000000">
+8.2 Quadratic Programming</A>
+</H1>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-146' xml:id='l2h-146' class="function">qp</tt></b>(</nobr></td>
+  <td><var>P, q, </var><big>[</big><var>, G, h </var><big>[</big><var>, A, b</var><big>[</big><var>,
+solver</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves a convex quadratic program  
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & (1/2) x^TPx + q^T x \\
+\mbox{subject to} & Gx \preceq h \\& Ax = b.
+\end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="199" HEIGHT="64" BORDER="0"
+ SRC="img116.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & (1/2) x^TPx + q^T x \\
+\mbox{subject to} & Gx \preceq h \\ & Ax = b.
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+<var>P</var> is a square dense or sparse real matrix, representing a 
+symmetric matrix in <code>'L'</code> storage, <EM>i.e.</EM>, only the lower 
+triangular part of <var>P</var> is referenced.
+<var>G</var> and <var>A</var> are dense or sparse real matrices.
+Their default values are sparse matrices with zero columns.
+<var>q</var>, <var>h</var> and <var>b</var> are single-column real dense matrices.
+The default values of <var>h</var> and <var>b</var> are matrices of size (0,1).
+
+<P>
+The default CVXOPT solver is used when the <var>solver</var> argument
+is absent or <code>None</code>.  The MOSEK solver (if installed) can be 
+selected by setting <var>solver</var>=<code>'mosek'</code>.
+
+<P>
+<tt class="function">qp()</tt> returns a dictionary with keys 
+<code>'status'</code>, <code>'x'</code>, <code>'s'</code>, <code>'y'</code>, <code>'z'</code>.
+The possible values of the <code>'status'</code> key are as follows.
+<DL>
+<DT><STRONG><code>'optimal'</code></STRONG></DT>
+<DD>In this case the 
+<code>'x'</code> entry is the primal optimal solution,
+the <code>'s'</code> entry is the corresponding slack in the inequality
+constraints, the <code>'z'</code> and <code>'y'</code> entries are the optimal 
+values of the dual variables associated with the linear inequality 
+and linear equality constraints.
+These values (approximately) satisfy the optimality conditions
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+Px + q + G^T z + A^T y = 0, \qquad Gx + s = h, \qquad
+ Ax = b, \qquad s \succeq 0, \qquad z \succeq 0, \qquad s^T z = 0.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="603" HEIGHT="27" BORDER="0"
+ SRC="img117.gif"
+ ALT="\begin{displaymath}
+Px + q + G^T z + A^T y = 0, \qquad Gx + s = h, \qquad
+Ax = b, \qquad s \succeq 0, \qquad z \succeq 0, \qquad s^T z = 0.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+</DD>
+<DT><STRONG><code>'primal infeasible'</code></STRONG></DT>
+<DD>This only applies when
+<var>solver</var> is <code>'mosek'</code>, and means that a certificate of
+primal infeasibility has been found.   The <code>'x'</code> and <code>'s'</code> 
+entries are <code>None</code>, and the
+<code>'z'</code> and <code>'y'</code> entries are vectors that approximately satisfy
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+G^Tz + A^T y = 0, \qquad h^Tz + b^Ty = -1, \qquad z \succeq 0.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="340" HEIGHT="27" BORDER="0"
+ SRC="img113.gif"
+ ALT="\begin{displaymath}
+G^T z + A^T y = 0, \qquad h^T z + b^T y = -1, \qquad z \succeq 0.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+</DD>
+<DT><STRONG><code>'dual infeasible'</code></STRONG></DT>
+<DD>This only applies when
+<var>solver</var> is <code>'mosek'</code>, and means that a certificate of
+dual infeasibility has been found.   The <code>'z'</code> and <code>'y'</code>
+entries are <code>None</code>, and the <code>'x'</code> and <code>'s'</code> entries are
+vectors that approximately satisfy
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+Px = 0, \qquad q^Tx = -1, \qquad Gx + s = 0, \qquad Ax=0, \qquad
+ s \succeq  0.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="442" HEIGHT="27" BORDER="0"
+ SRC="img118.gif"
+ ALT="\begin{displaymath}
+Px = 0, \qquad q^Tx = -1, \qquad Gx + s = 0, \qquad Ax=0, \qquad
+s \succeq 0.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+</DD>
+<DT><STRONG><code>'unknown'</code></STRONG></DT>
+<DD>This means that the algorithm reached
+the maximum number of iterations before a solution was found.
+The <code>'x'</code>, <code>'s'</code>, <code>'y'</code>, <code>'z'</code> entries are <code>None</code>. 
+</DD>
+</DL>
+</dl>
+
+<P>
+As an example we compute the trade-off curve on page 187
+of the book <em class="citetitle"><a
+ href="http://www.stanford.edu/~boyd/cvxbook"
+ title="Convex 
+Optimization"
+ >Convex 
+Optimization</a></em>, by solving the quadratic program 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & -\bar p^T x + \mu x^T S x \\
+\mbox{subject to} & {\bf 1}^T x = 1, \quad x \succeq 0
+\end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="195" HEIGHT="45" BORDER="0"
+ SRC="img119.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & -\bar p^T x + \mu x^T S ...
+...ox{subject to} & {\bf 1}^T x = 1, \quad x \succeq 0
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+for a sequence of positive values of <I>mu</I>. 
+The code below computes the trade-off curve and produces two figures 
+using the <a class="ulink" href="http://matplotlib.sourceforge.net"
+  >Matplotlib</a> package.
+<DIV ALIGN="CENTER">
+<IMG
+ WIDTH="453" HEIGHT="340" ALIGN="BOTTOM" BORDER="0"
+ SRC="img120.gif"
+ ALT="\includegraphics[width=10cm]{figures/portfolio1.eps}">
+ 
+<IMG
+ WIDTH="453" HEIGHT="340" ALIGN="BOTTOM" BORDER="0"
+ SRC="img121.gif"
+ ALT="\includegraphics[width=10cm]{figures/portfolio2.eps}">
+
+</DIV>
+
+<P>
+<div class="verbatim"><pre>
+from math import sqrt
+from cvxopt.base import matrix
+from cvxopt.blas import dot 
+from cvxopt.solvers import qp
+import pylab
+
+# Problem data.
+n = 4
+S = matrix([[ 4e-2,  6e-3, -4e-3,    0.0 ], 
+            [ 6e-3,  1e-2,  0.0,     0.0 ],
+            [-4e-3,  0.0,   2.5e-3,  0.0 ],
+            [ 0.0,   0.0,   0.0,     0.0 ]])
+pbar = matrix([.12, .10, .07, .03])
+G = matrix(0.0, (n,n))
+G[::n+1] = -1.0
+h = matrix(0.0, (n,1))
+A = matrix(1.0, (1,n))
+b = matrix(1.0)
+
+# Compute trade-off.
+N = 100
+mus = [ 10**(5.0*t/N-1.0) for t in xrange(N) ]
+portfolios = [ qp(mu*S, -pbar, G, h, A, b)['x'] for mu in mus ]
+returns = [ dot(pbar,x) for x in portfolios ]
+risks = [ sqrt(dot(x, S*x)) for x in portfolios ]
+
+# Plot trade-off curve and optimal allocations.
+pylab.figure(1, facecolor='w')
+pylab.plot(risks, returns)
+pylab.xlabel('standard deviation')
+pylab.ylabel('expected return')
+pylab.axis([0, 0.2, 0, 0.15])
+pylab.title('Risk-return trade-off curve (fig 4.12)')
+pylab.yticks([0.00, 0.05, 0.10, 0.15])
+
+pylab.figure(2, facecolor='w')
+c1 = [ x[0] for x in portfolios ] 
+c2 = [ x[0] + x[1] for x in portfolios ]
+c3 = [ x[0] + x[1] + x[2] for x in portfolios ] 
+c4 = [ x[0] + x[1] + x[2] + x[3] for x in portfolios ]
+pylab.fill(risks + [.20], c1 + [0.0], '#F0F0F0') 
+pylab.fill(risks[-1::-1] + risks, c2[-1::-1] + c1, '#D0D0D0') 
+pylab.fill(risks[-1::-1] + risks, c3[-1::-1] + c2, '#F0F0F0') 
+pylab.fill(risks[-1::-1] + risks, c4[-1::-1] + c3, '#D0D0D0') 
+pylab.axis([0.0, 0.2, 0.0, 1.0])
+pylab.xlabel('standard deviation')
+pylab.ylabel('allocation')
+pylab.text(.15,.5,'x1')
+pylab.text(.10,.7,'x2')
+pylab.text(.05,.7,'x3')
+pylab.text(.01,.7,'x4')
+pylab.title('Optimal allocations (fig 4.12)')
+pylab.show()
+</pre></div>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.1 Linear Programming"
+  href="s-lpsolver.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.3 Geometric Programming"
+  href="node48.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-lpsolver.html">8.1 Linear Programming</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node48.html">8.3 Geometric Programming</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node48.html b/doc/cvxopt/node48.html
new file mode 100644
index 0000000..845236d
--- /dev/null
+++ b/doc/cvxopt/node48.html
@@ -0,0 +1,293 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="s-sdpsolver.html" />
+<link rel="prev" href="node47.html" />
+<link rel="parent" href="node45.html" />
+<link rel="next" href="s-sdpsolver.html" />
+<meta name='aesop' content='information' />
+<title>8.3 Geometric Programming</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.2 Quadratic Programming"
+  href="node47.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.4 Semidefinite Programming"
+  href="s-sdpsolver.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node47.html">8.2 Quadratic Programming</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-sdpsolver.html">8.4 Semidefinite Programming</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0010300000000000000000">
+8.3 Geometric Programming</A>
+</H1>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-147' xml:id='l2h-147' class="function">gp</tt></b>(</nobr></td>
+  <td><var>K, F, g </var><big>[</big><var>, G, h </var><big>[</big><var>, A, b</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves a geometric program in convex form
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & f_0(x) = \mathop{\bf lse}(F_0x+g_0) \\
+\mbox{subject to} & f_i(x) = \mathop{\bf lse}(F_ix+g_i) \leq 0,\quad i=1,\ldots,m \\
+ & Gx \preceq h \\
+ & Ax=b
+\end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="359" HEIGHT="83" BORDER="0"
+ SRC="img122.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & f_0(x) = \mathop{\bf lse...
+...,\quad i=1,\ldots,m \\
+& Gx \preceq h \\
+& Ax=b
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\mathop{\bf lse}(u) = \log \sum_k \exp(u_k), \qquad
+ F = \left[ \begin{array}{cccc}
+ F_0^T & F_1^T & \cdots & F_m^T \end{array}\right]^T, \qquad
+ g = \left[ \begin{array}{cccc}
+ g_0^T & g_1^T & \cdots & g_m^T \end{array}\right]^T.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="649" HEIGHT="45" BORDER="0"
+ SRC="img123.gif"
+ ALT="\begin{displaymath}
+\mathop{\bf lse}(u) = \log \sum_k \exp(u_k), \qquad
+F = \l...
+...}{cccc}
+g_0^T & g_1^T & \cdots & g_m^T \end{array}\right]^T.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+<var>K</var> is a list of <var>m</var>+1 positive integers with 
+<code><var>K</var>[<var>i</var>]</code>
+equal to the number of rows in <I>Fi</I>.
+<var>F</var> is a dense or sparse real matrix of size 
+<code>(sum(<var>K</var>),<var>n</var>)</code>.
+<var>g</var> is a dense real matrix of size <code>(sum(<var>K</var>),1)</code>.
+<var>G</var> and <var>A</var> are dense or sparse real matrices.
+Their default values are sparse matrices with zero rows.
+<var>h</var> and <var>b</var> are dense real matrices with one column.
+Their default values are matrices of size (0,1).
+
+<P>
+<tt class="function">gp()</tt> returns a dictionary with keys 
+<code>'status'</code>, <code>'x'</code>, <code>'snl'</code>, <code>'sl'</code>, 
+<code>'y'</code>, <code>'znl'</code> and <code>'zl'</code>.
+The possible values of the <code>'status'</code> key are:
+<DL>
+<DT><STRONG><code>'optimal'</code></STRONG></DT>
+<DD>In this case the 
+<code>'x'</code> entry is the primal optimal solution,
+the <code>'snl'</code> and <code>'sl'</code> entries are the corresponding slacks 
+in the nonlinear and linear inequality constraints. 
+The <code>'znl'</code>, <code>'zl'</code> and <code>'y'</code> entries are the optimal 
+values of the dual variables associated with the nonlinear and linear 
+inequality constraints and the linear equality constraints.
+These values approximately satisfy
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\nabla f_0(x) + \sum_{k=1}^m z_{\mathrm{nl},k} 
+ \nabla f_k(x) + G^T z_\mathrm{l} + A^T y = 0, \qquad
+ f_k(x) + s_{\mathrm{nl},k} = 0, \quad k=1,\ldots,m,   \qquad 
+ Gx + s_\mathrm{l} = h, \qquad Ax=b
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="747" HEIGHT="53" BORDER="0"
+ SRC="img124.gif"
+ ALT="\begin{displaymath}
+\nabla f_0(x) + \sum_{k=1}^m z_{\mathrm{nl},k}
+\nabla f_k...
+...quad k=1,\ldots,m, \qquad
+Gx + s_\mathrm{l} = h, \qquad Ax=b
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+and
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+s_\mathrm{nl}\succeq 0, \qquad s_\mathrm{l}\succeq 0, \qquad 
+z_\mathrm{nl} \succeq 0, \qquad z_\mathrm{l} \succeq 0, \qquad
+s_\mathrm{nl}^T z_\mathrm{nl} + s_\mathrm{l}^T z_\mathrm{l} = 0.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="453" HEIGHT="28" BORDER="0"
+ SRC="img125.gif"
+ ALT="\begin{displaymath}
+s_\mathrm{nl}\succeq 0, \qquad s_\mathrm{l}\succeq 0, \qquad...
+...\mathrm{nl}^T z_\mathrm{nl} + s_\mathrm{l}^T z_\mathrm{l} = 0.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+</DD>
+<DT><STRONG><code>'unknown'</code></STRONG></DT>
+<DD>This means that the algorithm reached
+the maximum number of iterations before a solution was found.
+The <code>'x'</code>, <code>'snl'</code>, <code>'sl'</code>, <code>'y'</code>, <code>'znl'</code> 
+and <code>'zl'</code> entries are <code>None</code>. 
+</DD>
+</DL>
+</dl>
+
+<P>
+As an example, we solve the small GP on page 8 of the paper 
+<em class="citetitle"><a
+ href="http://www.stanford.edu/~boyd/gp_tutorial"
+ title="A Tutorial on Geometric Programming"
+ >A Tutorial on Geometric Programming</a></em>.  
+The  posynomial form of the problem is
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+ \mbox{minimize} & w^{-1} h^{-1} d^{-1} \\
+ \mbox{subject to} 
+  & (2/A_\mathrm{wall}) hw + (2/A_\mathrm{wall})hd \leq 1  \\
+  &  (1/A_\mathrm{flr}) wd \leq 1 \\
+  &  \alpha wh^{-1} \leq 1 \\
+  &  (1/\beta) hw^{-1} \leq 1 \\
+  &  \gamma wd^{-1} \leq 1 \\
+  &   (1/\delta)dw^{-1} \leq 1
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="288" HEIGHT="140" BORDER="0"
+ SRC="img126.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & w^{-1} h^{-1} d^{-1} \...
+...mma wd^{-1} \leq 1 \\
+& (1/\delta)dw^{-1} \leq 1
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+with variables <I>h</I>, <I>w</I>, <I>d</I>.
+
+<P>
+<div class="verbatim"><pre>
+from cvxopt.base import matrix, log, exp
+from cvxopt import solvers
+
+Aflr  = 1000.0
+Awall = 100.0
+alpha = 0.5
+beta  = 2.0
+gamma = 0.5
+delta = 2.0
+
+F = matrix( [[-1., 1., 1., 0., -1.,  1.,  0.,  0.], 
+             [-1., 1., 0., 1.,  1., -1.,  1., -1.], 
+             [-1., 0., 1., 1.,  0.,  0., -1.,  1.]])
+g = log( matrix( [1.0, 2/Awall, 2/Awall, 1/Aflr, alpha, 1/beta, gamma, 1/delta]) )
+K = [1, 2, 1, 1, 1, 1, 1]
+h, w, d = exp( solvers.gp(K, F, g)['x'] )
+</pre></div>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.2 Quadratic Programming"
+  href="node47.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.4 Semidefinite Programming"
+  href="s-sdpsolver.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node47.html">8.2 Quadratic Programming</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-sdpsolver.html">8.4 Semidefinite Programming</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node51.html b/doc/cvxopt/node51.html
new file mode 100644
index 0000000..3976a3c
--- /dev/null
+++ b/doc/cvxopt/node51.html
@@ -0,0 +1,558 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node52.html" />
+<link rel="prev" href="e-nlcp.html" />
+<link rel="parent" href="node45.html" />
+<link rel="next" href="node52.html" />
+<meta name='aesop' content='information' />
+<title>8.6 Exploiting Structure in LPs and SDPs</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.5 Nonlinear Convex Programming"
+  href="e-nlcp.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.7 Exploiting Structure in"
+  href="node52.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="e-nlcp.html">8.5 Nonlinear Convex Programming</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node52.html">8.7 Exploiting Structure in</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0010600000000000000000">
+8.6 Exploiting Structure in LPs and SDPs</A>
+</H1>
+The solvers <tt class="function">lp()</tt> and <tt class="function">sdp()</tt> are interfaces to
+a common function <tt class="function">conelp()</tt>, which can also be called 
+directly.  When calling <tt class="function">conelp()</tt>, the user must provide 
+functions for evaluating the constraint functions and for 
+solving the linear equations (KKT equations) that are solved in 
+each iteration of the algorithm.
+This is useful for LPs and SDPs that possess some interesting 
+structure that makes it possible to solve the KKT equations fast.
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-150' xml:id='l2h-150' class="function">conelp</tt></b>(</nobr></td>
+  <td><var>c, kktsolver</var><big>[</big><var>, Gl, hl</var><big>[</big><var>, 
+Gs, hs</var><big>[</big><var>, A, b</var><big>[</big><var>, primalstart</var><big>[</big><var>, dualstart</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves the pair of primal and dual SDPs (<A href="s-sdpsolver.html#e-sdp">8.2</A>).
+The arguments <var>c</var>, <var>hl</var>, <var>hs</var>, <var>b</var>, 
+<var>primalstart</var>, <var>dualstart</var> have the same meaning as in
+<tt class="function">sdp()</tt>.
+The arguments <var>kktsolver</var>, <var>Gl</var>, <var>Gs</var>, <var>A</var> are  
+functions that must handle the following calling sequences.
+
+<P>
+
+<UL>
+<LI><tt class="function">kktsolver</tt>(<var>d</var>, <var>R</var>) with <var>d</var> a positive 
+dense real matrix of size (<I>ml</I>,<I>1</I>), and 
+<var>R</var> a list of <I>N</I> square dense real matrices 
+<code><var>R</var>[k]</code> of order <I>m_k</I>, returns a function for 
+solving the equation 
+<P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{eqnarray*}
+A^T u_y + G_\mathrm{l}^T u_{z_\mathrm{l}} + 
+ G_\mathrm{s}^T(u_{z_\mathrm{s}}) & = & b_x \\
+ A u_x  & = & b_y \\
+G_\mathrm{l}u_x  - \mbox{\bf diag}\,(d)^{-2} u_{z_\mathrm{l}} & = & 
+ b_{z_\mathrm{l}} \\
+G_\mathrm{s}(u_x) - R^{-T} R^{-1} u_{z_\mathrm{s}} R^{-T} R^{-1}
+  & = & b_{z_\mathrm{s}}.
+\end{eqnarray*}
+ -->
+<IMG
+ WIDTH="276" HEIGHT="100" BORDER="0"
+ SRC="img148.gif"
+ ALT="\begin{eqnarray*}
+A^T u_y + G_\mathrm{l}^T u_{z_\mathrm{l}} +
+G_\mathrm{s}^T(...
+...} R^{-1} u_{z_\mathrm{s}} R^{-T} R^{-1}
+& = & b_{z_\mathrm{s}}.
+\end{eqnarray*}"></DIV>
+<BR CLEAR="ALL"><P></P>
+<BR CLEAR="ALL"><P></P>
+The function created by "<tt class="samp">f = kktsolver(d, R)</tt>" will be 
+called as "<tt class="samp">f(bx, by, bzl, bzs)</tt>".
+On entry, <var>bx</var>, <var>by</var>, <var>bzl</var> and <var>bzs</var> contain the 
+righthand side.  On exit, they should contain the solution of the KKT 
+system, with <I>uzl</I> and <I>uzs</I> scaled:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+b_x := u_x, \qquad
+  b_y := u_y, \qquad
+  b_{z_\mathrm{l}}  := \mbox{\bf diag}\,(d)^{-1} u_{z_\mathrm{l}}, \qquad
+  b_{z_\mathrm{s}}  := R^{-1} u_{z_\mathrm{s}} R^{-T}.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="494" HEIGHT="29" BORDER="0"
+ SRC="img149.gif"
+ ALT="\begin{displaymath}
+b_x := u_x, \qquad
+b_y := u_y, \qquad
+b_{z_\mathrm{l}} :=...
+...}, \qquad
+b_{z_\mathrm{s}} := R^{-1} u_{z_\mathrm{s}} R^{-T}.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+</LI>
+<LI><tt class="function">Gl</tt>(<var>x</var>, <var>y</var><big>[</big>, 
+<var>alpha</var>=1.0<big>[</big>, <var>beta</var>=0.0<big>[</big>, 
+<var>trans</var>=<code>'N'</code><big>]</big><big>]</big><big>]</big>) evaluates the matrix-vector products
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+y := \alpha G_\mathrm{l}x + \beta y \quad 
+  (\mathrm{trans} = \mathrm{'N'}), \qquad
+y := \alpha G_\mathrm{l}^T x + \beta y \quad 
+ (\mathrm{trans} = \mathrm{'T'}).
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="475" HEIGHT="28" BORDER="0"
+ SRC="img150.gif"
+ ALT="\begin{displaymath}
+y := \alpha G_\mathrm{l}x + \beta y \quad
+(\mathrm{trans} ...
+...thrm{l}^T x + \beta y \quad
+(\mathrm{trans} = \mathrm{'T'}).
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+</LI>
+<LI><tt class="function">Gs</tt>(<var>x</var>, <var>y</var><big>[</big>, 
+<var>alpha</var>=1.0<big>[</big>, <var>beta</var>=0.0<big>[</big>, 
+<var>trans</var>=<code>'N'</code><big>]</big><big>]</big><big>]</big>)
+evaluates the linear mappings
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+y := \alpha G_\mathrm{s}(x) + \beta y \quad 
+  (\mathrm{trans} = \mathrm{'N'}), \qquad
+y := \alpha G_\mathrm{s}^T(x) + \beta y \quad 
+ (\mathrm{trans} = \mathrm{'T'}).
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="501" HEIGHT="28" BORDER="0"
+ SRC="img151.gif"
+ ALT="\begin{displaymath}
+y := \alpha G_\mathrm{s}(x) + \beta y \quad
+(\mathrm{trans...
+...hrm{s}^T(x) + \beta y \quad
+(\mathrm{trans} = \mathrm{'T'}).
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+</LI>
+<LI><tt class="function">A</tt>(<var>x</var>, <var>y</var><big>[</big>, 
+<var>alpha</var>=1.0<big>[</big>, <var>beta</var>=0.0<big>[</big>, 
+<var>trans</var>=<code>'N'</code><big>]</big><big>]</big><big>]</big>)  
+evaluates the matrix vector products 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+y := \alpha Ax + \beta y \quad 
+  (\mathrm{trans} = \mathrm{'N'}), \qquad
+y := \alpha A^Tx + \beta y \quad 
+ (\mathrm{trans} = \mathrm{'T'}).
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="469" HEIGHT="28" BORDER="0"
+ SRC="img152.gif"
+ ALT="\begin{displaymath}
+y := \alpha Ax + \beta y \quad
+(\mathrm{trans} = \mathrm{'...
+...\alpha A^Tx + \beta y \quad
+(\mathrm{trans} = \mathrm{'T'}).
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+</LI>
+</UL>
+</dl>
+
+<P>
+<DL>
+<DT><STRONG>Example: 1-norm approximation</STRONG></DT>
+<DD><P>
+The optimization problem
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+ \mbox{minimize} & \|Pu-q\|_1
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="147" HEIGHT="30" BORDER="0"
+ SRC="img153.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & \Vert Pu-q\Vert _1
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+can be formulated as an LP
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+ \mbox{minimize} & {\bf 1}^T v \\
+ \mbox{subject to} & -v \preceq Pu - q  \preceq v.
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="201" HEIGHT="45" BORDER="0"
+ SRC="img154.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & {\bf 1}^T v \\
+\mbox{subject to} & -v \preceq Pu - q \preceq v.
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+By exploiting the structure in the inequalities, the cost of 
+an iteration of an interior-point method can be reduced
+to the cost of least-squares problem of the same dimensions. 
+(See section 11.8.2 in the book 
+<em class="citetitle"><a
+ href="http://www.ee.ucla.edu/~vandenbe/cvxbook"
+ title="Convex Optimization"
+ >Convex Optimization</a></em>.) 
+The code belows taks advantage of this fact.
+
+<P>
+<div class="verbatim"><pre>
+from cvxopt import base, blas, lapack, solvers
+from cvxopt.base import matrix, spmatrix, mul, div
+
+def l1(P, q):
+    """
+
+    Returns the solution u, w of the l1 approximation problem
+
+        (primal) minimize    ||P*u - q||_1       
+    
+        (dual)   maximize    q'*w
+                 subject to  P'*w = 0
+                             ||w||_infty <= 1.
+    """
+
+    m, n = P.size
+
+    # Solve equivalent LP 
+    #
+    #     minimize    [0; 1]' * [u; v]
+    #     subject to  [P, -I; -P, -I] * [u; v] <= [q; -q]
+    #
+    #     maximize    -[q; -q]' * z 
+    #     subject to  [P', -P']*z  = 0
+    #                 [-I, -I]*z + 1 = 0 
+    #                 z >= 0 
+    
+    c = matrix(n*[0.0] + m*[1.0])
+    h = matrix([q, -q])
+
+    def Fi(x, y, alpha=1.0, beta=0.0, trans='N'):    
+        if trans=='N':
+            # y := alpha * [P, -I; -P, -I] * x + beta*y
+            u = P*x[:n]
+            y[:m] = alpha * ( u - x[n:]) + beta*y[:m]
+            y[m:] = alpha * (-u - x[n:]) + beta*y[m:]
+
+        else:
+            # y := alpha * [P', -P'; -I, -I] * x + beta*y
+            y[:n] =  alpha * P.T * (x[:m] - x[m:]) + beta*y[:n]
+            y[n:] = -alpha * (x[:m] + x[m:]) + beta*y[n:]
+
+
+    def kktsolver(d, R): 
+
+        # Returns a function f(x,y,zl,zs) that solves
+        #
+        # [ 0  0  P'      -P'      ] [ x[:n] ]   [ bx[:n]  ]
+        # [ 0  0 -I       -I       ] [ x[n:] ]   [ bx[n:]  ]
+        # [ P -I -D1^{-1}  0       ] [ zl[:m]] = [ bzl[:m] ]
+        # [-P -I  0       -D2^{-1} ] [ zl[m:]]   [ bzl[m:] ]
+        #
+        # where D1 = diag(d[:m])^2, D2 = diag(d[m:])^2.
+        #
+        # On entry bx, bzl are stored in x, zl.
+        # On exit x, zl contain the solution, with zl scaled: zl./d is
+        # returned instead of zl. 
+
+        # Factor A = 4*P'*D*P where D = d1.*d2 ./(d1+d2) and
+        # d1 = d[:m].^2, d2 = d[m:].^2.
+
+        d1, d2 = d[:m]**2, d[m:]**2
+        D = div( mul(d1,d2), d1+d2 )  
+        A = P.T * spmatrix(4*D, range(m), range(m)) * P
+        lapack.potrf(A)
+
+        def f(x, y, zl, zs):
+
+            # Solve for x[:n]:
+            #
+            #    A*x[:n] = bx[:n] + P' * ( ((D1-D2)*(D1+D2)^{-1})*bx[n:]
+            #              + (2*D1*D2*(D1+D2)^{-1}) * (bzl[:m] - bzl[m:]) ).
+            x[:n] += P.T * ( mul(div(d1-d2, d1+d2), x[n:]) + mul(2*D, zl[:m]-zl[m:]) )
+            lapack.potrs(A, x)
+
+            # x[n:] := (D1+D2)^{-1} * (bx[n:] - D1*bzl[:m] - D2*bzl[m:] + (D1-D2)*P*x[:n])
+            u = P*x[:n]
+            x[n:] =  div(x[n:] - mul(d1, zl[:m]) - mul(d2, zl[m:]) + mul(d1-d2, u), d1+d2)
+
+            # z[:m] := d1[:m] .* ( P*x[:n] - x[n:] - bzl[:m])
+            # z[m:] := d2[m:] .* (-P*x[:n] - x[n:] - bzl[m:]) 
+            zl[:m] = mul(d[:m],  u-x[n:]-zl[:m])
+            zl[m:] = mul(d[m:], -u-x[n:]-zl[m:])
+
+        return f
+
+    sol = solvers.conelp(c, kktsolver, Gl=Fi, hl=h) 
+    return sol['x'][:n],  sol['zl'][m:] - sol['zl'][:m]
+</pre></div>
+
+<P>
+</DD>
+<DT><STRONG>Example: SDP with diagonal linear term</STRONG></DT>
+<DD><P>
+The SDP
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+ \mbox{minimize} & {\bf 1}^T x \\
+ \mbox{subject to} & W + \mbox{\bf diag}\,(x) \succeq 0 
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="195" HEIGHT="45" BORDER="0"
+ SRC="img155.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & {\bf 1}^T x \\
+\mbox{subject to} & W + \mbox{\bf diag}\,(x) \succeq 0
+\end{array}
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+can be solved efficiently by exploiting properties of the diag operator.
+
+<P>
+<div class="verbatim"><pre>
+from cvxopt import base, blas, lapack, solvers
+from cvxopt.base import matrix
+
+def mcsdp(w):
+    """
+    Returns solution x, z to 
+
+        (primal)  minimize    sum(x)
+                  subject to  w + diag(x) >= 0
+
+        (dual)    maximize    -tr(w*z)
+                  subject to  diag(z) = 1
+                              z >= 0.
+    """
+
+    n = w.size[0]
+
+    def Fs(x, y, alpha=1.0, beta=0.0, trans='N'):
+        """
+            y := alpha*(-diag(x)) + beta*y.   
+        """
+        if trans=='N':
+            # x is a vector; y[0] is a matrix.
+            y[0] *= beta
+            y[0][::n+1] -= alpha * x
+        else:   
+            # x[0] is a matrix; y is a vector.
+            y *= beta
+            y -= alpha * x[::n+1] 
+	 
+
+    def cngrnc(r, x, alpha=1.0):
+        """
+        Congruence transformation
+
+	    x := alpha * r'*x*r.
+
+        r and x are square 'd' matrices.  
+        """
+
+        # Scale diagonal of x by 1/2.  
+        x[::n+1] *= 0.5
+    
+        # a := tril(x)*r 
+        a = +r
+        blas.trmm(x, a, side='L')
+
+        # x := alpha*(a*r' + r*a') 
+        blas.syr2k(r, a, x, trans='T', alpha=alpha)
+
+
+    def kktsolver(d, r):
+
+        # t = r*r' as a nonsymmetric matrix.
+        t = matrix(0.0, (n,n))
+        blas.gemm(r[0], r[0], t, transB='T') 
+
+        # Cholesky factorization of tsq = t.*t.
+        tsq = t**2
+	lapack.potrf(tsq)
+
+	def f(x, y, zl, zs):
+            """
+            Solve
+                          -diag(zs)               = bx
+                -diag(x) - inv(r*r')*zs*inv(r*r') = bs.
+
+            On entry, x and zs contain bx and bs.  
+            On exit, they contain the solution, with zs scaled 
+            (inv(r)'*zs*inv(r) is returned instead of zs).
+
+            We solve 
+
+                ((r*r') .* (r*r')) * x = bx - diag(t*bs*t)
+
+            and take zs  = -r' * (diag(x) + bs) * r.
+            """
+
+            # tbst := t * zs * t = t * bs * t
+            tbst = +zs[0]
+            cngrnc(t, tbst) 
+
+            # x := x - diag(tbst) = bx - diag(r*r' * bs * r*r')
+            x -= tbst[::n+1]
+
+            # x := (t.*t)^{-1} * x = (t.*t)^{-1} * (bx - diag(t*bs*t))
+            lapack.potrs(tsq, x)
+
+            # zs := zs + diag(x) = bs + diag(x)
+            zs[0][::n+1] += x 
+
+            # zs := -r' * zs * r = -r' * (diag(x) + bs) * r 
+            cngrnc(r[0], zs[0], alpha=-1.0)
+
+	return f
+
+    c = matrix(1.0, (n,1))
+    sol = solvers.conelp(c, kktsolver, Gs=Fs, hs=[w]) 
+    return sol['x'], sol['zs'][0]
+</pre></div>
+</DD>
+</DL>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.5 Nonlinear Convex Programming"
+  href="e-nlcp.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.7 Exploiting Structure in"
+  href="node52.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="e-nlcp.html">8.5 Nonlinear Convex Programming</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node52.html">8.7 Exploiting Structure in</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node52.html b/doc/cvxopt/node52.html
new file mode 100644
index 0000000..0b50ff8
--- /dev/null
+++ b/doc/cvxopt/node52.html
@@ -0,0 +1,431 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="s-external.html" />
+<link rel="prev" href="node51.html" />
+<link rel="parent" href="node45.html" />
+<link rel="next" href="s-external.html" />
+<meta name='aesop' content='information' />
+<title>8.7 Exploiting Structure in Nonlinear Convex Programs</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.6 Exploiting Structure in"
+  href="node51.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.8 Optional Solvers"
+  href="s-external.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node51.html">8.6 Exploiting Structure in</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-external.html">8.8 Optional Solvers</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0010700000000000000000">
+8.7 Exploiting Structure in Nonlinear Convex Programs</A>
+</H1>
+The solvers <tt class="function">gp()</tt>, <tt class="function">gp()</tt> and <tt class="function">cp()</tt> are 
+interfaces to <tt class="function">nlcp()</tt>, which can also be called directly
+but requires user-provided functions for evaluating the constraint 
+and for solving the KKT equations.
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-151' xml:id='l2h-151' class="function">nlcp</tt></b>(</nobr></td>
+  <td><var>kktsolver, F</var><big>[</big><var>, G, h</var><big>[</big><var>, A, b</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves the nonlinear convex optimization problem (<A href="e-nlcp.html#e-nlcp">8.3</A>).
+
+<P>
+The meaning of the arguments <var>h</var> and <var>b</var> is the same 
+as for <tt class="function">cp()</tt>.
+The arguments <var>kktsolver</var>, <var>F</var>, <var>G</var> and <var>A</var> are  
+functions that must handle the following calling sequences.
+
+<UL>
+<LI><tt class="function">kktsolver</tt>(<var>x</var>, <var>z</var>, <var>dnl</var>, <var>dl</var>),
+returns a function for solving KKT systems
+<P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{eqnarray*}
+\sum_{k=0}^m z_k \nabla^2 f_k(x)u_x + A^T u_y + 
+ D \tilde f(x)^T u_{z_\mathrm{nl}} + 
+ G_\mathrm{l}^T u_{z_\mathrm{l}} & = & b_x \\
+ A x  & = & b_y \\
+ D\tilde f(x) x  - \mbox{\bf diag}\,(d_\mathrm{nl})^{-2} z_\mathrm{nl} & = & 
+    b_{z_\mathrm{nl}} \\
+ G_\mathrm{l}x  - \mbox{\bf diag}\,(d_\mathrm{l})^{-2} z_\mathrm{l} & = & 
+    b_{z_\mathrm{l}}
+\end{eqnarray*}
+ -->
+<IMG
+ WIDTH="402" HEIGHT="125" BORDER="0"
+ SRC="img156.gif"
+ ALT="\begin{eqnarray*}
+\sum_{k=0}^m z_k \nabla^2 f_k(x)u_x + A^T u_y +
+D \tilde f(...
+...diag}\,(d_\mathrm{l})^{-2} z_\mathrm{l} & = &
+b_{z_\mathrm{l}}
+\end{eqnarray*}"></DIV>
+<BR CLEAR="ALL"><P></P>
+<BR CLEAR="ALL"><P></P>
+where <!-- MATH
+ $\tilde f = (f_1, \ldots, f_m)$
+ -->
+<SPAN CLASS="MATH"><IMG
+ WIDTH="117" HEIGHT="38" ALIGN="MIDDLE" BORDER="0"
+ SRC="img142.gif"
+ ALT="$\tilde f = (f_1,\ldots, f_m)$"></SPAN>.
+The arguments are single-column real dense matrices. <var>x</var> is in the 
+domain of the objective and constraint functions.  <var>z</var>, <var>dnl</var>
+and <var>dl</var> are positive vectors.
+
+<P>
+The function <var>f</var> created by 
+"<tt class="samp">f = kktsolver(bx, by, bznl, bzl)</tt>" will be 
+called as "<tt class="samp">f(bx, by, bznl, bzl)</tt>".
+On entry, the arguments contain the righthand sides.  On exit, they
+should be replaced by the solution. 
+
+<P>
+</LI>
+<LI>Called with no arguments, <code><tt class="function">F</tt>()</code> returns a tuple
+(<var>m</var>, <var>x0</var>), where <var>m</var> is the number of nonlinear 
+inequality constraints) and <var>x0</var> is a point in the domain
+of <I>f</I>).
+
+<P>
+Called with one argument, <tt class="function">F(<var>x</var>)</tt> returns a tuple 
+(<var>f</var>, <var>Df</var>).  <var>f</var> is a dense matrix of size (<I>m</I>+1,1)
+with the function values of the objective function and the 
+nonlinear constraint functions at <var>x</var>.
+<var>Df</var> is a dense or sparse real matrix of size (<var>m</var>+1,<var>n</var>) 
+with <code><var>Df</var>[<var>k</var>,:]</code> equal to the transpose of the gradient
+of <I>f_k</I> at <I>x</I>.
+Alternatively, <var>Df</var> can be given as a function.  In that case
+the function call <tt class="function">Df</tt>(<var>u</var>,<var>v</var>), 
+where <var>u</var> and <var>v</var> are dense column vectors, should evaluate
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+v :=  \sum_{k=0}^m u_k \nabla f_k(x) + v.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="157" HEIGHT="53" BORDER="0"
+ SRC="img157.gif"
+ ALT="\begin{displaymath}
+v := \sum_{k=0}^m u_k \nabla f_k(x) + v.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+If <var>x</var> is not in the domain of <I>f</I>, <tt class="function">F</tt>(<var>x</var>)
+returns <code>None</code> or (<code>None</code>,<code>None</code>).
+
+<P>
+</LI>
+<LI><tt class="function">G</tt>(<var>x</var>, <var>y</var><big>[</big>, 
+<var>alpha</var>=1.0<big>[</big>, <var>beta</var>=0.0<big>[</big>, 
+<var>trans</var>=<code>'N'</code><big>]</big><big>]</big><big>]</big>) evaluates the matrix-vector products
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+y := \alpha G x + \beta y \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+y := \alpha G^T x + \beta y \quad (\mathrm{trans} = \mathrm{'T'}).
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="471" HEIGHT="28" BORDER="0"
+ SRC="img158.gif"
+ ALT="\begin{displaymath}
+y := \alpha G x + \beta y \quad (\mathrm{trans} = \mathrm{'N...
+... \alpha G^T x + \beta y \quad (\mathrm{trans} = \mathrm{'T'}).
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+Alternatively, <var>G</var> can be specified as a real sparse or dense 
+matrix. 
+
+<P>
+</LI>
+<LI><tt class="function">A</tt>(<var>x</var>, <var>y</var><big>[</big>, 
+<var>alpha</var>=1.0<big>[</big>, <var>beta</var>=0.0<big>[</big>, 
+<var>trans</var>=<code>'N'</code><big>]</big><big>]</big><big>]</big>)  evaluates the matrix vector products 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+y := \alpha Ax + \beta y \quad 
+  (\mathrm{trans} = \mathrm{'N'}), \qquad
+y := \alpha A^Tx + \beta y \quad 
+ (\mathrm{trans} = \mathrm{'T'}).
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="469" HEIGHT="28" BORDER="0"
+ SRC="img152.gif"
+ ALT="\begin{displaymath}
+y := \alpha Ax + \beta y \quad
+(\mathrm{trans} = \mathrm{'...
+...\alpha A^Tx + \beta y \quad
+(\mathrm{trans} = \mathrm{'T'}).
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+Alternatively, <var>A</var> can be specified as a real sparse or dense 
+matrix. 
+</LI>
+</UL>
+</dl>
+
+<P>
+As an example, we consider the 1-norm regularized least-squares problem
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & \|Ax - y\|_2^2 + \|x\|_1
+\end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="199" HEIGHT="30" BORDER="0"
+ SRC="img159.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & \Vert Ax - y\Vert _2^2 + \Vert x\Vert _1
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+with variable <I>x</I>.  The problem is equivalent to the quadratic 
+program
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+ \mbox{minimize} & \|Ax - y\|_2^2 + {\bf 1}^T u \\
+ \mbox{subject to} & -u \preceq x \preceq u
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="197" HEIGHT="45" BORDER="0"
+ SRC="img160.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & \Vert Ax - y\Vert _2^2...
+... u \\
+\mbox{subject to} & -u \preceq x \preceq u
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+with variables <I>x</I> and <I>u</I>.  The implementation below is 
+efficient when <I>A</I> has many more columns than rows. 
+
+<P>
+<div class="verbatim"><pre>
+from cvxopt.base import matrix, spmatrix, mul, div
+from cvxopt import blas, lapack, solvers
+
+m, n = A.size
+def F(x=None):
+    """
+    Function and gradient evaluation of
+
+	f = || A*x[:n] - y ||_2^2 +  sum(x[n:])
+    """
+
+    nvars = 2*n
+    if x is None: return 0, matrix(0.0, (nvars,1))
+    r = A*x[:n] - y
+    f = blas.nrm2(r)**2 + sum(x[n:])
+    gradf = matrix(1.0, (1,2*n))
+    blas.gemv(A, r, gradf, alpha=2.0, trans='T')  
+    return f, +gradf
+
+
+def G(u, v, alpha=1.0, beta=0.0, trans='N'):
+    """
+	v := alpha*[I, -I; -I, -I] * u + beta * v  (trans = 'N' or 'T')
+    """
+
+    v *= beta
+    v[:n] += alpha*(u[:n] - u[n:])
+    v[n:] += alpha*(-u[:n] - u[n:])
+
+h = matrix(0.0, (2*n,1))
+
+
+# Customized solver for the KKT system 
+#
+#     [  2.0*z[0]*A'*A  0    I      -I     ] [x[:n] ]     [bx[:n] ]
+#     [  0              0   -I      -I     ] [x[n:] ]  =  [bx[n:] ].
+#     [  I             -I   -D1^-1   0     ] [zl[:n]]     [bzl[:n]]
+#     [ -I             -I    0      -D2^-1 ] [zl[n:]]     [bzl[n:]]
+#
+#    
+# We first eliminate zl and x[n:]:
+#
+#     ( 2*z[0]*A'*A + 4*D1*D2*(D1+D2)^-1 ) * x[:n] = bx[:n] - (D2-D1)*(D1+D2)^-1 * bx[n:] 
+#         + D1 * ( I + (D2-D1)*(D1+D2)^-1 ) * bzl[:n] - D2 * ( I - (D2-D1)*(D1+D2)^-1 ) * bzl[n:]           
+#
+#     x[n:] = (D1+D2)^-1 * ( bx[n:] - D1*bzl[:n]  - D2*bzl[n:] ) - (D2-D1)*(D1+D2)^-1 * x[:n]         
+#     zl[:n] = D1 * ( x[:n] - x[n:] - bzl[:n] )
+#     zl[n:] = D2 * (-x[:n] - x[n:] - bzl[n:] ).
+#
+# The first equation has the form
+#
+#     (z[0]*A'*A + D)*x[:n]  =  rhs
+#
+# and is equivalent to
+#
+#     [ D    A'       ] [ x:n] ]  = [ rhs ]
+#     [ A   -1/z[0]*I ] [ v    ]    [ 0   ].
+#
+# It can be solved as 
+#
+#     ( A*D^-1*A' + 1/z[0]*I ) * v = A * D^-1 * rhs
+#     x[:n] = D^-1 * ( rhs - A'*v ).
+
+S = matrix(0.0, (m,m))
+Asc = matrix(0.0, (m,n))
+v = matrix(0.0, (m,1))
+def kktsolver(x, z, dnl, dl):
+
+    # Factor 
+    #
+    #     S = A*D^-1*A' + 1/z[0]*I 
+    #
+    # where D = 2*D1*D2*(D1+D2)^-1, D1 = dl[:n]**2, D2 = dl[n:]**2.
+
+    d1, d2 = dl[:n]**2, dl[n:]**2    # d1 = diag(D1), d2 = diag(D2)
+    # ds is square root of diagonal of D
+    ds = sqrt(2.0) * div( mul(dl[:n], dl[n:]), sqrt(d1+d2) )
+    d3 =  div(d2 - d1, d1 + d2)
+ 
+    # Asc = A*diag(d)^-1/2
+    Asc = A * spmatrix( ds**-1, range(n), range(n))
+
+    # S = 1/z[0]*I + A * D^-1 * A'
+    blas.syrk(Asc, S)
+    S[::m+1] += 1.0 / z[0] 
+    lapack.potrf(S)
+
+    def g(x, y, znl, zl):
+
+        x[:n] = 0.5 * ( x[:n] - mul(d3, x[n:]) + mul(d1, zl[:n] + mul(d3, zl[:n])) - mul(d2, zl[n:] - mul(d3, zl[n:])) )
+        x[:n] = div( x[:n], ds) 
+
+        # Solve
+        #
+        #     S * v = 0.5 * A * D^-1 * ( bx[:n] - (D2-D1)*(D1+D2)^-1 * bx[n:] 
+        #             + D1 * ( I + (D2-D1)*(D1+D2)^-1 ) * bzl[:n] - D2 * ( I - (D2-D1)*(D1+D2)^-1 ) * bzl[n:] )
+	    
+        blas.gemv(Asc, x, v)
+        lapack.potrs(S, v)
+	
+        # x[:n] = D^-1 * ( rhs - A'*v ).
+        blas.gemv(Asc, v, x, alpha=-1.0, beta=1.0, trans='T')
+        x[:n] = div(x[:n], ds)
+
+        # x[n:] = (D1+D2)^-1 * ( bx[n:] - D1*bzl[:n]  - D2*bzl[n:] ) - (D2-D1)*(D1+D2)^-1 * x[:n]         
+        x[n:] = div( x[n:] - mul(d1, zl[:n]) - mul(d2, zl[n:]), d1+d2 ) - mul( d3, x[:n] )
+	    
+        # zl[:n] = D1 * (  x[:n] - x[n:] - bzl[:n] )
+        # zl[n:] = D2 * ( -x[:n] - x[n:] - bzl[n:] ).
+        zl[:n] = mul( d1,  x[:n] - x[n:] - zl[:n] ) 
+        zl[n:] = mul( d2, -x[:n] - x[n:] - zl[n:] ) 
+
+    return g
+
+x = solvers.nlcp(kktsolver, F, G, h)['x'][:n]
+</pre></div>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.6 Exploiting Structure in"
+  href="node51.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.8 Optional Solvers"
+  href="s-external.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node51.html">8.6 Exploiting Structure in</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-external.html">8.8 Optional Solvers</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node55.html b/doc/cvxopt/node55.html
new file mode 100644
index 0000000..e45591d
--- /dev/null
+++ b/doc/cvxopt/node55.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node61.html" />
+<link rel="prev" href="node45.html" />
+<link rel="parent" href="cvxopt.html" />
+<link rel="next" href="s-variables.html" />
+<meta name='aesop' content='information' />
+<title>9. Modeling (cvxopt.modeling)</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.9 Algorithm Parameters"
+  href="s-parameters.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="9.1 Variables"
+  href="s-variables.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-parameters.html">8.9 Algorithm Parameters</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-variables.html">9.1 Variables</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0011000000000000000000"></A>
+<A NAME="chap:modeling"></A>
+<BR>
+9. Modeling (<tt class="module">cvxopt.modeling</tt>)
+</H1>
+The module <tt class="module">cvxopt.modeling</tt> can be used to specify and solve 
+optimization problems  with convex piecewise-linear objective and 
+constraint functions.
+
+<P>
+To specify an optimization problem one first defines 
+the optimization variables (see section <A href="s-variables.html#s-variables">9.1</A>),
+and then defines the objective and constraint functions 
+using linear operations (vector addition and subtraction,
+matrix-vector multiplication, indexing and slicing)
+and nested evaluations of <tt class="function">max()</tt>, <tt class="function">min()</tt>, 
+<tt class="function">abs()</tt> and <tt class="function">sum()</tt> (see section <A href="s-functions.html#s-functions">9.2</A>).
+
+<P>
+
+<p><br /></p><hr class='online-navigation' />
+<div class='online-navigation'>
+<!--Table of Child-Links-->
+<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></a>
+
+<UL CLASS="ChildLinks">
+<LI><A href="s-variables.html">9.1 Variables</a>
+<LI><A href="s-functions.html">9.2 Functions</a>
+<LI><A href="node58.html">9.3 Constraints</a>
+<LI><A href="s-lp.html">9.4 Optimization Problems</a>
+<LI><A href="node60.html">9.5 Examples</a>
+</ul>
+<!--End of Table of Child-Links-->
+</div>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.9 Algorithm Parameters"
+  href="s-parameters.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="9.1 Variables"
+  href="s-variables.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-parameters.html">8.9 Algorithm Parameters</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-variables.html">9.1 Variables</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node58.html b/doc/cvxopt/node58.html
new file mode 100644
index 0000000..a2526f9
--- /dev/null
+++ b/doc/cvxopt/node58.html
@@ -0,0 +1,209 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="s-lp.html" />
+<link rel="prev" href="s-functions.html" />
+<link rel="parent" href="node55.html" />
+<link rel="next" href="s-lp.html" />
+<meta name='aesop' content='information' />
+<title>9.3 Constraints</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="9.2 Functions"
+  href="s-functions.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="9. Modeling (cvxopt.modeling)"
+  href="node55.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="9.4 Optimization Problems"
+  href="s-lp.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-functions.html">9.2 Functions</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node55.html">9. Modeling (cvxopt.modeling)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-lp.html">9.4 Optimization Problems</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0011300000000000000000">
+9.3 Constraints</A>
+</H1>
+Linear equality and inequality constraints of the form
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+f(x_1,\ldots,x_n) = 0, \qquad f(x_1,\ldots,x_n) \preceq  0,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="283" HEIGHT="28" BORDER="0"
+ SRC="img174.gif"
+ ALT="\begin{displaymath}
+f(x_1,\ldots,x_n) = 0, \qquad f(x_1,\ldots,x_n) \preceq 0,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <SPAN CLASS="MATH"><IMG
+ WIDTH="13" HEIGHT="30" ALIGN="MIDDLE" BORDER="0"
+ SRC="img175.gif"
+ ALT="$f$"></SPAN> is a convex function, are represented by constraint
+objects.  Equality constraints are created by expressions of the form 
+<BLOCKQUOTE>
+<code><var>f1</var> == <var>f2</var></code>. 
+
+</BLOCKQUOTE>
+Here <var>f1</var> and <var>f2</var> can be any objects for which the 
+difference <code><var>f1</var>-<var>f2</var></code> yields an affine function.  
+Inequality constraints are created by expressions of the form 
+<BLOCKQUOTE>
+<code><var>f1</var> <= <var>f2</var></code>,         <code><var>f2</var> >= <var>f1</var></code>,
+
+</BLOCKQUOTE>
+where <var>f1</var> and <var>f2</var> can be any objects for which the difference 
+<code><var>f1</var>-<var>f2</var></code> yields a convex piecewise-linear function.  
+The comparison operators first convert the expressions to 
+<code><var>f1</var>-<var>f2</var> == 0</code>, resp. <code><var>f1</var>-<var>f2</var> <= 0</code>,
+and then return a new constraint object with constraint 
+function
+<code><var>f1</var>-<var>f2</var></code>.
+
+<P>
+In the following example we create three constraints
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+0 \preceq x \preceq {\bf 1}, \qquad {\bf 1}^T x = 2,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="168" HEIGHT="27" BORDER="0"
+ SRC="img176.gif"
+ ALT="\begin{displaymath}
+0 \preceq x \preceq {\bf 1}, \qquad {\bf 1}^T x = 2,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+for a variable of length 5.
+<div class="verbatim"><pre>
+>>> x = variable(5,'x')
+>>> c1 = (x <= 1)
+>>> c2 = (x >= 0)
+>>> c3 = (sum(x) == 2)
+</pre></div>
+
+<P>
+The built-in fucntion <tt class="function">len()</tt> returns the dimension of the
+constraint function.
+
+<P>
+Constraints have four public attributes.
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-159' xml:id='l2h-159' class="method">type</tt></b>(</nobr></td>
+  <td><var></var>)</td></tr></table></dt>
+<dd>
+Returns <code>'='</code> if the constraint is an equality constraint,
+and <code>'<'</code> if the constraint is an inequality constraint.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-160' xml:id='l2h-160' class="method">value</tt></b>(</nobr></td>
+  <td><var></var>)</td></tr></table></dt>
+<dd>
+Returns the value of the constraint function.  
+</dl>
+
+<P>
+<dl><dt><b><tt id='l2h-161' xml:id='l2h-161' class="member">multiplier</tt></b></dt>
+<dd>
+For a constraint <var>c</var>, <var>c</var>.<tt class="member">multiplier</tt> is a 
+variable object of dimension <code>len(<var>c</var>)</code>.   
+It is used to represent the Lagrange multiplier or dual variable 
+associated with the constraint.
+Its value is initialized as <code>None</code>, and can be modified
+by making an assignment to <var>c</var>.<tt class="member">multiplier</tt>.<tt class="member">value</tt>.
+</dl>
+
+<P>
+<dl><dt><b><tt id='l2h-162' xml:id='l2h-162' class="member">name</tt></b></dt>
+<dd>
+The name of the constraint.  Changing the name of a constraint
+also changes the name of the multiplier of <var>c</var>.
+For example, the command <code><var>c</var>.<tt class="member">name</tt> = 'newname'</code> also 
+changes
+<var>c</var>.<tt class="member">multiplier</tt>.<tt class="member">name</tt> to <code>'newname_mul'</code>.
+</dl>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="9.2 Functions"
+  href="s-functions.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="9. Modeling (cvxopt.modeling)"
+  href="node55.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="9.4 Optimization Problems"
+  href="s-lp.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-functions.html">9.2 Functions</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node55.html">9. Modeling (cvxopt.modeling)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-lp.html">9.4 Optimization Problems</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node6.html b/doc/cvxopt/node6.html
new file mode 100644
index 0000000..8d90cff
--- /dev/null
+++ b/doc/cvxopt/node6.html
@@ -0,0 +1,200 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="s-arithmetic.html" />
+<link rel="prev" href="s-creating-matrices.html" />
+<link rel="parent" href="node4.html" />
+<link rel="next" href="s-arithmetic.html" />
+<meta name='aesop' content='information' />
+<title>2.2 Attributes and Methods</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.1 Creating Matrices"
+  href="s-creating-matrices.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.3 Arithmetic Operations"
+  href="s-arithmetic.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-creating-matrices.html">2.1 Creating Matrices</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-arithmetic.html">2.3 Arithmetic Operations</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION004200000000000000000">
+2.2 Attributes and Methods</A>
+</H1> 
+A <tt class="class">matrix</tt> has the following attributes.
+
+<P>
+<dl><dt><b><tt id='l2h-2' xml:id='l2h-2' class="member">size</tt></b></dt>
+<dd>
+A tuple with the dimensions of the matrix. This is a read-only 
+attribute; operations that change the size of a matrix are not 
+permitted.
+</dl> 
+
+<P>
+<dl><dt><b><tt id='l2h-3' xml:id='l2h-3' class="member">typecode</tt></b></dt>
+<dd>
+A <tt class="ctype">char</tt>, either <code>'i'</code>, <code>'d'</code>, or <code>'z'</code>, for integer, real
+and complex matrices, respectively.  A read-only attribute.
+</dl> 
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-4' xml:id='l2h-4' class="method">trans</tt></b>(</nobr></td>
+  <td><var></var>)</td></tr></table></dt>
+<dd>
+Returns the transpose of the matrix as a new matrix.
+One can also use <code>A.T</code> instead of <code>A.trans()</code>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-5' xml:id='l2h-5' class="method">ctrans</tt></b>(</nobr></td>
+  <td><var></var>)</td></tr></table></dt>
+<dd>
+Returns the conjugate transpose of the matrix as a new matrix.
+One can also use <code>A.H</code> instead of <code>A.ctrans()</code>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-6' xml:id='l2h-6' class="method">real</tt></b>(</nobr></td>
+  <td><var></var>)</td></tr></table></dt>
+<dd>
+For complex matrices, returns the real part as a real matrix.
+For integer and real matrices, returns a copy of the matrix.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-7' xml:id='l2h-7' class="method">imag</tt></b>(</nobr></td>
+  <td><var></var>)</td></tr></table></dt>
+<dd>
+For complex matrices, returns the imaginary part as a real matrix.
+For integer and real matrices, returns an integer or real zero matrix.
+</dl>
+
+<P>
+<dl><dt><b><tt id='l2h-8' xml:id='l2h-8' class="member">__array_struct__</tt></b></dt>
+<dd>
+A PyCObject implementing the NumPy array interface  
+(see section <A href="s-array-interface.html#s-array-interface">2.8</A> for details).
+</dl> 
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-9' xml:id='l2h-9' class="method">tofile</tt></b>(</nobr></td>
+  <td><var>f</var>)</td></tr></table></dt>
+<dd>
+Writes the elements of the matrix in column-major order to a binary 
+file <var>f</var>. 
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-10' xml:id='l2h-10' class="method">fromfile</tt></b>(</nobr></td>
+  <td><var>f</var>)</td></tr></table></dt>
+<dd>
+Reads the contents of a binary file <var>f</var> into the matrix object.
+</dl>
+
+<P>
+The last two methods are illustrated in the following example.
+<div class="verbatim"><pre>
+>>> from cvxopt.base import matrix
+>>> A = matrix([[1.,2.,3.], [4.,5.,6.]])  
+>>> print A
+  1.0000e+00  4.0000e+00
+  2.0000e+00  5.0000e+00
+  3.0000e+00  6.0000e+00
+>>> f = open('mat.bin','w')
+>>> A.tofile(f)
+>>> f.close()
+>>> B = matrix(0.0, (2,3))
+>>> f = open('mat.bin','r')
+>>> B.fromfile(f)
+>>> f.close()
+>>> print B
+  1.0000e+00  3.0000e+00  5.0000e+00
+  2.0000e+00  4.0000e+00  6.0000e+00
+</pre></div>
+
+<P>
+Matrices can also be written to or read from files using the 
+<tt class="function">dump()</tt> and <tt class="function">load()</tt> functions in the 
+<tt class="module">pickle</tt> module. 
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.1 Creating Matrices"
+  href="s-creating-matrices.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.3 Arithmetic Operations"
+  href="s-arithmetic.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-creating-matrices.html">2.1 Creating Matrices</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-arithmetic.html">2.3 Arithmetic Operations</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node60.html b/doc/cvxopt/node60.html
new file mode 100644
index 0000000..17a440d
--- /dev/null
+++ b/doc/cvxopt/node60.html
@@ -0,0 +1,358 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="prev" href="s-lp.html" />
+<link rel="parent" href="node55.html" />
+<link rel="next" href="node61.html" />
+<meta name='aesop' content='information' />
+<title>9.5 Examples</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="9.4 Optimization Problems"
+  href="s-lp.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="9. Modeling (cvxopt.modeling)"
+  href="node55.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="10. C API"
+  href="node61.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-lp.html">9.4 Optimization Problems</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node55.html">9. Modeling (cvxopt.modeling)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node61.html">10. C API</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0011500000000000000000">
+9.5 Examples</A>
+</H1>
+
+<P>
+<DL>
+<DT><STRONG>Norm and Penalty Approximation</STRONG></DT>
+<DD><P>
+In the first example we solve the norm approximation problems
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll} 
+ \mbox{minimize} & \|Ax - b\|_\infty,
+ \end{array} \qquad
+ \begin{array}{ll} 
+ \mbox{minimize} & \|Ax - b\|_1
+ \end{array},
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="364" HEIGHT="30" BORDER="0"
+ SRC="img178.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & \Vert Ax - b\Vert _\i...
+...ay}{ll}
+\mbox{minimize} & \Vert Ax - b\Vert _1
+\end{array},
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+and the penalty approximation problem
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll} 
+ \mbox{minimize} & \sum_k \phi((Ax-b)_k), 
+ \end{array} \qquad
+ \phi(u) = \left\{\begin{array}{ll}
+    0 & |u| \leq 3/4 \\
+   |u|-3/4  & 3/4 \leq |u| \leq 3/2 \\
+   2|u|-9/4  & |u| \geq 3/2.\end{array}\right.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="503" HEIGHT="64" BORDER="0"
+ SRC="img179.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & \sum_k \phi((Ax-b)_k)...
+...
+2\vert u\vert-9/4 & \vert u\vert \geq 3/2.\end{array}\right.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+We use randomly generated data.
+
+<P>
+The code uses the <a class="ulink" href="http://matplotlib.sourceforge.net"
+  >Matplotlib</a>
+package for plotting the histograms of the residual vectors for the
+two solutions.  It generates the figure shown below.
+
+<P>
+<div class="verbatim"><pre>
+from cvxopt.random import normal
+from cvxopt.modeling import variable, op, max, sum
+import pylab
+
+m, n = 500, 100
+A = normal(m,n)
+b = normal(m)
+
+x1 = variable(n)
+op(max(abs(A*x1-b))).solve()
+
+x2 = variable(n)
+op(sum(abs(A*x2-b))).solve()
+
+x3 = variable(n)
+op(sum(max(0, abs(A*x3-b)-0.75, 2*abs(A*x3-b)-2.25))).solve()
+
+pylab.subplot(311)
+pylab.hist(A*x1.value-b, m/5)
+pylab.subplot(312)
+pylab.hist(A*x2.value-b, m/5)
+pylab.subplot(313)
+pylab.hist(A*x3.value-b, m/5)
+pylab.show()
+</pre></div>
+
+<P>
+<DIV ALIGN="CENTER">
+<IMG
+ WIDTH="556" HEIGHT="418" ALIGN="BOTTOM" BORDER="0"
+ SRC="img180.gif"
+ ALT="\includegraphics[width=\linewidth]{figures/normappr.eps}">
+
+</DIV>
+
+<P>
+Equivalently, we can formulate and solve the problems as LPs.
+<div class="verbatim"><pre>
+t = variable()
+x1 = variable(n)
+op(t, [-t <= A*x1-b, A*x1-b<=t]).solve()
+
+u = variable(m)
+x2 = variable(n)
+op(sum(u), [-u <= A*x2+b, A*x2+b <= u]).solve()
+
+v = variable(m)
+x3 = variable(n)
+op(sum(v), [v >= 0, v >= A*x3+b-0.75, v >= -(A*x3+b)-0.75, v >= 2*(A*x3-b)-2.25, v >= -2*(A*x3-b)-2.25]).solve()
+</pre></div>
+
+<P>
+</DD>
+<DT><STRONG>Robust Linear Programming</STRONG></DT>
+<DD>The robust LP
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+ \mbox{minimize} & c^T x \\
+ \mbox{subject to} & \sup_{\|v\|_\infty \leq 1} 
+    (a_i+v)^T x \leq b_i, \qquad i=1,\ldots,m
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="379" HEIGHT="46" BORDER="0"
+ SRC="img181.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & c^T x \\
+\mbox{subje...
+...leq 1}
+(a_i+v)^T x \leq b_i, \qquad i=1,\ldots,m
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+is equivalent to the problem
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+ \mbox{minimize} & c^Tx \\
+ \mbox{subject to} & a_i^Tx + \|x\|_1 \leq b_i, \qquad i=1,\ldots,m.
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="315" HEIGHT="45" BORDER="0"
+ SRC="img182.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & c^Tx \\
+\mbox{subjec...
+...x + \Vert x\Vert _1 \leq b_i, \qquad i=1,\ldots,m.
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+The following code computes the solution and the solution of
+the equivalent LP
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+ \mbox{minimize} & c^Tx \\
+ \mbox{subject to} & a_i^Tx + {\bf 1}^Ty \leq b_i, \qquad i=1,\ldots,m \\
+& -y \preceq x \preceq y
+\end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="308" HEIGHT="64" BORDER="0"
+ SRC="img183.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & c^Tx \\
+\mbox{subjec...
+...i, \qquad i=1,\ldots,m \\
+& -y \preceq x \preceq y
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+for randomly generated data.
+
+<P>
+<div class="verbatim"><pre>
+from cvxopt.random import normal, uniform
+from cvxopt.modeling import variable, dot, op, sum 
+from cvxopt.blas import nrm2
+
+m, n = 500, 100
+A = normal(m,n)
+b = uniform(m)
+c = normal(n)
+
+x = variable(n)
+op(dot(c,x), A*x+sum(abs(x)) <= b).solve()
+
+x2 = variable(n)
+y = variable(n)
+op(dot(c,x2), [A*x2+sum(y) <= b, -y <= x2, x2 <= y]).solve()
+</pre></div>
+
+<P>
+</DD>
+<DT><STRONG>1-Norm Support Vector Classifier</STRONG></DT>
+<DD><P>
+The following problem arises in classification:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & \|x\|_1 + {\bf 1}^Tu \\
+\mbox{subject to} & Ax \succeq {\bf 1}-u \\
+& u \succeq 0.
+\end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="157" HEIGHT="64" BORDER="0"
+ SRC="img184.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & \Vert x\Vert _1 + {\bf 1...
+...bject to} & Ax \succeq {\bf 1}-u \\
+& u \succeq 0.
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+It can be solved as follows.
+<div class="verbatim"><pre>
+x = variable(A.size[1],'x')
+u = variable(A.size[0],'u')
+op(sum(abs(x)) + sum(u), [A*x >= 1-u, u >= 0]).solve()
+</pre></div>
+An equivalent unconstrained formulation is
+<div class="verbatim"><pre>
+x = variable(A.size[1],'x')
+op(sum(abs(x)) + sum(max(0,1-A*x))).solve()
+</pre></div>
+</DD>
+</DL>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="9.4 Optimization Problems"
+  href="s-lp.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="9. Modeling (cvxopt.modeling)"
+  href="node55.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="10. C API"
+  href="node61.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-lp.html">9.4 Optimization Problems</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node55.html">9. Modeling (cvxopt.modeling)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node61.html">10. C API</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node61.html b/doc/cvxopt/node61.html
new file mode 100644
index 0000000..4ad04f4
--- /dev/null
+++ b/doc/cvxopt/node61.html
@@ -0,0 +1,135 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="genindex.html" />
+<link rel="prev" href="node55.html" />
+<link rel="parent" href="cvxopt.html" />
+<link rel="next" href="node62.html" />
+<meta name='aesop' content='information' />
+<title>10. C API</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="9.5 Examples"
+  href="node60.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="10.1 Dense Matrices"
+  href="node62.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node60.html">9.5 Examples</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node62.html">10.1 Dense Matrices</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0012000000000000000000"></A><A NAME="chap:c-api"></A>
+<BR>
+10. C API
+</H1>
+The API can be used to extend CVXOPT with interfaces to 
+external C routines and libraries. 
+A C program that creates or manipulates the dense or sparse matrix
+objects defined in <tt class="module">cvxopt.base</tt> must include the 
+<span class="file">cvxopt.h</span> header file in the <span class="file">src</span> directory of the 
+distribution.
+
+<P>
+Before the C-API can be used in an extension module it must be
+initialized by calling the macro <tt class="cfunction">import_cvxopt</tt>. 
+As an example
+we show the module initialization from the <tt class="module">cvxopt.blas</tt> module,
+which itself uses the API:
+<div class="verbatim"><pre>
+PyMODINIT_FUNC initblas(void)
+{
+  PyObject *m;
+
+  m = Py_InitModule3("cvxopt.blas", blas_functions, blas__doc__);
+
+  if (import_cvxopt() < 0)
+    return;
+}
+</pre></div>
+
+<P>
+
+<p><br /></p><hr class='online-navigation' />
+<div class='online-navigation'>
+<!--Table of Child-Links-->
+<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></a>
+
+<UL CLASS="ChildLinks">
+<LI><A href="node62.html">10.1 Dense Matrices</a>
+<LI><A href="node63.html">10.2 Sparse Matrices</a>
+</ul>
+<!--End of Table of Child-Links-->
+</div>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="9.5 Examples"
+  href="node60.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="CVXOPT: A Python Package"
+  href="cvxopt.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="10.1 Dense Matrices"
+  href="node62.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node60.html">9.5 Examples</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="cvxopt.html">CVXOPT: A Python Package</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node62.html">10.1 Dense Matrices</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node62.html b/doc/cvxopt/node62.html
new file mode 100644
index 0000000..2d01ed8
--- /dev/null
+++ b/doc/cvxopt/node62.html
@@ -0,0 +1,162 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node63.html" />
+<link rel="prev" href="node61.html" />
+<link rel="parent" href="node61.html" />
+<link rel="next" href="node63.html" />
+<meta name='aesop' content='information' />
+<title>10.1 Dense Matrices</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="10. C API"
+  href="node61.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="10. C API"
+  href="node61.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="10.2 Sparse Matrices"
+  href="node63.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node61.html">10. C API</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node61.html">10. C API</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node63.html">10.2 Sparse Matrices</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0012100000000000000000">
+10.1 Dense Matrices</A>
+</H1>
+As can be seen from the header file <span class="file">cvxopt.h</span>, a <tt class="class">matrix</tt> is
+essentially a  structure with four fields.
+The fields <tt class="cdata">nrows</tt> and <tt class="cdata">ncols</tt> are two integers that 
+specify the dimensions.
+The <tt class="cdata">id</tt> field controls the type of the matrix and can have 
+values <tt class="constant">DOUBLE</tt>, <tt class="constant">INT</tt> and <tt class="constant">COMPLEX</tt>. 
+The <tt class="cdata">buffer</tt> field is an array that contains the matrix elements 
+stored contiguously in column-major order. 
+
+<P>
+The following C functions can be used to create matrices.
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline"><td><nobr>matrix* <b><tt id='l2h-174' xml:id='l2h-174' class="cfunction">Matrix_New</tt></b>(</nobr></td><td>int <var>nrows</var>, int <var>ncols</var>, int <var>id</var>)</td></tr></table></dt>
+<dd>
+Returns a <tt class="class">matrix</tt> object of type <var>id</var> with <var>nrows</var> rows
+and <var>ncols</var> columns. The elements of the matrix are uninitialized.
+</dd></dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline"><td><nobr>matrix* <b><tt id='l2h-175' xml:id='l2h-175' class="cfunction">Matrix_NewFromMatrix</tt></b>(</nobr></td><td>matrix *<var>src</var>, int <var>id</var>)</td></tr></table></dt>
+<dd>
+Returns a copy of the matrix <var>src</var> converted to type <var>id</var>. 
+The following type conversions are allowed: <code>'i'</code> to <code>'d'</code>,
+<code>'i'</code> to <code>'z'</code> and <code>'d'</code>  to <code>'z'</code>.
+</dd></dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline"><td><nobr>matrix* <b><tt id='l2h-176' xml:id='l2h-176' class="cfunction">Matrix_NewFromSequence</tt></b>(</nobr></td><td>PyListObject *<var>x</var>, int <var>id</var>)</td></tr></table></dt>
+<dd>
+Creates a matrix of type <var>id</var> from the Python sequence type <var>x</var>. The
+returned matrix has size <code>(len(<var>x</var>),1)</code>.  
+The size can be changed by modifying the <tt class="member">nrows</tt> and 
+<tt class="member">ncols</tt> fields of the returned matrix.
+</dd></dl>
+
+<P>
+To illustrate the creation and manipulation of dense matrices (as well
+as the Python C API), we show the code for the <tt class="function">uniform()</tt> 
+function from <tt class="module">cvxopt.random</tt> described in 
+section <A href="s-random.html#s-random">2.7</A>.
+<div class="verbatim"><pre>
+PyObject * uniform(PyObject *self, PyObject *args, PyObject *kwrds) 
+{
+  matrix *obj;
+  int i, nrows, ncols = 1;
+  double a = 0, b = 1;
+  char *kwlist[] = {"nrows", "ncols", "a", "b", NULL};
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "i|idd", kwlist, 
+          &nrows, &ncols, &a, &b)) return NULL;
+  
+  if ((nrows<0) || (ncols<0)) {
+    PyErr_SetString(PyExc_TypeError, "dimensions must be non-negative");
+    return NULL;
+  }
+  
+  if (!(obj = Matrix_New(nrows, ncols, DOUBLE)))
+    return PyErr_NoMemory();
+  
+  for (i = 0; i < nrows*ncols; i++)
+    MAT_BUFD(obj)[i] = Uniform(a,b);
+  
+  return (PyObject *)obj;
+}
+</pre></div>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="10. C API"
+  href="node61.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="10. C API"
+  href="node61.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="10.2 Sparse Matrices"
+  href="node63.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node61.html">10. C API</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node61.html">10. C API</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node63.html">10.2 Sparse Matrices</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/node63.html b/doc/cvxopt/node63.html
new file mode 100644
index 0000000..dbcabb3
--- /dev/null
+++ b/doc/cvxopt/node63.html
@@ -0,0 +1,241 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="prev" href="node62.html" />
+<link rel="parent" href="node61.html" />
+<link rel="next" href="genindex.html" />
+<meta name='aesop' content='information' />
+<title>10.2 Sparse Matrices</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="10.1 Dense Matrices"
+  href="node62.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="10. C API"
+  href="node61.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="Index"
+  href="genindex.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node62.html">10.1 Dense Matrices</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node61.html">10. C API</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="genindex.html">Index</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0012200000000000000000">
+10.2 Sparse Matrices</A>
+</H1>
+Sparse matrices are stored in compressed column storage (CCS) 
+format.   For a general  <var>nrows</var> by <var>ncols</var> sparse matrix with 
+<var>nnz</var> nonzero entries this means the following.  The sparsity
+pattern and the nonzero values are stored in three fields:
+<DL>
+<DT><STRONG>values:</STRONG></DT>
+<DD>A <code>'d'</code> or <code>'z'</code> matrix of size <code>(<var>nnz</var>,1)</code> 
+ with the nonzero entries of the matrix stored columnwise.  
+</DD>
+<DT><STRONG>rowind:</STRONG></DT>
+<DD>An array of integers of length <var>nnz</var> containing the
+row indices of the nonzero entries, stored in the same order as 
+<var>values</var>.
+</DD>
+<DT><STRONG>colptr:</STRONG></DT>
+<DD>An array of integers of length <code><var>ncols</var>+1</code> with
+for each column of the matrix the index of the first element in 
+<var>values</var> from that column.  More precisely, 
+<code><var>colptr</var>[0]</code> is <code>0</code>, and for 
+<code><var>k</var> = 0, 1, ..., <var>ncols</var>-1</code>,
+<code><var>colptr</var>[k+1]</code> is equal to <code><var>colptr</var>[k]</code> plus the 
+number of nonzeros in column <var>k</var> of the matrix.
+Thus, <code><var>colptr</var>[<var>ncols</var>]</code> is equal to <var>nnz</var>, the 
+number of nonzero entries.
+</DD>
+</DL>
+
+<P>
+For example, for the matrix
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A=\left [\begin{array}{cccc}
+    1 & 0 & 0 & 5\\
+    2 & 0 & 4 & 0\\
+    0 & 0 & 0 & 6\\
+    3 & 0 & 0 & 0
+\end{array}\right]
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="144" HEIGHT="83" BORDER="0"
+ SRC="img185.gif"
+ ALT="\begin{displaymath}
+A=\left [\begin{array}{cccc}
+1 & 0 & 0 & 5\\
+2 & 0 & 4 & 0\\
+0 & 0 & 0 & 6\\
+3 & 0 & 0 & 0
+\end{array}\right]
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+the elements of <var>values</var>, <var>rowind</var> and <var>colptr</var> are:
+<BLOCKQUOTE>
+<var>values</var>: 1.0, 2.0, 3.0, 4.0, 5.0, 6.0,         
+  <var>rowind</var>: 0, 1,3, 1, 0, 2,         
+  <var>colptr</var>: 0, 3, 3, 4, 6.
+
+</BLOCKQUOTE>
+It is crucial that for each column the row indices in <var>rowind</var> are
+sorted; the equivalent representation 
+<BLOCKQUOTE>
+<var>values</var>: 3.0, 2.0, 1.0, 4.0, 5.0, 6.0,         
+  <var>rowind</var>: 3, 1, 0, 1, 0, 2,         
+  <var>colptr</var>: 0, 3, 3, 4, 6
+
+</BLOCKQUOTE>
+is not allowed (and will likely cause the program to crash).
+
+<P>
+The <tt class="cdata">nzmax</tt> field specifies the number of non-zero elements the
+matrix can store.  It is equal to the length of <var>rowind</var> and 
+<var>values</var>; this number can be larger that 
+<code><var>colptr</var>[<var>nrows</var>]</code>, but never less. 
+This field makes it possible to preallocate a certain amount of 
+memory to avoid reallocations if the matrix is constructed
+sequentially by filling in elements. 
+In general the <var>nzmax</var> field can safely be ignored, however, since 
+it will always be adjusted automatically as the number of non-zero 
+elements grows.
+
+<P>
+The <tt class="cdata">id</tt> field controls the type of the matrix and can have 
+values <tt class="constant">DOUBLE</tt> and <tt class="constant">COMPLEX</tt>. 
+
+<P>
+Sparse matrices are created using the following functions from the API. 
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline"><td><nobr>spmatrix* <b><tt id='l2h-177' xml:id='l2h-177' class="cfunction">SpMatrix_New</tt></b>(</nobr></td><td>int <var>nrows</var>, int <var>ncols</var>, int
+    <var>nzmax</var>, int <var>id</var>)</td></tr></table></dt>
+<dd> 
+  Returns a sparse zero matrix with <var>nrows</var> rows and
+  <var>ncols</var> columns. <var>nzmax</var> is the number of elements that will
+  be allocated (the length of the <var>values</var> and <var>rowind</var>
+  fields).  
+</dd></dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline"><td><nobr>spmatrix* <b><tt id='l2h-178' xml:id='l2h-178' class="cfunction">SpMatrix_NewFromMatrix</tt></b>(</nobr></td><td>spmatrix *<var>src</var>, int
+    <var>id</var>)</td></tr></table></dt>
+<dd>
+  Returns a copy the sparse matrix <var>src</var>. 
+</dd></dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline"><td><nobr>spmatrix* <b><tt id='l2h-179' xml:id='l2h-179' class="cfunction">SpMatrix_NewFromIJV</tt></b>(</nobr></td><td>matrix *I, matrix *J, 
+    matrix *V, int <var>nrows</var>, int <var>ncols</var>, int <var>nzmax</var>, int <var>id</var>)</td></tr></table></dt>
+<dd>
+  Creates a sparse matrix with <var>nrows</var> rows and <var>ncols</var>
+  columns from a triplet description. <var>I</var> and <var>J</var>
+  must be integer matrices and <var>V</var> either a double or complex matrix,
+  or <tt class="constant">NULL</tt>. If <var>V</var> is <tt class="constant">NULL</tt> the values of the 
+  entries in the matrix are undefined, otherwise they are
+  specified by <var>V</var>.  Repeated entries in <var>V</var> are summed. 
+  The number of allocated elements is given by <var>nzmax</var>, which is 
+  adjusted if it is smaller than the required amount. 
+</dd></dl>
+
+<P>
+We illustrate use of the sparse matrix class by listing the source
+code for the <tt class="method">real()</tt> method, which returns the real part of
+a sparse matrix: 
+
+<P>
+<div class="verbatim"><pre>
+static PyObject * spmatrix_real(spmatrix *self) {
+
+  if (SP_ID(self) != COMPLEX) 
+    return (PyObject *)SpMatrix_NewFromMatrix(self, 0, SP_ID(self));
+  
+  spmatrix *ret = SpMatrix_New(SP_NROWS(self), SP_NCOLS(self), 
+      SP_NNZ(self), DOUBLE);
+  if (!ret) return PyErr_NoMemory();
+
+  int i;
+  for (i=0; i < SP_NNZ(self); i++) 
+    SP_VALD(ret)[i] = creal(SP_VALZ(self)[i]);
+  
+  memcpy(SP_COL(ret), SP_COL(self), (SP_NCOLS(self)+1)*sizeof(int_t));
+  memcpy(SP_ROW(ret), SP_ROW(self), SP_NNZ(self)*sizeof(int_t));
+  return (PyObject *)ret;
+}
+</pre></div>
+ 
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="10.1 Dense Matrices"
+  href="node62.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="10. C API"
+  href="node61.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="Index"
+  href="genindex.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node62.html">10.1 Dense Matrices</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node61.html">10. C API</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="genindex.html">Index</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/previous.gif b/doc/cvxopt/previous.gif
new file mode 100644
index 0000000..de1da16
Binary files /dev/null and b/doc/cvxopt/previous.gif differ
diff --git a/doc/cvxopt/pyfav.gif b/doc/cvxopt/pyfav.gif
new file mode 100644
index 0000000..58271ed
Binary files /dev/null and b/doc/cvxopt/pyfav.gif differ
diff --git a/doc/cvxopt/s-arithmetic.html b/doc/cvxopt/s-arithmetic.html
new file mode 100644
index 0000000..41f194e
--- /dev/null
+++ b/doc/cvxopt/s-arithmetic.html
@@ -0,0 +1,269 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="s-indexing.html" />
+<link rel="prev" href="node6.html" />
+<link rel="parent" href="node4.html" />
+<link rel="next" href="s-indexing.html" />
+<meta name='aesop' content='information' />
+<title>2.3 Arithmetic Operations</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.2 Attributes and Methods"
+  href="node6.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.4 Indexing and Slicing"
+  href="s-indexing.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node6.html">2.2 Attributes and Methods</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-indexing.html">2.4 Indexing and Slicing</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION004300000000000000000"></A> <A NAME="s-arithmetic"></A>
+<BR>
+2.3 Arithmetic Operations
+</H1>
+The following table lists the arithmetic operations defined for 
+dense matrices.  In this table <var>A</var> and <var>B</var> are dense matrices 
+with compatible dimensions, <var>c</var> is a scalar (a Python number 
+or a dense 1 by 1 matrix), and <var>d</var> is a Python number.
+
+<P>
+<DIV ALIGN="CENTER">
+<TABLE CELLPADDING=3 BORDER="1">
+<TR><TD ALIGN="LEFT">Unary plus/minus</TD>
+<TD ALIGN="LEFT"><code>+<var>A</var></code>, <code>-<var>A</var></code></TD>
+</TR>
+<TR><TD ALIGN="LEFT">Addition</TD>
+<TD ALIGN="LEFT"><code><var>A</var>+<var>B</var></code>, <code><var>A</var>+<var>c</var></code>, 
+    <code><var>c</var>+<var>A</var></code></TD>
+</TR>
+<TR><TD ALIGN="LEFT">Subtraction</TD>
+<TD ALIGN="LEFT"><code><var>A</var>-<var>B</var></code>, <code><var>A</var>-<var>c</var></code>, 
+    <code><var>c</var>-<var>A</var></code></TD>
+</TR>
+<TR><TD ALIGN="LEFT">Matrix multiplication</TD>
+<TD ALIGN="LEFT"><var>A</var>*<var>B</var></TD>
+</TR>
+<TR><TD ALIGN="LEFT">Scalar multiplication and division</TD>
+<TD ALIGN="LEFT"><code><var>c</var>*<var>A</var></code>, 
+    <code><var>A</var>*<var>c</var></code>, <code><var>A</var>/<var>c</var></code></TD>
+</TR>
+<TR><TD ALIGN="LEFT">Remainder after division</TD>
+<TD ALIGN="LEFT"><code><var>A</var>%<var>c</var></code></TD>
+</TR>
+<TR><TD ALIGN="LEFT">Elementwise exponentiation</TD>
+<TD ALIGN="LEFT"><code><var>A</var>**<var>d</var></code></TD>
+</TR>
+</TABLE>
+</DIV>
+
+<P>
+If <var>c</var> in the expressions <code><var>A</var>+<var>c</var></code>, 
+<code><var>c</var>+<var>A</var></code>, <code><var>A</var>-<var>c</var></code>, 
+<code><var>c</var>-<var>A</var></code> is a number, then it is interpreted as a 
+matrix with the same dimensions as <var>A</var>, type given by the type 
+of <var>c</var>, and all entries equal to <var>c</var>.
+If <var>c</var>  is a 1 by 1 matrix and <var>A</var> is not 1 by 1, then <var>c</var> 
+is interpreted as a matrix with the same size of <var>A</var> and all 
+entries equal to <code><var>c</var>[0]</code>.
+
+<P>
+Postmultiplying a matrix with a number <var>c</var> means the same as 
+premultiplying, <EM>i.e.</EM>, scalar multiplication.  Dividing a matrix by 
+<var>c</var> means dividing all entries by <var>c</var>.  
+If <var>c</var> is a 1 by 1 matrix and the product
+<code><var>c</var>*<var>A</var></code> or <code><var>A</var>*<var>c</var></code> cannot be 
+interpreted as a matrix-matrix product, then it is interpreted as 
+<code><var>c</var>[0]*<var>A</var></code>. 
+The division <code><var>A</var>/<var>c</var></code> and remainder 
+<code><var>A</var>%<var>c</var></code> with <var>c</var> a 1 by 1 matrix are always 
+interpreted as <code><var>A</var>/<var>c</var>[0]</code>, resp.,
+<code><var>A</var>%<var>c</var>[0]</code>.
+
+<P>
+If one of the operands in the arithmetic operations is integer 
+(a scalar integer or a matrix of type <code>'i'</code>) and the other operand 
+is double (a scalar float or a matrix of type <code>'d'</code>), then the 
+integer operand is converted to double, and the result is a matrix of 
+type <code>'d'</code>.
+If one of the operands is integer or double, and the other operand is 
+complex (a scalar complex or a matrix of type <code>'z'</code>), 
+then the first operand is converted to complex, and the result is 
+a matrix of type <code>'z'</code>.  
+
+<P>
+The result of <code><var>A</var>**<var>d</var></code> is a complex matrix
+if <var>A</var> or <var>d</var> are complex, and real otherwise.
+
+<P>
+Note that Python rounds the result of an integer division towards minus 
+infinity.
+
+<P>
+The following in-place operations are also defined, but only if 
+they do not change the type or the size of the matrix <var>A</var>: 
+<DIV ALIGN="CENTER">
+<TABLE CELLPADDING=3 BORDER="1">
+<TR><TD ALIGN="LEFT">In-place addition</TD>
+<TD ALIGN="LEFT"><code><var>A</var>+=<var>B</var></code>, <code><var>A</var>+=<var>c</var></code></TD>
+</TR>
+<TR><TD ALIGN="LEFT">In-place subtraction</TD>
+<TD ALIGN="LEFT"><code><var>A</var>-=<var>B</var></code>, <code><var>A</var>-=<var>c</var></code></TD>
+</TR>
+<TR><TD ALIGN="LEFT">In-place scalar multiplication and division</TD>
+<TD ALIGN="LEFT"><code><var>A</var>*=<var>c</var></code>, <code><var>A</var>/=<var>c</var></code></TD>
+</TR>
+<TR><TD ALIGN="LEFT">In-place remainder</TD>
+<TD ALIGN="LEFT"><code><var>A</var>%=<var>c</var></code></TD>
+</TR>
+</TABLE>
+</DIV>
+
+<P>
+For example, if <var>A</var> has type <code>'i'</code>, then <code><var>A</var>+=<var>B</var></code> 
+is allowed if <var>B</var> has type <code>'i'</code>.
+It is not allowed if <var>B</var> has type <code>'d'</code>or <code>'z'</code>because the 
+addition <code><var>A</var>+<var>B</var></code> results in a matrix of 
+type <code>'d'</code>or <code>'z'</code>and therefore cannot be assigned to <var>A</var> 
+without changing its type.
+
+<P>
+In-place matrix-matrix products are not allowed.  (Except when
+<var>c</var> is a 1 by 1 matrix, in which case <code><var>A</var>*=<var>c</var></code> is 
+interpreted as the scalar product <code><var>A</var>*=<var>c</var>[0]</code>.)
+
+<P>
+It is important to know when a matrix operation creates
+a new object.  The following rules apply.
+
+<UL>
+<LI>A simple assignment ("<tt class="samp">A = B</tt>") is given the standard 
+Python interpretation, <EM>i.e.</EM>, it assigns to the variable <var>A</var> a 
+reference (or pointer) to the object referenced by <var>B</var>.
+<div class="verbatim"><pre>
+>>> B = matrix([[1.,2.], [3.,4.]])  
+>>> print B
+ 1.0000e+00   3.0000e+00
+ 2.0000e+00   4.0000e+00
+>>> A = B
+>>> A[0,0] = -1 
+>>> print B   # modifying A[0,0] also modified B[0,0]
+-1.0000e+00   3.0000e+00
+ 2.0000e+00   4.0000e+00
+</pre></div>
+
+<P>
+</LI>
+<LI>The regular (<EM>i.e.</EM>, not in-place) arithmetic operations always 
+return new objects.   Hence "<tt class="samp">A = +B</tt>" is equivalent to 
+"<tt class="samp">A = matrix(B)</tt>".
+<div class="verbatim"><pre>
+>>> B = matrix([[1.,2.], [3.,4.]])  
+>>> A = +B
+>>> A[0,0] = -1 
+>>> print B   # modifying A[0,0] does not modify B[0,0]
+ 1.0000e+00   3.0000e+00
+ 2.0000e+00   4.0000e+00
+</pre></div>
+
+<P>
+</LI>
+<LI>The in-place operations directly modify the 
+ coefficients of the existing matrix object and do not create a new
+ object. 
+<div class="verbatim"><pre>
+>>> B = matrix([[1.,2.], [3.,4.]])  
+>>> A = B
+>>> A *= 2
+>>> print B   # in-place operation also changed B
+ 2.0000e+00   6.0000e+00
+ 4.0000e+00   8.0000e+00
+>>> A = 2*A
+>>> print B   # regular operation creates a new A, so does not change B
+ 2.0000e+00   6.0000e+00
+ 4.0000e+00   8.0000e+00
+</pre></div>
+</LI>
+</UL>
+
+<P>
+The restrictions on in-place operations follow the principle that once 
+a matrix object is created, its size and type cannot be modified.  
+The only matrix attributes that can be changed are the values of the 
+elements.  The values can be changed by in-place operations or by an 
+indexed assignment, as explained in the next section. 
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.2 Attributes and Methods"
+  href="node6.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.4 Indexing and Slicing"
+  href="s-indexing.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node6.html">2.2 Attributes and Methods</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-indexing.html">2.4 Indexing and Slicing</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-array-interface.html b/doc/cvxopt/s-array-interface.html
new file mode 100644
index 0000000..80f3664
--- /dev/null
+++ b/doc/cvxopt/s-array-interface.html
@@ -0,0 +1,150 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node13.html" />
+<link rel="prev" href="s-random.html" />
+<link rel="parent" href="node4.html" />
+<link rel="next" href="node13.html" />
+<meta name='aesop' content='information' />
+<title>2.8 The NumPy Array Interface</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.7 Randomly Generated Matrices"
+  href="s-random.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.9 Printing Options"
+  href="node13.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-random.html">2.7 Randomly Generated Matrices</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node13.html">2.9 Printing Options</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION004800000000000000000"></A> <A NAME="s-array-interface"></A>
+<BR>
+2.8 The NumPy Array Interface
+</H1>
+
+<P>
+The CVXOPT <tt class="class">matrix</tt> object is compatible with the NumPy Array Interface, 
+which allows Python objects that represent multidimensional 
+arrays to exchange data using information stored in the 
+attribute <code>__array_struct__</code>.  
+
+<P>
+<div class="seealso">
+  <p class="heading">See Also:</p>
+
+<dl compact="compact" class="seeurl">
+    <dt><a href='http://numpy.scipy.org/array_interface.shtml'
+        >NumPy Array Interface Specification</a></dt>
+    <dd></dd>
+  </dl>
+
+<P>
+<dl compact="compact" class="seeurl">
+    <dt><a href='http://numpy.scipy.org'
+        >NumPy home page</a></dt>
+    <dd></dd>
+  </dl>
+</div>
+
+<P>
+As already mentioned in section <A href="s-creating-matrices.html#s-creating-matrices">2.1</A>,
+a two-dimensional array object (for example, a 2D <tt class="module">numarray</tt> 
+array) can be converted to a <tt class="class">matrix</tt> object by using the 
+<tt class="function">matrix()</tt> constructor.
+Conversely, CVXOPT matrices can be used as array-like objects
+in <tt class="module">numarray</tt>.  The following example illustrates the 
+compatibility of CVXOPT matrices and <tt class="module">numarray</tt> arrays. 
+<div class="verbatim"><pre>
+>>> from cvxopt import matrix
+>>> a = matrix(range(6), (2,3), 'd')
+>>> print a
+   0.0000e+00   2.0000e+00   4.0000e+00
+   1.0000e+00   3.0000e+00   5.0000e+00
+>>> from numarray import array
+>>> b = array(a)
+>>> print b
+[[ 0.  2.  4.]
+ [ 1.  3.  5.]]
+>>> print a*b
+[[  0.   4.  16.]
+ [  1.   9.  25.]]
+</pre></div>
+In the last expression <code>a*b</code> is interpreted as a <tt class="module">numarray</tt>
+multiplication (<EM>i.e.</EM>, componentwise) even though one operand is a 
+<tt class="class">matrix</tt> object.
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.7 Randomly Generated Matrices"
+  href="s-random.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.9 Printing Options"
+  href="node13.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-random.html">2.7 Randomly Generated Matrices</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node13.html">2.9 Printing Options</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-blas1.html b/doc/cvxopt/s-blas1.html
new file mode 100644
index 0000000..dee173e
--- /dev/null
+++ b/doc/cvxopt/s-blas1.html
@@ -0,0 +1,344 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="s-blas2.html" />
+<link rel="prev" href="s-conventions.html" />
+<link rel="parent" href="node14.html" />
+<link rel="next" href="s-blas2.html" />
+<meta name='aesop' content='information' />
+<title>3.2 Level 1 BLAS</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="3.1 Matrix Classes"
+  href="s-conventions.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="3. The BLAS Interface"
+  href="node14.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="3.3 Level 2 BLAS"
+  href="s-blas2.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-conventions.html">3.1 Matrix Classes</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node14.html">3. The BLAS Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-blas2.html">3.3 Level 2 BLAS</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION005200000000000000000"></A> <A NAME="s-blas1"></A>
+<BR>
+3.2 Level 1 BLAS
+</H1>
+The level 1 functions implement vector operations.  
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-28' xml:id='l2h-28' class="function">scal</tt></b>(</nobr></td>
+  <td><var>alpha, x</var>)</td></tr></table></dt>
+<dd>
+Scales a vector by a constant: 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+x := \alpha x.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="56" HEIGHT="24" BORDER="0"
+ SRC="img8.gif"
+ ALT="\begin{displaymath}
+x := \alpha x.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+If <var>x</var> is a real <tt class="class">matrix</tt>, the scalar argument <var>alpha</var> must be a 
+Python integer or float.  If <var>x</var> is complex, <var>alpha</var> can be an 
+integer, float, or complex.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-29' xml:id='l2h-29' class="function">nrm2</tt></b>(</nobr></td>
+  <td><var>x</var>)</td></tr></table></dt>
+<dd>
+Euclidean norm of a vector:  returns 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\|x\|_2.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="33" HEIGHT="28" BORDER="0"
+ SRC="img9.gif"
+ ALT="\begin{displaymath}
+\Vert x\Vert _2.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>  
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-30' xml:id='l2h-30' class="function">asum</tt></b>(</nobr></td>
+  <td><var>x</var>)</td></tr></table></dt>
+<dd>
+L-1 norm of a vector: returns 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\|x\|_1 \quad \mbox{($x$\  real)}, \qquad  
+\|\Re x\|_1 + \|\Im x\|_1 \quad \mbox{($x$\  complex)}.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="337" HEIGHT="28" BORDER="0"
+ SRC="img10.gif"
+ ALT="\begin{displaymath}
+\Vert x\Vert _1 \quad \mbox{($x$\ real)}, \qquad
+\Vert\Re x\Vert _1 + \Vert\Im x\Vert _1 \quad \mbox{($x$\ complex)}.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-31' xml:id='l2h-31' class="function">iamax</tt></b>(</nobr></td>
+  <td><var>x</var>)</td></tr></table></dt>
+<dd>
+Returns 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\mathop{\rm argmax}_{k=0,\ldots,n-1} |x_k| \quad \mbox{($x$\  real)}, \qquad
+ \mathop{\rm argmax}_{k=0,\ldots,n-1} |\Re x_k| + |\Im x_k| \quad 
+ \mbox{($x$\  complex)}.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="457" HEIGHT="41" BORDER="0"
+ SRC="img11.gif"
+ ALT="\begin{displaymath}
+\mathop{\rm argmax}_{k=0,\ldots,n-1} \vert x_k\vert \quad \...
+...e x_k\vert + \vert\Im x_k\vert \quad
+\mbox{($x$\ complex)}.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+If more than one coefficient achieves the maximum, the index of the 
+first <I>k</I> is returned.  
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-32' xml:id='l2h-32' class="function">swap</tt></b>(</nobr></td>
+  <td><var>x, y</var>)</td></tr></table></dt>
+<dd>
+Interchanges two vectors:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+x \leftrightarrow y.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="44" HEIGHT="27" BORDER="0"
+ SRC="img12.gif"
+ ALT="\begin{displaymath}
+x \leftrightarrow y.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+<var>x</var> and <var>y</var> are matrices of the same type (<code>'d'</code> or <code>'z'</code>).
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-33' xml:id='l2h-33' class="function">copy</tt></b>(</nobr></td>
+  <td><var>x, y</var>)</td></tr></table></dt>
+<dd>
+Copies a vector to another vector:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+y := x.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="47" HEIGHT="27" BORDER="0"
+ SRC="img13.gif"
+ ALT="\begin{displaymath}
+y := x.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+<var>x</var> and <var>y</var> are matrices of the same type (<code>'d'</code> or <code>'z'</code>).
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-34' xml:id='l2h-34' class="function">axpy</tt></b>(</nobr></td>
+  <td><var>x, y</var><big>[</big><var>,alpha=1.0</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Constant times a vector plus a vector:  
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+y := \alpha x + y.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="85" HEIGHT="27" BORDER="0"
+ SRC="img14.gif"
+ ALT="\begin{displaymath}
+y := \alpha x + y.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+<var>x</var> and <var>y</var> are matrices of the same type (<code>'d'</code> or <code>'z'</code>).
+If <var>x</var> is real, the scalar argument <var>alpha</var> must be a Python 
+integer or float.  If <var>x</var> is complex, <var>alpha</var> can be an integer, 
+float, or complex.  
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-35' xml:id='l2h-35' class="function">dot</tt></b>(</nobr></td>
+  <td><var>x, y</var>)</td></tr></table></dt>
+<dd>
+Returns 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+x^Hy.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="32" HEIGHT="27" BORDER="0"
+ SRC="img15.gif"
+ ALT="\begin{displaymath}
+x^Hy.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>  
+<var>x</var> and <var>y</var> are matrices of the same type (<code>'d'</code> or <code>'z'</code>).
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-36' xml:id='l2h-36' class="function">dotu</tt></b>(</nobr></td>
+  <td><var>x, y</var>)</td></tr></table></dt>
+<dd>
+Returns 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+x^Ty.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="30" HEIGHT="27" BORDER="0"
+ SRC="img16.gif"
+ ALT="\begin{displaymath}
+x^Ty.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>  
+<var>x</var> and <var>y</var> are matrices of the same type (<code>'d'</code> or <code>'z'</code>).
+</dl>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="3.1 Matrix Classes"
+  href="s-conventions.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="3. The BLAS Interface"
+  href="node14.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="3.3 Level 2 BLAS"
+  href="s-blas2.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-conventions.html">3.1 Matrix Classes</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node14.html">3. The BLAS Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-blas2.html">3.3 Level 2 BLAS</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-blas2.html b/doc/cvxopt/s-blas2.html
new file mode 100644
index 0000000..8a4fbc6
--- /dev/null
+++ b/doc/cvxopt/s-blas2.html
@@ -0,0 +1,661 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="s-blas3.html" />
+<link rel="prev" href="s-blas1.html" />
+<link rel="parent" href="node14.html" />
+<link rel="next" href="s-blas3.html" />
+<meta name='aesop' content='information' />
+<title>3.3 Level 2 BLAS</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="3.2 Level 1 BLAS"
+  href="s-blas1.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="3. The BLAS Interface"
+  href="node14.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="3.4 Level 3 BLAS"
+  href="s-blas3.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-blas1.html">3.2 Level 1 BLAS</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node14.html">3. The BLAS Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-blas3.html">3.4 Level 3 BLAS</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION005300000000000000000"></A> <A NAME="s-blas2"></A>
+<BR>
+3.3 Level 2 BLAS
+</H1>
+The level 2 functions implement matrix-vector products and 
+rank-1 and rank-2 matrix updates.
+Different types of matrix structure can be exploited using the 
+conventions of section <A href="s-conventions.html#s-conventions">3.1</A>. 
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-37' xml:id='l2h-37' class="function">gemv</tt></b>(</nobr></td>
+  <td><var>A, x, y</var><big>[</big><var>, trans='N'</var><big>[</big><var>, 
+alpha=1.0</var><big>[</big><var>, beta=0.0</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Matrix-vector product with a general matrix:  
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+y := \alpha Ax + \beta y \quad (\mathrm{trans} = \mathrm{'N'}),
+  \qquad 
+y := \alpha A^T x + \beta y \quad (\mathrm{trans} = \mathrm{'T'}), 
+  \qquad
+y := \alpha A^H x + \beta y \quad (\mathrm{trans} = \mathrm{'C'}).
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="707" HEIGHT="28" BORDER="0"
+ SRC="img17.gif"
+ ALT="\begin{displaymath}
+y := \alpha Ax + \beta y \quad (\mathrm{trans} = \mathrm{'N'...
+...\alpha A^H x + \beta y \quad (\mathrm{trans} = \mathrm{'C'}).
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+The arguments <var>A</var>, <var>x</var> and <var>y</var> must have the same type 
+(<code>'d'</code> or <code>'z'</code>).  Complex values of <var>alpha</var> and <var>beta</var> are only
+allowed if <var>A</var> is complex. 
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-38' xml:id='l2h-38' class="function">symv</tt></b>(</nobr></td>
+  <td><var>A, x, y</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+alpha=1.0</var><big>[</big><var>, beta=0.0</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Matrix-vector  product with a real symmetric matrix:  
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+y := \alpha A x + \beta y,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="107" HEIGHT="27" BORDER="0"
+ SRC="img18.gif"
+ ALT="\begin{displaymath}
+y := \alpha A x + \beta y,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is a real symmetric matrix.  
+The arguments <var>A</var>, <var>x</var> and <var>y</var> must have 
+type <code>'d'</code> and <var>alpha</var> and <var>beta</var> must be real.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-39' xml:id='l2h-39' class="function">hemv</tt></b>(</nobr></td>
+  <td><var>A, x, y</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+alpha=1.0</var><big>[</big><var>, beta=0.0</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Matrix-vector  product with a real symmetric or complex Hermitian 
+matrix: 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+y := \alpha A x + \beta y,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="107" HEIGHT="27" BORDER="0"
+ SRC="img18.gif"
+ ALT="\begin{displaymath}
+y := \alpha A x + \beta y,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is real symmetric or complex Hermitian.
+The arguments <var>A</var>, <var>x</var> and <var>y</var> must have the same
+type (<code>'d'</code> or <code>'z'</code>).  
+Complex values of <var>alpha</var> and <var>beta</var> are only
+allowed if <var>A</var> is complex. 
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-40' xml:id='l2h-40' class="function">trmv</tt></b>(</nobr></td>
+  <td><var>A, x</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+trans='N'</var><big>[</big><var>, diag='N'</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Matrix-vector  product with a triangular matrix: 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+x := Ax \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+x := A^T x \quad (\mathrm{trans} = \mathrm{'T'}), \qquad
+x := A^H x \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="586" HEIGHT="28" BORDER="0"
+ SRC="img19.gif"
+ ALT="\begin{displaymath}
+x := Ax \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+x := A...
+...'}), \qquad
+x := A^H x \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is square and triangular.
+The arguments <var>A</var> and <var>x</var> must have the same type 
+(<code>'d'</code> or <code>'z'</code>).
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-41' xml:id='l2h-41' class="function">trsv</tt></b>(</nobr></td>
+  <td><var>A, x</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+trans='N'</var><big>[</big><var>, diag='N'</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solution of a nonsingular triangular set of linear equations:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+x := A^{-1}x \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+x := A^{-T}x \quad (\mathrm{trans} = \mathrm{'T'}), \qquad 
+x := A^{-H}x \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="623" HEIGHT="28" BORDER="0"
+ SRC="img20.gif"
+ ALT="\begin{displaymath}
+x := A^{-1}x \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+x...
+..., \qquad
+x := A^{-H}x \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is square and triangular with nonzero diagonal 
+elements.  The arguments <var>A</var> and <var>x</var> must have the same type 
+(<code>'d'</code> or <code>'z'</code>).
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-42' xml:id='l2h-42' class="function">gbmv</tt></b>(</nobr></td>
+  <td><var>A, m, kl, x, y</var><big>[</big><var>, trans='N'
+</var><big>[</big><var>, alpha=1.0</var><big>[</big><var>, beta=0.0</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Matrix-vector product with a general band matrix:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+y := \alpha Ax + \beta y \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+y := \alpha A^T x + \beta y \quad (\mathrm{trans} = \mathrm{'T'}), 
+\qquad 
+y := \alpha A^H x + \beta y \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="708" HEIGHT="28" BORDER="0"
+ SRC="img21.gif"
+ ALT="\begin{displaymath}
+y := \alpha Ax + \beta y \quad (\mathrm{trans} = \mathrm{'N'...
+... \alpha A^H x + \beta y \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where  <I>A</I> is a rectangular band matrix with <var>m</var> rows and 
+<var>kl</var> subdiagonals.
+The arguments <var>A</var>, <var>x</var> and <var>y</var> must have the same
+type (<code>'d'</code> or <code>'z'</code>).
+Complex values of <var>alpha</var> and <var>beta</var> are only allowed if <var>A</var> is
+ complex.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-43' xml:id='l2h-43' class="function">sbmv</tt></b>(</nobr></td>
+  <td><var>A, x, y</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+alpha=1.0</var><big>[</big><var>, beta=0.0</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Matrix-vector  product with a real symmetric band matrix:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+y := \alpha Ax + \beta y,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="107" HEIGHT="27" BORDER="0"
+ SRC="img18.gif"
+ ALT="\begin{displaymath}
+y := \alpha A x + \beta y,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is a real symmetric band matrix.
+The arguments <var>A</var>, <var>x</var> and <var>y</var> must have type <code>'d'</code> and 
+<var>alpha</var> and <var>beta</var> must be real.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-44' xml:id='l2h-44' class="function">hbmv</tt></b>(</nobr></td>
+  <td><var>A, x, y</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+alpha=1.0</var><big>[</big><var>, beta=0.0</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Matrix-vector  product with a real symmetric or complex Hermitian 
+band matrix:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+y := \alpha Ax + \beta y,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="107" HEIGHT="27" BORDER="0"
+ SRC="img18.gif"
+ ALT="\begin{displaymath}
+y := \alpha A x + \beta y,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is a real symmetric or complex Hermitian band matrix.
+The arguments <var>A</var>, <var>x</var> and <var>y</var> must have the same type
+(<code>'d'</code> or <code>'z'</code>).  
+Complex values of <var>alpha</var> and <var>beta</var> are only allowed if 
+<var>A</var> is complex. 
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-45' xml:id='l2h-45' class="function">tbmv</tt></b>(</nobr></td>
+  <td><var>A, x</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+trans</var><big>[</big><var>, diag</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Matrix-vector  product with a triangular band matrix:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+x := Ax \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+x := A^T x \quad (\mathrm{trans} = \mathrm{'T'}), \qquad 
+x := A^H x \quad (\mathrm{trans} = \mathrm{'C'}).
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="585" HEIGHT="28" BORDER="0"
+ SRC="img22.gif"
+ ALT="\begin{displaymath}
+x := Ax \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+x := A...
+...}), \qquad
+x := A^H x \quad (\mathrm{trans} = \mathrm{'C'}).
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+The arguments <var>A</var> and <var>x</var> must have the same type 
+(<code>'d'</code> or <code>'z'</code>).  
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-46' xml:id='l2h-46' class="function">tbsv</tt></b>(</nobr></td>
+  <td><var>A, x</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+trans</var><big>[</big><var>, diag</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solution of a triangular banded set of linear equations:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+x := A^{-1}x \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+x := A^{-T} x \quad (\mathrm{trans} = \mathrm{'T'}), \qquad
+x := A^{-H} x \quad (\mathrm{trans} = \mathrm{'T'}),
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="623" HEIGHT="28" BORDER="0"
+ SRC="img23.gif"
+ ALT="\begin{displaymath}
+x := A^{-1}x \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+x...
+..., \qquad
+x := A^{-H} x \quad (\mathrm{trans} = \mathrm{'T'}),
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is a triangular band matrix of with nonzero diagonal 
+elements.
+The arguments <var>A</var> and <var>x</var> must have the same type 
+(<code>'d'</code> or <code>'z'</code>).  
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-47' xml:id='l2h-47' class="function">ger</tt></b>(</nobr></td>
+  <td><var>x, y, A</var><big>[</big><var>, alpha=1.0</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+General rank-1 update:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A := A + \alpha x y^H,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="112" HEIGHT="27" BORDER="0"
+ SRC="img24.gif"
+ ALT="\begin{displaymath}
+A := A + \alpha x y^H,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is a general matrix.
+The arguments <var>A</var>, <var>x</var> and <var>y</var> must have the same type 
+(<code>'d'</code> or <code>'z'</code>).  
+Complex values of <var>alpha</var> are only allowed if <var>A</var> is complex.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-48' xml:id='l2h-48' class="function">geru</tt></b>(</nobr></td>
+  <td><var>x, y, A</var><big>[</big><var>, alpha=1.0</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+General rank-1 update:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A := A + \alpha x y^T,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="110" HEIGHT="27" BORDER="0"
+ SRC="img25.gif"
+ ALT="\begin{displaymath}
+A := A + \alpha x y^T,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is a general matrix.
+The arguments <var>A</var>, <var>x</var> and <var>y</var> must have the same type 
+(<code>'d'</code> or <code>'z'</code>).  
+Complex values of <var>alpha</var> are only allowed if <var>A</var> is complex.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-49' xml:id='l2h-49' class="function">syr</tt></b>(</nobr></td>
+  <td><var>x, A</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, alpha=1.0</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Symmetric rank-1 update:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A := A + \alpha xx^T,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="112" HEIGHT="27" BORDER="0"
+ SRC="img26.gif"
+ ALT="\begin{displaymath}
+A := A + \alpha xx^T,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is a real symmetric matrix.
+The arguments <var>A</var> and <var>x</var> must have type <code>'d'</code>.  
+<var>alpha</var> must be a real number.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-50' xml:id='l2h-50' class="function">her</tt></b>(</nobr></td>
+  <td><var>x, A</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, alpha=1.0</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Hermitian rank-1 update:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A := A + \alpha xx^H,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="114" HEIGHT="27" BORDER="0"
+ SRC="img27.gif"
+ ALT="\begin{displaymath}
+A := A + \alpha xx^H,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is a real symmetric or complex Hermitian matrix.
+The arguments <var>A</var> and <var>x</var> must have the same type 
+(<code>'d'</code> or <code>'z'</code>).  
+<var>alpha</var> must be a real number.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-51' xml:id='l2h-51' class="function">syr2</tt></b>(</nobr></td>
+  <td><var>x, y, A</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+alpha=1.0</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Symmetric rank-2  update:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A := A + \alpha (xy^T + yx^T),
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="170" HEIGHT="28" BORDER="0"
+ SRC="img28.gif"
+ ALT="\begin{displaymath}
+A := A + \alpha (xy^T + yx^T),
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is a real symmetric matrix.
+The arguments <var>A</var>, <var>x</var> and <var>y</var> must have type <code>'d'</code>.  
+<var>alpha</var> must be real.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-52' xml:id='l2h-52' class="function">her2</tt></b>(</nobr></td>
+  <td><var>x, y, A</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+alpha=1.0</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Symmetric rank-2  update:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A := A + \alpha xy^H + \bar \alpha yx^H,
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="172" HEIGHT="27" BORDER="0"
+ SRC="img29.gif"
+ ALT="\begin{displaymath}
+A := A + \alpha xy^H + \bar \alpha yx^H,
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is a a real symmetric or complex Hermitian matrix.
+The arguments <var>A</var>, <var>x</var> and <var>y</var> must have the same type  
+(<code>'d'</code> or <code>'z'</code>).  
+Complex values of <var>alpha</var> are only allowed if <var>A</var> is complex.
+</dl>
+
+<P>
+As an example, the following code multiplies the tridiagonal matrix
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+A = \left[\begin{array}{rrrr}
+  1 &  6 &  0 & 0 \\
+  2 & -4 &  3 & 0 \\
+  0 & -3 & -1 & 1 
+  \end{array}\right]
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="169" HEIGHT="64" BORDER="0"
+ SRC="img30.gif"
+ ALT="\begin{displaymath}
+A = \left[\begin{array}{rrrr}
+1 & 6 & 0 & 0 \\
+2 & -4 & 3 & 0 \\
+0 & -3 & -1 & 1
+\end{array}\right]
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+with the vector <I>x</I> = (1,-1,2,-2).
+<div class="verbatim"><pre>
+>>> from cvxopt.base import matrix
+>>> from cvxopt.blas import gbmv
+>>> A = matrix([[0., 1., 2.],  [6., -4., -3.],  [3., -1., 0.],  [1., 0., 0.]])
+>>> x = matrix([1., -1., 2., -2.])
+>>> y = matrix(0., (3,1))
+>>> gbmv(A, 3, 1, x, y)
+>>> print y
+-5.0000e+00
+ 1.2000e+01
+-1.0000e+00
+</pre></div>
+
+<P>
+The following example illustrates the use of <tt class="function">tbsv()</tt>.
+<div class="verbatim"><pre>
+>>> from cvxopt.base import matrix
+>>> from cvxopt.blas import tbsv
+>>> A = matrix([-6., 5., -1., 2.], (1,4))
+>>> x = matrix(1.0, (4,1))
+>>> tbsv(A, x)  # x := diag(A)^{-1}*x
+>>> print x
+-1.6667e-01
+ 2.0000e-01
+-1.0000e+00
+ 5.0000e-01
+</pre></div>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="3.2 Level 1 BLAS"
+  href="s-blas1.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="3. The BLAS Interface"
+  href="node14.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="3.4 Level 3 BLAS"
+  href="s-blas3.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-blas1.html">3.2 Level 1 BLAS</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node14.html">3. The BLAS Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-blas3.html">3.4 Level 3 BLAS</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-blas3.html b/doc/cvxopt/s-blas3.html
new file mode 100644
index 0000000..8ed28cb
--- /dev/null
+++ b/doc/cvxopt/s-blas3.html
@@ -0,0 +1,435 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="prev" href="s-blas2.html" />
+<link rel="parent" href="node14.html" />
+<link rel="next" href="node19.html" />
+<meta name='aesop' content='information' />
+<title>3.4 Level 3 BLAS</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="3.3 Level 2 BLAS"
+  href="s-blas2.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="3. The BLAS Interface"
+  href="node14.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4. The LAPACK Interface"
+  href="node19.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-blas2.html">3.3 Level 2 BLAS</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node14.html">3. The BLAS Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node19.html">4. The LAPACK Interface</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION005400000000000000000"></A> <A NAME="s-blas3"></A>
+<BR>
+3.4 Level 3 BLAS
+</H1>
+The level 3 BLAS include functions for matrix-matrix multiplication.
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-53' xml:id='l2h-53' class="function">gemm</tt></b>(</nobr></td>
+  <td><var>A, B, C</var><big>[</big><var>, transA='N'</var><big>[</big><var>, 
+transB='N'</var><big>[</big><var>, alpha=1.0</var><big>[</big><var>, beta=0.0</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Matrix-matrix product of two general matrices:  
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+C := \alpha \mathop{\mathrm{op}}(A) \mathop{\mathrm{op}}(B) + \beta C
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="177" HEIGHT="28" BORDER="0"
+ SRC="img31.gif"
+ ALT="\begin{displaymath}
+C := \alpha \mathop{\mathrm{op}}(A) \mathop{\mathrm{op}}(B) + \beta C
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\mathop{\mathrm{op}}(A) =  \left\{ \begin{array}{ll}
+ A & \mathrm{transA} = \mathrm{'N'} \\
+ A^T & \mathrm{transA} = \mathrm{'T'} \\
+ A^H & \mathrm{transA} = \mathrm{'C'} \end{array} \right.
+\qquad
+\mathop{\mathrm{op}}(B) =  \left\{ \begin{array}{ll}
+ B & \mathrm{transB} = \mathrm{'N'} \\
+ B^T & \mathrm{transB} = \mathrm{'T'} \\
+ B^H & \mathrm{transB} = \mathrm{'C'}. \end{array} \right.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="474" HEIGHT="64" BORDER="0"
+ SRC="img32.gif"
+ ALT="\begin{displaymath}
+\mathop{\mathrm{op}}(A) = \left\{ \begin{array}{ll}
+A & \ma...
+...\\
+B^H & \mathrm{transB} = \mathrm{'C'}. \end{array} \right.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+The arguments <var>A</var>, <var>B</var> and <var>C</var> must have the same type 
+(<code>'d'</code> or <code>'z'</code>).
+Complex values of <var>alpha</var> and <var>beta</var> are only allowed 
+if <var>A</var> is complex.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-54' xml:id='l2h-54' class="function">symm</tt></b>(</nobr></td>
+  <td><var>A, B, C</var><big>[</big><var>, side='L'</var><big>[</big><var>, 
+uplo='L'</var><big>[</big><var>, alpha=1.0</var><big>[</big><var>,  beta=0.0</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Product of a real or complex symmetric matrix <I>A</I> and a general 
+matrix <I>B</I>:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+C := \alpha AB + \beta C \quad (\mathrm{side} = \mathrm{'L'}), \qquad 
+ C := \alpha BA + \beta C \quad (\mathrm{side} = \mathrm{'R'}).
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="462" HEIGHT="28" BORDER="0"
+ SRC="img33.gif"
+ ALT="\begin{displaymath}
+C := \alpha AB + \beta C \quad (\mathrm{side} = \mathrm{'L'...
+... := \alpha BA + \beta C \quad (\mathrm{side} = \mathrm{'R'}).
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+The arguments <var>A</var>, <var>B</var> and <var>C</var> must have the same type 
+(<code>'d'</code> or <code>'z'</code>).  Complex values of <var>alpha</var> and <var>beta</var> are 
+only allowed if <var>A</var> is complex.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-55' xml:id='l2h-55' class="function">hemm</tt></b>(</nobr></td>
+  <td><var>A, B, C</var><big>[</big><var>, side='L'</var><big>[</big><var>, 
+uplo='L'</var><big>[</big><var>, alpha=1.0</var><big>[</big><var>,  beta=0.0</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Product of a real symmetric or complex Hermitian matrix <I>A</I> and a 
+general matrix <I>B</I>:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+C := \alpha AB + \beta C \quad (\mathrm{side} = \mathrm{'L'}), \qquad 
+ C := \alpha BA + \beta C \quad (\mathrm{side} = \mathrm{'R'}).
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="462" HEIGHT="28" BORDER="0"
+ SRC="img33.gif"
+ ALT="\begin{displaymath}
+C := \alpha AB + \beta C \quad (\mathrm{side} = \mathrm{'L'...
+... := \alpha BA + \beta C \quad (\mathrm{side} = \mathrm{'R'}).
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+The arguments <var>A</var>, <var>B</var> and <var>C</var> must have the same type 
+(<code>'d'</code> or <code>'z'</code>).
+Complex values of <var>alpha</var> and <var>beta</var> are only allowed if 
+<var>A</var> is complex.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-56' xml:id='l2h-56' class="function">trmm</tt></b>(</nobr></td>
+  <td><var>A, B</var><big>[</big><var>, side='L'</var><big>[</big><var>, 
+uplo='L'</var><big>[</big><var>, transA='N'</var><big>[</big><var>, diag='N'</var><big>[</big><var>, 
+alpha=1.0</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Product of a triangular matrix <I>A</I> and a general matrix <I>B</I>:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+B := \alpha\mathop{\mathrm{op}}(A)B \quad (\mathrm{side} = \mathrm{'L'}), \qquad 
+ B := \alpha B\mathop{\mathrm{op}}(A) \quad (\mathrm{side} = \mathrm{'R'}), \qquad 
+ \mathop{\mathrm{op}}(A) =  \left\{ \begin{array}{ll}
+ A & \mathrm{transA} = \mathrm{'N'} \\
+ A^T & \mathrm{transA} = \mathrm{'T'} \\
+ A^H & \mathrm{transA} = \mathrm{'C'}. \end{array} \right.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="696" HEIGHT="64" BORDER="0"
+ SRC="img34.gif"
+ ALT="\begin{displaymath}
+B := \alpha\mathop{\mathrm{op}}(A)B \quad (\mathrm{side} = ...
+...\\
+A^H & \mathrm{transA} = \mathrm{'C'}. \end{array} \right.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+The arguments <var>A</var> and <var>B</var> must have the same type (<code>'d'</code> or 
+<code>'z'</code>).   Complex values of <var>alpha</var> are only allowed if <var>A</var> is 
+complex.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-57' xml:id='l2h-57' class="function">trsm</tt></b>(</nobr></td>
+  <td><var>A, B</var><big>[</big><var>, side='L'</var><big>[</big><var>, 
+uplo='L'</var><big>[</big><var>, transA='N'</var><big>[</big><var>, diag='N'</var><big>[</big><var>, 
+alpha=1.0</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solution of a nonsingular triangular system of equations:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+B := \alpha \mathop{\mathrm{op}}(A)^{-1}B \quad (\mathrm{side} = \mathrm{'L'}), \qquad 
+ B := \alpha B\mathop{\mathrm{op}}(A)^{-1} \quad (\mathrm{side} = \mathrm{'R'}), \qquad 
+ \mathop{\mathrm{op}}(A) =  \left\{ \begin{array}{ll}
+ A & \mathrm{transA} = \mathrm{'N'} \\
+ A^T & \mathrm{transA} = \mathrm{'T'} \\
+ A^H & \mathrm{transA} = \mathrm{'C'}, \end{array} \right.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="731" HEIGHT="64" BORDER="0"
+ SRC="img35.gif"
+ ALT="\begin{displaymath}
+B := \alpha \mathop{\mathrm{op}}(A)^{-1}B \quad (\mathrm{si...
+...\\
+A^H & \mathrm{transA} = \mathrm{'C'}, \end{array} \right.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is triangular and <I>B</I> is a general matrix.
+The arguments <var>A</var> and <var>B</var> must have the same type (<code>'d'</code> or 
+<code>'z'</code>).   Complex values of <var>alpha</var> are only allowed if <var>A</var> is 
+complex.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-58' xml:id='l2h-58' class="function">syrk</tt></b>(</nobr></td>
+  <td><var>A, C</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+trans='N'</var><big>[</big><var>, alpha=1.0</var><big>[</big><var>, beta=0.0</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Rank-<I>k</I> update of a real or complex symmetric matrix <I>C</I>:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+C := \alpha AA^T + \beta C \quad (\mathrm{trans} = \mathrm{'N'}), 
+ \qquad 
+ C := \alpha A^TA + \beta C \quad (\mathrm{trans} = \mathrm{'T'}),
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="501" HEIGHT="28" BORDER="0"
+ SRC="img36.gif"
+ ALT="\begin{displaymath}
+C := \alpha AA^T + \beta C \quad (\mathrm{trans} = \mathrm{...
+... \alpha A^TA + \beta C \quad (\mathrm{trans} = \mathrm{'T'}),
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is a general matrix.
+The arguments <var>A</var> and <var>C</var> must have the same type (<code>'d'</code> or 
+<code>'z'</code>).  Complex values of <var>alpha</var> and <var>beta</var> are only allowed 
+if <var>A</var> is complex.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-59' xml:id='l2h-59' class="function">herk</tt></b>(</nobr></td>
+  <td><var>A, C</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+trans='N'</var><big>[</big><var>, alpha=1.0</var><big>[</big><var>, beta=0.0</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Rank-<I>k</I> update of a real symmetric or complex Hermitian matrix
+<I>C</I>:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+C := \alpha AA^H + \beta C \quad (\mathrm{trans} = \mathrm{'N'}), 
+ \qquad 
+ C := \alpha A^HA + \beta C \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="505" HEIGHT="28" BORDER="0"
+ SRC="img37.gif"
+ ALT="\begin{displaymath}
+C := \alpha AA^H + \beta C \quad (\mathrm{trans} = \mathrm{...
+...= \alpha A^HA + \beta C \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> is a general matrix.
+The arguments <var>A</var> and <var>C</var> must have the same type (<code>'d'</code> or
+<code>'z'</code>).  <var>alpha</var> and <var>beta</var> must be real.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-60' xml:id='l2h-60' class="function">syr2k</tt></b>(</nobr></td>
+  <td><var>A, B, C</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+trans='N'</var><big>[</big><var>, alpha=1.0</var><big>[</big><var>, beta=0.0</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Rank-<I>2k</I> update of a real or complex symmetric matrix <I>C</I>:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+C := \alpha (AB^T + BA^T) + \beta C \quad 
+  (\mathrm{trans} = \mathrm{'N'}), \qquad 
+ C := \alpha (A^TB + B^TA) + \beta C \quad 
+  (\mathrm{trans} = \mathrm{'T'}).
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="607" HEIGHT="28" BORDER="0"
+ SRC="img38.gif"
+ ALT="\begin{displaymath}
+C := \alpha (AB^T + BA^T) + \beta C \quad
+(\mathrm{trans}...
+...TB + B^TA) + \beta C \quad
+(\mathrm{trans} = \mathrm{'T'}).
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+<I>A</I> and <I>B</I> are general real or complex matrices.
+The arguments <var>A</var>, <var>B</var> and <var>C</var> must have the same
+type.  Complex values of <var>alpha</var> and <var>beta</var> are only 
+allowed if <var>A</var> is complex.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-61' xml:id='l2h-61' class="function">her2k</tt></b>(</nobr></td>
+  <td><var>A, B, C</var><big>[</big><var>, uplo='L'</var><big>[</big><var>, 
+trans='N'</var><big>[</big><var>, alpha=1.0</var><big>[</big><var> beta=0.0</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Rank-<I>2k</I> update of a real symmetric or complex Hermitian matrix
+<I>C</I>:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+C := \alpha AB^H + \bar \alpha BA^H + \beta C \quad 
+  (\mathrm{trans} = \mathrm{'N'}), \qquad 
+ C := \alpha A^HB + \bar\alpha B^HA + \beta C \quad 
+  (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="612" HEIGHT="28" BORDER="0"
+ SRC="img39.gif"
+ ALT="\begin{displaymath}
+C := \alpha AB^H + \bar \alpha BA^H + \beta C \quad
+(\mat...
+...alpha B^HA + \beta C \quad
+(\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>A</I> and <I>B</I> are general matrices.
+The arguments <var>A</var>, <var>B</var> and <var>C</var> must have the same type 
+(<code>'d'</code> or <code>'z'</code>).  Complex values of <var>alpha</var> are only allowed if 
+<var>A</var> is complex.  <var>beta</var> must be real.
+</dl>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="3.3 Level 2 BLAS"
+  href="s-blas2.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="3. The BLAS Interface"
+  href="node14.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="4. The LAPACK Interface"
+  href="node19.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-blas2.html">3.3 Level 2 BLAS</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node14.html">3. The BLAS Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node19.html">4. The LAPACK Interface</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-builtinfuncs.html b/doc/cvxopt/s-builtinfuncs.html
new file mode 100644
index 0000000..22f6eea
--- /dev/null
+++ b/doc/cvxopt/s-builtinfuncs.html
@@ -0,0 +1,219 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="s-otherfuncs.html" />
+<link rel="prev" href="s-indexing.html" />
+<link rel="parent" href="node4.html" />
+<link rel="next" href="s-otherfuncs.html" />
+<meta name='aesop' content='information' />
+<title>2.5 Built-in Functions</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.4 Indexing and Slicing"
+  href="s-indexing.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.6 Other Matrix Functions"
+  href="s-otherfuncs.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-indexing.html">2.4 Indexing and Slicing</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-otherfuncs.html">2.6 Other Matrix Functions</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION004500000000000000000"></A> <A NAME="s-builtinfuncs"></A>
+<BR>
+2.5 Built-in Functions
+</H1>
+Many Python built-in functions and operations can be used with matrix 
+arguments.  We list some useful examples.
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-11' xml:id='l2h-11' class="function">len</tt></b>(</nobr></td>
+  <td><var>x</var>)</td></tr></table></dt>
+<dd>
+Returns the product of the number of rows and the number of columns. 
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-12' xml:id='l2h-12' class="function">bool</tt></b>(</nobr></td>
+  <td><var></var><big>[</big><var>x</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Returns <code>False</code> if <var>x</var> is empty (<EM>i.e.</EM>, <code>len(<var>x</var>)</code> is zero) 
+and <code>True</code> otherwise.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-13' xml:id='l2h-13' class="function">max</tt></b>(</nobr></td>
+  <td><var>x</var>)</td></tr></table></dt>
+<dd>
+Returns the maximum element of <var>x</var>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-14' xml:id='l2h-14' class="function">min</tt></b>(</nobr></td>
+  <td><var>x</var>)</td></tr></table></dt>
+<dd>
+Returns the minimum element of <var>x</var>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-15' xml:id='l2h-15' class="function">abs</tt></b>(</nobr></td>
+  <td><var>x</var>)</td></tr></table></dt>
+<dd>
+Returns a matrix with the absolute values of the elements of <var>x</var>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-16' xml:id='l2h-16' class="function">sum</tt></b>(</nobr></td>
+  <td><var>x</var><big>[</big><var>, start=0.0</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Returns the sum of <var>start</var> and the elements of <var>x</var>.
+</dl>
+
+<P>
+Matrices can be used as  arguments to the <tt class="function">list()</tt>, 
+<tt class="function">tuple()</tt>, <tt class="function">zip()</tt>, <tt class="function">map()</tt>, and 
+<tt class="function">filter()</tt> functions described in section 2.1 of the Python 
+Library Reference.  <code>list(<var>A</var>)</code> and <code>tuple(<var>A</var>)</code> 
+construct a list, respectively a tuple, from the elements of <var>A</var>.
+<code>zip(<var>A</var>,<var>B</var>,...)</code> returns a list of tuples, 
+with the <I>i</I>th tuple containing the <I>i</I>th elements of <var>A</var>, 
+<var>B</var>, ....
+
+<P>
+<div class="verbatim"><pre>
+>>> from cvxopt.base import matrix
+>>> A = matrix([[-11., -5., -20.], [-6., -0., 7.]])
+>>> B = matrix(range(6), (3,2))
+>>> list(A)
+[-11.0, -5.0, -20.0, -6.0, 0.0, 7.0]
+>>> tuple(B)
+(0, 1, 2, 3, 4, 5)
+>>> zip(A,B)
+[(-11.0, 0), (-5.0, 1), (-20.0, 2), (-6.0, 3), (0.0, 4), (7.0, 5)]
+</pre></div>
+
+<P>
+<code>map(<var>f</var>,<var>A</var>)</code>, where <var>f</var> is a function and <var>A</var> 
+is a matrix, returns a list constructed by applying <var>f</var> to each 
+element of <var>A</var>.  Multiple arguments can be provided, for example, 
+as in <code>map(<var>f</var>,<var>A</var>,<var>B</var>)</code>, if <var>f</var> is a function 
+with two arguments.
+<div class="verbatim"><pre>
+>>> A = matrix([[5, -4, 10, -7], [-1, -5, -6, 2], [6, 1, 5, 2],  [-1, 2, -3, -7]])
+>>> B = matrix([[4,-15, 9, -14], [-4, -12, 1, -22], [-10, -9, 9, 12], [-9, -7,-11, -6]])
+>>> print matrix(map(max, A, B), (4,4))   # takes componentwise maximum
+   5     -1      6     -1
+  -4     -5      1      2
+   10     1      9     -3
+  -7      2      12    -6
+</pre></div>
+
+<P>
+<code>filter(<var>f</var>,<var>A</var>)</code>, where <var>f</var> is a function and 
+<var>A</var> is a matrix, returns a list containing the elements of <var>A</var> 
+for which <var>f</var> is true.
+<div class="verbatim"><pre>
+>>> print filter(lambda x: x%2, A)         # list of odd elements in A
+[5, -7, -1, -5, 1, 5, -1, -3, -7]
+>>> print filter(lambda x: -2 < x < 3, A)  # list of elements between -2 and 3
+[-1, 2, 1, 2, -1, 2]
+</pre></div>
+
+<P>
+It is also possible to iterate over matrix elements, as illustrated in
+the following example.
+<div class="verbatim"><pre>
+>>> A = matrix([[5, -3], [9, 11]])
+>>> for x in A: print max(x,0)
+...
+5
+0
+9
+11
+>>> [max(x,0) for x in A]
+[5, 0, 9, 11]
+</pre></div>
+
+<P>
+The expression "<tt class="samp"><var>x</var> in <var>A</var></tt>" returns <code>True</code> if an element 
+of <var>A</var> is equal to <var>x</var> and <code>False</code> otherwise.
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.4 Indexing and Slicing"
+  href="s-indexing.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.6 Other Matrix Functions"
+  href="s-otherfuncs.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-indexing.html">2.4 Indexing and Slicing</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-otherfuncs.html">2.6 Other Matrix Functions</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-cholmod.html b/doc/cvxopt/s-cholmod.html
new file mode 100644
index 0000000..2980c4a
--- /dev/null
+++ b/doc/cvxopt/s-cholmod.html
@@ -0,0 +1,514 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="e-covsel.html" />
+<link rel="prev" href="s-umfpack.html" />
+<link rel="parent" href="c-spsolvers.html" />
+<link rel="next" href="e-covsel.html" />
+<meta name='aesop' content='information' />
+<title>7.3 Positive Definite Linear Equations (cvxopt.cholmod)</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="7.2 General Linear Equations"
+  href="s-umfpack.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="7. Sparse Linear Equation"
+  href="c-spsolvers.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="7.4 Example: Covariance Selection"
+  href="e-covsel.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-umfpack.html">7.2 General Linear Equations</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="c-spsolvers.html">7. Sparse Linear Equation</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="e-covsel.html">7.4 Example: Covariance Selection</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION009300000000000000000"></A> 
+<A NAME="s-cholmod"></A>
+<BR>
+7.3 Positive Definite Linear Equations (<tt class="module">cvxopt.cholmod</tt>)
+</H1>
+
+<P>
+<tt class="module">cvxopt.cholmod</tt> is an interface to the Cholesky factorization 
+routines of the CHOLMOD package.
+It includes functions for Cholesky factorization of sparse positive
+definite matrices, and for solving sparse sets of linear equations with 
+positive definite matrices. 
+The routines can also be used for computing LDL<SPAN CLASS="MATH"><IMG
+ WIDTH="14" HEIGHT="18" ALIGN="BOTTOM" BORDER="0"
+ SRC="img40.gif"
+ ALT="$\mathrm{{}^T}$"></SPAN> 
+(or LDL<SPAN CLASS="MATH"><IMG
+ WIDTH="14" HEIGHT="18" ALIGN="BOTTOM" BORDER="0"
+ SRC="img89.gif"
+ ALT="$\mathrm{{}^H}$"></SPAN>) factorizations of symmetric indefinite matrices 
+(with L unit lower-triangular and D diagonal and nonsingular) if 
+such a factorization exists.  
+
+<P>
+<div class="seealso">
+  <p class="heading">See Also:</p>
+
+<dl compact="compact" class="seeurl">
+    <dt><a href='http://www.cise.ufl.edu/research/sparse/cholmod'
+        >CHOLMOD code, documentation, copyright and license.</a></dt>
+    <dd></dd>
+  </dl>
+</div>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-138' xml:id='l2h-138' class="function">linsolve</tt></b>(</nobr></td>
+  <td><var>A, B</var><big>[</big><var>, p=<code>None</code></var><big>[</big><var>, 
+uplo='L'</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+AX = B
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="60" HEIGHT="24" BORDER="0"
+ SRC="img47.gif"
+ ALT="\begin{displaymath}
+AX=B
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+with <I>A</I> sparse and real symmetric or complex Hermitian.
+<var>B</var> is a dense matrix of the same type as <var>A</var>.  On exit it 
+is overwritten with the solution.
+The argument <var>p</var> is an integer matrix with length equal to the 
+order of <var>A</var>, and specifies an optional reordering of <var>A</var>.
+If <var>p</var> is not specified, CHOLMOD used a reordering from the
+AMD library.
+Raises an <code>ArithmeticError</code> if the factorization does not exist.
+</dl>
+
+<P>
+As an  example, we solve 
+<BR>
+<DIV ALIGN="RIGHT" CLASS="mathdisplay">
+
+<!-- MATH
+ \begin{equation}
+\left[ \begin{array}{rrrr}
+ 10 &  0 & 3 &  0 \\
+  0 &  5 & 0 & -2 \\
+  3 &  0 & 5 &  0 \\
+  0 & -2 & 0 &  2 
+  \end{array}\right] X = \left[ \begin{array}{cc}
+   0 & 4 \\1 & 5 \\2 & 6 \\3 & 7\end{array} \right].
+\end{equation}
+ -->
+<A NAME="e-A-pd"></A>
+<TABLE WIDTH="100%" ALIGN="CENTER">
+<TR VALIGN="MIDDLE"><TD></TD><TD ALIGN="CENTER" NOWRAP><A NAME="e-A-pd"></A><IMG
+ WIDTH="258" HEIGHT="83" BORDER="0"
+ SRC="img90.gif"
+ ALT="\begin{displaymath}
+\left[ \begin{array}{rrrr}
+10 & 0 & 3 & 0 \\
+0 & 5 & 0 & ...
+...ray}{cc}
+0 & 4 \\ 1 & 5 \\ 2 & 6 \\ 3 & 7\end{array} \right].
+\end{displaymath}"></TD>
+<TD CLASS="eqno" WIDTH=10 ALIGN="RIGHT">
+(7.2)</TD></TR>
+</TABLE>
+<BR CLEAR="ALL"></DIV><P></P>
+<div class="verbatim"><pre>
+>>> from cvxopt.base import matrix, spmatrix
+>>> from cvxopt import cholmod
+>>> A = spmatrix([10,3, 5,-2, 5, 2], [0,2, 1,3, 2, 3], [0,0, 1,1, 2, 3])
+>>> X = matrix(range(8), (4,2), 'd')
+>>> cholmod.linsolve(A,X)
+>>> print X
+-1.4634e-01   4.8780e-02
+ 1.3333e+00   4.0000e+00
+ 4.8780e-01   1.1707e+00
+ 2.8333e+00   7.5000e+00
+</pre></div>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-139' xml:id='l2h-139' class="function">splinsolve</tt></b>(</nobr></td>
+  <td><var>A, B</var><big>[</big><var>, p=<code>None</code></var><big>[</big><var>, 
+uplo='L'</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Similar to <tt class="function">linsolve()</tt> except that <var>B</var> is a sparse 
+matrix and that the solution is returned as an output 
+argument (as a new sparse matrix).  <var>B</var> is not modified.
+</dl>
+
+<P>
+The following code computes the inverse of the coefficient matrix 
+in (<A HREF="#e-A-pd">7.2</A>) as a sparse matrix.
+<div class="verbatim"><pre>
+>>> X = cholmod.splinsolve(A, spmatrix(1.0,range(4),range(4)))
+>>> print X
+SIZE: (4,4)
+(0, 0)  1.2195e-01
+(2, 0) -7.3171e-02
+(1, 1)  3.3333e-01
+(3, 1)  3.3333e-01
+(0, 2) -7.3171e-02
+(2, 2)  2.4390e-01
+(1, 3)  3.3333e-01
+(3, 3)  8.3333e-01
+</pre></div>
+
+<P>
+The functions <tt class="function">linsolve()</tt> and <tt class="function">splinsolve()</tt> are
+equivalent to <tt class="function">symbolic()</tt> and <tt class="function">numeric()</tt> called in
+sequence, followed by <tt class="function">solve()</tt>, respectively, 
+<tt class="function">spsolve()</tt>.
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-140' xml:id='l2h-140' class="function">symbolic</tt></b>(</nobr></td>
+  <td><var>A</var><big>[</big><var>, p=<code>None</code></var><big>[</big><var>, uplo='L'</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Performs a symbolic analysis of a sparse real symmetric or
+complex Hermitian matrix <var>A</var> for one of the two factorizations:
+<BR>
+<DIV ALIGN="RIGHT" CLASS="mathdisplay">
+
+<!-- MATH
+ \begin{equation}
+PAP^T = LL^T, \qquad PAP^T = LL^H,
+\end{equation}
+ -->
+<A NAME="e-chol-ll"></A>
+<TABLE WIDTH="100%" ALIGN="CENTER">
+<TR VALIGN="MIDDLE"><TD></TD><TD ALIGN="CENTER" NOWRAP><A NAME="e-chol-ll"></A><IMG
+ WIDTH="244" HEIGHT="27" BORDER="0"
+ SRC="img91.gif"
+ ALT="\begin{displaymath}
+PAP^T = LL^T, \qquad PAP^T = LL^H,
+\end{displaymath}"></TD>
+<TD CLASS="eqno" WIDTH=10 ALIGN="RIGHT">
+(7.3)</TD></TR>
+</TABLE>
+<BR CLEAR="ALL"></DIV><P></P>
+and 
+<BR>
+<DIV ALIGN="RIGHT" CLASS="mathdisplay">
+
+<!-- MATH
+ \begin{equation}
+PAP^T = LDL^T, \qquad PAP^T = LDL^H,
+\end{equation}
+ -->
+<A NAME="e-chol-ldl"></A>
+<TABLE WIDTH="100%" ALIGN="CENTER">
+<TR VALIGN="MIDDLE"><TD></TD><TD ALIGN="CENTER" NOWRAP><A NAME="e-chol-ldl"></A><IMG
+ WIDTH="272" HEIGHT="27" BORDER="0"
+ SRC="img92.gif"
+ ALT="\begin{displaymath}
+PAP^T = LDL^T, \qquad PAP^T = LDL^H,
+\end{displaymath}"></TD>
+<TD CLASS="eqno" WIDTH=10 ALIGN="RIGHT">
+(7.4)</TD></TR>
+</TABLE>
+<BR CLEAR="ALL"></DIV><P></P>
+where <I>P</I> is a permutation matrix, <I>L</I> is lower triangular 
+(unit lower triangular in the second factorization), and 
+<I>D</I> is nonsingular diagonal.  The type of factorization depends 
+on the value of <code>options['supernodal']</code>.
+
+<P>
+If <var>uplo</var> is <code>'L'</code>, only the lower triangular part of <var>A</var> 
+is accessed and the upper triangular part is ignored.
+If <var>uplo</var> is <code>'U'</code>, only the upper triangular part of <var>A</var> 
+is accessed and the lower triangular part is ignored.
+
+<P>
+The symbolic factorization is returned as an opaque C object that 
+can be passed to <tt class="function">cholmod.numeric()</tt>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-141' xml:id='l2h-141' class="function">numeric</tt></b>(</nobr></td>
+  <td><var>A, F</var>)</td></tr></table></dt>
+<dd>
+Performs a numeric factorization of a sparse symmetric matrix 
+as (<A HREF="#e-chol-ll">7.3</A>) or (<A HREF="#e-chol-ldl">7.4</A>).  
+The argument <var>F</var> is the symbolic factorization
+computed by <tt class="function">cholmod.symbolic()</tt> applied to the matrix <var>A</var>,
+or to another sparse  matrix with the same sparsity pattern and 
+typecode, or by
+<tt class="function">cholmod.numeric()</tt> applied to a matrix with the same
+sparsity pattern and typecode as <var>A</var>.
+
+<P>
+If <var>F</var> was created by a <tt class="function">cholmod.symbolic</tt> with 
+<var>uplo</var> equal to <code>'L'</code>, then only the lower triangular part 
+of <var>A</var> is accessed and the upper triangular part is ignored.
+If it was created with <var>uplo</var> is <code>'U'</code>, then only the upper 
+triangular part of <var>A</var> is accessed and the lower triangular part 
+is ignored.
+
+<P>
+On successful exit, the factorization is stored in <var>F</var>.
+Raises an <code>ArithmeticError</code> if the factorization does not
+exist.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-142' xml:id='l2h-142' class="function">solve</tt></b>(</nobr></td>
+  <td><var>F, B</var><big>[</big><var>, sys=0</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves one of the following linear equations where <var>B</var> is a dense 
+matrix and <var>F</var> is the numeric 
+factorization (<A HREF="#e-chol-ll">7.3</A>) or (<A HREF="#e-chol-ldl">7.4</A>) computed by 
+<tt class="function">cholmod_numeric()</tt>.  
+<var>sys</var> is an integer with values between 0 and 8. 
+
+<P>
+<DIV ALIGN="CENTER">
+<TABLE CELLPADDING=3 BORDER="1">
+<TR><TD ALIGN="CENTER"><var>sys</var></TD>
+<TD ALIGN="CENTER">equation</TD>
+</TR>
+<TR><TD ALIGN="CENTER">0</TD>
+<TD ALIGN="CENTER"><SPAN CLASS="MATH"><IMG
+ WIDTH="64" HEIGHT="14" ALIGN="BOTTOM" BORDER="0"
+ SRC="img93.gif"
+ ALT="$AX=B$"></SPAN></TD>
+</TR>
+<TR><TD ALIGN="CENTER">1</TD>
+<TD ALIGN="CENTER"><SPAN CLASS="MATH"><IMG
+ WIDTH="98" HEIGHT="16" ALIGN="BOTTOM" BORDER="0"
+ SRC="img94.gif"
+ ALT="$LDL^TX=B$"></SPAN></TD>
+</TR>
+<TR><TD ALIGN="CENTER">2</TD>
+<TD ALIGN="CENTER"><SPAN CLASS="MATH"><IMG
+ WIDTH="88" HEIGHT="14" ALIGN="BOTTOM" BORDER="0"
+ SRC="img95.gif"
+ ALT="$LDLX=B$"></SPAN></TD>
+</TR>
+<TR><TD ALIGN="CENTER">3</TD>
+<TD ALIGN="CENTER"><SPAN CLASS="MATH"><IMG
+ WIDTH="87" HEIGHT="16" ALIGN="BOTTOM" BORDER="0"
+ SRC="img96.gif"
+ ALT="$DL^TX=B$"></SPAN></TD>
+</TR>
+<TR><TD ALIGN="CENTER">4</TD>
+<TD ALIGN="CENTER"><SPAN CLASS="MATH"><IMG
+ WIDTH="63" HEIGHT="14" ALIGN="BOTTOM" BORDER="0"
+ SRC="img97.gif"
+ ALT="$LX=B$"></SPAN></TD>
+</TR>
+<TR><TD ALIGN="CENTER">5</TD>
+<TD ALIGN="CENTER"><SPAN CLASS="MATH"><IMG
+ WIDTH="73" HEIGHT="16" ALIGN="BOTTOM" BORDER="0"
+ SRC="img98.gif"
+ ALT="$L^TX=B$"></SPAN></TD>
+</TR>
+<TR><TD ALIGN="CENTER">6</TD>
+<TD ALIGN="CENTER"><SPAN CLASS="MATH"><IMG
+ WIDTH="66" HEIGHT="14" ALIGN="BOTTOM" BORDER="0"
+ SRC="img99.gif"
+ ALT="$DX=B$"></SPAN></TD>
+</TR>
+<TR><TD ALIGN="CENTER">7</TD>
+<TD ALIGN="CENTER"><SPAN CLASS="MATH"><IMG
+ WIDTH="75" HEIGHT="16" ALIGN="BOTTOM" BORDER="0"
+ SRC="img100.gif"
+ ALT="$P^TX=B$"></SPAN></TD>
+</TR>
+<TR><TD ALIGN="CENTER">8</TD>
+<TD ALIGN="CENTER"><SPAN CLASS="MATH"><IMG
+ WIDTH="65" HEIGHT="14" ALIGN="BOTTOM" BORDER="0"
+ SRC="img101.gif"
+ ALT="$PX=B$"></SPAN></TD>
+</TR>
+</TABLE>
+</DIV>
+
+<P>
+(If <var>F</var> is a Cholesky factorization of the form (<A HREF="#e-chol-ll">7.3</A>), 
+<I>D</I> is an identity matrix in this table. 
+If <var>A</var> is complex, <SPAN CLASS="MATH"><IMG
+ WIDTH="25" HEIGHT="16" ALIGN="BOTTOM" BORDER="0"
+ SRC="img102.gif"
+ ALT="$L^T$"></SPAN> should be replaced by <SPAN CLASS="MATH"><IMG
+ WIDTH="27" HEIGHT="16" ALIGN="BOTTOM" BORDER="0"
+ SRC="img103.gif"
+ ALT="$L^H$"></SPAN>.)
+
+<P>
+The matrix <var>B</var> is a dense <code>'d'</code> or <code>'z'</code> matrix, with the same type
+as <var>A</var>.  On exit it is overwritten by the solution.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-143' xml:id='l2h-143' class="function">spsolve</tt></b>(</nobr></td>
+  <td><var>F, B</var><big>[</big><var>, sys=0</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Similar to <tt class="function">solve()</tt>, except that <var>B</var> is a 
+sparse matrix, and the solution is returned as an output argument
+(as a sparse matrix).  <var>B</var> must have the same typecode as <var>A</var>.
+</dl>
+
+<P>
+For the same example as above:
+<div class="verbatim"><pre>
+>>> X = matrix(range(8), (4,2), 'd')
+>>> F = cholmod.symbolic(A)
+>>> cholmod.numeric(A,F)
+>>> cholmod.solve(F,X)
+>>> print X
+-1.4634e-01   4.8780e-02
+ 1.3333e+00   4.0000e+00
+ 4.8780e-01   1.1707e+00
+ 2.8333e+00   7.5000e+00
+</pre></div>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-144' xml:id='l2h-144' class="function">diag</tt></b>(</nobr></td>
+  <td><var>F</var>)</td></tr></table></dt>
+<dd>
+Returns the diagonal elements of the Cholesky factor <I>L</I> 
+in (<A HREF="#e-chol-ll">7.3</A>), as a dense matrix of the same type as <var>A</var>.
+Note that this only applies to Cholesky factorizations.
+The matrix <I>D</I> in an LDL<SPAN CLASS="MATH"><IMG
+ WIDTH="14" HEIGHT="18" ALIGN="BOTTOM" BORDER="0"
+ SRC="img40.gif"
+ ALT="$\mathrm{{}^T}$"></SPAN> factorization can be 
+retrieved via <tt class="function">cholmod.solve()</tt> with <var>sys</var> equal to 6.
+</dl>
+
+<P>
+In the functions listed above, the default values of the control 
+parameters described in the CHOLMOD user guide are used, except for 
+<tt class="ctype">Common->print</tt> which is set to 0 instead of 3
+and 
+<tt class="ctype">Common->supernodal</tt> which is set to 2 instead of 1.
+These parameters (and a few others) can be modified by making an 
+entry in the dictionary <tt class="member">cholmod.options</tt>. 
+The meaning of these parameters is as follows.
+<DL>
+<DT><STRONG><code>options['supernodal']</code></STRONG></DT>
+<DD>If equal to 0, a 
+factorization (<A HREF="#e-chol-ldl">7.4</A>) is computed using a simplicial 
+algorithm.
+If equal to 2, a factorization (<A HREF="#e-chol-ll">7.3</A>) is
+computed using a supernodal algorithm.
+If equal to 1, the most efficient of the two factorizations is
+selected, based on the sparsity pattern.  Default: 2.
+
+<P>
+</DD>
+<DT><STRONG><code>options['print']</code></STRONG></DT>
+<DD>A nonnegative integer that controls the 
+amount of output printed to the screen.
+Default: 0 (no output).
+</DD>
+</DL>
+
+<P>
+As an example that illustrates <tt class="function">diag()</tt> and the use of 
+<tt class="member">cholmod.options</tt>, we compute the logarithm of the determinant 
+of the coefficient matrix in (<A HREF="#e-A-pd">7.2</A>) by two methods.
+<div class="verbatim"><pre>
+>>> import math
+>>> from cvxopt.cholmod import options
+>>> from cvxopt.base import log
+>>> options['supernodal'] = 2
+>>> F = cholmod.symbolic(A)
+>>> cholmod.numeric(A,F)
+>>> print 2.0 * sum(log(cholmod.diag(F)))
+5.50533153593
+</pre></div>
+<div class="verbatim"><pre>
+>>> options['supernodal'] = 0
+>>> F = cholmod.symbolic(A)
+>>> cholmod.numeric(A,F)
+>>> Di = matrix(1.0, (4,1))
+>>> cholmod.solve(F,Di,sys=6)
+>>> print -sum(log(Di))
+5.50533153593
+</pre></div>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="7.2 General Linear Equations"
+  href="s-umfpack.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="7. Sparse Linear Equation"
+  href="c-spsolvers.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="7.4 Example: Covariance Selection"
+  href="e-covsel.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-umfpack.html">7.2 General Linear Equations</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="c-spsolvers.html">7. Sparse Linear Equation</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="e-covsel.html">7.4 Example: Covariance Selection</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-conventions.html b/doc/cvxopt/s-conventions.html
new file mode 100644
index 0000000..7f2305e
--- /dev/null
+++ b/doc/cvxopt/s-conventions.html
@@ -0,0 +1,470 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="s-blas1.html" />
+<link rel="prev" href="node14.html" />
+<link rel="parent" href="node14.html" />
+<link rel="next" href="s-blas1.html" />
+<meta name='aesop' content='information' />
+<title>3.1 Matrix Classes</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="3. The BLAS Interface"
+  href="node14.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="3. The BLAS Interface"
+  href="node14.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="3.2 Level 1 BLAS"
+  href="s-blas1.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node14.html">3. The BLAS Interface</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node14.html">3. The BLAS Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-blas1.html">3.2 Level 1 BLAS</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION005100000000000000000"></A> <A NAME="s-conventions"></A>
+<BR>
+3.1 Matrix Classes
+</H1>
+
+<P>
+The BLAS exploit several types of matrix structure: symmetric, 
+Hermitian, triangular, and banded.   We represent all these matrix 
+classes by dense real or complex <tt class="class">matrix</tt> objects, with additional 
+arguments that specify the structure.
+
+<P>
+<DL>
+<DT><STRONG>Vector</STRONG></DT>
+<DD>A real or complex <I>n</I>-vector is represented by a <tt class="class">matrix</tt> of type 
+<code>'d'</code> or <code>'z'</code> and length <I>n</I>, with the entries of the vector 
+stored in column-major order. 
+
+<P>
+</DD>
+<DT><STRONG>General matrix</STRONG></DT>
+<DD>A general real or complex <I>m</I> by <I>n</I> matrix is represented by 
+a real or complex <tt class="class">matrix</tt> of size (<I>m</I>, <I>n</I>).
+
+<P>
+</DD>
+<DT><STRONG>Symmetric matrix</STRONG></DT>
+<DD>A real or complex symmetric matrix of order <I>n</I> is represented
+by a real or complex <tt class="class">matrix</tt> of size (<I>n</I>, <I>n</I>), and a character 
+argument <var>uplo</var> with two possible values:  
+<code>'L'</code> and <code>'U'</code>.
+If <var>uplo</var> is <code>'L'</code>, the lower triangular part of the
+symmetric matrix is stored; if <var>uplo</var> is <code>'U'</code>, the upper
+triangular part is stored.  A square <tt class="class">matrix</tt> <var>X</var> of size 
+(<I>n</I>, <I>n</I>) can therefore be used to represent the symmetric 
+matrices
+<P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{eqnarray*}
+&  \left[\begin{array}{ccccc}
+X[0,0]   & X[1,0]   & X[2,0]   & \cdots & X[n-1,0] \\
+X[1,0]   & X[1,1]   & X[2,1]   & \cdots & X[n-1,1] \\
+X[2,0]   & X[2,1]   & X[2,2]   & \cdots & X[n-1,2] \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots \\
+X[n-1,0] & X[n-1,1] & X[n-1,2] & \cdots & X[n-1,n-1]
+\end{array}\right] & \mbox{if uplo = 'L'}, \\
+& \left[\begin{array}{ccccc}
+X[0,0]   & X[0,1]   & X[0,2]   & \cdots & X[0,n-1] \\
+X[0,1]   & X[1,1]   & X[1,2]   & \cdots & X[1,n-1] \\
+X[0,2]   & X[1,2]   & X[2,2]   & \cdots & X[2,n-1] \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots \\
+X[0,n-1] & X[1,n-1] & X[2,n-1] & \cdots & X[n-1,n-1]
+\end{array}\right] & \mbox{if uplo = U'}.
+\end{eqnarray*}
+ -->
+<IMG
+ WIDTH="542" HEIGHT="225" BORDER="0"
+ SRC="img1.gif"
+ ALT="\begin{eqnarray*}
+& \left[\begin{array}{ccccc}
+X[0,0] & X[1,0] & X[2,0] & \cdots...
+...& \cdots & X[n-1,n-1]
+\end{array}\right] & \mbox{if uplo = U'}.
+\end{eqnarray*}"></DIV>
+<BR CLEAR="ALL"><P></P>
+<BR CLEAR="ALL"><P></P>
+
+<P>
+</DD>
+<DT><STRONG>Complex Hermitian matrix</STRONG></DT>
+<DD>A complex Hermitian matrix of order <I>n</I> is represented
+by a <tt class="class">matrix</tt> of type <code>'z'</code> and size (<I>n</I>, <I>n</I>), and
+a character argument <var>uplo</var> with the ame meaning as for symmetric 
+matrices.
+A complex <tt class="class">matrix</tt> <var>X</var> of size (<I>n</I>, <I>n</I>) can 
+represent the Hermitian  matrices
+<P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{eqnarray*}
+&
+\left[\begin{array}{ccccc}
+\Re X[0,0]   & \bar X[1,0]   & \bar X[2,0]   & \cdots & \bar X[n-1,0] \\
+X[1,0]   & \Re X[1,1]   & \bar X[2,1]   & \cdots & \bar X[n-1,1] \\
+X[2,0]   & X[2,1]   & \Re X[2,2]   & \cdots & \bar X[n-1,2] \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots \\
+X[n-1,0] & X[n-1,1] & X[n-1,2] & \cdots & \Re X[n-1,n-1]
+\end{array}\right] & \mbox{if uplo = 'L'}, \\
+& \left[\begin{array}{ccccc}
+\Re X[0,0]   & X[0,1]   & X[0,2]   & \cdots & X[0,n-1] \\
+\bar X[0,1]   & \Re X[1,1]   & X[1,2]   & \cdots & X[1,n-1] \\
+\bar X[0,2]   & \bar X[1,2]   & \Re X[2,2]   & \cdots & X[2,n-1] \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots \\
+\bar X[0,n-1] & \bar X[1,n-1] & \bar X[2,n-1] & \cdots & \Re X[n-1,n-1]
+\end{array}\right] & \mbox{if uplo = 'U'}.
+\end{eqnarray*}
+ -->
+<IMG
+ WIDTH="556" HEIGHT="225" BORDER="0"
+ SRC="img2.gif"
+ ALT="\begin{eqnarray*}
+&
+\left[\begin{array}{ccccc}
+\Re X[0,0] & \bar X[1,0] & \bar X...
+...dots & \Re X[n-1,n-1]
+\end{array}\right] & \mbox{if uplo = 'U'}.
+\end{eqnarray*}"></DIV>
+<BR CLEAR="ALL"><P></P>
+<BR CLEAR="ALL"><P></P>
+
+<P>
+</DD>
+<DT><STRONG>Triangular matrix</STRONG></DT>
+<DD>A real or complex triangular matrix of order <I>n</I> is represented
+by a real or complex <tt class="class">matrix</tt> of size (<I>n</I>, <I>n</I>), and two 
+character arguments: an argument <var>uplo</var> with possible values 
+<code>'L'</code> and <code>'U'</code> to distinguish between lower and upper 
+triangular matrices, and an argument <var>diag</var> with possible values 
+<code>'U'</code> and <code>'N'</code> to distinguish between unit and non-unit 
+triangular matrices.  A square <tt class="class">matrix</tt> <var>X</var> of size 
+(<I>n</I>, <I>n</I>) can represent the triangular matrices
+<P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{eqnarray*}
+& \left[\begin{array}{ccccc}
+X[0,0]   & 0        & 0        & \cdots & 0 \\
+X[1,0]   & X[1,1]   & 0        & \cdots & 0 \\
+X[2,0]   & X[2,1]   & X[2,2]   & \cdots & 0 \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots \\
+X[n-1,0] & X[n-1,1] & X[n-1,2] & \cdots & X[n-1,n-1]
+\end{array}\right] & \mbox{if uplo = 'L' and diag = 'N'}, \\
+& \left[\begin{array}{ccccc}
+1   & 0   & 0   & \cdots & 0 \\
+X[1,0]   & 1   & 0   & \cdots & 0 \\
+X[2,0]   & X[2,1]   & 1   & \cdots & 0 \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots \\
+X[n-1,0] & X[n-1,1] & X[n-1,2] & \cdots & 1
+\end{array}\right] & \mbox{if uplo = 'L' and diag = 'U'}, \\
+& \left[\begin{array}{ccccc}
+X[0,0]   & X[0,1]   & X[0,2]   & \cdots & X[0,n-1] \\
+0   & X[1,1]   & X[1,2]   & \cdots & X[1,n-1] \\
+0   & 0   & X[2,2]   & \cdots & X[2,n-1] \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots \\
+0 & 0 & 0 & \cdots & X[n-1,n-1]
+\end{array}\right] & \mbox{if uplo = 'U' and diag = 'N'}, \\
+& \left[\begin{array}{ccccc}
+1   & X[0,1]   & X[0,2]   & \cdots & X[0,n-1] \\
+0   & 1   & X[1,2]   & \cdots & X[1,n-1] \\
+0   & 0   & 1   & \cdots & X[2,n-1] \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots \\
+0 & 0 & 0 & \cdots & 1
+\end{array}\right] & \mbox{if uplo = 'U' and diag = 'U'}.
+\end{eqnarray*}
+ -->
+<IMG
+ WIDTH="643" HEIGHT="450" BORDER="0"
+ SRC="img3.gif"
+ ALT="\begin{eqnarray*}
+& \left[\begin{array}{ccccc}
+X[0,0] & 0 & 0 & \cdots & 0 \\
+X...
+...ts & 1
+\end{array}\right] & \mbox{if uplo = 'U' and diag = 'U'}.
+\end{eqnarray*}"></DIV>
+<BR CLEAR="ALL"><P></P>
+<BR CLEAR="ALL"><P></P>
+
+<P>
+</DD>
+<DT><STRONG>General band matrix</STRONG></DT>
+<DD>A general real or complex <I>m</I> by <I>n</I> band matrix  with <I>kl</I>
+subdiagonals and <I>ku</I> superdiagonals is represented by a real or 
+complex <tt class="class">matrix</tt> <var>X</var> of size (<I>kl+ku+1</I>, <I>n</I>), and the two 
+integers <I>m</I> and <I>kl</I>.   
+The diagonals of the band matrix are stored in the rows of <var>X</var>, 
+starting at the top diagonal, and shifted horizontally so that the 
+entries of the 
+<I>k</I>th column of the band matrix are stored in column <I>k</I> of 
+<var>X</var>.  A <tt class="class">matrix</tt> <var>X</var> of size (<I>kl+ku+1</I>, <I>n</I>) therefore
+represents the <I>m</I> by <I>n</I> band matrix
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\left[ \begin{array}{ccccccc}
+X[k_u,0]     & X[k_u-1,1]     & X[k_u-2,2]     & \cdots & X[0,k_u] & 0               & \cdots \\
+X[k_u+1,0]   & X[k_u,1]       & X[k_u-1,2]     & \cdots & X[1,k_u] & X[0,k_u+1]   & \cdots \\
+X[k_u+2,0]   & X[k_u+1,1]     & X[k_u,2]       & \cdots & X[2,k_u] & X[1,k_u+1] & \cdots \\
+ \vdots      & \vdots         &  \vdots        & \ddots & \vdots   & \vdots          & \ddots  \\
+X[k_u+k_l,0] & X[k_u+k_l-1,1] & X[k_u+k_l-2,2] & \cdots &  &  & \\
+0            & X[k_u+k_l,1]   & X[k_u+k_l-1,2] & \cdots &  &  & \\
+\vdots       & \vdots         & \vdots         & \ddots &  &  & 
+\end{array}\right].
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="624" HEIGHT="161" BORDER="0"
+ SRC="img4.gif"
+ ALT="\begin{displaymath}
+\left[ \begin{array}{ccccccc}
+X[k_u,0] & X[k_u-1,1] & X[k_u-...
+...
+\vdots & \vdots & \vdots & \ddots & & &
+\end{array}\right].
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+</DD>
+<DT><STRONG>Symmetric band matrix</STRONG></DT>
+<DD>A real or complex symmetric band matrix of order <I>n</I> with <I>k</I>
+subdiagonals, is represented by a real or complex matrix <var>X</var> of 
+size (<I>k</I>+1, <I>n</I>), and an argument <I>uplo</I> to indicate 
+whether the subdiagonals (<I>uplo</I> is <code>'L'</code>) or superdiagonals 
+(<I>uplo</I> is <code>'U'</code>) are stored.
+The <I>k</I>+1 diagonals are stored as rows of <var>X</var>, starting at the top 
+diagonal (<EM>i.e.</EM>, the main diagonal if <I>uplo</I> is <code>'L'</code>,  or
+the <I>k</I>th superdiagonal if <I>uplo</I> is <code>'U'</code>) and shifted
+horizontally so that the entries of the 
+<I>k</I>th column of the band matrix are stored in column <I>k</I> of 
+<var>X</var>.  A <tt class="class">matrix</tt> <I>X</I> of size (<I>k</I>+1, <I>n</I>) can therefore
+represent the band matrices 
+<P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{eqnarray*}
+& \left[ \begin{array}{ccccccc}
+X[0,0] & X[1,0]   & X[2,0]   & \cdots & X[k,0]   & 0        & \cdots \\
+X[1,0] & X[0,1]   & X[1,1]   & \cdots & X[k-1,1] & X[k,1]   & \cdots \\
+X[2,0] & X[1,1]   & X[0,2]   & \cdots & X[k-2,2] & X[k-1,2] & \cdots \\
+\vdots & \vdots   &  \vdots  & \ddots & \vdots   & \vdots   & \ddots \\
+X[k,0] & X[k-1,1] & X[k-2,2] & \cdots &  &  & \\
+0      & X[k,1]   & X[k-1,2] & \cdots &  &  & \\
+\vdots & \vdots   & \vdots   & \ddots &  &  & 
+\end{array}\right] & \mbox{if uplo = 'L'}, \\
+& 
+\left[ \begin{array}{ccccccc}
+X[k,0]   & X[k-1,1] & X[k-2,2] & \cdots & X[0,k] & 0        & \cdots \\
+X[k-1,1] & X[k,1]   & X[k-1,2] & \cdots & X[1,k] & X[0,k+1] & \cdots \\
+X[k-2,2] & X[k-1,2] & X[k,2]   & \cdots & X[2,k] & X[1,k+1] & \cdots \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots & \vdots   & \ddots \\
+X[0,k]   & X[1,k]   & X[2,k]   & \cdots &  &  & \\
+0        & X[0,k+1] & X[1,k+1] & \cdots &  &  & \\
+\vdots   & \vdots   & \vdots   & \ddots &  &  & 
+\end{array}\right] & \mbox{if uplo='U'}.
+\end{eqnarray*}
+ -->
+<IMG
+ WIDTH="608" HEIGHT="322" BORDER="0"
+ SRC="img5.gif"
+ ALT="\begin{eqnarray*}
+& \left[ \begin{array}{ccccccc}
+X[0,0] & X[1,0] & X[2,0] & \cd...
+... \vdots & \ddots & & &
+\end{array}\right] & \mbox{if uplo='U'}.
+\end{eqnarray*}"></DIV>
+<BR CLEAR="ALL"><P></P>
+<BR CLEAR="ALL"><P></P>
+
+<P>
+</DD>
+<DT><STRONG>Hermitian  band matrix</STRONG></DT>
+<DD>A complex Hermitian band matrix of order <I>n</I> with <I>k</I> 
+subdiagonals is represented by a complex matrix of size 
+(<I>k+1</I>, <I>n</I>) and an argument <var>uplo</var>.  
+A <tt class="class">matrix</tt> <I>X</I> of size (<I>k</I>+1, <I>n</I>) can represent the band
+matrices 
+<P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{eqnarray*}
+& \left[ \begin{array}{ccccccc}
+\Re X[0,0] & \bar X[1,0]   & \bar X[2,0]   & \cdots & \bar X[k,0]   & 0        & \cdots \\
+X[1,0] & \Re X[0,1]   & \bar X[1,1]   & \cdots & \bar X[k-1,1] & \bar X[k,1]   & \cdots \\
+X[2,0] & X[1,1]   & \Re X[0,2]   & \cdots & \bar X[k-2,2] & \bar X[k-1,2] & \cdots \\
+\vdots & \vdots   &  \vdots  & \ddots & \vdots   & \vdots   & \ddots \\
+X[k,0] & X[k-1,1] & X[k-2,2] & \cdots &  &  & \\
+0      & X[k,1]   & X[k-1,2] & \cdots &  &  & \\
+\vdots & \vdots   & \vdots   & \ddots &  &  & 
+\end{array}\right] & \mbox{if uplo = 'L'}, \\
+& 
+\left[ \begin{array}{ccccccc}
+\Re X[k,0]   & X[k-1,1] & X[k-2,2] & \cdots & X[0,k] & 0        & \cdots \\
+\bar X[k-1,1] & \Re X[k,1]   & X[k-1,2] & \cdots & X[1,k] & X[0,k+1] & \cdots \\
+\bar X[k-2,2] & \bar X[k-1,2] & \Re X[k,2]   & \cdots & X[2,k] & X[1,k+1] & \cdots \\
+\vdots   & \vdots   & \vdots   & \ddots & \vdots & \vdots   & \ddots \\
+\bar X[0,k]   & \bar X[1,k]   & \bar X[2,k]   & \cdots &  &  & \\
+0        & \bar X[0,k+1] & \bar X[1,k+1] & \cdots &  &  & \\
+\vdots   & \vdots   & \vdots   & \ddots &  &  & 
+\end{array}\right] & \mbox{if uplo='U'}.
+\end{eqnarray*}
+ -->
+<IMG
+ WIDTH="619" HEIGHT="322" BORDER="0"
+ SRC="img6.gif"
+ ALT="\begin{eqnarray*}
+& \left[ \begin{array}{ccccccc}
+\Re X[0,0] & \bar X[1,0] & \ba...
+... \vdots & \ddots & & &
+\end{array}\right] & \mbox{if uplo='U'}.
+\end{eqnarray*}"></DIV>
+<BR CLEAR="ALL"><P></P>
+<BR CLEAR="ALL"><P></P>
+
+<P>
+</DD>
+<DT><STRONG>Triangular band matrix</STRONG></DT>
+<DD>A triangular band matrix of order <I>n</I> with <I>k</I> subdiagonals or
+superdiagonals is represented by a real complex matrix of size 
+(<I>k+1</I>, <I>n</I>) and two character arguments <var>uplo</var> and 
+<var>diag</var>.  
+A <tt class="class">matrix</tt> <I>X</I> of size (<I>k</I>+1, <I>n</I>) can represent the band
+matrices 
+<P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{eqnarray*}
+& \left[ \begin{array}{cccc}
+X[0,0] & 0        & 0        & \cdots \\
+X[1,0] & X[0,1]   & 0        & \cdots  \\
+X[2,0] & X[1,1]   & X[0,2]   & \cdots \\
+\vdots & \vdots   & \vdots   & \ddots \\
+X[k,0] & X[k-1,1] & X[k-2,2] & \cdots \\
+0      & X[k,1]   & X[k-1,1] & \cdots \\
+\vdots & \vdots   & \vdots   & \ddots 
+\end{array}\right] & \mbox{if uplo = 'L' and diag = 'N'},  \\
+& \left[ \begin{array}{cccc}
+1      & 0        & 0        & \cdots \\
+X[1,0] & 1        & 0        & \cdots  \\
+X[2,0] & X[1,1]   & 1        & \cdots \\
+\vdots & \vdots   & \vdots   & \ddots \\
+X[k,0] & X[k-1,1] & X[k-2,2] & \cdots \\
+0      & X[k,1]   & X[k-1,2] & \cdots \\
+\vdots & \vdots   & \vdots   & \ddots 
+\end{array}\right] & \mbox{if uplo = 'L'  and diag = 'U'}, \\
+& \left[ \begin{array}{ccccccc}
+X[k,0] & X[k-1,1] & X[k-2,3] & \cdots & X[0,k]  & 0        & \cdots\\
+0      & X[k,1]   & X[k-1,2] & \cdots & X[1,k]  & X[0,k+1] & \cdots \\
+0      & 0        & X[k,2]   & \cdots & X[2,k]  & X[1,k+1] & \cdots \\
+\vdots & \vdots   &  \vdots  & \ddots & \vdots  & \vdots   & \ddots  
+\end{array}\right] & \mbox{if uplo = 'U' and diag = 'N'}, \\
+& \left[ \begin{array}{ccccccc}
+1      & X[k-1,1] & X[k-2,3] & \cdots & X[0,k]  & 0        & \cdots\\
+0      & 1        & X[k-1,2] & \cdots & X[1,k]  & X[0,k+1] & \cdots \\
+0      & 0        & 1        & \cdots & X[2,k]  & X[1,k+1] & \cdots \\
+\vdots & \vdots   &  \vdots  & \ddots & \vdots  & \vdots   & \ddots  
+\end{array}\right] & \mbox{if uplo = 'U' and diag = 'U'}.
+\end{eqnarray*}
+ -->
+<IMG
+ WIDTH="681" HEIGHT="509" BORDER="0"
+ SRC="img7.gif"
+ ALT="\begin{eqnarray*}
+& \left[ \begin{array}{cccc}
+X[0,0] & 0 & 0 & \cdots \\
+X[1,0...
+...ddots
+\end{array}\right] & \mbox{if uplo = 'U' and diag = 'U'}.
+\end{eqnarray*}"></DIV>
+<BR CLEAR="ALL"><P></P>
+<BR CLEAR="ALL"><P></P>
+</DD>
+</DL>
+
+<P>
+When discussing BLAS functions in the following sections we will
+omit several less important optional arguments that can 
+be used to select submatrices for in-place operations. 
+The complete specification is  documented in the docstrings of the 
+source code and the <b class="program">pydoc</b> help program.
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="3. The BLAS Interface"
+  href="node14.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="3. The BLAS Interface"
+  href="node14.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="3.2 Level 1 BLAS"
+  href="s-blas1.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node14.html">3. The BLAS Interface</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node14.html">3. The BLAS Interface</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-blas1.html">3.2 Level 1 BLAS</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-creating-matrices.html b/doc/cvxopt/s-creating-matrices.html
new file mode 100644
index 0000000..8602706
--- /dev/null
+++ b/doc/cvxopt/s-creating-matrices.html
@@ -0,0 +1,261 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node6.html" />
+<link rel="prev" href="node4.html" />
+<link rel="parent" href="node4.html" />
+<link rel="next" href="node6.html" />
+<meta name='aesop' content='information' />
+<title>2.1 Creating Matrices</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.2 Attributes and Methods"
+  href="node6.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node6.html">2.2 Attributes and Methods</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION004100000000000000000"></A><A NAME="s-creating-matrices"></A>
+<BR>
+2.1 Creating Matrices
+</H1>
+A <tt class="class">matrix</tt> object is created by calling the function <tt class="function">matrix()</tt>. 
+The arguments specify the values of the coefficients, the
+dimensions, and the type (integer, double or complex) of the matrix.
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-1' xml:id='l2h-1' class="function">matrix</tt></b>(</nobr></td>
+  <td><var>x</var><big>[</big><var>, size</var><big>[</big><var>, tc</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+<var>size</var> is a tuple of length two with the matrix dimensions.
+The number of rows and/or the number of columns can be zero.
+
+<P>
+<var>tc</var> stands for typecode. The possible values are <code>'i'</code>, <code>'d'</code> and 
+<code>'z'</code>, for integer, real (double) and complex matrices, respectively.  
+
+<P>
+<var>x</var> can be a number, a sequence of numbers, a dense or sparse 
+matrix, a two-dimensional <tt class="module">numarray</tt> array, or a list of
+lists of matrices and numbers.  
+
+<UL>
+<LI>If <var>x</var> is a number (Python integer, float or complex), a matrix
+is created with the dimensions specified by <var>size</var> and with all the 
+coefficients equal to <var>x</var>.  
+The default value of <var>size</var> is (1,1), and the default value
+of <var>tc</var> is the type of <var>x</var>.
+If necessary, the type of <var>x</var> is converted (from integer to double
+when used to create a matrix of type <code>'d'</code>, and from integer or
+double to complex when used to create a matrix of type <code>'z'</code>).
+
+<P>
+<div class="verbatim"><pre>
+>>> from cvxopt.base import matrix
+>>> A = matrix(1, (1,4))   
+>>> print A
+   1      1      1      1
+>>> A = matrix(1.0, (1,4))   
+>>> print A
+   1.0000e+00   1.0000e+00   1.0000e+00   1.0000e+00
+>>> A = matrix(1+1j)     
+>>> print A
+   1.0000e+00+j1.0000e+00
+</pre></div>
+
+<P>
+</LI>
+<LI>If <var>x</var> is a sequence of numbers (list, tuple, <tt class="module">array</tt>
+array, xrange object, one-dimensional <tt class="module">numarray</tt> array, ...),
+then the numbers are interpreted as the coefficients of a matrix in 
+column-major order.  The length of <var>x</var> must be equal to the product 
+of <var>size</var>[0] and <var>size</var>[1].
+If <var>size</var> is not specified, a matrix with one column is created. 
+If <var>tc</var> is not specified, it is determined from the elements of 
+<var>x</var> (and if that is impossible, for example because <var>x</var> is
+an empty list, a value <code>'i'</code> is used).  
+Type conversion takes place as for scalar <var>x</var>.
+
+<P>
+The following example shows several ways to define the same integer 
+matrix.
+<div class="verbatim"><pre>
+>>> A = matrix([0, 1, 2, 3], (2,2))  
+>>> A = matrix((0, 1, 2, 3), (2,2))  
+>>> A = matrix(xrange(4), (2,2))
+>>> from array import array
+>>> A = matrix(array('i', [0,1,2,3]), (2,2))
+>>> print A
+   0      2
+   1      3
+</pre></div>
+
+<P>
+</LI>
+<LI>If <var>x</var> is a dense or sparse matrix (a <tt class="class">matrix</tt> or a <tt class="class">spmatrix</tt> 
+object), or a two-dimensional <tt class="module">numarray</tt> array of type <code>'i'</code>, 
+<code>'d'</code> or <code>'z'</code>, then the  coefficients of <var>x</var> are copied, in 
+column-major order, to a new matrix of the given size.  
+The total number of elements in the new matrix (the product of 
+<var>size</var>[0] and <var>size</var>[1]) must be the same as the product of  
+the dimensions of <var>x</var>.  If <var>size</var> is not specified, the 
+dimensions of <var>x</var> are used.  
+The default value of <var>tc</var> is the type of <var>x</var>. 
+Type conversion takes place when the type of <var>x</var> differs from 
+<var>tc</var>, in a similar way as for scalar <var>x</var>.  
+
+<P>
+<div class="verbatim"><pre>
+>>> A = matrix([1., 2., 3., 4., 5., 6.], (2,3))  
+>>> print A
+   1.0000e+00   3.0000e+00   5.0000e+00   
+   2.0000e+00   4.0000e+00   6.0000e+00   
+>>> B = matrix(A, (3,2))  
+>>> print B
+   1.0000e+00   4.0000e+00   
+   2.0000e+00   5.0000e+00   
+   3.0000e+00   6.0000e+00   
+>>> C = matrix(B, tc='z')      
+>>> print C
+   1.0000e+00-j0.0000e+00   4.0000e+00-j0.0000e+00
+   2.0000e+00-j0.0000e+00   5.0000e+00-j0.0000e+00
+   3.0000e+00-j0.0000e+00   6.0000e+00-j0.0000e+00
+>>> from numarray import array
+>>> x = array([1., 2., 3., 4., 5., 6.], shape=(2,3))
+>>> print x
+[[ 1.  2.  3.]
+ [ 4.  5.  6.]]
+>>> y = matrix(x)
+>>> print y
+   1.0000e+00   2.0000e+00   3.0000e+00
+   4.0000e+00   5.0000e+00   6.0000e+00
+</pre></div>
+
+<P>
+</LI>
+<LI>If <var>x</var> is a list of lists of matrices 
+(<tt class="class">matrix</tt> or <tt class="class">spmatrix</tt> objects) or numbers (Python integer, float or 
+complex), then each element of <var>x</var> is interpreted as a 
+block-column stored in column-major order. 
+If <var>size</var> is not specified, the block-columns are juxtaposed
+to obtain a matrix with <code>len(<var>x</var>)</code> block-columns.
+If <var>size</var> is specified, then the matrix with <code>len(<var>x</var>)</code>
+block-columns is resized by copying its elements in column-major order 
+into a matrix of the dimensions given by <var>size</var>.  
+If <var>tc</var> is not specified, it is determined from the elements of 
+<var>x</var> (and if that is impossible, for example because <var>x</var> is
+a list of empty lists, a value <code>'i'</code> is used).  
+The same rules for type conversion apply as for scalar <var>x</var>.
+
+<P>
+<div class="verbatim"><pre>
+>>> A = matrix([[1., 2.], [3., 4.], [5., 6.]])
+>>> print A
+   1.0000e+00   3.0000e+00   5.0000e+00
+   2.0000e+00   4.0000e+00   6.0000e+00
+>>> A1 = matrix([1, 2], (2,1))
+>>> B1 = matrix([6, 7, 8, 9, 10, 11], (2,3))
+>>> B2 = matrix([12, 13, 14, 15, 16, 17], (2,3))
+>>> B3 = matrix([18, 19, 20], (1,3))
+>>> print matrix([[A1, 3.0, 4.0, 5.0], [B1, B2, B3]])
+   1.0000e+00   6.0000e+00   8.0000e+00   1.0000e+01
+   2.0000e+00   7.0000e+00   9.0000e+00   1.1000e+01
+   3.0000e+00   1.2000e+01   1.4000e+01   1.6000e+01
+   4.0000e+00   1.3000e+01   1.5000e+01   1.7000e+01
+   5.0000e+00   1.8000e+01   1.9000e+01   2.0000e+01
+</pre></div>
+
+<P>
+A matrix with a single block-column can be represented by a single 
+list (<EM>i.e.</EM>, when the length of <var>x</var> is one, it can be replaced with
+<code><var>x</var>[0]</code>).
+<div class="verbatim"><pre>
+>>> print matrix([B1, B2, B3])
+   6      8      10  
+   7      9      11  
+   12     14     16  
+   13     15     17  
+   18     19     20
+</pre></div>
+</LI>
+</UL>
+</dl>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.2 Attributes and Methods"
+  href="node6.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node6.html">2.2 Attributes and Methods</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-creating-spmatrix.html b/doc/cvxopt/s-creating-spmatrix.html
new file mode 100644
index 0000000..b73a27e
--- /dev/null
+++ b/doc/cvxopt/s-creating-spmatrix.html
@@ -0,0 +1,359 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="e-spA-example.html" />
+<link rel="prev" href="node33.html" />
+<link rel="parent" href="node33.html" />
+<link rel="next" href="e-spA-example.html" />
+<meta name='aesop' content='information' />
+<title>6.1 Creating Sparse Matrices</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="6. Sparse Matrices (cvxopt.base)"
+  href="node33.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="6. Sparse Matrices (cvxopt.base)"
+  href="node33.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="6.2 Attributes and Methods"
+  href="e-spA-example.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node33.html">6. Sparse Matrices (cvxopt.base)</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node33.html">6. Sparse Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="e-spA-example.html">6.2 Attributes and Methods</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION008100000000000000000"></A> <A NAME="s-creating-spmatrix"></A>
+<BR>
+6.1 Creating Sparse Matrices
+</H1>
+A general <tt class="class">spmatrix</tt> object can be thought of as a <em>triplet 
+description</em> of a sparse matrix, <EM>i.e.</EM>, a list of entries of the matrix, 
+with for each entry the value, row index, and column index.  
+Entries that are not included in the list are assumed to be zero.  
+For example, the sparse matrix
+<BR>
+<DIV ALIGN="RIGHT" CLASS="mathdisplay">
+
+<!-- MATH
+ \begin{equation}
+A = \left[ \begin{array}{rrrrr}
+  0 & 2 & 0 & 0 & 3 \\
+  2 & 0 & 0 & 0 & 0 \\
+ -1 & -2 & 0 & 4 & 0 \\
+  0 & 0 & 1 & 0 & 0 \end{array} \right]
+\end{equation}
+ -->
+<A NAME="e-sparse-A"></A>
+<TABLE WIDTH="100%" ALIGN="CENTER">
+<TR VALIGN="MIDDLE"><TD></TD><TD ALIGN="CENTER" NOWRAP><A NAME="e-sparse-A"></A><IMG
+ WIDTH="193" HEIGHT="83" BORDER="0"
+ SRC="img78.gif"
+ ALT="\begin{displaymath}
+A = \left[ \begin{array}{rrrrr}
+0 & 2 & 0 & 0 & 3 \\
+2 &...
+...-1 & -2 & 0 & 4 & 0 \\
+0 & 0 & 1 & 0 & 0 \end{array} \right]
+\end{displaymath}"></TD>
+<TD CLASS="eqno" WIDTH=10 ALIGN="RIGHT">
+(6.1)</TD></TR>
+</TABLE>
+<BR CLEAR="ALL"></DIV><P></P>
+has the triplet description 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+(2,1,0), \qquad (-1,2,0), \qquad (2,0,1), \qquad (-2,2,1), \qquad
+(1,3,2), \qquad (4,2,3), \qquad (3,0,4).
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="611" HEIGHT="28" BORDER="0"
+ SRC="img79.gif"
+ ALT="\begin{displaymath}
+(2,1,0), \qquad (-1,2,0), \qquad (2,0,1), \qquad (-2,2,1), \qquad
+(1,3,2), \qquad (4,2,3), \qquad (3,0,4).
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+The list may include entries with a zero value, so triplet
+descriptions are not necessarily unique.
+The list
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+(2,1,0), \qquad (-1,2,0), \qquad (0,3,0), \qquad (2,0,1), \qquad 
+ (-2,2,1), \qquad (1,3,2), \qquad (4,2,3), \qquad (3,0,4)
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="696" HEIGHT="28" BORDER="0"
+ SRC="img80.gif"
+ ALT="\begin{displaymath}
+(2,1,0), \qquad (-1,2,0), \qquad (0,3,0), \qquad (2,0,1), \qquad
+(-2,2,1), \qquad (1,3,2), \qquad (4,2,3), \qquad (3,0,4)
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+is another triplet description of the same matrix.
+
+<P>
+An <tt class="class">spmatrix</tt> object corresponds to a particular triplet 
+description of a sparse matrix.  We will refer to the entries in
+the triplet description as the <em>nonzero entries</em> of the object, 
+even though they may have a numerical value zero.
+
+<P>
+Two functions are provided to create sparse matrices. 
+The first, <tt class="function">spmatrix()</tt>, constructs a sparse matrix from 
+a triplet description. 
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-115' xml:id='l2h-115' class="function">spmatrix</tt></b>(</nobr></td>
+  <td><var>x, I, J</var><big>[</big><var>, size</var><big>[</big><var>, tc</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+
+<P>
+<var>I</var> and <var>J</var> are sequences of integers (lists, tuples, 
+<tt class="module">array</tt> arrays, xrange objects, ...) or integer matrices 
+(<tt class="class">matrix</tt> objects with typecode <code>'i'</code>), containing the row and column 
+indices of the nonzero entries.  
+The lengths of <var>I</var> and <var>J</var> must be  equal.  If they 
+are matrices, they are treated as lists of indices stored in 
+column-major order, <EM>i.e.</EM>, as lists <code>list(<var>I</var>)</code>, respectively, 
+<code>list(<var>J</var>)</code>. 
+
+<P>
+<var>size</var> is a tuple of nonnegative integers with the row and column 
+dimensions of the matrix.
+The <var>size</var> argument is only needed when creating a matrix with 
+a zero last row or last column.  If <var>size</var> is not specified, it 
+is determined from <var>I</var> and <var>J</var>:
+the default value for <code><var>size</var>[0]</code> is <code>max(<var>I</var>)+1</code> 
+if <var>I</var> is nonempty and zero otherwise.  
+The default value for <code><var>size</var>[1]</code> is 
+<code>max(<var>J</var>)+1</code> if <var>J</var> is nonempty and zero otherwise.
+
+<P>
+<var>tc</var> is the typecode, <code>'d'</code> or <code>'z'</code>, for double and complex 
+matrices, respectively.   Integer sparse matrices are not implemented.
+
+<P>
+<var>x</var> can be a number, a sequence of numbers, or a dense matrix.  
+This argument specifies the numerical values of the nonzero entries.
+
+<UL>
+<LI>If <var>x</var> is a number (Python integer, float or complex), 
+a matrix is created with the sparsity pattern defined by <var>I</var> and 
+<var>J</var>, and nonzero entries initialized to the value of <var>x</var>.  
+The default value of <var>tc</var> is <code>'d'</code> if <var>x</var> is integer or float,
+and <code>'z'</code> if <var>x</var> is complex.  
+
+<P>
+The following code creates a 4 by 4 sparse identity matrix.
+<div class="verbatim"><pre>
+>>> from cvxopt.base import spmatrix
+>>> A = spmatrix(1.0, range(4), range(4))
+>>> print A  
+SIZE: (4,4)
+(0, 0)  1.0000e+00
+(1, 1)  1.0000e+00
+(2, 2)  1.0000e+00
+(3, 3)  1.0000e+00
+</pre></div>
+
+<P>
+</LI>
+<LI>If <var>x</var> is a sequence of numbers, a sparse matrix is created 
+with the entries of <var>x</var> copied to the entries indexed by <var>I</var> 
+and <var>J</var>.  The list <var>x</var> must have the same length as <var>I</var> and 
+<var>J</var>.
+The default value of <var>tc</var> is determined from the elements of 
+<var>x</var>: 
+<code>'d'</code> if <var>x</var> contains integers and floating-point numbers or
+if <var>x</var> is an empty list,
+and <code>'z'</code> if <var>x</var> contains at least one complex number.
+
+<P>
+As an example, the matrix (<A HREF="#e-sparse-A">6.1</A>) can be created as follows.
+<div class="verbatim"><pre>
+>>> A = spmatrix([2,-1,2,-2,1,4,3], [1,2,0,2,3,2,0], [0,0,1,1,2,3,4])
+>>> print A 
+SIZE: (4,5)
+(1, 0)  2.0000e+00
+(2, 0) -1.0000e+00
+(0, 1)  2.0000e+00
+(2, 1) -2.0000e+00
+(3, 2)  1.0000e+00
+(2, 3)  4.0000e+00
+(0, 4)  3.0000e+00
+</pre></div>
+
+<P>
+</LI>
+<LI>If <var>x</var> is a dense matrix, a sparse matrix is created with 
+all the entries of <var>x</var> copied, in column-major order, to the 
+entries indexed by <var>I</var> and <var>J</var>.
+The matrix <var>x</var> must have the same length as <var>I</var> and <var>J</var>.
+The default value of <var>tc</var> is <code>'d'</code> if <var>x</var> is an <code>'i'</code> or <code>'d'</code> matrix, and <code>'z'</code> otherwise.
+</LI>
+</UL>
+
+<P>
+If <var>I</var> and <var>J</var> contain repeated entries, the corresponding 
+values of the coefficients are added.
+</dl>
+
+<P>
+The function <tt class="function">sparse()</tt> constructs a sparse matrix from
+a block-matrix description.
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-116' xml:id='l2h-116' class="function">sparse</tt></b>(</nobr></td>
+  <td><var>x</var><big>[</big><var>, tc</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+<var>tc</var> is the typecode, <code>'d'</code> or <code>'z'</code>, for double and complex 
+matrices, respectively.
+
+<P>
+<var>x</var> can be a <tt class="class">matrix</tt>, <tt class="class">spmatrix</tt>, or a list of lists of matrices 
+(<tt class="class">matrix</tt> or <tt class="class">spmatrix</tt> objects) and numbers (Python integer, float or 
+complex). 
+
+<UL>
+<LI>If <var>x</var> is a <tt class="class">matrix</tt> or <tt class="class">spmatrix</tt> object, then a sparse matrix 
+of the same size and the same numerical value is created. 
+Numerical zeros in <var>x</var> are treated as structural zeros and removed 
+from the triplet description of the new sparse matrix.
+
+<P>
+</LI>
+<LI>If <var>x</var> is a list of lists of matrices (<tt class="class">matrix</tt> or <tt class="class">spmatrix</tt>) 
+and numbers (Python integer, float or complex) then each element of 
+<var>x</var> is interpreted as a (block-)column matrix stored in 
+colum-major order, and a block-matrix is constructed by juxtaposing
+the <code>len(<var>x</var>)</code> block-columns
+(as in <tt class="function">matrix()</tt>, see section <A href="s-creating-matrices.html#s-creating-matrices">2.1</A>). 
+Numerical zeros are removed from the triplet description of the new 
+matrix.  
+
+<P>
+The following example shows how to construct a sparse block-matrix.
+<div class="verbatim"><pre>
+>>> from cvxopt.base import matrix, spmatrix, sparse
+>>> A = matrix([[1, 2, 0], [2, 1, 2], [0, 2, 1]])
+>>> B = spmatrix([], [], [], (3,3))
+>>> C = spmatrix([3, 4, 5], [0, 1, 2], [0, 1, 2])
+>>> print sparse([[A, B], [B, C]])
+SIZE: (6,6)
+(0, 0)  1.0000e+00
+(1, 0)  2.0000e+00
+(0, 1)  2.0000e+00
+(1, 1)  1.0000e+00
+(2, 1)  2.0000e+00
+(1, 2)  2.0000e+00
+(2, 2)  1.0000e+00
+(3, 3)  3.0000e+00
+(4, 4)  4.0000e+00
+(5, 5)  5.0000e+00
+</pre></div>
+
+<P>
+A matrix with a single block-column can be represented by a single
+list.
+<div class="verbatim"><pre>
+>>> print sparse([A, C])
+SIZE: (6,3)
+(0, 0)  1.0000e+00
+(1, 0)  2.0000e+00
+(3, 0)  3.0000e+00
+(0, 1)  2.0000e+00
+(1, 1)  1.0000e+00
+(2, 1)  2.0000e+00
+(4, 1)  4.0000e+00
+(1, 2)  2.0000e+00
+(2, 2)  1.0000e+00
+(5, 2)  5.0000e+00
+</pre></div>
+</LI>
+</UL>
+
+<P>
+</dl>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="6. Sparse Matrices (cvxopt.base)"
+  href="node33.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="6. Sparse Matrices (cvxopt.base)"
+  href="node33.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="6.2 Attributes and Methods"
+  href="e-spA-example.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node33.html">6. Sparse Matrices (cvxopt.base)</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node33.html">6. Sparse Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="e-spA-example.html">6.2 Attributes and Methods</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-external.html b/doc/cvxopt/s-external.html
new file mode 100644
index 0000000..f6a36d3
--- /dev/null
+++ b/doc/cvxopt/s-external.html
@@ -0,0 +1,129 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="s-parameters.html" />
+<link rel="prev" href="node52.html" />
+<link rel="parent" href="node45.html" />
+<link rel="next" href="s-parameters.html" />
+<meta name='aesop' content='information' />
+<title>8.8 Optional Solvers</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.7 Exploiting Structure in"
+  href="node52.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.9 Algorithm Parameters"
+  href="s-parameters.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node52.html">8.7 Exploiting Structure in</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-parameters.html">8.9 Algorithm Parameters</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0010800000000000000000"></A> <A NAME="s-external"></A>
+<BR>
+8.8 Optional Solvers
+</H1>
+CVXOPT includes optional interfaces to several other optimization 
+libraries.
+
+<P>
+<DL>
+<DT><STRONG>GLPK</STRONG></DT>
+<DD><tt class="function">lp()</tt> with the <code>solver='glpk'</code> option uses 
+the the simplex algorithm in 
+<a class="ulink" href="http://www.gnu.org/software/glpk/glpk.html"
+  >GLPK (GNU Linear Programming Kit)</a>.   
+
+<P>
+</DD>
+<DT><STRONG>MOSEK</STRONG></DT>
+<DD><tt class="function">lp()</tt> and <tt class="function">qp()</tt> with the 
+<code>solver='mosek'</code> option call routines from  
+<a class="ulink" href="http://www.mosek.com"
+  >MOSEK</a> version 4.  
+
+<P>
+</DD>
+<DT><STRONG>DSDP</STRONG></DT>
+<DD><tt class="function">sdp()</tt> with the <code>solver='dsdp'</code> option uses 
+the 
+<a class="ulink" href="http://www-unix.mcs.anl.gov/DSDP"
+  >DSDP5.8</a> solver.  
+</DD>
+</DL>
+GLPK, MOSEK and DSDP are not included in the CVXOPT distribution and 
+need to be installed separately.  
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.7 Exploiting Structure in"
+  href="node52.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.9 Algorithm Parameters"
+  href="s-parameters.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node52.html">8.7 Exploiting Structure in</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-parameters.html">8.9 Algorithm Parameters</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-functions.html b/doc/cvxopt/s-functions.html
new file mode 100644
index 0000000..cbe15b2
--- /dev/null
+++ b/doc/cvxopt/s-functions.html
@@ -0,0 +1,511 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node58.html" />
+<link rel="prev" href="s-variables.html" />
+<link rel="parent" href="node55.html" />
+<link rel="next" href="node58.html" />
+<meta name='aesop' content='information' />
+<title>9.2 Functions</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="9.1 Variables"
+  href="s-variables.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="9. Modeling (cvxopt.modeling)"
+  href="node55.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="9.3 Constraints"
+  href="node58.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-variables.html">9.1 Variables</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node55.html">9. Modeling (cvxopt.modeling)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node58.html">9.3 Constraints</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0011200000000000000000"></A> <A NAME="s-functions"></A>
+<BR>
+9.2 Functions
+</H1>
+Objective and constraint functions can be defined via overloaded 
+operations on variables and other functions.  A function <var>f</var> is 
+interpreted as a column vector, with length <code>len(<var>f</var>)</code> 
+and with a value that depends on the values of its variables.  
+Functions have two public attributes.  
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-155' xml:id='l2h-155' class="method">variables</tt></b>(</nobr></td>
+  <td><var></var>)</td></tr></table></dt>
+<dd>
+Returns a copy of the list of variables of the function.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-156' xml:id='l2h-156' class="method">value</tt></b>(</nobr></td>
+  <td><var></var>)</td></tr></table></dt>
+<dd>
+The function value.  If any of the variables of <var>f</var> has value 
+<code>None</code>, then <var>f</var>.<tt class="method">value()</tt> returns <code>None</code>.
+Otherwise, it returns a dense <code>'d'</code> matrix of size 
+(<code>len(<var>f</var>)</code>,1) with the function value computed from the 
+<tt class="member">value</tt> attributes of the variables of <var>f</var>.  
+</dl>
+
+<P>
+Three types of functions are supported: affine, convex 
+piecewise-linear and concave piecewise-linear.
+
+<P>
+<b>Affine functions</b> represent vector valued functions of the form
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+f(x_1,\ldots,x_n) = A_1 x_1 + \cdots + A_n x_n + b.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="272" HEIGHT="28" BORDER="0"
+ SRC="img169.gif"
+ ALT="\begin{displaymath}
+f(x_1,\ldots,x_n) = A_1 x_1 + \cdots + A_n x_n + b.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+The coefficients can be scalars or dense or sparse matrices. The 
+constant term is a scalar or a column vector.
+
+<P>
+Affine functions result from the following operations.
+<DL>
+<DT><STRONG>Unary operations</STRONG></DT>
+<DD>For a variable <var>x</var>, the unary operation <code>+<var>x</var></code> results in 
+an affine function with <var>x</var> as variable, coefficient 1.0, and 
+constant term 0.0.  The unary operation <code>-<var>x</var></code> returns an 
+affine function with <var>x</var> as variable, coefficient -1.0, and 
+constant term 0.0.  For an affine function <var>f</var>, <code>+<var>f</var></code> is 
+a copy of <var>f</var>, and <code>-<var>f</var></code> is a copy of <var>f</var> with the 
+signs of its coefficients and constant term reversed.
+
+<P>
+</DD>
+<DT><STRONG>Addition and subtraction</STRONG></DT>
+<DD>Sums and differences of affine functions, variables and constants 
+result in new affine functions.
+The constant terms in the sum can be of type integer or float, or
+dense or sparse <code>'d'</code> matrices with one column. 
+
+<P>
+The rules for addition and subtraction follow the conventions for 
+matrix addition and subtraction in sections <A href="s-arithmetic.html#s-arithmetic">2.3</A>
+and <A href="s-spmatrix-arith.html#s-spmatrix-arith">6.3</A>, with variables and affine functions 
+interpreted as dense <code>'d'</code> matrices with one column.
+In particular, a scalar term (integer, float, 1 by 1 dense <code>'d'</code> matrix, 
+variable of length 1, or affine function of length 1) can be added 
+to an affine function or variable of length greater than 1.
+
+<P>
+</DD>
+<DT><STRONG>Multiplication</STRONG></DT>
+<DD>Suppose <var>v</var> is an affine function or a variable, and <var>a</var> is 
+an integer, float, sparse or dense <code>'d'</code> matrix.  The products 
+<code><var>a</var>*<var>v</var></code> and  <code><var>v</var>*<var>a</var></code> are 
+valid affine functions whenever the product is allowed under the rules 
+for matrix and scalar multiplication  of sections <A href="s-arithmetic.html#s-arithmetic">2.3</A> 
+and <A href="s-spmatrix-arith.html#s-spmatrix-arith">6.3</A>, with <var>v</var> interpreted as a <code>'d'</code> matrix 
+with one column.
+In particular, the product <code><var>a</var>*<var>v</var></code> is defined if 
+<var>a</var> is a scalar (integer, float or 1 by 1 dense <code>'d'</code> matrix), 
+or a matrix (dense or sparse) with 
+<code><var>a</var>.<tt class="member">size</tt>[1] = len(<var>v</var>)</code>.   
+The operation <code><var>v</var>*<var>a</var></code> is defined if <var>a</var> is scalar,
+or if <code>len(<var>v</var>)</code> = 1 and <var>a</var> is a matrix with one 
+column.
+
+<P>
+</DD>
+<DT><STRONG>Inner products</STRONG></DT>
+<DD>The following two functions return scalar affine functions defined
+as inner products of a constant vector with  a variable or affine
+function.
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-157' xml:id='l2h-157' class="function">sum</tt></b>(</nobr></td>
+  <td><var>v</var>)</td></tr></table></dt>
+<dd>
+The argument is an affine function or a variable.  The result is an
+affine function of length 1, with the sum of the components of the
+argument <var>v</var>.  
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-158' xml:id='l2h-158' class="function">dot</tt></b>(</nobr></td>
+  <td><var>u,v</var>)</td></tr></table></dt>
+<dd>
+If <var>v</var> is a variable or affine function and <var>u</var> is a <code>'d'</code> matrix of size  (<code>len(<var>v</var>)</code>,1), then 
+<code>dot(<var>u</var>,<var>v</var>)</code> and <code>dot(<var>v</var>,<var>u</var>)</code> are 
+equivalent to <code><var>u</var>.<tt class="method">trans()</tt>*<var>v</var></code>.
+
+<P>
+If <var>u</var> and <var>v</var> are dense matrices, then 
+<code>dot(<var>u</var>,<var>v</var>)</code> 
+is equivalent to the function <code>blas.dot(<var>u</var>,<var>v</var>)</code> 
+defined in section <A href="s-blas1.html#s-blas1">3.2</A>, <EM>i.e.</EM>, it returns the inner product of 
+the two matrices.
+</dl>
+</DD>
+</DL>
+
+<P>
+In the following example, the variable <var>x</var> has length 1 and
+<var>y</var> has length 2.
+The functions <var>f</var> and <var>g</var> are given by
+<P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{eqnarray*}
+f(x,y) & = & \left[ \begin{array}{c} 2 \\2 \end{array}\right] x 
+  + y + \left[ \begin{array}{c} 3 \\3 \end{array}\right], \\
+ g(x,y) & = &
+  \left[ \begin{array}{cc} 1 & 3 \\2 & 4 \end{array}\right] f(x,y)
+  + \left[ \begin{array}{cc} 1 & 1 \\1 & 1 \end{array} \right] y + 
+  \left[ \begin{array}{c} 1 \\-1 \end{array} \right] \\
+ & = & \left[ \begin{array}{c} 8 \\12 \end{array}\right] x 
+  + \left[ \begin{array}{cc} 2 & 4 \\3 & 5 \end{array}\right] y
+  + \left[ \begin{array}{c} 13 \\17\end{array}\right].
+\end{eqnarray*}
+ -->
+<IMG
+ WIDTH="366" HEIGHT="134" BORDER="0"
+ SRC="img170.gif"
+ ALT="\begin{eqnarray*}
+f(x,y) & = & \left[ \begin{array}{c} 2 \\ 2 \end{array}\right...
+...\right] y
++ \left[ \begin{array}{c} 13 \\ 17\end{array}\right].
+\end{eqnarray*}"></DIV>
+<BR CLEAR="ALL"><P></P>
+<BR CLEAR="ALL"><P></P>
+<div class="verbatim"><pre>
+>>> from cvxopt.modeling import variable
+>>> x = variable(1,'x')
+>>> y = variable(2,'y')
+>>> f = 2*x + y + 3  
+>>> A = matrix([[1., 2.], [3.,4.]])
+>>> b = matrix([1.,-1.])
+>>> g = A*f + sum(y) + b 
+>>> print g
+affine function of length 2
+constant term:
+ 1.3000e+01
+ 1.7000e+01
+linear term: linear function of length 2
+coefficient of variable(2,'y'):
+ 2.0000e+00   4.0000e+00
+ 3.0000e+00   5.0000e+00
+coefficient of variable(1,'x'):
+ 8.0000e+00
+ 1.2000e+01
+</pre></div>
+
+<P>
+<DL>
+<DT><STRONG>In-place operations</STRONG></DT>
+<DD>For an affine function <var>f</var> the operations <code><var>f</var> += <var>u</var></code> 
+and <code><var>f</var> -= <var>u</var></code>, with <var>u</var> a constant, a variable or 
+an affine function, are allowed if they do not change the length of 
+<var>f</var>, <EM>i.e.</EM>, if <var>u</var> has length <code>len(<var>f</var>)</code> or length 1.
+In-place multiplication <code><var>f</var> *= <var>u</var></code> and division 
+<code><var>f</var> /= <var>u</var></code> are allowed if <var>u</var> is an integer, float, or 
+1 by 1 matrix.
+</DD>
+</DL>
+
+<P>
+<DL>
+<DT><STRONG>Indexing and slicing</STRONG></DT>
+<DD>Variables and affine functions admit 
+single-argument indexing of the four types described in 
+section <A href="s-indexing.html#s-indexing">2.4</A>.  The result of an indexing or slicing 
+operation is an affine function.  
+</DD>
+</DL>
+
+<P>
+<div class="verbatim"><pre>
+>>> x = variable(4,'x')
+>>> f = x[::2]
+>>> print f 
+>>> linear function of length 2
+linear term: linear function of length 2
+coefficient of variable(4,'x'):
+TYPE: general
+SIZE: (2,4)
+(0, 0)  1.0000e+00
+(1, 2)  1.0000e+00
+>>> y = variable(3,'x')
+>>> g = matrix(range(12),(3,4),'d')*x - 3*y + 1
+>>> print g[0] + g[2]
+affine function of length 1 
+constant term:
+ 2.0000e+00
+linear term: linear function of length 1
+coefficient of variable(4,'x'):
+ 2.0000e+00   8.0000e+00   1.4000e+01   2.0000e+01
+coefficient of variable(3,'y'):
+TYPE: general
+SIZE: (1,3)
+(0, 0) -3.0000e+00
+(0, 2) -3.0000e+00
+</pre></div>
+
+<P>
+The general expression of a <b>convex piecewise-linear</b> function is
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+f(x_1,\ldots,x_n) = b + A_1 x_1 + \cdots + A_n x_n + 
+  \sum_{k=1}^K \max (y_1, y_2, \ldots, y_{m_k}).
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="458" HEIGHT="56" BORDER="0"
+ SRC="img171.gif"
+ ALT="\begin{displaymath}
+f(x_1,\ldots,x_n) = b + A_1 x_1 + \cdots + A_n x_n +
+\sum_{k=1}^K \max (y_1, y_2, \ldots, y_{m_k}).
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+The maximum in this expression is a componentwise maximum of its 
+vector arguments, which can be constant vectors, variables, affine 
+functions or convex piecewise-linear functions.
+The general expression for a <b>concave piecewise-linear</b> function
+is
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+f(x_1,\ldots,x_n) = b + A_1 x_1 + \cdots + A_n x_n + 
+  \sum_{k=1}^K \min (y_1, y_2, \ldots, y_{m_k}).
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="456" HEIGHT="56" BORDER="0"
+ SRC="img172.gif"
+ ALT="\begin{displaymath}
+f(x_1,\ldots,x_n) = b + A_1 x_1 + \cdots + A_n x_n +
+\sum_{k=1}^K \min (y_1, y_2, \ldots, y_{m_k}).
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+Here the arguments of the <tt class="function">min()</tt> can be constants, variables, 
+affine functions or concave piecewise-linear functions.
+
+<P>
+Piecewise-linear functions can be created using the following 
+operations.
+<DL>
+<DT><STRONG><tt class="function">max</tt></STRONG></DT>
+<DD>If the arguments in 
+<code><var>f</var> = max(<var>y1</var>,<var>y2</var>, ...)</code> 
+do not include any variables or functions, then the Python built-in 
+<tt class="function">max()</tt> is evaluated.  
+
+<P>
+If one or more of the arguments are variables or functions, 
+<tt class="function">max()</tt> returns a piecewise-linear function defined as the 
+elementwise maximum of its arguments. 
+In other words, <var>f</var>[<var>k</var>] = 
+<code>max(<var>y1</var>[<var>k</var>],<var>y2</var>[<var>k</var>], ...)</code> 
+for <var>k</var>=0, ..., <code>len(<var>f</var>)</code>-1.
+The length of <var>f</var> is equal to the maximum of the lengths of the 
+arguments.  Each argument must have length equal to 
+<code>len(<var>f</var>)</code> or length one.  
+Arguments with length one are interpreted as vectors of 
+length <code>len(<var>f</var>)</code> with identical entries.
+
+<P>
+The arguments can be scalars of type integer or float, 
+dense <code>'d'</code> matrices with one column, variables, affine functions or 
+convex piecewise-linear functions.
+
+<P>
+With one argument, <code><var>f</var> = max(<var>u</var>)</code> is interpreted as
+<code><var>f</var> = max(<var>u</var>[0],<var>u</var>[1],...,
+<var>u</var>[<tt class="function">len</tt>(<var>u</var>)-1])</code>.  
+
+<P>
+</DD>
+<DT><STRONG><tt class="function">min</tt></STRONG></DT>
+<DD>Similar to <tt class="function">max()</tt> but returns a concave 
+piecewise-linear function.  The arguments can be scalars of type 
+integer or float, dense <code>'d'</code> matrices with one column, 
+variables, affine functions or concave piecewise-linear functions.
+
+<P>
+</DD>
+<DT><STRONG><tt class="function">abs</tt></STRONG></DT>
+<DD>If <var>u</var> is a variable or affine function then 
+<code><var>f</var> = abs(<var>u</var>)</code> returns the convex piecewise-linear 
+function <code>max(<var>u</var>,-<var>u</var>)</code>.
+
+<P>
+</DD>
+<DT><STRONG>Unary plus and minus</STRONG></DT>
+<DD><code>+<var>f</var></code> creates a copy of <var>f</var>.
+<code>-<var>f</var></code> is a concave piecewise-linear function if <var>f</var> is 
+convex and a convex piecewise-linear function if <var>f</var> is concave.
+
+<P>
+</DD>
+<DT><STRONG>Addition and subtraction</STRONG></DT>
+<DD>Sums and differences involving 
+piecewise-linear functions are allowed if they result in convex
+or concave functions. For example, one can add two convex or two
+concave functions, but not a convex and a concave function.
+The command <code>sum(<var>f</var>)</code> is equivalent
+to <code><var>f</var>[0] + <var>f</var>[1] + ...+ <var>f</var>[len(<var>f</var>)-1]</code>.
+
+<P>
+</DD>
+<DT><STRONG>Multiplication</STRONG></DT>
+<DD>Scalar multiplication <code><var>a</var>*<var>f</var></code> of a 
+piecewise-linear function <var>f</var> is defined if <var>a</var>
+is an integer, float, 1 by 1 <code>'d'</code> matrix. 
+Matrix-matrix multiplications <code><var>a</var>*<var>f</var></code> or 
+<code><var>f</var>*<var>a</var></code> are only defined if <var>a</var> is a dense or 
+sparse 1 by 1 matrix.
+
+<P>
+</DD>
+<DT><STRONG>Indexing and slicing</STRONG></DT>
+<DD>Piecewise-linear functions admit 
+single-argument indexing of the four types described in 
+section <A href="s-indexing.html#s-indexing">2.4</A>.  The result of an indexing or slicing 
+operation is a new piecewise-linear function.
+</DD>
+</DL>
+
+<P>
+In the following example, <var>f</var> is the 1-norm of a vector
+variable <var>x</var> of length 10, <var>g</var> is its infinity-norm and 
+<var>h</var> is the function
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+h(x) = \sum_k  \phi(x[k]),\qquad
+  \phi(u) = \left\{\begin{array}{ll}
+     0 & |u| \leq 1 \\
+    |u|-1  & 1 \leq |u| \leq 2 \\
+    2|u|-3  & |u| \geq 2. \end{array}\right.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="383" HEIGHT="64" BORDER="0"
+ SRC="img173.gif"
+ ALT="\begin{displaymath}
+h(x) = \sum_k \phi(x[k]),\qquad
+\phi(u) = \left\{\begin{ar...
+...\\
+2\vert u\vert-3 & \vert u\vert \geq 2. \end{array}\right.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+<div class="verbatim"><pre>
+>>> f = sum(abs(x))    
+>>> g = max(abs(x))   
+>>> h = sum(max(0, abs(x)-1, 2*abs(x)-3))
+</pre></div>
+
+<P>
+<DL>
+<DT><STRONG>In-place operations</STRONG></DT>
+<DD>If <var>f</var> is piecewise-linear then the in-place operations  
+<code><var>f</var> += <var>u</var></code>, <code><var>f</var> -= <var>u</var></code>, 
+<code><var>f</var> *= <var>u</var></code>, <code><var>f</var> /= <var>u</var></code> are defined if the 
+corresponding expanded operations <code><var>f</var> = <var>f</var>+<var>u</var></code>, 
+<code><var>f</var> = <var>f</var>-<var>u</var></code>, <code><var>f</var> = <var>f</var>*<var>u</var></code>
+and <code><var>f</var> = <var>f</var>/<var>u</var></code> are defined and if they do not 
+change the length of <var>f</var>.
+</DD>
+</DL>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="9.1 Variables"
+  href="s-variables.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="9. Modeling (cvxopt.modeling)"
+  href="node55.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="9.3 Constraints"
+  href="node58.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-variables.html">9.1 Variables</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node55.html">9. Modeling (cvxopt.modeling)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node58.html">9.3 Constraints</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-indexing.html b/doc/cvxopt/s-indexing.html
new file mode 100644
index 0000000..49636bd
--- /dev/null
+++ b/doc/cvxopt/s-indexing.html
@@ -0,0 +1,263 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="s-builtinfuncs.html" />
+<link rel="prev" href="s-arithmetic.html" />
+<link rel="parent" href="node4.html" />
+<link rel="next" href="s-builtinfuncs.html" />
+<meta name='aesop' content='information' />
+<title>2.4 Indexing and Slicing</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.3 Arithmetic Operations"
+  href="s-arithmetic.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.5 Built-in Functions"
+  href="s-builtinfuncs.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-arithmetic.html">2.3 Arithmetic Operations</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-builtinfuncs.html">2.5 Built-in Functions</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION004400000000000000000"></A> <A NAME="s-indexing"></A>
+<BR>
+2.4 Indexing and Slicing
+</H1>
+
+<P>
+Matrices can be indexed using one or two arguments.  In single-argument
+indexing of a matrix <var>A</var>, the index runs from 
+<code>-len(<var>A</var>)</code> to <code>len(<var>A</var>)-1</code>, and is interpreted as an
+index in the one-dimensional array of coefficients of <var>A</var> 
+in column-major order.   Negative indices have the standard Python 
+interpretation: for negative <var>k</var>, <code><var>A</var>[<var>k</var>]</code> is the 
+same element as  <code><var>A</var>[len(<var>A</var>)+<var>k</var>]</code>.
+
+<P>
+Four different types of one-argument indexing are implemented.
+
+<OL>
+<LI>The index can be a single integer.  This returns a 
+number, <EM>e.g.</EM>, <code><var>A</var>[0]</code> is the first element of <var>A</var>.
+
+<P>
+</LI>
+<LI>The index can be an integer matrix.  This returns a 
+column matrix: the command "<tt class="samp">A[matrix([0,1,2,3])]</tt>" 
+returns the 4 by 1 matrix consisting of the first four elements of
+<var>A</var>.   The size of the index matrix is ignored: 
+"<tt class="samp">A[matrix([0,1,2,3], (2,2))]</tt>" returns the same 4 by 1 matrix.
+
+<P>
+</LI>
+<LI>The index can be a list of integers.  This returns a column 
+matrix, <EM>e.g.</EM>, <code><var>A</var>[[0,1,2,3]]</code> is the 4 by 1 matrix consisting 
+of elements 0, 1, 2, 3 of <var>A</var>.   
+
+<P>
+</LI>
+<LI>The index can be a Python slice.  This returns a matrix with one 
+column (possibly 0 by 1, or 1 by 1).  For example, <code><var>A</var>[::2]</code> 
+is the column matrix defined by taking every other element of <var>A</var>, 
+stored in column-major order.  
+<code><var>A</var>[0:0]</code> is a matrix with size (0,1).
+</LI>
+</OL>
+Thus, single-argument indexing returns a scalar (if the index is an 
+integer), or a matrix with one column.  This is consistent with the 
+interpretation that single-argument indexing accesses the matrix in 
+column-major order.
+
+<P>
+Note that an index list or an index matrix are equivalent,
+but they are both useful, especially when we perform operations on 
+index sets.  For example, if <var>I</var> and <var>J</var> are lists then 
+<code><var>I</var>+<var>J</var></code> is the concatenated list, and <code>2*<var>I</var></code> 
+is <var>I</var> repeated twice.  If they are matrices, these operations are 
+interpreted as arithmetic operations.
+For large index sets, indexing with integer matrices is also faster 
+than indexing with lists. 
+
+<P>
+The following example illustrates one-argument indexing.
+<div class="verbatim"><pre>
+>>> from cvxopt.base import matrix 
+>>> A = matrix(range(16), (4,4), 'd')
+>>> print A
+   0.0000e+00   4.0000e+00   8.0000e+00   1.2000e+01
+   1.0000e+00   5.0000e+00   9.0000e+00   1.3000e+01
+   2.0000e+00   6.0000e+00   1.0000e+01   1.4000e+01
+   3.0000e+00   7.0000e+00   1.1000e+01   1.5000e+01
+>>> A[4]
+4.0
+>>> I = matrix([0, 5, 10, 15])
+>>> print A[I]      # the diagonal
+   0.0000e+00
+   5.0000e+00
+   1.0000e+01
+   1.5000e+01
+>>> I = [0,2];  J = [1,3]
+>>> print A[2*I+J]  # duplicate I and append J
+   0.0000e+00
+   2.0000e+00
+   0.0000e+00
+   2.0000e+00
+   1.0000e+00
+   3.0000e+00
+>>> I = matrix([0, 2]);  J =  matrix([1, 3])
+>>> print A[2*I+J]  # multiply I by 2 and add J
+   1.0000e+00
+   7.0000e+00
+>>> print A[4::4]   # get every fourth element skipping the first four  
+   4.0000e+00
+   8.0000e+00
+   1.2000e+01
+</pre></div>
+
+<P>
+In two-argument indexing the arguments can be any combinations of the
+four types listed above.  The first argument indexes the rows of 
+the matrix and the second argument indexes the columns.  If both 
+indices are scalars, then a scalar is returned.  In all other cases, 
+a matrix is returned.  We continue the example.
+<div class="verbatim"><pre>
+>>> print A[:,1]
+   4.0000e+00
+   5.0000e+00
+   6.0000e+00
+   7.0000e+00
+>>> J = matrix([0, 2])
+>>> print A[J,J]
+   0.0000e+00   8.0000e+00
+   2.0000e+00   1.0000e+01
+>>> print A[:2, -2:]   
+   8.0000e+00   1.2000e+01
+   9.0000e+00   1.3000e+01
+</pre></div>
+
+<P>
+Expressions of the form <code><var>A</var>[<var>I</var>]</code> or 
+<code><var>A</var>[<var>I</var>,<var>J</var>]</code> can also appear on the lefthand side 
+of an assignment.   
+The righthand side must be a scalar (<EM>i.e.</EM>, a number or a 1 by 1 dense
+matrix), a sequence of numbers, or a dense or sparse matrix. 
+If the righthand side is a scalar, it is interpreted as a 
+matrix with identical entries and the dimensions of the lefthand side.
+If the righthand side is a sequence of numbers (list, tuple, 
+<tt class="module">array</tt> array, xrange object, ...) its values are 
+interpreted as the coefficients of the lefthand side in column-major 
+order.  If the righthand side is a matrix (<tt class="class">matrix</tt> or <tt class="class">spmatrix</tt>), it must 
+have the same size as the lefthand side.  Sparse matrices are 
+converted to dense in the assignment.
+
+<P>
+Indexed assignments are only allowed if they do not change the type of 
+the matrix.  For example, if <var>A</var> is a matrix with type <code>'d'</code>, then 
+<code><var>A</var>[<var>I</var>] = <var>B</var></code> is only permitted if <var>B</var> is 
+an integer, a float, or a matrix of type <code>'i'</code> or <code>'d'</code>.
+If <var>A</var> is an integer matrix, then <code><var>A</var>[<var>I</var>] = <var>B</var></code> 
+is only permitted if <var>B</var> is an integer  or an integer matrix.
+
+<P>
+The following example illlustrates indexed assignment.
+<div class="verbatim"><pre>
+>>> A = matrix(range(16), (4,4))
+>>> A[::2,::2] = matrix([[-1, -2], [-3, -4]])
+>>> print A
+  -1      4     -3      12
+   1      5      9      13
+  -2      6     -4      14
+   3      7      11     15
+>>> A[::5] += 1
+>>> print A
+   0      4     -3      12
+   1      6      9      13
+  -2      6     -3      14
+   3      7      11     16
+>>> A[0,:] = -1, 1, -1, 1
+>>> print A
+  -1      1     -1      1 
+   1      6      9      13
+  -2      6     -3      14
+   3      7      11     16
+>>> A[2:,2:] = xrange(4)
+>>> print A
+  -1      1     -1      1 
+   1      6      9      13
+  -2      6      0      2
+   3      7      1      3
+</pre></div>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.3 Arithmetic Operations"
+  href="s-arithmetic.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.5 Built-in Functions"
+  href="s-builtinfuncs.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-arithmetic.html">2.3 Arithmetic Operations</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-builtinfuncs.html">2.5 Built-in Functions</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-lp.html b/doc/cvxopt/s-lp.html
new file mode 100644
index 0000000..067ce00
--- /dev/null
+++ b/doc/cvxopt/s-lp.html
@@ -0,0 +1,359 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node60.html" />
+<link rel="prev" href="node58.html" />
+<link rel="parent" href="node55.html" />
+<link rel="next" href="node60.html" />
+<meta name='aesop' content='information' />
+<title>9.4 Optimization Problems</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="9.3 Constraints"
+  href="node58.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="9. Modeling (cvxopt.modeling)"
+  href="node55.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="9.5 Examples"
+  href="node60.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node58.html">9.3 Constraints</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node55.html">9. Modeling (cvxopt.modeling)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node60.html">9.5 Examples</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0011400000000000000000"></A> <A NAME="s-lp"></A>
+<BR>
+9.4 Optimization Problems
+</H1>
+
+<P>
+Optimization problems are be constructed by calling the following
+function.
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><span class="typelabel">class</span> <tt id='l2h-163' xml:id='l2h-163' class="class">op</tt></b>(</nobr></td>
+  <td><var></var><big>[</big><var>objective</var><big>[</big><var>, constraints</var><big>[</big><var>, name</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+The first argument specifies the objective function to be minimized.
+It can be an affine or convex piecewise-linear function with length 1, 
+a variable with length 1, or a scalar constant
+(integer, float or 1 by 1 dense <code>'d'</code> matrix).  The default value is
+<code>0.0</code>.
+
+<P>
+The second argument is a single constraint, or a list of 
+constraint objects.  The default value is an empty list.
+
+<P>
+The third argument is a string with a name for the problem.
+The default value is the empty string.
+</dl>
+
+<P>
+The following attributes and methods are useful for examining
+and modifying optimization problems.
+
+<P>
+<dl><dt><b><tt id='l2h-164' xml:id='l2h-164' class="member">objective</tt></b></dt>
+<dd>
+The objective or cost function.  One can write to this 
+attribute to change the objective of an existing problem.  
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-165' xml:id='l2h-165' class="method">variables</tt></b>(</nobr></td>
+  <td><var></var>)</td></tr></table></dt>
+<dd>
+Returns a list of the variables of the problem.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-166' xml:id='l2h-166' class="method">constraints</tt></b>(</nobr></td>
+  <td><var></var>)</td></tr></table></dt>
+<dd>
+Returns a list of the constraints.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-167' xml:id='l2h-167' class="method">inequalities</tt></b>(</nobr></td>
+  <td><var></var>)</td></tr></table></dt>
+<dd>
+Returns a list of the inequality constraints.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-168' xml:id='l2h-168' class="method">equalities</tt></b>(</nobr></td>
+  <td><var></var>)</td></tr></table></dt>
+<dd>
+Returns a list of the equality constraints.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-169' xml:id='l2h-169' class="method">delconstraint</tt></b>(</nobr></td>
+  <td><var>c</var>)</td></tr></table></dt>
+<dd>
+Deletes constraint <TT>c</TT> from the problem.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-170' xml:id='l2h-170' class="method">addconstraint</tt></b>(</nobr></td>
+  <td><var>c</var>)</td></tr></table></dt>
+<dd>
+Adds constraint <TT>c</TT> to the problem.
+</dl>
+
+<P>
+An optimization problem with convex piecewise-linear objective and
+constraints can be solved by calling the method <tt class="function">solve()</tt>.
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-171' xml:id='l2h-171' class="method">solve</tt></b>(</nobr></td>
+  <td><var></var><big>[</big><var>format</var><big>[</big><var>, solver</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd> 
+This function converts the optimization problem to a linear program
+in matrix form and then solves it using the solver described in 
+section <A href="s-lpsolver.html#s-lpsolver">8.1</A>.
+
+<P>
+The first argument is either <code>'dense'</code> or <code>'sparse'</code>, and 
+denotes the matrix types used in the matrix representation of the LP.
+The default value is <code>'dense'</code>.
+
+<P>
+The second argument is either <code>None</code>. <code>'glpk'</code> or <code>'mosek'</code>,
+and selects one of three available LP solvers: a default solver 
+written in Python, the GLPK solver (if installed) or the
+MOSEK LP solver (if installed); see section <A href="s-lpsolver.html#s-lpsolver">8.1</A>.
+The default value  is <code>None</code>.
+
+<P>
+The solver reports the outcome of optimization by setting 
+the attribute <var>self</var>.<tt class="member">status</tt> and by modifying  
+the <tt class="member">value</tt> attributes of the variables and the constraint 
+multipliers of the problem.
+
+<UL>
+<LI>If the problem is solved to optimality, 
+<var>self</var>.<tt class="member">status</tt> is set to <code>'optimal'</code>.  
+The <tt class="member">value</tt> attributes of the variables in the problem  are set 
+to their computed solutions, and the <tt class="member">value</tt> attributes of the 
+multipliers of the constraints of the problem are set to the computed 
+dual optimal solution.
+
+<P>
+</LI>
+<LI>If it is determined that the problem is infeasible, 
+<var>self</var>.<tt class="member">status</tt> is set to <code>'primal infeasible'</code>.  
+The <tt class="member">value</tt> attributes of the variables are set to <code>None</code>.
+The <tt class="member">value</tt> attributes of the 
+multipliers of the constraints of the problem are set to a certificate 
+of primal infeasibility.
+With the <code>'glpk'</code> option, <tt class="function">solve()</tt>
+does not provide certificates of infeasibility.
+
+<P>
+</LI>
+<LI>If it is determined that the problem is dual infeasible, 
+<var>self</var>.<tt class="member">status</tt> is set to <code>'dual infeasible'</code>.  
+The <tt class="member">value</tt> attributes of the multipliers of the constraints of 
+the problem are set to <code>None</code>.
+The <tt class="member">value</tt> attributes of the 
+variables are set to a certificate of dual infeasibility. 
+With the <code>'glpk'</code> option, <tt class="function">solve()</tt> does not provide 
+certificates of infeasibility.
+
+<P>
+</LI>
+<LI>If the problem was not solved successfully,
+<var>self</var>.<tt class="member">status</tt> is set to <code>'unknown'</code>.  
+The <tt class="member">value</tt> attributes of the variables and the constraint
+multipliers are set to <code>None</code>.
+</LI>
+</UL>
+</dl>
+We refer to section <A href="s-lpsolver.html#s-lpsolver">8.1</A> for details on the algorithms and
+the different solver options.
+
+<P>
+As an example we solve the LP
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+  \mbox{minimize} & -4x - 5y \\
+  \mbox{subject to} &  2x +y \leq 3 \\
+ &  x +2y \leq 3 \\
+ & x \geq 0, \quad y \geq 0.
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="179" HEIGHT="83" BORDER="0"
+ SRC="img177.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & -4x - 5y \\
+\mbox{su...
+...
+& x +2y \leq 3 \\
+& x \geq 0, \quad y \geq 0.
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+<div class="verbatim"><pre>
+>>> x = variable()
+>>> y = variable()
+>>> c1 = ( 2*x+y <= 3 ) 
+>>> c2 = ( x+2*y <= 3 )
+>>> c3 = ( x >= 0 )
+>>> c4 = ( y >= 0 ) 
+>>> lp1 = op(-4*x-5*y, [c1,c2,c3,c4]) 
+>>> lp1.solve()
+>>> print lp1.status
+optimal
+>>> print lp1.objective.value()
+-9.0000e+00
+>>> print x.value
+ 1.0000e-00
+>>> print y.value
+ 1.0000e-00
+>>> print c1.multiplier.value
+ 1.0000e-00
+>>> print c2.multiplier.value
+ 2.0000e-00
+>>> print c3.multiplier.value
+ 8.8912e-09
+>>> print c4.multiplier.value
+ 9.8567e-09
+</pre></div>
+
+<P>
+We can solve the same LP in  matrix form as follows.
+<div class="verbatim"><pre>
+>>> x = variable(2)
+>>> A = matrix([[2.,1.,-1.,0.], [1.,2.,0.,-1.]])
+>>> b = matrix([3.,3.,0.,0.])
+>>> c = matrix([-4.,-5.])
+>>> ineq = ( A*x <= b )
+>>> lp2 = op(dot(c,x), ineq)
+>>> lp2.solve()
+>>> print lp2.objective.value()
+-9.0000e+00
+>>> print x.value
+ 1.0000e-00
+ 1.0000e-00
+>>> print ineq.multiplier.value
+ 1.0000e+00
+ 2.0000e+00
+ 8.8912e-09
+ 9.8567e-09
+</pre></div>
+
+<P>
+The op class also includes two methods for writing and reading
+files in 
+<a class="ulink" href="http://www-fp.mcs.anl.gov/otc/Guide/OptWeb/continuous/constrained/linearprog/mps.html"
+  >MPS format</a>.
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-172' xml:id='l2h-172' class="method">tofile</tt></b>(</nobr></td>
+  <td><var>filename</var>)</td></tr></table></dt>
+<dd>
+If the problem is an LP, writes it to the file <code>'filename'</code> using 
+the MPS format.  Row and column labels are assigned based on the 
+variable and constraint names in the LP.  
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-173' xml:id='l2h-173' class="method">fromfile</tt></b>(</nobr></td>
+  <td><var>filename</var>)</td></tr></table></dt>
+<dd>
+Reads the LP from the file <code>'filename'</code>.  The file must be 
+a fixed-format MPS file.  Some features of the MPS format are not 
+supported: comments beginning with dollar signs,
+the row types 'DE', 'DL', 'DG', and 'DN', and the capability of
+reading multiple righthand side, bound or range vectors.
+</dl>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="9.3 Constraints"
+  href="node58.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="9. Modeling (cvxopt.modeling)"
+  href="node55.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="9.5 Examples"
+  href="node60.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node58.html">9.3 Constraints</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node55.html">9. Modeling (cvxopt.modeling)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node60.html">9.5 Examples</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-lpsolver.html b/doc/cvxopt/s-lpsolver.html
new file mode 100644
index 0000000..2abd657
--- /dev/null
+++ b/doc/cvxopt/s-lpsolver.html
@@ -0,0 +1,290 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node47.html" />
+<link rel="prev" href="node45.html" />
+<link rel="parent" href="node45.html" />
+<link rel="next" href="node47.html" />
+<meta name='aesop' content='information' />
+<title>8.1 Linear Programming</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.2 Quadratic Programming"
+  href="node47.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node47.html">8.2 Quadratic Programming</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0010100000000000000000"></A> <A NAME="s-lpsolver"></A>
+<BR>
+8.1 Linear Programming
+</H1>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-145' xml:id='l2h-145' class="function">lp</tt></b>(</nobr></td>
+  <td><var>c, G, h</var><big>[</big><var>, A, b</var><big>[</big><var>, 
+solver</var><big>[</big><var>, primalstart</var><big>[</big><var>, dualstart</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves the pair of primal and dual LPs
+<BR>
+<DIV ALIGN="RIGHT" CLASS="mathdisplay">
+
+<!-- MATH
+ \begin{equation}
+\mbox{Primal:}\quad \begin{array}[t]{ll}
+\mbox{minimize} & c^Tx \\
+\mbox{subject to} &  Gx + s = h \\& Ax=b \\& s \succeq 0
+\end{array} \qquad\qquad
+\mbox{Dual:}\quad
+\begin{array}[t]{ll}
+\mbox{maximize}   & -h^T z - b^T y \\
+\mbox{subject to} & G^Tz + A^T y  + c = 0 \\& z \succeq 0.
+\end{array}
+\end{equation}
+ -->
+<A NAME="e-lp"></A>
+<TABLE WIDTH="100%" ALIGN="CENTER">
+<TR VALIGN="MIDDLE"><TD></TD><TD ALIGN="CENTER" NOWRAP><A NAME="e-lp"></A><IMG
+ WIDTH="571" HEIGHT="87" BORDER="0"
+ SRC="img111.gif"
+ ALT="\begin{displaymath}
+\mbox{Primal:}\quad \begin{array}[t]{ll}
+\mbox{minimize} & c...
+...ubject to} & G^Tz + A^T y + c = 0 \\ & z \succeq 0.
+\end{array}\end{displaymath}"></TD>
+<TD CLASS="eqno" WIDTH=10 ALIGN="RIGHT">
+(8.1)</TD></TR>
+</TABLE>
+<BR CLEAR="ALL"></DIV><P></P>
+<var>c</var>, <var>h</var> and <var>b</var> are real single-column dense matrices.
+<var>G</var> and <var>A</var> are real dense or sparse matrices.
+The default values for <var>A</var> and <var>b</var> are sparse matrices with 
+zero rows, meaning that there are no equality constraints.  
+
+<P>
+The <var>solver</var> argument is used to choose among three solvers.  
+When it is omitted or <code>None</code>, the default CVXOPT solver is used.   
+The external solvers GLPK and MOSEK (if installed) can be selected by 
+setting <code><var>solver</var>='glpk'</code> or 
+<code><var>solver</var>='mosek'</code>; see section <A href="s-external.html#s-external">8.8</A>.
+
+<P>
+The optional arguments <var>primalstart</var> and <var>dualstart</var> are only
+referenced by the default solver.  
+<var>primalstart</var> is a dictionary with keys <code>'x'</code> and <code>'s'</code>, 
+used as an optional primal starting point. 
+<var>dualstart</var> is a dictionary with keys <code>'y'</code> and <code>'z'</code>, 
+used as an optional dual starting point.
+
+<P>
+<tt class="function">lp()</tt> returns a dictionary with keys <code>'status'</code>, 
+<code>'x'</code>, <code>'s'</code>, <code>'y'</code>, <code>'z'</code>.  
+The possible values of the <code>'status'</code> item are as follows.
+<DL>
+<DT><STRONG><code>'optimal'.</code></STRONG></DT>
+<DD>In this case the <code>'x'</code>, <code>'s'</code>, 
+<code>'y'</code> and <code>'z'</code> entries contain the primal and dual solutions,
+which approximately satisfy
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+Gx + s = h, \qquad Ax=b, \qquad G^T z  + A^T y + c = 0, \qquad 
+ s \succeq 0, \qquad z \succeq 0,  \qquad s^T z =0.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="567" HEIGHT="27" BORDER="0"
+ SRC="img112.gif"
+ ALT="\begin{displaymath}
+Gx + s = h, \qquad Ax=b, \qquad G^T z + A^T y + c = 0, \qquad
+s \succeq 0, \qquad z \succeq 0, \qquad s^T z =0.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+</DD>
+<DT><STRONG><code>'primal infeasible'.</code></STRONG></DT>
+<DD>The <code>'x'</code> and <code>'s'</code> entries are <code>None</code>, and the <code>'y'</code>, 
+<code>'z'</code> entries provide an approximate certificate of 
+infeasibility, <EM>i.e.</EM>, vectors that approximately satisfy
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+G^T z + A^T y = 0, \qquad h^T z + b^T y = -1, \qquad z \succeq 0.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="340" HEIGHT="27" BORDER="0"
+ SRC="img113.gif"
+ ALT="\begin{displaymath}
+G^T z + A^T y = 0, \qquad h^T z + b^T y = -1, \qquad z \succeq 0.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+With the <code>'glpk'</code> option, no proof of infeasibility is returned
+(all entries of the dictionary are <code>None</code>).
+
+<P>
+</DD>
+<DT><STRONG><code>'dual infeasible'.</code></STRONG></DT>
+<DD>The LP is dual infeasible.
+The <code>'y'</code> and <code>'z'</code> entries are <code>None</code>, and the <code>'x'</code> 
+and <code>'s'</code> entries contain an approximate certificate of dual 
+infeasibility 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+Gx + s = 0, \qquad Ax=0, \qquad  c^T x = -1, \qquad s \succeq 0.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="350" HEIGHT="27" BORDER="0"
+ SRC="img114.gif"
+ ALT="\begin{displaymath}
+Gx + s = 0, \qquad Ax=0, \qquad c^T x = -1, \qquad s \succeq 0.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+With the <code>'glpk'</code> option, no proof of dual infeasibility is 
+returned.
+
+<P>
+</DD>
+<DT><STRONG><code>'unknown'</code>.</STRONG></DT>
+<DD>The <code>'x'</code>, <code>'s'</code>, <code>'y'</code>, 
+<code>'z'</code> entries are <code>None</code>.
+</DD>
+</DL>
+
+<P>
+</dl>
+
+<P>
+As a simple example we solve the LP
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}[t]{ll}
+  \mbox{minimize} & -4x_1 - 5x_2 \\
+  \mbox{subject to} &  2x_1 + x_2 \leq 3 \\
+ & x_1 + 2x_2 \leq 3 \\
+ & x_1 \geq 0, \quad x_2 \geq 0.
+ \end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="195" HEIGHT="87" BORDER="0"
+ SRC="img115.gif"
+ ALT="\begin{displaymath}
+\begin{array}[t]{ll}
+\mbox{minimize} & -4x_1 - 5x_2 \\
+\...
+...2x_2 \leq 3 \\
+& x_1 \geq 0, \quad x_2 \geq 0.
+\end{array}
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+<div class="verbatim"><pre>
+>>> from cvxopt.base import matrix
+>>> from cvxopt import solvers 
+>>> c = matrix([-4., -5.])
+>>> G = matrix([[2., 1., -1., 0.], [1., 2., 0., -1.]])
+>>> h = matrix([3., 3., 0., 0.])
+>>> sol = solvers.lp(c,G,h)
+>>> print sol['x']
+   1.0000e-00
+   1.0000e-00
+</pre></div>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.2 Quadratic Programming"
+  href="node47.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node47.html">8.2 Quadratic Programming</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-orderings.html b/doc/cvxopt/s-orderings.html
new file mode 100644
index 0000000..9dff675
--- /dev/null
+++ b/doc/cvxopt/s-orderings.html
@@ -0,0 +1,174 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="s-umfpack.html" />
+<link rel="prev" href="c-spsolvers.html" />
+<link rel="parent" href="c-spsolvers.html" />
+<link rel="next" href="s-umfpack.html" />
+<meta name='aesop' content='information' />
+<title>7.1 Matrix Orderings (cvxopt.amd)</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="7. Sparse Linear Equation"
+  href="c-spsolvers.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="7. Sparse Linear Equation"
+  href="c-spsolvers.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="7.2 General Linear Equations"
+  href="s-umfpack.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="c-spsolvers.html">7. Sparse Linear Equation</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="c-spsolvers.html">7. Sparse Linear Equation</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-umfpack.html">7.2 General Linear Equations</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION009100000000000000000"></A> <A NAME="s-orderings"></A>
+<BR>
+7.1 Matrix Orderings (<tt class="module">cvxopt.amd</tt>)
+</H1>
+
+<P>
+CVXOPT includes an interface to the AMD library for computing 
+approximate minimum degree orderings of sparse matrices.
+
+<P>
+<div class="seealso">
+  <p class="heading">See Also:</p>
+
+<dl compact="compact" class="seeurl">
+    <dt><a href='http://www.cise.ufl.edu/research/sparse/amd'
+        >AMD code, 
+documentation, copyright and license.</a></dt>
+    <dd></dd>
+  </dl>
+<div class="seetext"><p>P. R. Amestoy, T. A. Davis, I. S. Duff,
+Algorithm 837: AMD, An Approximate Minimum Degree Ordering Algorithm,
+ACM Transactions on Mathematical Software, 30(3), 381-388, 2004.</p></div>
+</div>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-133' xml:id='l2h-133' class="function">order</tt></b>(</nobr></td>
+  <td><var>A</var><big>[</big><var>, uplo='L'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Computes the approximate mimimum degree ordering of a symmetric  sparse
+matrix <I>A</I>.  
+The ordering is returned as an integer dense matrix with length equal 
+to the order of <var>A</var>.  Its entries specify a permutation that 
+reduces fill-in during the Cholesky factorization.
+More precisely, if <code><var>p</var> = order(<var>A</var>)</code>, then  
+<code><var>A</var>[<var>p</var>,<var>p</var>]</code> has sparser Cholesky factors 
+than <code><var>A</var></code>.   
+</dl>
+
+<P>
+As an example we consider the matrix 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\left[ \begin{array}{rrrr}
+ 10 &  0 & 3 &  0 \\
+  0 &  5 & 0 & -2 \\
+  3 &  0 & 5 &  0 \\
+  0 & -2 & 0 &  2 
+\end{array}\right].
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="150" HEIGHT="83" BORDER="0"
+ SRC="img85.gif"
+ ALT="\begin{displaymath}
+\left[ \begin{array}{rrrr}
+10 & 0 & 3 & 0 \\
+0 & 5 & 0 & -2 \\
+3 & 0 & 5 & 0 \\
+0 & -2 & 0 & 2
+\end{array}\right].
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+<div class="verbatim"><pre>
+>>> from cvxopt.base import spmatrix
+>>> from cvxopt import amd 
+>>> A = spmatrix([10,3,5,-2,5,2], [0,2,1,2,2,3], [0,0,1,1,2,3])
+>>> P = amd.order(A)
+>>> print P
+ 1
+ 0
+ 2
+ 3
+</pre></div>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="7. Sparse Linear Equation"
+  href="c-spsolvers.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="7. Sparse Linear Equation"
+  href="c-spsolvers.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="7.2 General Linear Equations"
+  href="s-umfpack.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="c-spsolvers.html">7. Sparse Linear Equation</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="c-spsolvers.html">7. Sparse Linear Equation</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-umfpack.html">7.2 General Linear Equations</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-otherfuncs.html b/doc/cvxopt/s-otherfuncs.html
new file mode 100644
index 0000000..b0a598c
--- /dev/null
+++ b/doc/cvxopt/s-otherfuncs.html
@@ -0,0 +1,171 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="s-random.html" />
+<link rel="prev" href="s-builtinfuncs.html" />
+<link rel="parent" href="node4.html" />
+<link rel="next" href="s-random.html" />
+<meta name='aesop' content='information' />
+<title>2.6 Other Matrix Functions</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.5 Built-in Functions"
+  href="s-builtinfuncs.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.7 Randomly Generated Matrices"
+  href="s-random.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-builtinfuncs.html">2.5 Built-in Functions</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-random.html">2.7 Randomly Generated Matrices</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION004600000000000000000"></A> <A NAME="s-otherfuncs"></A>
+<BR>
+2.6 Other Matrix Functions
+</H1>
+The following functions of dense matrices can be imported from 
+<tt class="module">cvxopt.base</tt>.
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-17' xml:id='l2h-17' class="function">sqrt</tt></b>(</nobr></td>
+  <td><var>x</var>)</td></tr></table></dt>
+<dd>
+The elementwise square root of <var>x</var>.  The result is returned 
+as a real matrix if <var>x</var> is an integer or real matrix and 
+as a complex matrix if <var>x</var> is a complex matrix.  Raises an 
+exception when <var>x</var> is an integer or real matrix with negative 
+elements.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-18' xml:id='l2h-18' class="function">sin</tt></b>(</nobr></td>
+  <td><var>x</var>)</td></tr></table></dt>
+<dd>
+The sine function applied elementwise to <var>x</var>.  
+The result is returned as a real matrix if <var>x</var> is an integer
+or real matrix and as a complex matrix otherwise.  
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-19' xml:id='l2h-19' class="function">cos</tt></b>(</nobr></td>
+  <td><var>x</var>)</td></tr></table></dt>
+<dd>
+The cosine function applied elementwise to <var>x</var>.  
+The result is returned as a real matrix if <var>x</var> is an integer
+or real matrix and as a complex matrix otherwise.  
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-20' xml:id='l2h-20' class="function">exp</tt></b>(</nobr></td>
+  <td><var>x</var>)</td></tr></table></dt>
+<dd>
+The exponential function applied elementwise to <var>x</var>.  
+The result is returned as a real matrix if <var>x</var> is an integer 
+or real matrix and as a complex matrix otherwise.  
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-21' xml:id='l2h-21' class="function">log</tt></b>(</nobr></td>
+  <td><var>x</var>)</td></tr></table></dt>
+<dd>
+The natural logarithm applied elementwise to <var>x</var>.  
+The result is returned as a real matrix if <var>x</var> is an integer
+or real matrix and as a complex matrix otherwise.  
+Raises an exception when <var>x</var> is an integer or real matrix with 
+nonnegative elements, or a complex matrix with zero elements.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-22' xml:id='l2h-22' class="function">mul</tt></b>(</nobr></td>
+  <td><var>x, y</var>)</td></tr></table></dt>
+<dd>
+The elementwise product of <var>x</var> and <var>y</var>.  
+The two matrices must have the same size and type.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-23' xml:id='l2h-23' class="function">div</tt></b>(</nobr></td>
+  <td><var>x, y</var>)</td></tr></table></dt>
+<dd>
+The elementwise division of <var>x</var> by <var>y</var>.  
+The two matrices must have the same size and type.
+</dl>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.5 Built-in Functions"
+  href="s-builtinfuncs.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.7 Randomly Generated Matrices"
+  href="s-random.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-builtinfuncs.html">2.5 Built-in Functions</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-random.html">2.7 Randomly Generated Matrices</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-parameters.html b/doc/cvxopt/s-parameters.html
new file mode 100644
index 0000000..be3655d
--- /dev/null
+++ b/doc/cvxopt/s-parameters.html
@@ -0,0 +1,401 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="prev" href="s-external.html" />
+<link rel="parent" href="node45.html" />
+<link rel="next" href="node55.html" />
+<meta name='aesop' content='information' />
+<title>8.9 Algorithm Parameters</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.8 Optional Solvers"
+  href="s-external.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="9. Modeling (cvxopt.modeling)"
+  href="node55.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-external.html">8.8 Optional Solvers</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node55.html">9. Modeling (cvxopt.modeling)</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0010900000000000000000"></A> <A NAME="s-parameters"></A>
+<BR>
+8.9 Algorithm Parameters
+</H1>
+In this section we list some algorithm control parameters that can 
+be modified without editing the source code.  
+These control parameters are accessible via the dictionary 
+<tt class="member">solvers.options</tt>.  By default the dictionary 
+is empty and the default values of the parameters are used.
+
+<P>
+One can change the parameters in the <b>default</b> solvers by 
+adding entries with the following key values.  
+<DL>
+<DT><STRONG><code>'show_progress'</code></STRONG></DT>
+<DD><code>True</code>  or <code>False</code>; turns the output to the screen on or off  
+(default: <code>True</code>).
+</DD>
+<DT><STRONG><code>'maxiters'</code></STRONG></DT>
+<DD>maximum number of iterations (default: 100).
+</DD>
+<DT><STRONG><code>'abstol'</code></STRONG></DT>
+<DD>absolute accuracy (default: <code>1e-7</code>).
+</DD>
+<DT><STRONG><code>'reltol'</code></STRONG></DT>
+<DD>relative accuracy (default: <code>1e-7</code>).
+</DD>
+<DT><STRONG><code>'feastol'</code></STRONG></DT>
+<DD>tolerance for feasibility conditions (default:
+<code>1e-7</code>).
+</DD>
+<DT><STRONG><code>'refinement'</code></STRONG></DT>
+<DD><code>True</code> or <code>False</code>.  If <code>True</code>, 
+one step of iterative refinement is applied after solving KKT equations
+in <tt class="function">conelp()</tt>, <tt class="function">lp()</tt>, and <tt class="function">sdp()</tt> 
+(default: <code>True</code>). 
+</DD>
+</DL>
+For example the command
+<div class="verbatim"><pre>
+>>> from cvxopt import solvers
+>>> solvers.options['show_progress'] = False
+</pre></div>
+turns off the screen output during calls to the solvers.
+The tolerances <var>abstol</var>, <var>reltol</var> and <var>feastol</var> have the
+following meaning.   <tt class="function">conelp()</tt> terminates with 
+status <code>'optimal'</code>, if
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+s_\mathrm{l} \succeq 0, \qquad S_\mathrm{s} \succeq 0, 
+\qquad 
+ \frac{\|G_\mathrm{l}x+s_\mathrm{l}-h_\mathrm{l}\|_2}
+ {\max\{1,\|h_\mathrm{l}\|_2\}} \leq \epsilon_\mathrm{feas}, 
+\qquad 
+\frac{\|G_\mathrm{s}(x)+S_\mathrm{s}-H_\mathrm{s}\|_F}
+{\max\{1,\|H_\mathrm{s}\|_F\}} \leq \epsilon_\mathrm{feas}, 
+\qquad
+\frac{\|Ax-b\|_2}{\max\{1,\|b\|_2\}} \leq \epsilon_\mathrm{feas},
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="748" HEIGHT="44" BORDER="0"
+ SRC="img161.gif"
+ ALT="\begin{displaymath}
+s_\mathrm{l} \succeq 0, \qquad S_\mathrm{s} \succeq 0,
+\qqu...
+...t _2}{\max\{1,\Vert b\Vert _2\}} \leq \epsilon_\mathrm{feas},
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+z_\mathrm{l} \succeq 0, \qquad Z_\mathrm{s} \succeq 0, \qquad
+\frac{\|G_\mathrm{l}^Tz_\mathrm{l}+
+G_\mathrm{s}^T(Z_\mathrm{s}) + A^Ty+c\|_2}{\max\{1,\|c\|_2\}} 
+\leq \epsilon_\mathrm{feas},
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="426" HEIGHT="45" BORDER="0"
+ SRC="img162.gif"
+ ALT="\begin{displaymath}
+z_\mathrm{l} \succeq 0, \qquad Z_\mathrm{s} \succeq 0, \qqua...
+... _2}{\max\{1,\Vert c\Vert _2\}}
+\leq \epsilon_\mathrm{feas},
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+and
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+s_\mathrm{l}^T z_\mathrm{l} + \mathop{\bf tr}(S_\mathrm{s}Z_\mathrm{s}) \leq 
+ \epsilon_\mathrm{abs} \qquad \mbox{or} \qquad
+\left( \min\left\{c^Tx,  
+ h_\mathrm{l}^T z_\mathrm{l} + \mathop{\bf tr}(H_\mathrm{s} Z_\mathrm{s})
+ + b^Ty \right\} < 0, \quad 
+ \frac{s_\mathrm{l}^Tz_\mathrm{l} + \mathop{\bf tr}(S_\mathrm{s}Z_\mathrm{s})}
+ {-\min\{c^Tx, h_\mathrm{l}^Tz_\mathrm{l} + 
+ \mathop{\bf tr}(H_\mathrm{s} Z_\mathrm{s}) + b^T y\}} \leq \epsilon_\mathrm{rel}
+\right).
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="842" HEIGHT="47" BORDER="0"
+ SRC="img163.gif"
+ ALT="\begin{displaymath}
+s_\mathrm{l}^T z_\mathrm{l} + \mathop{\bf tr}(S_\mathrm{s}Z...
+...} Z_\mathrm{s}) + b^T y\}} \leq \epsilon_\mathrm{rel}
+\right).
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+It returns with status  <code>'primal infeasible'</code> if 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+z_\mathrm{l} \succeq 0, \qquad
+Z_\mathrm{s} \succeq 0, \qquad
+\qquad \|G_\mathrm{l}^Tz_\mathrm{l} + G_\mathrm{s}^T(Z_\mathrm{s})
+ +A^Ty\|_2 \leq \epsilon_\mathrm{feas}, 
+ \qquad h_\mathrm{l}^Tz_\mathrm{l} + \mathop{\bf tr}(H_\mathrm{s} Z_\mathrm{s}) 
+ +b^Ty = -1.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="637" HEIGHT="28" BORDER="0"
+ SRC="img164.gif"
+ ALT="\begin{displaymath}
+z_\mathrm{l} \succeq 0, \qquad
+Z_\mathrm{s} \succeq 0, \qqua...
+...{l} + \mathop{\bf tr}(H_\mathrm{s} Z_\mathrm{s})
++b^Ty = -1.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+It returns with status <code>'dual infeasible'</code> if 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+s_\mathrm{l} \succeq 0, \qquad
+S_\mathrm{s} \succeq 0, \qquad
+\qquad
+\|G_\mathrm{l}x+s_\mathrm{l}\|_2 \leq \epsilon_\mathrm{feas}, \qquad
+\|G_\mathrm{s}(x)+S_\mathrm{s}\|_F \leq \epsilon_\mathrm{feas}, \qquad
+\|Ax\|_2 \leq \epsilon_\mathrm{feas},  \qquad
+c^Tx = -1.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="742" HEIGHT="28" BORDER="0"
+ SRC="img165.gif"
+ ALT="\begin{displaymath}
+s_\mathrm{l} \succeq 0, \qquad
+S_\mathrm{s} \succeq 0, \qqua...
+...Vert Ax\Vert _2 \leq \epsilon_\mathrm{feas}, \qquad
+c^Tx = -1.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+The functions <tt class="function">lp()</tt> and <tt class="function">sdp()</tt> call 
+<tt class="function">conelp()</tt> and hence use the same stopping criteria.
+
+<P>
+<tt class="function">nlcp()</tt> returns with status <code>'optimal'</code> if
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\frac{\| \nabla f_0(x) +  D\tilde f(x)^Tz_\mathrm{nl} + 
+ G^Tz_\mathrm{l} + A^T y \|_2 }
+{\max\{ 1, 
+\| \nabla f_0(x_0) + D\tilde f(x_0)^T{\bf 1}+ G^T{\bf 1}\|_2 \}} 
+\leq \epsilon_\mathrm{feas}, \qquad
+\frac{\| ( \tilde f(x) + s_{\mathrm{nl}},  Gx + s_\mathrm{l} - h, 
+ Ax-b ) \|_2} 
+{\max\{1, \| ( \tilde f(x_0) + {\bf 1},  
+Gx_0 + {\bf 1}-h, Ax_0-b) \|_2 \}} \leq \epsilon_\mathrm{feas}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="742" HEIGHT="49" BORDER="0"
+ SRC="img166.gif"
+ ALT="\begin{displaymath}
+\frac{\Vert \nabla f_0(x) + D\tilde f(x)^Tz_\mathrm{nl} +
+...
+...+ {\bf 1}-h, Ax_0-b) \Vert _2 \}} \leq \epsilon_\mathrm{feas}
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <I>x0</I> is the point returned by <code>F()</code>, and
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\mathrm{gap} \leq \epsilon_\mathrm{abs}
+\qquad \mbox{or} \qquad \left( f_0(x) < 0, \quad
+\frac{\mathrm{gap}} {-f_0(x)} \leq \epsilon_\mathrm{rel} \right)
+\qquad \mbox{or} \qquad
+\left( L(x,y,z) > 0, \quad \frac{\mathrm{gap}}
+{L(x,y,z)} \leq \epsilon_\mathrm{rel} \right)
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="684" HEIGHT="45" BORDER="0"
+ SRC="img167.gif"
+ ALT="\begin{displaymath}
+\mathrm{gap} \leq \epsilon_\mathrm{abs}
+\qquad \mbox{or} \qq...
+...ac{\mathrm{gap}}
+{L(x,y,z)} \leq \epsilon_\mathrm{rel} \right)
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\mathrm{gap} = 
+\left[\begin{array}{c} s_\mathrm{nl} \\s_\mathrm{l} 
+\end{array}\right]^T
+\left[\begin{array}{c} z_\mathrm{nl} \\z_\mathrm{l} 
+\end{array}\right],
+\qquad
+L(x,y,z) = f_0(x) + z_\mathrm{nl}^T \tilde f(x) + 
+ z_\mathrm{l}^T (Gx-h) + y^T(Ax-b).
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="558" HEIGHT="48" BORDER="0"
+ SRC="img168.gif"
+ ALT="\begin{displaymath}
+\mathrm{gap} =
+\left[\begin{array}{c} s_\mathrm{nl} \\ s_\...
+...athrm{nl}^T \tilde f(x) +
+z_\mathrm{l}^T (Gx-h) + y^T(Ax-b).
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+The functions <tt class="function">qp()</tt>, <tt class="function">gp()</tt> and <tt class="function">cp()</tt>
+call <tt class="function">nlcp()</tt> and hence use the same stopping criteria
+(with <I>x0</I>=0 for <tt class="function">qp()</tt> and <tt class="function">gp()</tt>).
+
+<P>
+The control parameters listed in the <b>GLPK</b> documentation are 
+set to their default values and can also be customized by making 
+an entry in <tt class="member">solvers.options</tt>.
+The keys in the dictionary are strings with the name of the GLPK 
+parameter.  The command
+<div class="verbatim"><pre>
+>>> from cvxopt import solvers 
+>>> solvers.options['LPX_K_MSGLEV'] = 0
+</pre></div>
+turns off the screen output subsequent calls <tt class="function">lp()</tt> with 
+the <code>'glpk'</code> option.
+
+<P>
+The <b>MOSEK</b> <a class="ulink" href="http://www.mosek.com/products/3/tools/doc/html/tools/node22.html"
+  >control parameters</a>
+are set to their default values.
+The corresponding keys in <code>solvers.options</code> are strings with the 
+name of the MOSEK parameter.  For example the command
+<div class="verbatim"><pre>
+>>> from cvxopt import solvers 
+>>> solvers.options['MSK_IPAR_LOG'] = 0
+</pre></div>
+turns off the screen output during calls of  <tt class="function">lp()</tt> 
+and <tt class="function">qp()</tt> with the <code>'mosek'</code> option.
+
+<P>
+The following control parameters affect the <b>DSDP</b> algorithm:
+<DL>
+<DT><STRONG><code>'DSDP_Monitor'</code></STRONG></DT>
+<DD>the interval (in number of iterations)
+ at which output is printed to the screen
+(default: 0).
+</DD>
+<DT><STRONG><code>'DSDP_MaxIts'</code></STRONG></DT>
+<DD>maximum number of iterations.
+</DD>
+<DT><STRONG><code>'DSDP_GapTolerance'</code></STRONG></DT>
+<DD>relative accuracy (default: 
+<code>1e-5</code>).
+</DD>
+</DL>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.8 Optional Solvers"
+  href="s-external.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="9. Modeling (cvxopt.modeling)"
+  href="node55.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-external.html">8.8 Optional Solvers</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node55.html">9. Modeling (cvxopt.modeling)</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-random.html b/doc/cvxopt/s-random.html
new file mode 100644
index 0000000..47e0f57
--- /dev/null
+++ b/doc/cvxopt/s-random.html
@@ -0,0 +1,167 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="s-array-interface.html" />
+<link rel="prev" href="s-otherfuncs.html" />
+<link rel="parent" href="node4.html" />
+<link rel="next" href="s-array-interface.html" />
+<meta name='aesop' content='information' />
+<title>2.7 Randomly Generated Matrices</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.6 Other Matrix Functions"
+  href="s-otherfuncs.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.8 The NumPy Array"
+  href="s-array-interface.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-otherfuncs.html">2.6 Other Matrix Functions</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-array-interface.html">2.8 The NumPy Array</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION004700000000000000000"></A> <A NAME="s-random"></A>
+<BR>
+2.7 Randomly Generated Matrices
+</H1>
+The module <tt class="module">cvxopt.random</tt> provides functions for generating
+random matrices.  Two types of random matrices are defined:
+matrices with normally distributed entries and matrices with uniformly 
+distributed entries.   
+
+<P>
+The pseudo-random number generators used to 
+generate the random matrices are from the package described in the 
+references below.  
+<div class="seealso">
+  <p class="heading">See Also:</p>
+
+<dl compact="compact" class="seeurl">
+    <dt><a href='http://www.cs.wm.edu/~va/software/park/park.html'
+        >S. Park, Random Number Generators.</a></dt>
+    <dd></dd>
+  </dl>
+
+<P>
+S. Park, D. Geyer, Random Number Generators: Good Ones Are 
+Hard To Find,
+Communications of the ACM, October 1988.
+</div>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-24' xml:id='l2h-24' class="function">normal</tt></b>(</nobr></td>
+  <td><var>nrows</var><big>[</big><var>, ncols</var><big>[</big><var>, 
+ mean</var><big>[</big><var>, std</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Returns a type <code>'d'</code> matrix of size <var>nrows</var> by 
+<var>ncols</var> with random elements chosen from a normal distribution 
+with mean <var>mean</var> and standard deviation <var>std</var>.
+The default values for the optional arguments are 
+<var>ncols</var>=1, <var>mean</var>=0.0, <var>std</var>=1.0.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-25' xml:id='l2h-25' class="function">uniform</tt></b>(</nobr></td>
+  <td><var>nrows</var><big>[</big><var>, ncols</var><big>[</big><var>, 
+  a</var><big>[</big><var>, b</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Returns a type <code>'d'</code> matrix of size <var>nrows</var> by 
+<var>ncols</var> matrix with random elements, uniformly distributed 
+between <var>a</var> and <var>b</var>.
+The default values for the optional arguments are 
+<var>ncols</var>=1, <var>a</var>=0.0, <var>b</var>=1.0.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-26' xml:id='l2h-26' class="function">getseed</tt></b>(</nobr></td>
+  <td><var></var>)</td></tr></table></dt>
+<dd>
+Returns the current seed value (the state of the random number 
+generator).
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-27' xml:id='l2h-27' class="function">setseed</tt></b>(</nobr></td>
+  <td><var></var><big>[</big><var>value</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Sets the seed value.  <var>value</var> must be a nonnegative integer.
+If <var>value</var> is absent or equal to zero, the seed value is taken 
+from the system clock.  
+</dl>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="2.6 Other Matrix Functions"
+  href="s-otherfuncs.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="2. Dense Matrices (cvxopt.base)"
+  href="node4.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="2.8 The NumPy Array"
+  href="s-array-interface.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-otherfuncs.html">2.6 Other Matrix Functions</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node4.html">2. Dense Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-array-interface.html">2.8 The NumPy Array</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-sdpsolver.html b/doc/cvxopt/s-sdpsolver.html
new file mode 100644
index 0000000..08b15c7
--- /dev/null
+++ b/doc/cvxopt/s-sdpsolver.html
@@ -0,0 +1,483 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="e-nlcp.html" />
+<link rel="prev" href="node48.html" />
+<link rel="parent" href="node45.html" />
+<link rel="next" href="e-nlcp.html" />
+<meta name='aesop' content='information' />
+<title>8.4 Semidefinite Programming</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.3 Geometric Programming"
+  href="node48.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.5 Nonlinear Convex Programming"
+  href="e-nlcp.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node48.html">8.3 Geometric Programming</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="e-nlcp.html">8.5 Nonlinear Convex Programming</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0010400000000000000000"></A> <A NAME="s-sdpsolver"></A>
+<BR>
+8.4 Semidefinite Programming
+</H1>
+We use the following notation for a pair of primal and dual 
+semidefinite programs (SDPs): 
+<BR>
+<DIV ALIGN="RIGHT" CLASS="mathdisplay">
+
+<!-- MATH
+ \begin{equation}
+\mbox{Primal:}\quad \begin{array}[t]{ll}
+\mbox{minimize} & c^Tx \\
+\mbox{subject to} &  G_\mathrm{l}x + s_\mathrm{l} = h_\mathrm{l} \\
+ & G_\mathrm{s}(x) + S_\mathrm{s} = H_\mathrm{s} \\
+ & Ax=b \\& s_\mathrm{l} \succeq 0, \quad S_\mathrm{s} \succeq 0 
+\end{array} \qquad\qquad
+\mbox{Dual:}\quad
+\begin{array}[t]{ll}
+\mbox{maximize}   & -h_\mathrm{l}^T z_\mathrm{l} - 
+ \mathop{\bf tr}(H_\mathrm{s} Z_\mathrm{s}) - b^T y \\
+\mbox{subject to} & G_\mathrm{l}^Tz_\mathrm{l} + 
+  G_\mathrm{s}^T(Z_\mathrm{s}) + A^T y  + c = 0 \\
+ & z_\mathrm{l} \succeq 0, \quad Z_\mathrm{s} \succeq 0.
+\end{array}
+\end{equation}
+ -->
+<A NAME="e-sdp"></A>
+<TABLE WIDTH="100%" ALIGN="CENTER">
+<TR VALIGN="MIDDLE"><TD></TD><TD ALIGN="CENTER" NOWRAP><A NAME="e-sdp"></A><IMG
+ WIDTH="682" HEIGHT="106" BORDER="0"
+ SRC="img127.gif"
+ ALT="\begin{displaymath}
+\mbox{Primal:}\quad \begin{array}[t]{ll}
+\mbox{minimize} & c...
+...\mathrm{l} \succeq 0, \quad Z_\mathrm{s} \succeq 0.
+\end{array}\end{displaymath}"></TD>
+<TD CLASS="eqno" WIDTH=10 ALIGN="RIGHT">
+(8.2)</TD></TR>
+</TABLE>
+<BR CLEAR="ALL"></DIV><P></P>
+The dimensions of the primal and dual variables are
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+x\in {\mbox{\bf R}}^n, \qquad s_\mathrm{l} \in {\mbox{\bf R}}^m, 
+\qquad S_\mathrm{s} \in {\mbox{\bf S}}^{m_0} \times \cdots \times 
+{\mbox{\bf S}}^{m_{N-1}}, \qquad
+ y \in{\mbox{\bf R}}^p, \qquad z_\mathrm{l}\in {\mbox{\bf R}}^m, 
+\qquad Z_\mathrm{s} \in {\mbox{\bf S}}^{m_0} \times \cdots \times 
+{\mbox{\bf S}}^{m_{N-1}},
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="705" HEIGHT="27" BORDER="0"
+ SRC="img128.gif"
+ ALT="\begin{displaymath}
+x\in {\mbox{\bf R}}^n, \qquad s_\mathrm{l} \in {\mbox{\bf R...
+...{\bf S}}^{m_0} \times \cdots \times
+{\mbox{\bf S}}^{m_{N-1}},
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <!-- MATH
+ ${\mbox{\bf S}}^n$
+ -->
+<SPAN CLASS="MATH"><IMG
+ WIDTH="21" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
+ SRC="img129.gif"
+ ALT="${\mbox{\bf S}}^n$"></SPAN> is the set of real symmetric matrices
+of order <I>n</I>.  The problem data are the matrices
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+c\in{\mbox{\bf R}}^n, \qquad G_\mathrm{l} \in{\mbox{\bf R}}^{m\times n},
+\qquad h_\mathrm{l} \in {\mbox{\bf R}}^{m}, \qquad
+ H_\mathrm{s} \in {\mbox{\bf S}}^{m_0} \times \cdots \times {\mbox{\bf S}}^{m_{N-1}}, 
+\qquad
+A \in {\mbox{\bf R}}^{p\times n}, \qquad b \in {\mbox{\bf R}}^{p},
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="645" HEIGHT="27" BORDER="0"
+ SRC="img130.gif"
+ ALT="\begin{displaymath}
+c\in{\mbox{\bf R}}^n, \qquad G_\mathrm{l} \in{\mbox{\bf R}}^...
+... {\mbox{\bf R}}^{p\times n}, \qquad b \in {\mbox{\bf R}}^{p},
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+and the linear mapping
+<!-- MATH
+ $G_\mathrm{s} : {\mbox{\bf R}}^n \rightarrow {\mbox{\bf S}}^{m_1} \times \cdots \times 
+{\mbox{\bf S}}^{m_N}$
+ -->
+<SPAN CLASS="MATH"><IMG
+ WIDTH="196" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
+ SRC="img131.gif"
+ ALT="$G_\mathrm{s} : {\mbox{\bf R}}^n \rightarrow {\mbox{\bf S}}^{m_1} \times \cdots \times
+{\mbox{\bf S}}^{m_N}$"></SPAN> and its adjoint <!-- MATH
+ $G_\mathrm{s}^T$
+ -->
+<SPAN CLASS="MATH"><IMG
+ WIDTH="26" HEIGHT="35" ALIGN="MIDDLE" BORDER="0"
+ SRC="img132.gif"
+ ALT="$G_\mathrm{s}^T$"></SPAN>.
+As for LPs we store vector variables as dense real matrices with one 
+column.
+Block-diagonal symmetric matrices are stored as lists of square 
+dense real matrices, with the lower triangular part of each matrix 
+representing the lower triangular part of a diagonal block.  Entries 
+above the diagonal are not referenced.
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-148' xml:id='l2h-148' class="function">sdp</tt></b>(</nobr></td>
+  <td><var>c</var><big>[</big><var>, Gl, hl</var><big>[</big><var>, 
+ Gs, hs</var><big>[</big><var>, A, b</var><big>[</big><var>, solver</var><big>[</big><var>, 
+ primalstart</var><big>[</big><var>, dualstart</var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+
+<P>
+Solves the pair of primal and dual SDPs (<A HREF="#e-sdp">8.2</A>).
+
+<P>
+<var>c</var> is a dense real matrix with one column.
+<var>Gl</var> and <var>A</var> are dense or sparse real matrices.
+<var>hl</var> and <var>b</var> are dense real matrices with one column.
+The default values for <var>Gl</var>, <var>hl</var>, <var>A</var> and <var>b</var> are 
+empty matrices, <EM>i.e.</EM>, matrices with zero rows. 
+
+<P>
+<var>Gs</var> and <var>hs</var> are lists of length <I>N</I> that specify the 
+linear matrix inequality constraints.
+<var>hs</var> is a list of square dense real matrices <code><var>hs</var>[k]</code> of 
+order <I>m_k</I>.
+<var>Gs</var> is a list of dense or sparse real matrices 
+<code><var>Gs</var>[k]</code> with <I>m_k</I>*<I>m_k</I> rows and <I>n</I> columns,
+such that the product <code><var>Gs</var>[k]*<var>x</var></code> 
+is the <I>k</I>th diagonal block of <I>Gs</I>(<var>x</var>), stored 
+columnwise.
+
+<P>
+The <var>solver</var> argument is used to choose between two
+solvers: the default solver (used when <var>solver</var> is absent or
+equal to <code>None</code>) and the external solver DSDP5 
+(<code><var>solver</var>='dsdp'</code>); see section <A href="s-external.html#s-external">8.8</A>.
+With the <code>'dsdp'</code> option the code does not accept problems with 
+equality constraints.
+
+<P>
+The optional argument <var>primalstart</var> is a dictionary with keys 
+<code>'x'</code>, <code>'sl'</code>, and <code>'ss'</code>, used as an optional primal 
+starting point. 
+<var>dualstart</var> is a dictionary with keys <code>'y'</code>, <code>'zl'</code>, 
+<code>'zs'</code>, used as an optional dual starting point.
+These two arguments are ignored when the DSDP solver is used.
+
+<P>
+<tt class="function">sdp()</tt> returns a dictionary with keys <code>'status'</code>, 
+<code>'x'</code>, <code>'sl'</code>, <code>'ss'</code>, <code>'y'</code>, <code>'zl'</code>,  
+<code>'ss'</code>.
+The possible values of the <code>'status'</code> item are as follows.
+<DL>
+<DT><STRONG><code>'optimal'.</code></STRONG></DT>
+<DD>In this case the <code>'x'</code>, <code>'sl'</code>, 
+<code>'ss'</code>, <code>'y'</code>, <code>'zl'</code>, <code>'zs'</code> entries contain 
+primal and dual optimal solutions, which approximately satisfy
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+G_\mathrm{l}x+s_\mathrm{l} = h_\mathrm{l},
+\qquad 
+G_\mathrm{s}(x)+S_\mathrm{s} = H_\mathrm{s}, 
+\qquad
+Ax=b, \qquad
+G_\mathrm{l}^Tz_\mathrm{l} + G_\mathrm{s}^T(Z_\mathrm{s}) + A^Ty+c = 0
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="553" HEIGHT="28" BORDER="0"
+ SRC="img133.gif"
+ ALT="\begin{displaymath}
+G_\mathrm{l}x+s_\mathrm{l} = h_\mathrm{l},
+\qquad
+G_\mathr...
+...m{l}^Tz_\mathrm{l} + G_\mathrm{s}^T(Z_\mathrm{s}) + A^Ty+c = 0
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+and
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+s_\mathrm{l} \succeq 0, \qquad S_\mathrm{s} \succeq 0, \qquad 
+ z_\mathrm{l} \succeq 0, \qquad Z_\mathrm{s} \succeq 0, \qquad
+ s_\mathrm{l}^T z_\mathrm{l} + \mathop{\bf tr}(S_\mathrm{s}Z_\mathrm{s}) = 0.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="469" HEIGHT="28" BORDER="0"
+ SRC="img134.gif"
+ ALT="\begin{displaymath}
+s_\mathrm{l} \succeq 0, \qquad S_\mathrm{s} \succeq 0, \qqu...
+... z_\mathrm{l} + \mathop{\bf tr}(S_\mathrm{s}Z_\mathrm{s}) = 0.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+</DD>
+<DT><STRONG><code>'primal infeasible'.</code></STRONG></DT>
+<DD>The <code>'x'</code>, <code>'sl'</code> and <code>'ss'</code> entries are <code>None</code>, 
+and the <code>'y'</code>, <code>'zl'</code>, <code>'zs'</code> entries provide an 
+approximate certificate of infeasibility: 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+G_\mathrm{l}^Tz_\mathrm{l} + G_\mathrm{s}^T(Z_\mathrm{s}) +A^Ty = 0
+\qquad h_\mathrm{l}^Tz_\mathrm{l} + \mathop{\bf tr}(H_\mathrm{s} Z_\mathrm{s}) 
+ +b^Ty = -1, \qquad
+z_\mathrm{l} \succeq 0, \qquad Z_\mathrm{s} \succeq 0.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="553" HEIGHT="28" BORDER="0"
+ SRC="img135.gif"
+ ALT="\begin{displaymath}
+G_\mathrm{l}^Tz_\mathrm{l} + G_\mathrm{s}^T(Z_\mathrm{s}) +A...
+...\qquad
+z_\mathrm{l} \succeq 0, \qquad Z_\mathrm{s} \succeq 0.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+</DD>
+<DT><STRONG><code>'dual infeasible'.</code></STRONG></DT>
+<DD>The SDP is dual infeasible.
+The <code>'y'</code>, <code>'zl'</code> and <code>'zs'</code> entries are <code>None</code>, 
+and the <code>'x'</code>, <code>'sl'</code>, <code>'ss'</code> entries contain an 
+approximate certificate of dual infeasibility:
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+G_\mathrm{l}x+s_\mathrm{l} = 0, \qquad
+G_\mathrm{s}(x)+S_\mathrm{s} = 0, \qquad
+Ax = 0, \qquad c^Tx = -1, \qquad
+s_\mathrm{l} \succeq 0, \qquad S_\mathrm{s} \succeq 0.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="576" HEIGHT="28" BORDER="0"
+ SRC="img136.gif"
+ ALT="\begin{displaymath}
+G_\mathrm{l}x+s_\mathrm{l} = 0, \qquad
+G_\mathrm{s}(x)+S_\ma...
+...\qquad
+s_\mathrm{l} \succeq 0, \qquad S_\mathrm{s} \succeq 0.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+
+<P>
+</DD>
+<DT><STRONG><code>'unknown'</code>.</STRONG></DT>
+<DD>The <code>'x'</code>, <code>'sl'</code>, <code>'ss'</code>,
+<code>'y'</code>, <code>'zl'</code> and <code>'zs'</code> entries are <code>None</code>.
+</DD>
+</DL>
+</dl>
+
+<P>
+We illustrate the calling sequence with a small example.
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & x_1 - x_2 + x_3 \\
+\mbox{subject to} & 
+  x_1 \left[ \begin{array}{cc} -7 &  -11 \\-11 &  3
+ \end{array}\right] + 
+  x_2 \left[ \begin{array}{cc}
+  7 & -18 \\-18 & 8 \end{array}\right] + 
+  x_3 \left[ \begin{array}{cc}
+  -2 & -8 \\-8 & 1 
+ \end{array}\right] \preceq  
+ \left[ \begin{array}{cc} 
+ 33 & -9 \\-9 & 26 \end{array}\right] \\*[1ex]
+& x_1 \left[ \begin{array}{ccc} 
+ -21 & -11 & 0  \\-11 & 10 & 8 \\0 & 8 & 5
+ \end{array}\right] + 
+ x_2 \left[ \begin{array}{ccc} 
+ 0 & 10  & 16 \\
+10 & -10 & -10 \\
+16 & -10 & 3 
+ \end{array}\right] + 
+ x_3 \left[ \begin{array}{ccc} 
+ -5  & 2 & -17 \\
+ 2  & -6 & -7 \\
+ -17 & 8 & 6 
+ \end{array}\right]  
+\preceq  \left[ \begin{array}{ccc}
+ 14 &  9 & 40 \\
+  9  & 91 & 10 \\
+ 40 & 10 & 15
+\end{array} \right]
+\end{array}
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="726" HEIGHT="121" BORDER="0"
+ SRC="img137.gif"
+ ALT="\begin{displaymath}
+\begin{array}{ll}
+\mbox{minimize} & x_1 - x_2 + x_3 \\
+\mbo...
+...
+9 & 91 & 10 \\
+40 & 10 & 15
+\end{array} \right]
+\end{array}\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+<div class="verbatim"><pre>
+>>> from cvxopt.base import matrix
+>>> from cvxopt import solvers
+>>> c = matrix([1.,-1.,1.])
+>>> G = [ matrix([[-7., -11., -11., 3.], 
+                  [ 7., -18., -18., 8.], 
+                  [-2.,  -8.,  -8., 1.]]) ]
+>>> G += [ matrix([[-21., -11.,   0., -11.,  10.,   8.,   0.,   8., 5.], 
+                   [ 0.,  10.,  16.,  10., -10., -10.,  16., -10., 3.], 
+                   [ -5.,   2., -17.,   2.,  -6.,   8., -17.,  -7., 6.]]) ]
+>>> h = [ matrix([[33., -9.], [-9., 26.]]) ]
+>>> h += [ matrix([[14., 9., 40.], [9., 91., 10.], [40., 10., 15.]]) ]
+>>> sol = solvers.sdp(c, Gs=G, hs=h)  
+>>> print sol['x']
+  -3.6775e-01
+   1.8983e+00
+  -8.8747e-01
+>>> print sol['zs'][0]
+   3.9613e-03   0.0000e+00
+  -4.3390e-03   4.7526e-03
+>>> print sol['zs'][1]
+   5.5803e-02   0.0000e+00   0.0000e+00
+  -2.4103e-03   1.0411e-04   0.0000e+00
+   2.4214e-02  -1.0459e-03   1.0507e-02
+</pre></div>
+Note that only the lower triangular parts of the dual variables are
+returned (in the example the returned values of the upper triangular 
+elements happen to be zero, but this is not necessarily the case).
+
+<P>
+Only the entries in <var>Gs</var> and <var>hs</var> that correspond to lower 
+triangular entries need to be provided, so in the example <var>h</var> and 
+<var>G</var> can also be defined as follows.
+<div class="verbatim"><pre>
+>>> G = [ matrix([[-7., -11., 0., 3.], 
+                  [ 7., -18., 0., 8.], 
+                  [-2.,  -8., 0., 1.]]) ]
+>>> G += [ matrix([[-21., -11.,   0., 0.,  10.,   8., 0., 0., 5.], 
+                   [  0.,  10.,  16., 0., -10., -10., 0., 0., 3.], 
+                   [ -5.,   2., -17., 0.,  -6.,   8., 0., 0., 6.]]) ]
+>>> h = [ matrix([[33., -9.], [0., 26.]]) ]
+>>> h += [ matrix([[14., 9., 40.], [0., 91., 10.], [0., 0., 15.]]) ]
+</pre></div>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="8.3 Geometric Programming"
+  href="node48.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="8. Optimization Routines (cvxopt.solvers)"
+  href="node45.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="8.5 Nonlinear Convex Programming"
+  href="e-nlcp.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node48.html">8.3 Geometric Programming</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node45.html">8. Optimization Routines (cvxopt.solvers)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="e-nlcp.html">8.5 Nonlinear Convex Programming</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-spmatrix-arith.html b/doc/cvxopt/s-spmatrix-arith.html
new file mode 100644
index 0000000..85aab4f
--- /dev/null
+++ b/doc/cvxopt/s-spmatrix-arith.html
@@ -0,0 +1,221 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node37.html" />
+<link rel="prev" href="e-spA-example.html" />
+<link rel="parent" href="node33.html" />
+<link rel="next" href="node37.html" />
+<meta name='aesop' content='information' />
+<title>6.3 Arithmetic Operations</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="6.2 Attributes and Methods"
+  href="e-spA-example.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="6. Sparse Matrices (cvxopt.base)"
+  href="node33.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="6.4 Indexing and Slicing"
+  href="node37.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="e-spA-example.html">6.2 Attributes and Methods</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node33.html">6. Sparse Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node37.html">6.4 Indexing and Slicing</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION008300000000000000000"></A> <A NAME="s-spmatrix-arith"></A>
+<BR>
+6.3 Arithmetic Operations
+</H1>
+Most of the operations defined for dense <code>'d'</code> and <code>'z'</code> matrices
+(section <A href="s-arithmetic.html#s-arithmetic">2.3</A>) are also defined for sparse matrices.
+In the following table, <var>A</var> is a sparse matrix,
+<var>B</var> is sparse or dense, and <var>c</var> is a scalar, defined as a
+Python number or a 1 by 1 dense matrix.
+
+<P>
+<DIV ALIGN="CENTER">
+<TABLE CELLPADDING=3 BORDER="1">
+<TR><TD ALIGN="LEFT">Unary plus/minus</TD>
+<TD ALIGN="LEFT"><code>+<var>A</var></code>, <code>-<var>A</var></code></TD>
+</TR>
+<TR><TD ALIGN="LEFT">Addition</TD>
+<TD ALIGN="LEFT"><code><var>A</var>+<var>B</var></code>, <code><var>B</var>+<var>A</var></code>, 
+   <code><var>A</var>+<var>c</var></code>, <code><var>c</var>+<var>A</var></code></TD>
+</TR>
+<TR><TD ALIGN="LEFT">Subtraction</TD>
+<TD ALIGN="LEFT"><code><var>A</var>-<var>B</var></code>, <code><var>B</var>-<var>A</var></code>, 
+    <code><var>A</var>-<var>c</var></code>, <code><var>c</var>-<var>A</var></code></TD>
+</TR>
+<TR><TD ALIGN="LEFT">Matrix multiplication</TD>
+<TD ALIGN="LEFT"><code><var>A</var>*<var>B</var></code>, 
+  <code><var>B</var>*<var>A</var></code></TD>
+</TR>
+<TR><TD ALIGN="LEFT">Scalar multiplication and division</TD>
+<TD ALIGN="LEFT"><code><var>c</var>*<var>A</var></code>, 
+   <code><var>A</var>*<var>c</var></code>, <code><var>A</var>/<var>c</var></code></TD>
+</TR>
+</TABLE>
+</DIV>
+
+<P>
+If <var>B</var> is a dense matrix, then the result of 
+<code><var>A</var>+<var>B</var></code>, <code><var>B</var>+<var>A</var></code>, <code><var>A</var>-<var>B</var></code>, 
+<code><var>B</var>-<var>A</var></code> is a dense  matrix.
+The typecode of the result is <code>'d'</code> if <var>A</var> has typcode <code>'d'</code> and 
+<var>B</var> has typecode <code>'i'</code> or <code>'d'</code>,
+and it is <code>'z'</code> if <var>A</var> and/or <var>B</var> have typecode <code>'z'</code>.
+
+<P>
+If <var>B</var> is a sparse matrix, then the result of
+<code><var>A</var>+<var>B</var></code>, <code><var>B</var>+<var>A</var></code>, 
+<code><var>A</var>-<var>B</var></code>, <code><var>B</var>-<var>A</var></code> is a sparse 
+matrix.  The typecode of the result is <code>'d'</code> if <var>A</var> and <var>B</var>
+have typecode <code>'d'</code>,  and <code>'z'</code> otherwise.
+
+<P>
+If <var>c</var> in <code><var>A</var>+<var>c</var></code>, <code><var>A</var>-<var>c</var></code>, 
+<code><var>c</var>+<var>A</var></code>, <code><var>c</var>-<var>A</var></code> is a number,
+then it is interpreted as a dense matrix with the same size as 
+<var>A</var>, typecode given by the type of <var>c</var>, and all entries equal 
+to <var>c</var>. 
+If <var>c</var> is a 1 by 1 dense matrix and the size of <var>A</var> is not 1 
+by 1, then <var>c</var>
+is interpreted as a dense matrix of the same size as <var>A</var>,
+typecode given by the typecode of <var>c</var>, and all entries equal to 
+<code><var>c</var>[0]</code>.
+
+<P>
+The result of a matrix-matrix product <code><var>A</var>*<var>B</var></code> or 
+<code><var>B</var>*<var>A</var></code> is a dense matrix if <var>B</var> is dense, and sparse
+if <var>B</var> is sparse.   The matrix-matrix product is not allowed if 
+<var>B</var> is a dense <code>'i'</code> matrix.  
+
+<P>
+If <var>c</var> is a number (Python integer float or complex), then the 
+operations <code><var>c</var>*<var>A</var></code> and <code><var>A</var>*<var>c</var></code> define 
+scalar multiplication and return a sparse matrix.
+
+<P>
+If <var>c</var> is a 1 by 1 dense matrix, then, if possible, the products 
+<code><var>c</var>*<var>A</var></code> and <code><var>A</var>*<var>c</var></code> are interpreted as 
+matrix-matrix products and a dense matrix is returned.  
+If the product cannot be interpreted as a matrix-matrix product
+(either because the dimensions of <var>A</var> are incompatible or because
+<var>c</var> has typecode <code>'i'</code>), then the product is interpreted as the 
+scalar multiplication with <code><var>c</var>[0]</code> and a sparse matrix is 
+returned.
+
+<P>
+The division <code><var>A</var>/<var>c</var></code> is interpreted as scalar 
+multiplication with <code>1.0/<var>c</var></code> if <var>c</var> is a number, 
+or with  <code>1.0/<var>c</var>[0]</code> if <var>c</var> is a 1 by 1 dense matrix.
+
+<P>
+The following in-place operations are defined for a sparse matrix 
+<var>A</var> if they do not change the dimensions or type of <var>A</var>.
+<DIV ALIGN="CENTER">
+<TABLE CELLPADDING=3 BORDER="1">
+<TR><TD ALIGN="LEFT">In-place addition</TD>
+<TD ALIGN="LEFT"><code><var>A</var>+=<var>B</var></code>, 
+    <code><var>A</var>+=<var>c</var></code></TD>
+</TR>
+<TR><TD ALIGN="LEFT">In-place subtraction</TD>
+<TD ALIGN="LEFT"><code><var>A</var>-=<var>B</var></code>, 
+    <code><var>A</var>-=<var>c</var></code></TD>
+</TR>
+<TR><TD ALIGN="LEFT">In-place scalar multiplication and division</TD>
+<TD ALIGN="LEFT"><code><var>A</var>*=<var>c</var></code>, <code><var>A</var>/=<var>c</var></code></TD>
+</TR>
+</TABLE>
+</DIV>
+
+<P>
+For example, "<tt class="samp"><var>A</var> += 1.0</tt>" is not allowed because the 
+operation "<tt class="samp"><var>A</var> = <var>A</var> + 1.0</tt>" results in a dense matrix, 
+so it cannot be assigned to <var>A</var> without changing its type.
+
+<P>
+In-place matrix-matrix products are not allowed.  (Except when
+<var>c</var> is a 1 by 1 dense matrix, in which case <code><var>A</var>*=<var>c</var></code> 
+is interpreted as a scalar product <code><var>A</var>*=<var>c</var>[0]</code>.)
+
+<P>
+As for dense operations, the in-place sparse operations do not return
+a new matrix but modify the existing object <var>A</var>.
+The restrictions on in-place operations follow the principle that once 
+a sparse matrix is created, its size and type cannot be modified.  
+The only attributes that can be modified are the sparsity pattern and 
+the numerical values of the nonzero elements.
+These attributes can be modified by in-place operations or by indexed 
+assignments.
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="6.2 Attributes and Methods"
+  href="e-spA-example.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="6. Sparse Matrices (cvxopt.base)"
+  href="node33.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="6.4 Indexing and Slicing"
+  href="node37.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="e-spA-example.html">6.2 Attributes and Methods</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node33.html">6. Sparse Matrices (cvxopt.base)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node37.html">6.4 Indexing and Slicing</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-umfpack.html b/doc/cvxopt/s-umfpack.html
new file mode 100644
index 0000000..fb9fcce
--- /dev/null
+++ b/doc/cvxopt/s-umfpack.html
@@ -0,0 +1,346 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="s-cholmod.html" />
+<link rel="prev" href="s-orderings.html" />
+<link rel="parent" href="c-spsolvers.html" />
+<link rel="next" href="s-cholmod.html" />
+<meta name='aesop' content='information' />
+<title>7.2 General Linear Equations (cvxopt.umfpack)</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="7.1 Matrix Orderings (cvxopt.amd)"
+  href="s-orderings.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="7. Sparse Linear Equation"
+  href="c-spsolvers.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="7.3 Positive Definite Linear"
+  href="s-cholmod.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-orderings.html">7.1 Matrix Orderings (cvxopt.amd)</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="c-spsolvers.html">7. Sparse Linear Equation</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-cholmod.html">7.3 Positive Definite Linear</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION009200000000000000000"></A> 
+<A NAME="s-umfpack"></A>
+<BR>
+7.2 General Linear Equations (<tt class="module">cvxopt.umfpack</tt>)
+</H1>
+The module <tt class="module">cvxopt.umfpack</tt> includes four functions for solving 
+sparse non-symmetric sets of linear equations.  
+They call routines from the UMFPACK library, with all control options 
+set to the default values described in the UMFPACK user guide.  
+
+<P>
+<div class="seealso">
+  <p class="heading">See Also:</p>
+
+<dl compact="compact" class="seeurl">
+    <dt><a href='http://www.cise.ufl.edu/research/sparse/umfpack'
+        >UMFPACK code, documentation, copyright and license.</a></dt>
+    <dd></dd>
+  </dl>
+<div class="seetext"><p>T. A. Davis,
+Algorithm 832: UMFPACK - an unsymmetric-pattern multifrontal method 
+with a column pre-ordering strategy,
+ACM Transactions on Mathematical Software, 30(2), 196-199, 2004.</p></div>
+</div>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-134' xml:id='l2h-134' class="function">linsolve</tt></b>(</nobr></td>
+  <td><var>A, B</var><big>[</big><var>, trans='N'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves a sparse set of linear equations 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+AX = B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+ A^TX = B \quad (\mathrm{trans} = \mathrm{'T'}), \qquad
+ A^HX = B \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="601" HEIGHT="28" BORDER="0"
+ SRC="img43.gif"
+ ALT="\begin{displaymath}
+AX=B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+A^TX=B ...
+...'T'}), \qquad
+A^HX=B \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <var>A</var> is a sparse matrix and <var>B</var> is a dense matrix of
+the same type (<code>'d'</code> or <code>'z'</code>) as <var>A</var>.  On exit <var>B</var> contains 
+the solution.
+Raises an <code>ArithmeticError</code> exception if the coefficient matrix 
+is singular.
+</dl>
+In the following example we solve an equation with 
+coefficient matrix 
+<BR>
+<DIV ALIGN="RIGHT" CLASS="mathdisplay">
+
+<!-- MATH
+ \begin{equation}
+A = \left[\begin{array}{rrrrr}
+ 2 & 3 & 0 & 0 & 0 \\
+ 3 & 0 & 4 & 0 & 6 \\
+ 0 &-1 &-3 & 2 & 0 \\
+ 0 & 0 & 1 & 0 & 0 \\
+ 0 & 4 & 2 & 0 & 1 
+ \end{array}\right].
+\end{equation}
+ -->
+<A NAME="e-sp-Adef"></A>
+<TABLE WIDTH="100%" ALIGN="CENTER">
+<TR VALIGN="MIDDLE"><TD></TD><TD ALIGN="CENTER" NOWRAP><A NAME="e-sp-Adef"></A><IMG
+ WIDTH="205" HEIGHT="102" BORDER="0"
+ SRC="img86.gif"
+ ALT="\begin{displaymath}
+A = \left[\begin{array}{rrrrr}
+2 & 3 & 0 & 0 & 0 \\
+3 & 0...
+...0 & 0 & 1 & 0 & 0 \\
+0 & 4 & 2 & 0 & 1
+\end{array}\right].
+\end{displaymath}"></TD>
+<TD CLASS="eqno" WIDTH=10 ALIGN="RIGHT">
+(7.1)</TD></TR>
+</TABLE>
+<BR CLEAR="ALL"></DIV><P></P>
+<div class="verbatim"><pre>
+>>> from cvxopt.base import spmatrix, matrix
+>>> from cvxopt import umfpack 
+>>> V = [2,3, 3,-1,4, 4,-3,1,2, 2, 6,1]
+>>> I = [0,1, 0, 2,4, 1, 2,3,4, 2, 1,4]
+>>> J = [0,0, 1, 1,1, 2, 2,2,2, 3, 4,4]
+>>> A = spmatrix(V,I,J)
+>>> B = matrix(1.0, (5,1))
+>>> umfpack.linsolve(A,B)
+>>> print B
+ 5.7895e-01
+-5.2632e-02
+ 1.0000e+00
+ 1.9737e+00
+-7.8947e-01
+</pre></div>
+The function <tt class="function">umfpack.linsolve()</tt> is equivalent to the 
+following three functions called in sequence.  
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-135' xml:id='l2h-135' class="function">symbolic</tt></b>(</nobr></td>
+  <td><var>A</var>)</td></tr></table></dt>
+<dd>
+Reorders the columns of <var>A</var> to reduce fill-in and performs a 
+symbolic LU factorization.  <var>A</var> is a sparse, possibly rectangular,
+matrix.
+Returns the symbolic factorization as an opaque C object that can be 
+passed on to <tt class="function">umfpack.numeric()</tt>.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-136' xml:id='l2h-136' class="function">numeric</tt></b>(</nobr></td>
+  <td><var>A, F</var>)</td></tr></table></dt>
+<dd>
+Performs a numeric LU factorization of a sparse, possibly rectangular,
+matrix <var>A</var>.   The argument <var>F</var> is the symbolic factorization
+computed by <tt class="function">umfpack.symbolic()</tt> applied to the matrix <var>A</var>,
+or another sparse matrix with the same sparsity pattern, dimensions,
+and type.  The numeric factorization is returned as an opaque C object 
+that that can be passed on to <tt class="function">umfpack.solve()</tt>.  Raises an
+<code>ArithmeticError</code> if the matrix is singular.
+</dl>
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-137' xml:id='l2h-137' class="function">solve</tt></b>(</nobr></td>
+  <td><var>A, F, B</var><big>[</big><var>, trans='N'</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Solves a set of linear equations
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+AX = B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+ A^TX = B \quad (\mathrm{trans} = \mathrm{'T'}), \qquad
+ A^HX = B \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="601" HEIGHT="28" BORDER="0"
+ SRC="img43.gif"
+ ALT="\begin{displaymath}
+AX=B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+A^TX=B ...
+...'T'}), \qquad
+A^HX=B \quad (\mathrm{trans} = \mathrm{'C'}),
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+where <var>A</var> is a sparse matrix and <var>B</var> is a dense matrix of 
+the same type as <var>A</var>.
+The argument <var>F</var> is a numeric factorization computed by 
+<tt class="function">umfpack.numeric()</tt>.
+On exit <var>B</var> is overwritten by the solution.
+</dl>
+These separate functions are useful for solving several sets
+of linear equations with the same coefficient matrix and different 
+righthand sides, or with coefficient matrices that share the same 
+sparsity pattern.
+The symbolic factorization depends only on the sparsity pattern of
+the matrix, and not on the numerical values of the nonzero 
+coefficients. 
+The numerical factorization on the other hand depends on the sparsity 
+pattern of the matrix and on its the numerical values.
+
+<P>
+As an example, suppose <I>A</I> is the matrix (<A HREF="#e-sp-Adef">7.1</A>) and 
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+B = \left[\begin{array}{rrrrr}
+ 4 & 3 & 0 & 0 & 0 \\
+ 3 & 0 & 4 & 0 & 6 \\
+ 0 &-1 &-3 & 2 & 0 \\
+ 0 & 0 & 1 & 0 & 0 \\
+ 0 & 4 & 2 & 0 & 2 
+ \end{array}\right],
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="206" HEIGHT="102" BORDER="0"
+ SRC="img87.gif"
+ ALT="\begin{displaymath}
+B = \left[\begin{array}{rrrrr}
+4 & 3 & 0 & 0 & 0 \\
+3 & 0...
+...0 & 0 & 1 & 0 & 0 \\
+0 & 4 & 2 & 0 & 2
+\end{array}\right],
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+which differs from <I>A</I> in its first and last entries.
+The following code computes
+<BR><P></P>
+<DIV ALIGN="CENTER" CLASS="mathdisplay">
+<!-- MATH
+ \begin{displaymath}
+x = A^{-T}B^{-1}A^{-1}{\bf 1}.
+\end{displaymath}
+ -->
+
+<IMG
+ WIDTH="132" HEIGHT="24" BORDER="0"
+ SRC="img88.gif"
+ ALT="\begin{displaymath}
+x = A^{-T}B^{-1}A^{-1}{\bf 1}.
+\end{displaymath}">
+</DIV>
+<BR CLEAR="ALL">
+<P></P>
+<div class="verbatim"><pre>
+>>> from cvxopt.base import spmatrix, matrix
+>>> from cvxopt import umfpack
+>>> VA = [2,3, 3,-1,4, 4,-3,1,2, 2, 6,1]
+>>> VB = [4,3, 3,-1,4, 4,-3,1,2, 2, 6,2]
+>>> I =  [0,1, 0, 2,4, 1, 2,3,4, 2, 1,4]
+>>> J =  [0,0, 1, 1,1, 2, 2,2,2, 3, 4,4]
+>>> A = spmatrix(VA, I, J)
+>>> B = spmatrix(VB, I, J)
+>>> x = matrix(1.0, (5,1))
+>>> Fs = umfpack.symbolic(A)
+>>> FA = umfpack.numeric(A, Fs)
+>>> FB = umfpack.numeric(B, Fs)
+>>> umfpack.solve(A, FA, x)
+>>> umfpack.solve(B, FB, x)
+>>> umfpack.solve(A, FA, x, trans='T')
+>>> print x
+ 5.8065e-01
+-2.3660e-01
+ 1.6280e+00
+ 8.0656e+00
+-1.3075e-01
+</pre></div>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="7.1 Matrix Orderings (cvxopt.amd)"
+  href="s-orderings.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="7. Sparse Linear Equation"
+  href="c-spsolvers.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="7.3 Positive Definite Linear"
+  href="s-cholmod.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="s-orderings.html">7.1 Matrix Orderings (cvxopt.amd)</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="c-spsolvers.html">7. Sparse Linear Equation</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-cholmod.html">7.3 Positive Definite Linear</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/s-variables.html b/doc/cvxopt/s-variables.html
new file mode 100644
index 0000000..7063350
--- /dev/null
+++ b/doc/cvxopt/s-variables.html
@@ -0,0 +1,162 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="cvxopt.css" type='text/css' />
+<link rel="first" href="cvxopt.html" title='CVXOPT: A Python Package for Convex Optimization' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='index' href='genindex.html' title='Index' />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="s-functions.html" />
+<link rel="prev" href="node55.html" />
+<link rel="parent" href="node55.html" />
+<link rel="next" href="s-functions.html" />
+<meta name='aesop' content='information' />
+<title>9.1 Variables</title>
+</head>
+<body>
+<DIV CLASS="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="9. Modeling (cvxopt.modeling)"
+  href="node55.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="9. Modeling (cvxopt.modeling)"
+  href="node55.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="9.2 Functions"
+  href="s-functions.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node55.html">9. Modeling (cvxopt.modeling)</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node55.html">9. Modeling (cvxopt.modeling)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-functions.html">9.2 Functions</A>
+</div>
+<hr /></div>
+</DIV>
+<!--End of Navigation Panel-->
+
+<H1><A NAME="SECTION0011100000000000000000"></A> <A NAME="s-variables"></A>
+<BR>
+9.1 Variables
+</H1>
+Optimization variables are represented by variable objects.
+
+<P>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><span class="typelabel">class</span> <tt id='l2h-152' xml:id='l2h-152' class="class">variable</tt></b>(</nobr></td>
+  <td><var></var><big>[</big><var>size</var><big>[</big><var>, name</var><big>]</big><var></var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+A vector variable.  The first argument is the dimension of the
+vector (a positive integer with default value 1). 
+The second argument is a string with a name for the variable.
+The name is optional and has default value <code>""</code>. It is only used 
+when displaying variables (or objects that depend on variables, such 
+as functions or constraints) 
+using <tt class="function">print</tt> statements, when calling the built-in functions
+<tt class="function">repr()</tt>  or <tt class="function">str()</tt>, or when writing linear programs
+to MPS files.
+</dl>
+The function <tt class="function">len()</tt> returns the length of a 
+variable.  A variable <var>x</var> has two attributes.
+<dl><dt><b><tt id='l2h-153' xml:id='l2h-153' class="member">name</tt></b></dt>
+<dd>
+The name of the variable.  
+</dl>
+
+<P>
+<dl><dt><b><tt id='l2h-154' xml:id='l2h-154' class="member">value</tt></b></dt>
+<dd>
+Either <code>None</code>  or a dense <code>'d'</code> matrix of size <code>len(<var>x</var>)</code> by 1.
+
+<P>
+The attribute <var>x</var>.<tt class="member">value</tt> is set to <code>None</code> when the 
+variable <var>x</var> is created.   It can be given a numerical value later, 
+typically by solving an LP that has <var>x</var> as one of its variables.   
+One can also make an explicit assignment 
+<code><var>x</var>.<tt class="member">value</tt> = <var>y</var></code>.  The
+assigned value <var>y</var> must be an integer or float, or a 
+dense <code>'d'</code> matrix of size (<code>len(<var>x</var>)</code>,1). 
+If <var>y</var> is an integer or float all the elements of 
+<var>x</var>.<tt class="member">value</tt> are set to the value of <var>y</var>.
+</dl>
+
+<P>
+<div class="verbatim"><pre>
+>>> from cvxopt.base import matrix
+>>> from cvxopt.modeling import variable
+>>> x = variable(3,'a')
+>>> len(x)
+3
+>>> print x.name
+a
+>>> print x.value 
+None
+>>> x.value = matrix([1.,2.,3.])
+>>> print x.value
+ 1.0000e+00
+ 2.0000e+00
+ 3.0000e+00
+>>> x.value = 1
+>>> print x.value
+ 1.0000e+00
+ 1.0000e+00
+ 1.0000e+00
+</pre></div>
+
+<P>
+
+<DIV CLASS="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="9. Modeling (cvxopt.modeling)"
+  href="node55.html"><img src='previous.gif'
+  border='0' height='32'  alt='Previous Page' width='32' /></A></td>
+<td class='online-navigation'><a rel="parent" title="9. Modeling (cvxopt.modeling)"
+  href="node55.html"><img src='up.gif'
+  border='0' height='32'  alt='Up One Level' width='32' /></A></td>
+<td class='online-navigation'><a rel="next" title="9.2 Functions"
+  href="s-functions.html"><img src='next.gif'
+  border='0' height='32'  alt='Next Page' width='32' /></A></td>
+<td align="center" width="100%">CVXOPT: A Python Package for Convex Optimization</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.gif'
+  border='0' height='32'  alt='Contents' width='32' /></A></td>
+<td class='online-navigation'><img src='blank.gif'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><a rel="index" title="Index"
+  href="genindex.html"><img src='index.gif'
+  border='0' height='32'  alt='Index' width='32' /></A></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node55.html">9. Modeling (cvxopt.modeling)</A>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node55.html">9. Modeling (cvxopt.modeling)</A>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="s-functions.html">9.2 Functions</A>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.8.2, documentation updated on February 6, 2007.</span>
+</DIV>
+<!--End of Navigation Panel-->
+
+</BODY>
+</HTML>
diff --git a/doc/cvxopt/up.gif b/doc/cvxopt/up.gif
new file mode 100644
index 0000000..a9d3e13
Binary files /dev/null and b/doc/cvxopt/up.gif differ
diff --git a/doc/fftw.tex b/doc/fftw.tex
new file mode 100644
index 0000000..c8e98ca
--- /dev/null
+++ b/doc/fftw.tex
@@ -0,0 +1,92 @@
+\chapter{Discrete Transforms (\module{cvxopt.fftw})} \label{c-fftw}
+
+The \module{cvxopt.fftw} module is an interface to the FFTW library
+and contains routines for discrete Fourier, cosine, and sine 
+transforms.  This module is optional, and only installed when 
+the FFTW library is made available during the CVXOPT installation.
+
+\begin{seealso}
+\seelink{http://www.fftw.org}{FFTW3 code, documentation, copyright and
+license.}{}
+\end{seealso}
+
+\section{Discrete Fourier Transform} 
+\begin{funcdesc}{dft}{X}
+Replaces the columns of a dense complex matrix with their discrete 
+Fourier transforms:  if \var{X} has {\it n} rows,
+\[
+  X[k,:] := \sum_{j=0}^{n-1} e^{-2\pi j k \sqrt{-1}/n} X[j,:],
+ \qquad k=0,\ldots,n-1.
+\]
+\end{funcdesc}
+
+\begin{funcdesc}{idft}{X}
+Replaces the columns of a dense complex matrix with their inverse 
+discrete Fourier transforms: if \var{X} has {\it n} rows,
+\[
+  X[k,:] := 
+ \frac{1}{n} \sum_{j=0}^{n-1} e^{2\pi j k \sqrt{-1}/n} X[j,:],
+  \qquad k=0,\ldots,n-1.
+\]
+\end{funcdesc}
+
+\section{Discrete Cosine Transform} 
+\begin{funcdesc}{dct}{X\optional{, type=2}}
+Replaces the columns of a dense real matrix with their discrete
+cosine transforms.  The second argument, an integer between 1 and 4,
+denotes the type of transform (DCT-I, DCT-II, DCT-III, DCT-IV).
+The DCT-I transform requires that the row dimension of \var{X} is at 
+least 2.
+These transforms are defined as follows 
+(for a matrix with {\it n} rows).
+\BEAS
+\mbox{DCT-I:} \qquad
+ X[k,:]  & := & X[0,:] + (-1)^k X[n-1,:] + 
+ 2 \sum_{j=1}^{n-2} X[j,:] \cos(\pi j k /(n-1)), 
+ \qquad k=0,\ldots,n-1.\\
+\mbox{DCT-II:} \qquad
+ X[k,:]  & := & 2 \sum_{j=0}^{n-1} X[j,:] \cos(\pi(j+1/2)k/n), 
+ \qquad k=0,\ldots,n-1.\\
+\mbox{DCT-III:} \qquad
+ X[k,:]  & := & X[0,:] + 2 \sum_{j=1}^{n-1} X[j,:] \cos(\pi j(k+1/2)/n),
+ \qquad k=0,\ldots,n-1.\\
+\mbox{DCT-IV:} \qquad
+ X[k,:]  & := & 2 \sum_{j=0}^{n-1} X[j,:] \cos(\pi (j+1/2)(k+1/2)/n), 
+ \qquad k=0,\ldots,n-1.
+\EEAS
+\end{funcdesc}
+
+\begin{funcdesc}{idct}{X\optional{, type=2}}
+Replaces the columns of a dense real matrix with the inverses
+of the discrete cosine transforms defined above.  
+\end{funcdesc}
+
+\section{Discrete Sine Transform} 
+\begin{funcdesc}{dst}{X\optional{, type=1}}
+Replaces the columns of a dense real matrix with their discrete
+sine transforms.  The second argument, an integer between 1 and 4,
+denotes the type of transform (DST-I, DST-II, DST-III, DST-IV).
+These transforms are defined as follows 
+(for a matrix with {\it n} rows).
+\BEAS
+\mbox{DST-I:} \qquad
+ X[k,:] & := & 
+ 2 \sum_{j=0}^{n-1} X[j,:] \sin(\pi(j+1)(k+1)/(n+1)), 
+ \qquad k=0,\ldots,n-1.\\
+\mbox{DST-II:} \qquad
+ X[k,:]  & := & 2 \sum_{j=0}^{n-1} X[j,:] \sin(\pi(j+1/2)(k+1)/n), 
+ \qquad k=0,\ldots,n-1.\\
+\mbox{DST-III:} \qquad
+ X[k,:]  & := & (-1)^k X[n-1,:] + 2 \sum_{j=0}^{n-2} 
+ X[j,:] \sin(\pi(j+1)(k+1/2)/n), 
+ \qquad k=0,\ldots,n-1. \\
+\mbox{DST-IV:} \qquad
+ X[k,:]  & := & 2 \sum_{j=0}^{n-1} X[j,:] \sin(\pi (j+1/2)(k+1/2)/n), 
+ \qquad k=0,\ldots,n-1.
+\EEAS
+\end{funcdesc}
+
+\begin{funcdesc}{idst}{X\optional{, type=1}}
+Replaces the columns of a dense real matrix with the inverses
+of the discrete sine transforms defined above.  
+\end{funcdesc}
diff --git a/doc/figures/floorplan.eps b/doc/figures/floorplan.eps
new file mode 100644
index 0000000..4c5b4bf
--- /dev/null
+++ b/doc/figures/floorplan.eps
@@ -0,0 +1,2622 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Title: /home/vandenbe/src/python/docs/figures/floorplan.eps
+%%Creator: matplotlib version 0.83.2, http://matplotlib.sourceforge.net/
+%%CreationDate: Fri Oct 14 14:11:57 2005
+%%BoundingBox: 18 180 594 612
+%%EndComments
+%%BeginProlog
+/mpldict 7 dict def
+mpldict begin
+/m { moveto } bind def
+/l { lineto } bind def
+/r { rlineto } bind def
+/box {
+m
+1 index 0 r
+0 exch r
+neg 0 r
+closepath
+} bind def
+/clipbox {
+box
+clip
+newpath
+} bind def
+/ellipse {
+newpath
+matrix currentmatrix 7 1 roll
+translate
+scale
+0 0 1 5 3 roll arc
+setmatrix
+closepath
+} bind def
+%%BeginFont: BitstreamVeraSans-Roman
+%!PS-TrueType-1.0-2.0
+8 dict begin
+/FontName /BitstreamVeraSans-Roman def
+/FontMatrix [1 0 0 1 0 0] def
+/FontType 42 def
+/Encoding StandardEncoding def
+/FontBBox [-375 -483 2636 1901] def
+/PaintType 0 def
+/FontInfo 7 dict dup begin
+/Notice (Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.) def
+/FamilyName (Bitstream Vera Sans) def
+/FullName (Bitstream Vera Sans) def
+/version (Release 1.10) def
+/isFixedPitch false def
+/UnderlinePosition -213 def
+/UnderlineThickness 143 def
+end readonly def
+/sfnts [
+<0001000000110100000400104F532F32B45FF4630000EB700000005650434C54D18A5E97
+0000EBC800000036636D6170A4C3E8A00000B16C0000035863767420FFD31D3900001EFC
+000001FC6670676DE7B4F1C4000026600000008B6761737000070007000101480000000C
+676C79660C7441CF000026EC00008A7E68646D7834F0210E0000EC000000154868656164
+DD84A2D00001015400000036686865611045086F0000EB4C00000024686D747809C68EB2
+0000B4C4000004306B65726EDC52D5990000BDA000002D8A6C6F6361F3CBD23D0000BB84
+0000021A6D6178700547063A0000EB2C000000206E616D65D9BCC8B50000011C00001DDF
+706F7374B45A2FBB0000B8F40000028E707265703B07F100000020F80000056800000016
+010E0001000000000000003A000000010000000000010013003A00010000000000020005
+005F00010000000000030013003A00010000000000040013003A0001000000000005000C
+006400010000000000060017004D0001000000000007003000AD0001000000000008000E
+086C000100000000000B00180983000100000000000D0913007000030001040900000074
+099B000300010409000100260A0F0003000104090002000A0A5900030001040900030026
+0A0F000300010409000400260A0F000300010409000500180A630003000104090006002E
+0A35000300010409000700600AF50003000104090008001C1A73000300010409000B0030
+1CA1000300010409000D12260A7B436F7079726967687420286329203230303320627920
+42697473747265616D2C20496E632E20416C6C205269676874732052657365727665642E
+42697473747265616D20566572612053616E7342697473747265616D5665726153616E73
+2D526F6D616E52656C6561736520312E3130436F70797269676874202863292032303033
+2062792042697473747265616D2C20496E632E0D0A416C6C205269676874732052657365
+727665642E0D0A42697473747265616D205665726120697320612074726164656D61726B
+206F662042697473747265616D2C20496E632E0D0A0D0A5065726D697373696F6E206973
+20686572656279206772616E7465642C2066726565206F66206368617267652C20746F20
+616E7920706572736F6E206F627461696E696E67206120636F7079206F66207468652066
+6F6E7473206163636F6D70616E79696E672074686973206C6963656E7365202822466F6E
+7473222920616E64206173736F63696174656420646F63756D656E746174696F6E206669
+6C657320287468652022466F6E7420536F66747761726522292C20746F20726570726F64
+75636520616E6420646973747269627574652074686520466F6E7420536F667477617265
+2C20696E636C7564696E6720776974686F7574206C696D69746174696F6E207468652072
+696768747320746F207573652C20636F70792C206D657267652C207075626C6973682C20
+646973747269627574652C20616E642F6F722073656C6C20636F70696573206F66207468
+6520466F6E7420536F6674776172652C20616E6420746F207065726D697420706572736F
+6E7320746F2077686F6D2074686520466F6E7420536F667477617265206973206675726E
+697368656420746F20646F20736F2C207375626A65637420746F2074686520666F6C6C6F
+77696E6720636F6E646974696F6E733A0D0A0D0A5468652061626F766520636F70797269
+67687420616E642074726164656D61726B206E6F746963657320616E6420746869732070
+65726D697373696F6E206E6F74696365207368616C6C20626520696E636C756465642069
+6E20616C6C20636F70696573206F66206F6E65206F72206D6F7265206F66207468652046
+6F6E7420536F667477617265207479706566616365732E0D0A0D0A54686520466F6E7420
+536F667477617265206D6179206265206D6F6469666965642C20616C74657265642C206F
+7220616464656420746F2C20616E6420696E20706172746963756C617220746865206465
+7369676E73206F6620676C79706873206F72206368617261637465727320696E20746865
+20466F6E7473206D6179206265206D6F64696669656420616E64206164646974696F6E61
+6C20676C79706873206F722063686172616374657273206D617920626520616464656420
+746F2074686520466F6E74732C206F6E6C792069662074686520666F6E74732061726520
+72656E616D656420746F206E616D6573206E6F7420636F6E7461696E696E672065697468
+65722074686520776F726473202242697473747265616D22206F722074686520776F7264
+202256657261222E0D0A0D0A54686973204C6963656E7365206265636F6D6573206E756C
+6C20616E6420766F696420746F2074686520657874656E74206170706C696361626C6520
+746F20466F6E7473206F7220466F6E7420536F6674776172652074686174206861732062
+65656E206D6F64696669656420616E6420697320646973747269627574656420756E6465
+7220746865202242697473747265616D205665726122206E616D65732E0D0A0D0A546865
+20466F6E7420536F667477617265206D617920626520736F6C642061732070617274206F
+662061206C617267657220736F667477617265207061636B61676520627574206E6F2063
+6F7079206F66206F6E65206F72206D6F7265206F662074686520466F6E7420536F667477
+61726520747970656661636573206D617920626520736F6C6420627920697473656C662E
+0D0A0D0A54484520464F4E5420534F4654574152452049532050524F5649444544202241
+53204953222C20574954484F55542057415252414E5459204F4620414E59204B494E442C
+2045585052455353204F5220494D504C4945442C20494E434C5544494E4720425554204E
+4F54204C494D4954454420544F20414E592057415252414E54494553204F46204D455243
+48414E544142494C4954592C204649544E45535320464F52204120504152544943554C41
+5220505552504F534520414E44204E4F4E494E4652494E47454D454E54204F4620434F50
+5952494748542C20504154454E542C2054524144454D41524B2C204F52204F5448455220
+52494748542E20494E204E4F204556454E54205348414C4C2042495453545245414D204F
+522054484520474E4F4D4520464F554E444154494F4E204245204C4941424C4520464F52
+20414E5920434C41494D2C2044414D41474553204F52204F54484552204C494142494C49
+54592C20494E434C5544494E4720414E592047454E4552414C2C205350454349414C2C20
+494E4449524543542C20494E434944454E54414C2C204F5220434F4E53455155454E5449
+414C2044414D414745532C205748455448455220494E20414E20414354494F4E204F4620
+434F4E54524143542C20544F5254204F52204F54484552574953452C2041524953494E47
+2046524F4D2C204F5554204F462054484520555345204F5220494E4142494C4954592054
+4F205553452054484520464F4E5420534F465457415245204F522046524F4D204F544845
+52204445414C494E475320494E2054484520464F4E5420534F4654574152452E0D0A0D0A
+45786365707420617320636F6E7461696E656420696E2074686973206E6F746963652C20
+746865206E616D6573206F6620476E6F6D652C2074686520476E6F6D6520466F756E6461
+74696F6E2C20616E642042697473747265616D20496E632E2C207368616C6C206E6F7420
+6265207573656420696E206164766572746973696E67206F72206F746865727769736520
+746F2070726F6D6F7465207468652073616C652C20757365206F72206F74686572206465
+616C696E677320696E207468697320466F6E7420536F66747761726520776974686F7574
+207072696F72207772697474656E20617574686F72697A6174696F6E2066726F6D207468
+6520476E6F6D6520466F756E646174696F6E206F722042697473747265616D20496E632E
+2C20726573706563746976656C792E20466F72206675727468657220696E666F726D6174
+696F6E2C20636F6E746163743A20666F6E747320617420676E6F6D6520646F74206F7267
+2E687474703A2F2F7777772E62697473747265616D2E636F6D0043006F00700079007200
+690067006800740020002800630029002000320030003000330020006200790020004200
+69007400730074007200650061006D002C00200049006E0063002E00200041006C006C00
+20005200690067006800740073002000520065007300650072007600650064002E004200
+69007400730074007200650061006D00200056006500720061002000530061006E007300
+420069007400730074007200650061006D005600650072006100530061006E0073002D00
+52006F006D0061006E00520065006C006500610073006500200031002E00310030004300
+6F0070007900720069006700680074002000280063002900200032003000300033002000
+620079002000420069007400730074007200650061006D002C00200049006E0063002E00
+0D000A0041006C006C002000520069006700680074007300200052006500730065007200
+7600650064002E000D000A00420069007400730074007200650061006D00200056006500
+72006100200069007300200061002000740072006100640065006D00610072006B002000
+6F0066002000420069007400730074007200650061006D002C00200049006E0063002E00
+0D000A000D000A005000650072006D0069007300730069006F006E002000690073002000
+68006500720065006200790020006700720061006E007400650064002C00200066007200
+6500650020006F00660020006300680061007200670065002C00200074006F0020006100
+6E007900200070006500720073006F006E0020006F0062007400610069006E0069006E00
+670020006100200063006F007000790020006F0066002000740068006500200066006F00
+6E007400730020006100630063006F006D00700061006E00790069006E00670020007400
+68006900730020006C006900630065006E007300650020002800220046006F006E007400
+730022002900200061006E00640020006100730073006F00630069006100740065006400
+200064006F00630075006D0065006E0074006100740069006F006E002000660069006C00
+65007300200028007400680065002000220046006F006E007400200053006F0066007400
+7700610072006500220029002C00200074006F00200072006500700072006F0064007500
+63006500200061006E006400200064006900730074007200690062007500740065002000
+740068006500200046006F006E007400200053006F006600740077006100720065002C00
+200069006E0063006C007500640069006E006700200077006900740068006F0075007400
+20006C0069006D00690074006100740069006F006E002000740068006500200072006900
+6700680074007300200074006F0020007500730065002C00200063006F00700079002C00
+20006D0065007200670065002C0020007000750062006C006900730068002C0020006400
+6900730074007200690062007500740065002C00200061006E0064002F006F0072002000
+730065006C006C00200063006F00700069006500730020006F0066002000740068006500
+200046006F006E007400200053006F006600740077006100720065002C00200061006E00
+6400200074006F0020007000650072006D0069007400200070006500720073006F006E00
+7300200074006F002000770068006F006D002000740068006500200046006F006E007400
+200053006F0066007400770061007200650020006900730020006600750072006E006900
+7300680065006400200074006F00200064006F00200073006F002C002000730075006200
+6A00650063007400200074006F002000740068006500200066006F006C006C006F007700
+69006E006700200063006F006E0064006900740069006F006E0073003A000D000A000D00
+0A005400680065002000610062006F0076006500200063006F0070007900720069006700
+68007400200061006E0064002000740072006100640065006D00610072006B0020006E00
+6F0074006900630065007300200061006E00640020007400680069007300200070006500
+72006D0069007300730069006F006E0020006E006F007400690063006500200073006800
+61006C006C00200062006500200069006E0063006C007500640065006400200069006E00
+200061006C006C00200063006F00700069006500730020006F00660020006F006E006500
+20006F00720020006D006F007200650020006F0066002000740068006500200046006F00
+6E007400200053006F006600740077006100720065002000740079007000650066006100
+6300650073002E000D000A000D000A00540068006500200046006F006E00740020005300
+6F0066007400770061007200650020006D006100790020006200650020006D006F006400
+690066006900650064002C00200061006C00740065007200650064002C0020006F007200
+200061006400640065006400200074006F002C00200061006E006400200069006E002000
+70006100720074006900630075006C006100720020007400680065002000640065007300
+690067006E00730020006F006600200067006C00790070006800730020006F0072002000
+6300680061007200610063007400650072007300200069006E0020007400680065002000
+46006F006E007400730020006D006100790020006200650020006D006F00640069006600
+690065006400200061006E00640020006100640064006900740069006F006E0061006C00
+200067006C00790070006800730020006F00720020006300680061007200610063007400
+65007200730020006D006100790020006200650020006100640064006500640020007400
+6F002000740068006500200046006F006E00740073002C0020006F006E006C0079002000
+690066002000740068006500200066006F006E0074007300200061007200650020007200
+65006E0061006D0065006400200074006F0020006E0061006D006500730020006E006F00
+7400200063006F006E007400610069006E0069006E006700200065006900740068006500
+72002000740068006500200077006F007200640073002000220042006900740073007400
+7200650061006D00220020006F0072002000740068006500200077006F00720064002000
+2200560065007200610022002E000D000A000D000A00540068006900730020004C006900
+630065006E007300650020006200650063006F006D006500730020006E0075006C006C00
+200061006E006400200076006F0069006400200074006F00200074006800650020006500
+7800740065006E00740020006100700070006C0069006300610062006C00650020007400
+6F00200046006F006E007400730020006F007200200046006F006E007400200053006F00
+660074007700610072006500200074006800610074002000680061007300200062006500
+65006E0020006D006F00640069006600690065006400200061006E006400200069007300
+200064006900730074007200690062007500740065006400200075006E00640065007200
+200074006800650020002200420069007400730074007200650061006D00200056006500
+72006100220020006E0061006D00650073002E000D000A000D000A005400680065002000
+46006F006E007400200053006F0066007400770061007200650020006D00610079002000
+62006500200073006F006C0064002000610073002000700061007200740020006F006600
+2000610020006C0061007200670065007200200073006F00660074007700610072006500
+20007000610063006B00610067006500200062007500740020006E006F00200063006F00
+7000790020006F00660020006F006E00650020006F00720020006D006F00720065002000
+6F0066002000740068006500200046006F006E007400200053006F006600740077006100
+72006500200074007900700065006600610063006500730020006D006100790020006200
+6500200073006F006C006400200062007900200069007400730065006C0066002E000D00
+0A000D000A00540048004500200046004F004E005400200053004F004600540057004100
+520045002000490053002000500052004F00560049004400450044002000220041005300
+20004900530022002C00200057004900540048004F005500540020005700410052005200
+41004E005400590020004F004600200041004E00590020004B0049004E0044002C002000
+450058005000520045005300530020004F005200200049004D0050004C00490045004400
+2C00200049004E0043004C005500440049004E004700200042005500540020004E004F00
+540020004C0049004D004900540045004400200054004F00200041004E00590020005700
+41005200520041004E00540049004500530020004F00460020004D004500520043004800
+41004E0054004100420049004C004900540059002C0020004600490054004E0045005300
+5300200046004F00520020004100200050004100520054004900430055004C0041005200
+200050005500520050004F0053004500200041004E00440020004E004F004E0049004E00
+4600520049004E00470045004D0045004E00540020004F004600200043004F0050005900
+520049004700480054002C00200050004100540045004E0054002C002000540052004100
+440045004D00410052004B002C0020004F00520020004F00540048004500520020005200
+49004700480054002E00200049004E0020004E004F0020004500560045004E0054002000
+5300480041004C004C002000420049005400530054005200450041004D0020004F005200
+2000540048004500200047004E004F004D004500200046004F0055004E00440041005400
+49004F004E0020004200450020004C004900410042004C004500200046004F0052002000
+41004E005900200043004C00410049004D002C002000440041004D004100470045005300
+20004F00520020004F00540048004500520020004C0049004100420049004C0049005400
+59002C00200049004E0043004C005500440049004E004700200041004E00590020004700
+45004E004500520041004C002C0020005300500045004300490041004C002C0020004900
+4E004400490052004500430054002C00200049004E0043004900440045004E0054004100
+4C002C0020004F005200200043004F004E00530045005100550045004E00540049004100
+4C002000440041004D0041004700450053002C0020005700480045005400480045005200
+200049004E00200041004E00200041004300540049004F004E0020004F00460020004300
+4F004E00540052004100430054002C00200054004F005200540020004F00520020004F00
+540048004500520057004900530045002C002000410052004900530049004E0047002000
+460052004F004D002C0020004F005500540020004F004600200054004800450020005500
+5300450020004F005200200049004E004100420049004C00490054005900200054004F00
+20005500530045002000540048004500200046004F004E005400200053004F0046005400
+570041005200450020004F0052002000460052004F004D0020004F005400480045005200
+20004400450041004C0049004E0047005300200049004E00200054004800450020004600
+4F004E005400200053004F004600540057004100520045002E000D000A000D000A004500
+78006300650070007400200061007300200063006F006E007400610069006E0065006400
+200069006E002000740068006900730020006E006F0074006900630065002C0020007400
+6800650020006E0061006D006500730020006F006600200047006E006F006D0065002C00
+2000740068006500200047006E006F006D006500200046006F0075006E00640061007400
+69006F006E002C00200061006E0064002000420069007400730074007200650061006D00
+200049006E0063002E002C0020007300680061006C006C0020006E006F00740020006200
+650020007500730065006400200069006E00200061006400760065007200740069007300
+69006E00670020006F00720020006F007400680065007200770069007300650020007400
+6F002000700072006F006D006F007400650020007400680065002000730061006C006500
+2C00200075007300650020006F00720020006F0074006800650072002000640065006100
+6C0069006E0067007300200069006E0020007400680069007300200046006F006E007400
+200053006F00660074007700610072006500200077006900740068006F00750074002000
+7000720069006F00720020007700720069007400740065006E0020006100750074006800
+6F00720069007A006100740069006F006E002000660072006F006D002000740068006500
+200047006E006F006D006500200046006F0075006E0064006100740069006F006E002000
+6F0072002000420069007400730074007200650061006D00200049006E0063002E002C00
+200072006500730070006500630074006900760065006C0079002E00200046006F007200
+20006600750072007400680065007200200069006E0066006F0072006D00610074006900
+6F006E002C00200063006F006E0074006100630074003A00200066006F006E0074007300
+200061007400200067006E006F006D006500200064006F00740020006F00720067002E00
+68007400740070003A002F002F007700770077002E006200690074007300740072006500
+61006D002E0063006F006D00013500B800CB00CB00C100AA009C01A600B8006600000071
+00CB00A002B20085007500B800C301CB0189022D00CB00A600F000D300AA008700CB03AA
+0400014A003300CB000000D9050200F4015400B4009C01390114013907060400044E04B4
+045204B804E704CD0037047304CD04600473013303A2055605A60556053903C5021200C9
+001F00B801DF007300BA03E9033303BC0444040E00DF03CD03AA00E503AA0404000000CB
+008F00A4007B00B80014016F007F027B0252008F00C705CD009A009A006F00CB00CD019E
+01D300F000BA018300D5009803040248009E01D500C100CB00F600830354027F00000333
+026600D300C700A400CD008F009A0073040005D5010A00FE022B00A400B4009C00000062
+009C0000001D032D05D505D505D505F0007F007B005400A406B80614072301D300B800CB
+00A601C301EC069300A000D3035C037103DB0185042304A80448008F0139011401390360
+008F05D5019A0614072306660179046004600460047B009C00000277046001AA00E90460
+0762007B00C5007F027B000000B4025205CD006600BC00660077061000CD013B01850389
+008F007B0000001D00CD074A042F009C009C0000077D006F0000006F0335006A006F007B
+00AE00B2002D0396008F027B00F600830354063705F6008F009C04E10266008F018D02F6
+00CD03440029006604EE007300001400B8028040FFFBFE03FA1403F92503F83203F79603
+F60E03F5FE03F4FE03F32503F20E03F19603F02503EF8A4105EFFE03EE9603ED9603ECFA
+03EBFA03EAFE03E93A03E84203E7FE03E63203E5E45305E59603E48A4105E45303E3E22F
+05E3FA03E22F03E1FE03E0FE03DF3203DE1403DD9603DCFE03DB1203DA7D03D9BB03D8FE
+03D68A4105D67D03D5D44705D57D03D44703D3D21B05D3FE03D21B03D1FE03D0FE03CFFE
+03CEFE03CD9603CCCB1E05CCFE03CB1E03CA3203C9FE03C6851105C61C03C51603C4FE03
+C3FE03C2FE03C1FE03C0FE03BFFE03BEFE03BDFE03BCFE03BBFE03BA1103B9862505B9FE
+03B8B7BB05B8FE03B7B65D05B7BB03B78004B6B52505B65D40FF03B64004B52503B4FE03
+B39603B2FE03B1FE03B0FE03AFFE03AE6403AD0E03ACAB2505AC6403ABAA1205AB2503AA
+1203A98A4105A9FA03A8FE03A7FE03A6FE03A51203A4FE03A3A20E05A33203A20E03A164
+03A08A4105A096039FFE039E9D0C059EFE039D0C039C9B19059C64039B9A10059B19039A
+1003990A0398FE0397960D0597FE03960D03958A410595960394930E05942803930E0392
+FA039190BB0591FE03908F5D0590BB039080048F8E25058F5D038F40048E25038DFE038C
+8B2E058CFE038B2E038A8625058A410389880B05891403880B0387862505876403868511
+0586250385110384FE038382110583FE0382110381FE0380FE037FFE0340FF7E7D7D057E
+FE037D7D037C64037B5415057B25037AFE0379FE03780E03770C03760A0375FE0374FA03
+73FA0372FA0371FA0370FE036FFE036EFE036C21036BFE036A1142056A530369FE03687D
+036711420566FE0365FE0364FE0363FE0362FE03613A0360FA035E0C035DFE035BFE035A
+FE0359580A0559FA03580A035716190557320356FE035554150555420354150353011005
+531803521403514A130551FE03500B034FFE034E4D10054EFE034D10034CFE034B4A1305
+4BFE034A4910054A1303491D0D05491003480D0347FE0346960345960344FE0343022D05
+43FA0342BB03414B0340FE033FFE033E3D12053E14033D3C0F053D12033C3B0D053C40FF
+0F033B0D033AFE0339FE033837140538FA033736100537140336350B05361003350B0334
+1E03330D0332310B0532FE03310B03302F0B05300D032F0B032E2D09052E10032D09032C
+32032B2A25052B64032A2912052A25032912032827250528410327250326250B05260F03
+250B0324FE0323FE03220F03210110052112032064031FFA031E1D0D051E64031D0D031C
+1142051CFE031BFA031A42031911420519FE031864031716190517FE0316011005161903
+15FE0314FE0313FE031211420512FE0311022D05114203107D030F64030EFE030D0C1605
+0DFE030C0110050C16030BFE030A100309FE0308022D0508FE0307140306640304011005
+04FE03401503022D0503FE0302011005022D0301100300FE0301B80164858D012B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B002B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B1DB6060504
+030201002C2010B002254964B040515820C859212D2CB002254964B040515820C859212D
+2C20100720B00050B00D7920B8FFFF5058041B0559B0051CB0032508B0042523E120B000
+50B00D7920B8FFFF5058041B0559B0051CB0032508E12D2C4B505820B0FD454459212D2C
+B002254560442D2C4B5358B00225B0022545445921212D2C45442D0000020066FE960466
+05A400030007001A400C04FB0006FB0108057F0204002FC4D4EC310010D4ECD4EC301311
+211125211121660400FC73031BFCE5FE96070EF8F2720629000201350000020005D50003
+00090040400F07008304810208070501030400000A10FC3CEC32393931002FE4FCCC3001
+4BB00B5458BD000A00400001000A000AFFC03811373859B6000B200B500B035D25331523
+1133110323030135CBCBCB14A215FEFE05D5FD71FE9B0165000200C503AA02E905D50003
+0007004D400F05018404008108040506000502040810FCFCDCEC310010F43CEC3230014B
+B012544BB013545B58BD00080040000100080008FFC03811373859400F30094009500960
+097009A009BF09075D0111231121112311016FAA0224AA05D5FDD5022BFDD5022B000002
+009E0000061705BE0003001F006040311B0B008707041D0905190D028717130F15111F1E
+1C1B1A17161514131211100E0D0C090807060504030201001A0A18062010FCCC17393100
+2F3CD43C3CFC3C3CD43C3CC432EC32323040110B010B020B0C0B0D14041A111A12141F08
+015D012103210B0121133303211521032115210323132103231321352113213521130417
+FEDD5401254468012469A0670138FEA152013EFE9B68A067FEDB67A168FEC5016054FEBE
+0169660385FEB20387FE61019FFE619AFEB299FE62019EFE62019E99014E9A019F000003
+00AAFED3046D061400210028002F00D5405522020A0B0A27012628020B0B0A1D011E1C02
+2F292F1B0229292F42131110220A1B29041706092A21050217861606860511231A8A1689
+10002A8A0589022D08160A1E07291A1203000922100903010726080D05063010FC3CECF4
+173CFC173CF4E4EC31002FE4ECC4D4E4EC32C410EE10EE11123911391112173911123930
+4B5358071004ED07100EED11173907100EED111739071004ED5922014BB0095458BD0030
+0040000100300030FFC03811373859014BB00C544BB010545B4BB00F545B58BD0030FFC0
+000100300030004038113738590123032E0127351E0117112E01353436373533151E0117
+152E0127111E011514060703110E0115141617113E0135342602B4640169D26A66D16FDD
+C9DACC645DAE5353AF5CE3D6E3D664747A71E17F817BFED3012D022D2DB440410101C824
+AC96A3BC0EEBE8041F1BAF2A2E04FE5523B49CA9C30F0300019A0D6A585660D5FE4F116E
+5A58680000050071FFE3072905F0000B001700230027003300954036240F252625260F27
+24274200920C1E922E8D18922406920C8D26128C2824913427211B2509030D150E090D0F
+210D2B0E1B0D0F310B3410FCC4ECF4EC10EEF6EE1139111239310010E432F43CE4EC10EE
+F6EE10EE304B5358071005ED071005ED5922014BB009544BB00B545B4BB00C545B4BB014
+545B4BB00E545B4BB00D545B58BD00340040000100340034FFC038113738590122061514
+163332363534262732161514062322263534360122061514163332363534262533012313
+321615140623222635343605D157636357556363559EBABB9DA0BABBFC97566362575763
+640331A0FC5AA01F9EBCBB9F9FB9BA029194848295958283957FDCBBBBDBDBBBBCDB0261
+95828494948481967FF9F3060DDBBBBDDADBBCBADC0000020081FFE305FE05F000090030
+01CD40960D010E0C861112110B860A0B1212110986000915161507010608861616150201
+0301861D1E1D008609001E1E1D201F02211E110A130A17161503181411130A0708020609
+1113130A0201020300110A130A171602181511130A141113130A42120B090306000A1E03
+28150E0628270695182B9527942491188C0E130A2E0B0E09002E1215270E1E032E122721
+0E110F132103121B103110FCECC4D4D4EC10C6EE1139111239391139391139113931002F
+C6E4F6E6EE10EE10C6111239111739111739304B5358071005ED0705ED111739071005ED
+111739071005ED1117390705ED111739071005ED111739071008ED07100EED1117390710
+0EED111739071008ED071008ED07100EED1117395922B20F3201015D40B2070B05220929
+1C001C011F02170B2A002A0126123A003412440B5E0059015A0A55125A1A5A1F5930671E
+7B009B009A0199029708950B931595169522992D1F090B090C08110C270C2818021B0919
+0B190C19111C141C15161D1F3227002701290923122A132A1428152F323B09341239133F
+324A094C144B1546194F3256015A09590C551259135C1F5F326A0C691160327501790C7A
+1193009301970295059C079C089F089A099B0B9A0C9032A032B032395D005D010E011514
+163332363709013E0137330602070123270E01232200353436372E013534363332161715
+2E0123220615141601F25B55D4A05FA649FE7B01FC3B4206BA0C685D0117FC8F68E483F1
+FECE86863032DEB853A555579E4469833B032351A15892C23F40028FFDF859CB7284FEFE
+7EFEE39359570113D780E1633F7D3CA2C52424B62F316F583367000100C503AA016F05D5
+00030042400A0184008104000502040410FCEC310010F4EC30014BB012544BB013545B58
+BD00040040000100040004FFC03811373859400D40055005600570059005A005065D0111
+2311016FAA05D5FDD5022B00000100B0FEF2027B0612000D004F400F069800970E0D0700
+03120600130A0E10DCE432EC113939310010FCEC30014BB0135458BD000E00400001000E
+000EFFC03811373859014BB00F5458BD000EFFC00001000E000E00403811373859010602
+1514121723260235341237027B86828385A0969594970612E6FE3EE7E7FE3BE5EB01C6E0
+DF01C4EC000100A4FEF2026F0612000D001F400F079800970E0701000B12041308000E10
+DC3CF4EC113939310010FCEC301333161215140207233612353402A4A096959596A08583
+830612ECFE3CDFE0FE3AEBE501C5E7E701C20001003D024A03C305F00011004E402C100D
+0B00040C090704020408039905110C990A010E9112080C0A030906110301030200140F04
+0B09140D061210D43CE432DC3CE432173911121739310010F4D43CEC32C4EC3217391217
+393001050507251123110527252537051133112503C3FE9901673AFEB072FEB03A0167FE
+993A015072015004DFC2C362CBFE870179CB62C3C263CB0179FE87CB000100D9000005DB
+0504000B002340110009019C07030502150400170A0615080C10DCFC3CFC3CEC31002FD4
+3CFC3CC43001112115211123112135211103AE022DFDD3A8FDD3022D0504FDD3AAFDD302
+2DAA022D0001009EFF1201C300FE00050019400C039E0083060304011900180610FCECD4
+CC310010FCEC30373315032313F0D3A48152FEACFEC001400001006401DF027F02830003
+0011B6009C020401000410DCCC310010D4EC301321152164021BFDE50283A400000100DB
+000001AE00FE00030011B7008302011900180410FCEC31002FEC3037331523DBD3D3FEFE
+00010000FF4202B205D50003002D4014001A010201021A03000342029F00810402000103
+2FC43939310010F4EC304B5358071005ED071005ED5922013301230208AAFDF8AA05D5F9
+6D0000020087FFE3048F05F0000B00170023401306A01200A00C91128C18091C0F1E031C
+151B1810FCECF4EC310010E4F4EC10EE3001220211101233321211100227320011100023
+2200111000028B9C9D9D9C9D9D9D9DFB0109FEF7FBFBFEF701090550FECDFECCFECDFECD
+0133013301340133A0FE73FE86FE87FE73018D0179017A018D00000100E10000045A05D5
+000A004B40154203A00402A005810700A009081F061C03001F010B10D4ECC4FCEC31002F
+EC32F4ECD4EC304B53585922014BB00F5458BD000BFFC00001000B000B00403811373859
+B40F030F04025D3721110535253311211521FE014AFE990165CA014AFCA4AA047348B848
+FAD5AA00000100960000044A05F0001C00A54027191A1B03181C11050400110505044210
+A111940DA014910400A00200100A02010A1C171003061D10FCC4D4ECC0C011123931002F
+EC32F4ECF4EC304B5358071005ED0705ED1117395922014BB015544BB016545B4BB01454
+5B58BD001D00400001001D001DFFC0381137385940325504560556077A047A05761B8719
+0704000419041A041B051C74007606751A731B741C82008619821A821B821CA800A81B11
+5D005D25211521353600373E0135342623220607353E01333204151406070600018902C1
+FC4C73018D33614DA7865FD3787AD458E80114455B19FEF4AAAAAA7701913A6D97497796
+4243CC3132E8C25CA5701DFEEB000001009CFFE3047305F00028007B402E0015130A8609
+1F862013A0150DA00993061CA020932391068C15A329161C13000314191C2620101C0314
+1F09062910FCC4C4D4ECF4EC11173939310010ECE4F4E4EC10E6EE10EE10EE10EE111239
+30014BB016544BB014545B58BD00290040000100290029FFC038113738594009641E611F
+6120642104005D011E0115140421222627351E013332363534262B013533323635342623
+220607353E01333204151406033F91A3FED0FEE85EC76A54C86DBEC7B9A5AEB6959EA398
+53BE7273C959E6010C8E03251FC490DDF22525C33132968F8495A67770737B2426B42020
+D1B27CAB00020064000004A405D50002000D008C401D010D030D0003030D4200030B07A0
+0501038109010C0A001C0608040C0E10DCD43CC4EC32113931002FE4D43CEC321239304B
+5358071004C9071005C95922014BB00B544BB00D545B58BD000E00400001000E000EFFC0
+3811373859402A0B002A0048005900690077008A000716012B0026012B0336014E014F0C
+4F0D5601660175017A0385010D5D005D09012103331133152311231121350306FE0201FE
+35FED5D5C9FD5E0525FCE303CDFC33A8FEA00160C3000001009EFFE3046405D5001D0075
+4023041A071186101D1AA00714A010890D02A000810D8C07A41E171C010A031C000A1006
+1E10FCC4D4EC10C4EE310010E4E4F4EC10E6EE10FEC410EE11123930014BB016544BB014
+545B58BD001E00400001001E001EFFC03811373859014BB00F5458BD001EFFC00001001E
+001E0040381137385913211521113E0133320015140021222627351E0133323635342623
+220607DD0319FDA02C582CFA0124FED4FEEF5EC3685AC06BADCACAAD51A15405D5AAFE92
+0F0FFEEEEAF1FEF52020CB3130B69C9CB62426000002008FFFE3049605F0000B00240058
+40241306000D860C00A01606A01C16A510A00C8922911C8C250C22091C191E131C03211F
+1B2510FCECECF4ECE4310010E4F4E4FCE410EE10EE10EE111239304014CB00CB01CD02CD
+03CD04CB05CB0607A41EB21E025D015D01220615141633323635342601152E0123220203
+3E0133320015140023200011100021321602A4889F9F88889F9F01094C9B4CC8D30F3BB2
+6BE10105FEF0E2FEFDFEEE0150011B4C9B033BBAA2A1BBBBA1A2BA0279B82426FEF2FEEF
+575DFEEFEBE6FEEA018D0179016201A51E00000100A80000046805D50006006340180511
+02030203110405044205A0008103050301040100060710FCCCC411393931002FF4EC304B
+5358071005ED071005ED5922014BB0165458BD00070040000100070007FFC03811373859
+401258020106031A05390548056703B000B006075D005D13211501230121A803C0FDE2D3
+01FEFD3305D556FA81052B000003008BFFE3048B05F0000B0023002F00434025180C00A0
+2706A01E2DA012911E8C27A330180C242A1C15241C0F091C151B1E031C0F211B3010FCC4
+ECF4C4EC10EE10EE113939310010ECE4F4EC10EE10EE3939300122061514163332363534
+262526263534363332161514060716161514042322243534361314163332363534262322
+06028B90A5A59090A6A5FEA58291FFDEDFFE918192A3FEF7F7F7FEF7A448918382939382
+839102C59A87879A9B86879A5620B280B3D0D0B380B22022C68FD9E8E8D98FC601617482
+82747482820000020081FFE3048705F00018002400584023071F1901860019A00AA504A0
+0089161FA01091168C25071C1C21131E0022221C0D1B2510FCECE4F4ECEC310010E4F4EC
+10E6FEF5EE10EE111239304016C419C21AC01BC01CC01DC21EC41F07AA12BC12E912035D
+015D37351E01333212130E01232200353400332000111000212226013236353426232206
+151416E14C9C4BC8D30F3AB26CE0FEFB0110E201030111FEB1FEE54C9C013E889F9F8888
+9F9F1FB82426010D0112565C010FEBE60116FE73FE86FE9FFE5B1E0297BAA2A1BBBBA1A2
+BA00000200F0000001C3042300030007001C400E068304A60083020501030400180810FC
+3CEC3231002FECF4EC303733152311331523F0D3D3D3D3FEFE0423FE0002009EFF1201C3
+04230003000900254013028300079E048300A60A07080501190400180A10FC3CEC32D4CC
+310010E4FCEC10EE3013331523113315032313F0D3D3D3A481520423FEFDD9ACFEC00140
+000100D9005E05DB04A60006004D402A029C030403019C0001040403019C020105060500
+9C06054205040201000503A806A7070102002404230710FCEC3239310010F4EC1739304B
+53580704ED071008ED071008ED071004ED592209021501350105DBFBF80408FAFE050203
+F0FE91FE93B601D1A601D100000200D9016005DB03A200030007001C400D009C02069C04
+0805010400230810FC3CC432310010D4ECD4EC301321152115211521D90502FAFE0502FA
+FE03A2A8F0AA000100D9005E05DB04A60006004F402B069C0006030403059C040403009C
+010201069C05060202014206050302000504A801A7070602240400230710FC3CEC393100
+10F4EC1739304B5358071008ED071004ED071004ED071008ED592213350115013501D905
+02FAFE040603F0B6FE2FA6FE2FB6016D00020093000003B005F0000300240070402B241E
+0906040A1D13040014861388109517910083021D1A0D0905040A1E010D1C1A041C050103
+00261A132510DCC4FCECD4EC10EE11393911123911123931002FEEF6FEF4EE10CD113939
+173930014BB00C5458BD00250040000100250025FFC03811373859B679097A0A7A20035D
+2533152313233534363F013E0135342623220607353E013332161514060F010E01070E01
+150187CBCBC5BF385A5A3933836C4FB3615EC167B8DF485A582F27080606FEFE01919A65
+825659355E31596E4643BC3938C29F4C8956562F3519153C340000020087FE9C077105A2
+000B004C00954032180C0309A919151B03A94C0F34330FAC30A93715AC24A937434D3334
+1E1A00281206180C281A2B1E2849122B2A28492C3D4D10DCECFCEC10FEFDFE3CC610EE11
+123939310010D4C4FCEC10FEEDD4C610C5EE3210C4EE11393930004BB009544BB00C545B
+4BB010545B4BB013545B4BB014545B58BD004DFFC00001004D004D004038113738594009
+0F4E1F4E2F4E3F4E04015D011416333236353426232206010E0123222635343633321617
+3533113E0135342627262423220607060215141217160433323637170604232224272602
+353412373624333204171E011510000502FA8E7C7B8D907A798F02213C9B67ACD7D8AB67
+9C3B8F92A53F4068FED5B07BE2609DB1736D6901149D81F9685A7DFED998B9FEB8808086
+887E810152BDD4016B7B4B4FFEC2FEE802198FA3A48E8CA5A4FE484D49F9C8C8FA4B4C83
+FD2016DFB16BBC50838B414066FEB5C19FFEEA6A686D57516F6167837D7D0149BDB6014A
+7D7F87AEA062E67BFEF9FED00600000200100000056805D50002000A00BA404100110100
+040504021105050401110A030A0011020003030A0711050406110505040911030A08110A
+030A4200030795010381090509080706040302010009050A0B10D4C4173931002F3CE4D4
+EC1239304B5358071005ED0705ED071005ED0705ED071008ED071005ED071005ED071008
+ED5922B2200C01015D403A0F005800760070008C00050701080206030904160119025601
+5802500C67016802780176027C0372047707780887018802800C980299039604175D005D
+090121013301230321032302BCFEEE0225FE7BE50239D288FD5F88D5050EFD1903AEFA2B
+017FFE81000300C9000004EC05D5000800110020004340231900950A0995128101950AAD
+1F110B080213191F05000E1C1605191C2E09001C12042110FCEC32FCECD4EC1117393939
+31002FECECF4EC10EE3930B20F2201015D01112132363534262301112132363534262325
+213216151406071E01151404232101930144A39D9DA3FEBC012B94919194FE0B0204E7FA
+807C95A5FEF0FBFDE802C9FDDD878B8C850266FE3E6F727170A6C0B189A21420CB98C8DA
+00010073FFE3052705F000190036401A0DA10EAE0A951101A100AE04951791118C1A0719
+0D003014101A10FCEC32EC310010E4F4ECF4EC10EEF6EE30B40F1B1F1B02015D01152E01
+23200011100021323637150E01232000111000213216052766E782FF00FEF00110010082
+E7666AED84FEADFE7A0186015386ED0562D55F5EFEC7FED8FED9FEC75E5FD34848019F01
+670168019F47000200C9000005B005D500080011002E4015009509810195100802100A00
+05190D32001C09041210FCECF4EC113939393931002FECF4EC30B2601301015D01113320
+00111000212521200011100029010193F40135011FFEE1FECBFE42019F01B20196FE68FE
+50FE61052FFB770118012E012C0117A6FE97FE80FE7EFE96000100C90000048B05D5000B
+002E401506950402950081089504AD0A05010907031C00040C10FCEC32D4C4C431002FEC
+ECF4EC10EE30B21F0D01015D132115211121152111211521C903B0FD1A02C7FD3902F8FC
+3E05D5AAFE46AAFDE3AA000100C90000042305D50009002940120695040295008104AD08
+050107031C00040A10FCEC32D4C431002FECF4EC10EE30B20F0B01015D13211521112115
+211123C9035AFD700250FDB0CA05D5AAFE48AAFD370000010073FFE3058B05F0001D0039
+402000051B0195031B950812A111AE15950E91088C1E02001C1134043318190B101E10FC
+ECFCE4FCC4310010E4F4ECF4EC10FED4EE11393930251121352111060423200011100021
+32041715262623200011100021323604C3FEB6021275FEE6A0FEA2FE75018B015E920107
+6F70FC8BFEEEFEED011301126BA8D50191A6FD7F53550199016D016E01994846D75F60FE
+CEFED1FED2FECE25000100C90000053B05D5000B002C4014089502AD0400810A0607031C
+053809011C00040C10FCEC32FCEC3231002F3CE432FCEC30B2500D01015D133311211133
+112311211123C9CA02DECACAFD22CA05D5FD9C0264FA2B02C7FD3900000100C900000193
+05D500030039B700AF02011C00040410FCEC31002FEC30014BB0105458BD0004FFC00001
+0004000400403811373859400D30054005500560058F059F05065D13331123C9CACA05D5
+FA2B0001FF96FE66019305D5000B004D40130B0200079505B000810C05080639011C0004
+0C10FCECE43939310010E4FCEC11393930014BB0105458BD000CFFC00001000C000C0040
+3811373859400D300D400D500D600D8F0D9F0D065D13331110062B013533323635C9CACD
+E34D3F866E05D5FA93FEF2F4AA96C200000100C90000056A05D5000A00EF402808110506
+0507110606050311040504021105050442080502030300AF09060501040608011C00040B
+10FCEC32D4C4113931002F3CEC321739304B5358071004ED071005ED071005ED071004ED
+5922B2080301015D40921402010402090816022805280837023605340847024605430855
+02670276027705830288058F0894029B08E702150603090509061B031907050A030A0718
+0328052B062A073604360536063507300C41034004450540064007400C62036004680567
+077705700C8B038B058E068F078F0C9A039D069D07B603B507C503C507D703D607E803E9
+04E805EA06F703F805F9062C5D71005D711333110121090121011123C9CA029E0104FD1B
+031AFEF6FD33CA05D5FD890277FD48FCE302CFFD3100000100C90000046A05D500050025
+400C0295008104011C033A00040610FCECEC31002FE4EC30400930075007800380040401
+5D133311211521C9CA02D7FC5F05D5FAD5AA000100C90000061F05D5000C00BF40340311
+0708070211010208080702110302090A0901110A0A09420A070203080300AF080B050908
+030201050A061C043E0A1C00040D10FCECFCEC11173931002F3CC4EC32111739304B5358
+071005ED071008ED071008ED071005ED5922B2700E01015D405603070F080F09020A1502
+1407130A260226072007260A200A3407350A69027C027B07790A80028207820A90021604
+010B0313011B0323012C032708280934013C035608590965086A097608790981018D0395
+019B03145D005D13210901211123110123011123C9012D017D017F012DC5FE7FCBFE7FC4
+05D5FC0803F8FA2B051FFC000400FAE1000100C90000053305D500090079401E07110102
+0102110607064207020300AF0805060107021C0436071C00040A10FCECFCEC1139393100
+2F3CEC323939304B5358071004ED071004ED5922B21F0B01015D40303602380748024707
+690266078002070601090615011A06460149065701580665016906790685018A0695019A
+069F0B105D005D13210111331121011123C901100296C4FEF0FD6AC405D5FB1F04E1FA2B
+04E1FB1F00020073FFE305D905F0000B00170023401306951200950C91128C1809190F33
+031915101810FCECFCEC310010E4F4EC10EE300122001110003332001110002720001110
+002120001110000327DCFEFD0103DCDC0101FEFFDC013A0178FE88FEC6FEC5FE87017905
+4CFEB8FEE5FEE6FEB80148011A011B0148A4FE5BFE9EFE9FFE5B01A40162016201A50002
+00C90000048D05D500080013003A40180195100095098112100A0802040005190D3F1100
+1C09041410FCEC32FCEC11173931002FF4ECD4EC30400B0F151F153F155F15AF1505015D
+011133323635342623252132041514042B0111230193FE8D9A9A8DFE3801C8FB0101FEFF
+FBFECA052FFDCF92878692A6E3DBDDE2FDA800020073FEF805D905F0000B001D0052402A
+1110020F010C0D0C0E010D0D0C420F1E0C06951200951891128C0D1E0D1B0F0C0309191B
+33031915101E10FCECFCEC1139391139310010C4E4F4EC10EE391239304B5358071005ED
+071005ED1739592201220011100033320011100013012327060623200011100021200011
+10020327DCFEFD0103DCDC0101FEFF3F010AF4DD212310FEC5FE870179013B013A0178D1
+054CFEB8FEE5FEE6FEB80148011A011B0148FACFFEDDEF020201A50161016201A5FE5BFE
+9EFEFCFE8E00000200C90000055405D50013001C00B14035090807030A06110304030511
+0404034206040015030415950914950D810B040506031109001C160E050A191904113F14
+0A1C0C041D10FCEC32FCC4EC1117391139393931002F3CF4ECD4EC123912391239304B53
+58071005ED071005ED1117395922B2401E01015D40427A13010500050105020603070415
+00150114021603170425002501250226032706260726082609201E360136024601460268
+0575047505771388068807980698071F5D005D011E01171323032E012B01112311212016
+151406011133323635342623038D417B3ECDD9BF4A8B78DCCA01C80100FC83FD89FE9295
+959202BC16907EFE68017F9662FD8905D5D6D88DBA024FFDEE878383850000010087FFE3
+04A205F00027007E403C0D0C020E0B021E1F1E080902070A021F1F1E420A0B1E1F041501
+0015A11494189511049500942591118C281E0A0B1F1B0700221B190E2D071914222810DC
+C4ECFCECE4111239393939310010E4F4E4EC10EEF6EE10C6111739304B535807100EED11
+173907100EED1117395922B20F2901015DB61F292F294F29035D01152E01232206151416
+1F011E0115140421222627351E013332363534262F012E01353424333216044873CC5FA5
+B377A67AE2D7FEDDFEE76AEF807BEC72ADBC879A7BE2CA0117F569DA05A4C53736807663
+651F192BD9B6D9E0302FD04546887E6E7C1F182DC0ABC6E426000001FFFA000004E905D5
+0007004A400E0602950081040140031C0040050810D4E4FCE431002FF4EC3230014BB00A
+5458BD00080040000100080008FFC03811373859401300091F00100110021F0710094009
+70099F09095D03211521112311210604EFFDEECBFDEE05D5AAFAD5052B00000100B2FFE3
+052905D50011004B40160802110B0005950E8C09008112081C0A38011C00411210FCECFC
+EC310010E432F4EC113939393930014BB0105458BD00120040000100120012FFC0381137
+3859B61F138F139F13035D133311141633323635113311100021200011B2CBAEC3C2AECB
+FEDFFEE6FEE5FEDF05D5FC75F0D3D3F0038BFC5CFEDCFED6012A01240001001000000568
+05D5000600B7402704110506050311020306060503110403000100021101010042030401
+AF0006040302000505010710D4C4173931002FEC3239304B5358071005ED071008ED0710
+08ED071005ED5922B2500801015D406200032A03470447055A037D038303070600070208
+040906150114021A041A052A002601260229042905250620083800330133023C043C0537
+06480045014502490449054706590056066602690469057A007601760279047905750680
+0898009706295D005D21013309013301024AFDC6D301D901DAD2FDC705D5FB1704E9FA2B
+00010044000007A605D5000C017B4049051A0605090A09041A0A09031A0A0B0A021A0102
+0B0B0A061107080705110405080807021103020C000C011100000C420A050203060300AF
+0B080C0B0A09080605040302010B07000D10D4CC173931002F3CEC32321739304B535807
+1005ED071008ED071008ED071005ED071008ED071005ED0705ED071008ED5922B2000E01
+015D40F206020605020A000A000A120A2805240A200A3E023E05340A300A4C024D05420A
+400A59026A026B05670A600A7B027F027C057F05800A960295051D070009020803000406
+050005000601070408000807090009040A0A0C000E1A0315041508190C100E2004210520
+06200720082309240A250B200E200E3C023A033504330530083609390B3F0C300E460046
+014A0240044505400542064207420840084009440A4D0C400E400E58025608590C500E66
+026703610462056006600760086409640A640B770076017B027803770474057906790777
+087008780C7F0C7F0E860287038804890585098A0B8F0E97049F0EAF0E5B5D005D133309
+0133090133012309012344CC013A0139E3013A0139CDFE89FEFEC5FEC2FE05D5FB1204EE
+FB1204EEFA2B0510FAF00001003D0000053B05D5000B015D404609110A0B0A081107080B
+0B0A081109080506050711060605031104050402110102050504021103020B000B011100
+000B420B080502040300AF09060B08050204000406000A0C10D4C4DCC411173931002F3C
+EC321739304B5358071005ED071008ED071008ED071005ED071005ED071008ED071008ED
+071005ED5922014BB00C544BB00D545B4BB00E545B58BD000CFFC00001000C000C004038
+1137385940B80702080816021908170B2708270B34023808360B4B0858055B0866026B08
+7702770B8602800287058B08850B9402900297059D08960B1B0601090308070709160119
+0319071709100D260128022903260528072709290B200D350034013C033B043A063B0734
+09340A380B3F0D48094F0D580B5F0D650065016A036A046805690669076C096C0A780379
+06790778087D097F0A780B800080018302880385058408830B8F0D900090019402970597
+069508930B9F0DAF0D405D005D13330901330901230901230181D901730175D9FE200200
+D9FE5CFE59DA021505D5FDD5022BFD33FCF8027BFD85031D0001FFFC000004E705D50008
+0094402803110405040211010205050402110302080008011100000842020300AF060207
+0440051C0040070910D4E4FCE4123931002FEC3239304B5358071005ED071008ED071008
+ED071005ED5922B2000A01015D403C050214023502300230053008460240024005400851
+02510551086502840293021016011A031F0A2601290337013803400A670168037803700A
+9F0A0D5D005D03330901330111231104D9019E019BD9FDF0CB05D5FD9A0266FCF2FD3902
+C7000001005C0000051F05D50009009B401B031107080708110203024208950081039505
+08030001420400060A10DCC4D4E411393931002FECF4EC304B5358071005ED071005ED59
+22014BB009544BB00A545B58BD000A00400001000A000AFFC03811373859404005020A07
+18072902260738074802470748080905030B08000B16031A08100B2F0B350339083F0B47
+034A084F0B55035908660369086F0B770378087F0B9F0B165D005D132115012115213501
+21730495FC5003C7FB3D03B0FC6705D59AFB6FAA9A049100000100B0FEF2025806140007
+0053400F04A906B202A900B10805010343000810DCFCCC32310010FCECF4EC30014BB00C
+5458BD0008FFC000010008000800403811373859014BB012544BB013545B58BD00080040
+000100080008FFC038113738591321152311331521B001A8F0F0FE5806148FF9FC8F0001
+0000FF4202B205D50003002D4014021A010100001A03030242019F008104020001032FC4
+3939310010F4EC304B5358071005ED071005ED592213012301AA0208AAFDF805D5F96D06
+9300000100C7FEF2026F06140007003C401003A901B205A900B1080043040602040810FC
+3CDCEC310010FCECF4EC30014BB00F544BB010545B58BD0008FFC0000100080008004038
+113738590111213533112335026FFE58EFEF0614F8DE8F06048F000100D903A805DB05D5
+00060018400A0304010081070301050710DCCC39310010F4CC3239300101230101230103
+BC021FC9FE48FE48C9021F05D5FDD3018BFE75022D000001FFECFE1D0414FEAC0003000F
+B500A90100020410C4C43100D4EC30011521350414FBD8FEAC8F8F00000100AA04F00289
+066600030031400901B400B3040344010410DCEC310010F4EC30004BB009544BB00E545B
+58BD0004FFC00001000400040040381137385909012301016F011A99FEBA0666FE8A0176
+0002007BFFE3042D047B000A002500BC4027191F0B17090E00A91706B90E1120861FBA1C
+B923B8118C170C001703180D09080B1F030814452610FCECCCD4EC323211393931002FC4
+E4F4FCF4EC10C6EE10EE11391139123930406E301D301E301F3020302130223F27401D40
+1E401F402040214022501D501E501F50205021502250277027851D871E871F8720872185
+229027A027F0271E301E301F30203021401E401F40204021501E501F50205021601E601F
+60206021701E701F70207021801E801F80208021185D015D0122061514163332363D0137
+1123350E01232226353436332135342623220607353E0133321602BEDFAC816F99B9B8B8
+3FBC88ACCBFDFB0102A79760B65465BE5AF3F00233667B6273D9B4294CFD81AA6661C1A2
+BDC0127F8B2E2EAA2727FC00000200BAFFE304A40614000B001C0038401903B90C0F09B9
+18158C0FB81B971900121247180C06081A461D10FCEC3232F4EC31002FECE4F4C4EC10C6
+EE30B6601E801EA01E03015D013426232206151416333236013E01333212111002232226
+271523113303E5A79292A7A79292A7FD8E3AB17BCCFFFFCC7BB13AB9B9022FCBE7E7CBCB
+E7E702526461FEBCFEF8FEF8FEBC6164A806140000010071FFE303E7047B0019003F401B
+00860188040E860D880AB91104B917B8118C1A07120D004814451A10FCE432EC310010E4
+F4EC10FEF4EE10F5EE30400B0F1B101B801B901BA01B05015D01152E0123220615141633
+323637150E0123220011100021321603E74E9D50B3C6C6B3509D4E4DA55DFDFED6012D01
+0655A20435AC2B2BE3CDCDE32B2BAA2424013E010E0112013A2300020071FFE3045A0614
+0010001C003840191AB9000E14B905088C0EB801970317040008024711120B451D10FCEC
+F4EC323231002FECE4F4C4EC10C4EE30B6601E801EA01E03015D0111331123350E012322
+0211101233321601141633323635342623220603A2B8B83AB17CCBFFFFCB7CB1FDC7A792
+92A8A89292A703B6025EF9ECA86461014401080108014461FE15CBE7E7CBCBE7E7000002
+0071FFE3047F047B0014001B00704024001501098608880515A90105B90C01BB18B912B8
+0C8C1C1B1502081508004B02120F451C10FCECF4ECC4111239310010E4F4ECE410EE10EE
+10F4EE1112393040293F1D701DA01DD01DF01D053F003F013F023F153F1B052C072F082F
+092C0A6F006F016F026F156F1B095D71015D0115211E0133323637150E01232000111000
+333200072E0123220607047FFCB20CCDB76AC76263D06BFEF4FEC70129FCE20107B802A5
+889AB90E025E5ABEC73434AE2A2C0138010A01130143FEDDC497B4AE9E000001002F0000
+02F8061400130070401C0510010C08A906018700970E06BC0A02130700070905080D0F0B
+4C1410FC3CC4FC3CC4C412393931002FE432FCEC10EE3212393930014BB00A5458BD0014
+FFC000010014001400403811373859014BB00E5458BD00140040000100140014FFC03811
+373859B640155015A015035D01152322061D012115211123112335333534363302F8B063
+4D012FFED1B9B0B0AEBD0614995068638FFC2F03D18F4EBBAB0000020071FE56045A047B
+000B0028004A4023190C1D0912861316B90F03B92623B827BC09B90FBD1A1D261900080C
+4706121220452910FCC4ECF4EC323231002FC4E4ECE4F4C4EC10FED5EE1112393930B660
+2A802AA02A03015D01342623220615141633323617100221222627351E013332363D010E
+0123220211101233321617353303A2A59594A5A59495A5B8FEFEFA61AC51519E52B5B439
+B27CCEFCFCCE7CB239B8023DC8DCDCC8C7DCDCEBFEE2FEE91D1EB32C2ABDBF5B6362013A
+01030104013A6263AA00000100BA000004640614001300344019030900030E0106870E11
+B80C970A010208004E0D09080B461410FCEC32F4EC31002F3CECF4C4EC1112173930B260
+1501015D0111231134262322061511231133113E013332160464B87C7C95ACB9B942B375
+C1C602A4FD5C029E9F9EBEA4FD870614FD9E6564EF00000200C100000179061400030007
+002B400E06BE04B100BC020501080400460810FC3CEC3231002FE4FCEC30400B10094009
+50096009700905015D1333112311331523C1B8B8B8B80460FBA00614E9000002FFDBFE56
+01790614000B000F0044401C0B0207000EBE0C078705BD00BC0CB110081005064F0D0108
+0C00461010FC3CEC32E4391239310010ECE4F4EC10EE1112393930400B10114011501160
+11701105015D13331114062B01353332363511331523C1B8A3B54631694CB8B80460FB8C
+D6C09C61990628E9000100BA0000049C0614000A00BC4029081105060507110606050311
+0405040211050504420805020303BC009709060501040608010800460B10FCEC32D4C411
+3931002F3CECE41739304B5358071004ED071005ED071005ED071004ED5922B2100C0101
+5D405F04020A081602270229052B0856026602670873027705820289058E089302960597
+08A3021209050906020B030A072803270428052B062B07400C6803600C8903850489058D
+068F079A039707AA03A705B607C507D607F703F003F704F0041A5D71005D133311013309
+0123011123BAB90225EBFDAE026BF0FDC7B90614FC6901E3FDF4FDAC0223FDDD000100C1
+00000179061400030022B7009702010800460410FCEC31002FEC30400D10054005500560
+057005F00506015D13331123C1B8B80614F9EC00000100BA0000071D047B0022005A4026
+061209180F00061D07150C871D2003B81BBC19100700110F0808065011080F501C18081A
+462310FCEC32FCFCFCEC11123931002F3C3CE4F43CC4EC32111217393040133024502470
+249024A024A024BF24DF24FF2409015D013E013332161511231134262322061511231134
+262322061511231133153E01333216042945C082AFBEB972758FA6B972778DA6B9B93FB0
+797AAB03897C76F5E2FD5C029EA19CBEA4FD87029EA29BBFA3FD870460AE67627C000001
+00BA00000464047B001300364019030900030E0106870E11B80CBC0A010208004E0D0908
+0B461410FCEC32F4EC31002F3CE4F4C4EC1112173930B46015CF1502015D011123113426
+2322061511231133153E013332160464B87C7C95ACB9B942B375C1C602A4FD5C029E9F9E
+BEA4FD870460AE6564EF00020071FFE30475047B000B0017004A401306B91200B90CB812
+8C1809120F51031215451810FCECF4EC310010E4F4EC10EE3040233F197B007B067F077F
+087F097F0A7F0B7B0C7F0D7F0E7F0F7F107F117B12A019F01911015D0122061514163332
+36353426273200111000232200111000027394ACAB9593ACAC93F00112FEEEF0F1FEEF01
+1103DFE7C9C9E7E8C8C7E99CFEC8FEECFEEDFEC70139011301140138000200BAFE5604A4
+047B0010001C003E401B1AB9000E14B90508B80E8C01BD03BC1D11120B47170400080246
+1D10FCEC3232F4EC310010E4E4E4F4C4EC10C4EE304009601E801EA01EE01E04015D2511
+231133153E013332121110022322260134262322061514163332360173B9B93AB17BCCFF
+FFCC7BB10238A79292A7A79292A7A8FDAE060AAA6461FEBCFEF8FEF8FEBC6101EBCBE7E7
+CBCBE7E700020071FE56045A047B000B001C003E401B03B90C0F09B91815B80F8C1BBD19
+BC1D180C06081A47001212451D10FCECF4EC3232310010E4E4E4F4C4EC10C6EE30400960
+1E801EA01EE01E04015D011416333236353426232206010E012322021110123332161735
+331123012FA79292A8A89292A702733AB17CCBFFFFCB7CB13AB8B8022FCBE7E7CBCBE7E7
+FDAE646101440108010801446164AAF9F600000100BA0000034A047B001100304014060B
+0700110B03870EB809BC070A06080008461210FCC4EC3231002FE4F4ECC4D4CC11123930
+B450139F1302015D012E012322061511231133153E0133321617034A1F492C9CA7B9B93A
+BA85132E1C03B41211CBBEFDB20460AE666305050001006FFFE303C7047B002700E7403C
+0D0C020E0B531F1E080902070A531E1F1E420A0B1E1F041500860189041486158918B911
+04B925B8118C281E0A0B1F1B0700521B080E07081422452810FCC4ECD4ECE41112393939
+39310010E4F4EC10FEF5EE10F5EE121739304B535807100EED111739070EED1117395922
+B2002701015D406D1C0A1C0B1C0C2E092C0A2C0B2C0C3B093B0A3B0B3B0C0B2000200124
+02280A280B2A132F142F152A16281E281F292029212427860A860B860C860D1200000001
+0202060A060B030C030D030E030F03100319031A031B031C041D09272F293F295F297F29
+80299029A029F029185D005D7101152E012322061514161F011E0115140623222627351E
+013332363534262F012E01353436333216038B4EA85A898962943FC4A5F7D85AC36C66C6
+61828C65AB40AB98E0CE66B4043FAE282854544049210E2A99899CB62323BE353559514B
+50250F2495829EAC1E0000010037000002F2059E0013003840190E05080F03A9001101BC
+08870A0B08090204000810120E461410FC3CC4FC3CC432393931002FECF43CC4EC321139
+3930B2AF1501015D01112115211114163B01152322263511233533110177017BFE854B73
+BDBDD5A28787059EFEC28FFDA0894E9A9FD202608F013E00000100AEFFE3045804600013
+00364019030900030E0106870E118C0A01BC0C0D09080B4E020800461410FCECF4EC3231
+002FE432F4C4EC1112173930B46015CF1502015D1311331114163332363511331123350E
+01232226AEB87C7C95ADB8B843B175C1C801BA02A6FD619F9FBEA4027BFBA0AC6663F000
+0001003D0000047F04600006011240270311040504021101020505040211030206000601
+1100000642020300BF0506050302010504000710D4C4173931002FEC3239304B53580710
+05ED071008ED071008ED071005ED5922014BB00A5458BD0007FFC0000100070007004038
+11373859014BB014544BB015545B58BD00070040000100070007FFC03811373859408E48
+026A027B027F02860280029102A402080600060109030904150015011A031A0426002601
+290329042008350035013A033A0430084600460149034904460548064008560056015903
+590450086600660169036904670568066008750074017B037B0475057A06850085018903
+8904890586069600960197029A03980498059706A805A706B008C008DF08FF083E5D005D
+133309013301233DC3015E015EC3FE5CFA0460FC5403ACFBA00000010056000006350460
+000C0201404905550605090A0904550A0903550A0B0A025501020B0B0A06110708070511
+0405080807021103020C000C011100000C420A050203060300BF0B080C0B0A0908060504
+0302010B07000D10D4CC173931002F3CEC32321739304B5358071005ED071008ED071008
+ED071005ED071008ED071005ED0705ED071008ED5922014BB00A544BB011545B4BB01254
+5B4BB013545B4BB00B545B58BD000DFFC00001000D000D00403811373859014BB00C544B
+B00D545B4BB010545B58BD000D00400001000D000DFFC0381137385940FF050216021605
+220A350A49024905460A400A5B025B05550A500A6E026E05660A79027F0279057F058702
+99029805940ABC02BC05CE02C703CF051D0502090306040B050A080B09040B050C150219
+0316041A051B081B09140B150C2500250123022703210425052206220725082709240A21
+0B230C390336043608390C300E460248034604400442054006400740084409440A440B40
+0E400E560056015602500451055206520750085309540A550B6300640165026A0365046A
+056A066A076E09610B670C6F0E7500750179027D0378047D057A067F067A077F07780879
+097F097B0A760B7D0C870288058F0E97009701940293039C049B05980698079908402F96
+0C9F0EA600A601A402A403AB04AB05A906A907AB08A40CAF0EB502B103BD04BB05B809BF
+0EC402C303CC04CA05795D005D13331B01331B013301230B012356B8E6E5D9E6E5B8FEDB
+D9F1F2D90460FC96036AFC96036AFBA00396FC6A0001003B000004790460000B015A4046
+0511060706041103040707060411050401020103110202010B110001000A11090A010100
+0A110B0A0708070911080807420A070401040800BF05020A0704010408000208060C10D4
+C4D4C411173931002F3CEC321739304B5358071005ED071008ED071008ED071005ED0710
+05ED071008ED071008ED071005ED5922014BB00A544BB00F545B4BB010545B4BB011545B
+58BD000CFFC00001000C000C00403811373859014BB0145458BD000C00400001000C000C
+FFC0381137385940980A04040A1A04150A260A3D04310A55045707580A660A76017A0476
+07740A8D04820A99049F049707920A900AA601A904AF04A507A30AA00A1C0A0304050509
+0A0B1A03150515091A0B2903260525092A0B200D3A013903370534073609390B300D4903
+460545094A0B400D590056015902590357055606590756085609590B500D6F0D78017F0D
+9B019407AB01A407B00DCF0DDF0DFF0D2F5D005D09022309012309013309010464FE6B01
+AAD9FEBAFEBAD901B3FE72D9012901290460FDDFFDC101B8FE48024A0216FE71018F0001
+003DFE56047F0460000F01A240430708020911000F0A110B0A00000F0E110F000F0D110C
+0D00000F0D110E0D0A0B0A0C110B0B0A420D0B0910000B058703BD0E0BBC100E0D0C0A09
+060300080F040F0B1010D4C4C4111739310010E432F4EC113911391239304B5358071005
+ED071008ED071008ED071005ED071008ED0705ED17325922014BB00A544BB008545B58BD
+0010FFC000010010001000403811373859014BB0145458BD00100040000100100010FFC0
+381137385940F0060005080609030D160A170D100D230D350D490A4F0A4E0D5A095A0A6A
+0A870D800D930D120A000A09060B050C0B0E0B0F1701150210041005170A140B140C1A0E
+1A0F2700240124022004200529082809250A240B240C270D2A0E2A0F2011370035013502
+30043005380A360B360C380D390E390F3011410040014002400340044005400640074008
+4209450A470D490E490F40115400510151025503500450055606550756085709570A550B
+550C590E590F501166016602680A690E690F60117B08780E780F89008A09850B850C890D
+890E890F9909950B950C9A0E9A0FA40BA40CAB0EAB0FB011CF11DF11FF11655D005D050E
+012B01353332363F01013309013302934E947C936C4C543321FE3BC3015E015EC368C87A
+9A488654044EFC94036C00010058000003DB0460000900B4401A08110203020311070807
+4208A900BC03A905080301000401060A10DCC432C411393931002FECF4EC304B53580710
+05ED071005ED5922014BB00B544BB00C545B58BD000A00400001000A000AFFC038113738
+59014BB0135458BD000AFFC00001000A000A004038113738594042050216022602470249
+07050B080F0B18031B082B08200B36033908300B40014002450340044005430857035908
+5F0B6001600266036004600562087F0B800BAF0B1B5D005D132115012115213501217103
+6AFD4C02B4FC7D02B4FD650460A8FCDB93A8032500010100FEB204170614002400824034
+190F150B0625091A10151D0B05202103000BA90900A901C00915A913B1250C090A052416
+19001D0A05130214002019430A0F052510D43CC4FC3CC432393911123911123939111239
+39310010FCECC4F4EC10EE12173912391139391112391112393930014BB00C5458BD0025
+FFC000010025002500403811373859B20026015D05152322263D0134262B01353332363D
+0134363B01152322061D011406071E011D0114163304173EF9A96C8E3D3D8F6BA9F93E44
+8D565B6E6F5A568DBE9094DDEF97748F7395F0DD938F588DF89D8E191B8E9CF88D580001
+0104FE1D01AE061D00030012B70100B1040005020410D4EC310010FCCC300111231101AE
+AA061DF80008000000010100FEB2041706140024009E40361F251B160C0F081B0B15190F
+040520030019A91B00A923C01B0FA911B1251C191A150F010400081A15231204001A1F15
+4310000B042510D43CC432FC3CC4111239391112391112393911123939310010FCECC4F4
+EC10EE12173911123939113911393911123930014BB00A5458BD00250040000100250025
+FFC03811373859014BB00E5458BD0025FFC000010025002500403811373859B20026015D
+053332363D013436372E013D0134262B01353332161D0114163B01152322061D0114062B
+010100468C555A6F6F5A558C463FF9A76C8E3E3E8E6CA7F93FBE568FF89C8E1B198E9DF8
+8E578F93DDF095738F7497EFDD94000100D901D305DB0331001D0023401001101B0C0013
+049C1B139C0C1E000F1E10D4C4310010D4FCD4EC10C01112393930011506062322272627
+26272623220607353636333217161716171633323605DB69B3616E920B05070F9B5E58AC
+6269B3616E930A05080E9B5E56A90331B24F443B040203053E4D53B24F453C040203053E
+4C00FFFF001000000568074E02270024000000000007010300BC01750003001000000568
+076D000B000E002100CB40540C110D0C1B1C1B0E111C1B1E111C1B1D111C1C1B0D11210F
+210C110E0C0F0F2120110F211F11210F21420C1B0F0D0903C115091E950D098E201C1E1D
+1C18201F210D12060E180C061B0056181C0F0656121C212210D4C4D4EC3210D4EE321139
+11391112391139391112393931002F3CE6D6EE10D4EE1112393939304B5358071005ED07
+05ED071008ED071005ED071005ED0705ED0705ED071008ED5922B2202301015D40201A0C
+730C9B0C03070F081B5023660D690E750D7B0E791C791D7620762180230C5D005D013426
+232206151416333236030121012E01353436333216151406070123032103230354593F40
+57583F3F5998FEF00221FE583D3E9F7372A13F3C0214D288FD5F88D5065A3F5957413F58
+58FEF3FD19034E29734973A0A172467629FA8B017FFE8100FFFF0073FE75052705F00227
+002600000000000700DD012D0000FFFF00C90000048B076B022700280000000000070104
+009E0175FFFF00C900000533075E02270031000000000007010500FE0175FFFF0073FFE3
+05D9074E02270032000000000007010301270175FFFF00B2FFE30529074E022700380000
+00000007010300EE0175FFFF007BFFE3042D066602270044000000000007008D00520000
+FFFF007BFFE3042D066602270044000000000007004300520000FFFF007BFFE3042D0666
+0227004400000000000700D700520000FFFF007BFFE3042D061002270044000000000007
+008E00520000FFFF007BFFE3042D06370227004400000000000700D800520000FFFF007B
+FFE3042D07060227004400000000000700DC00520000FFFF0071FE7503E7047B02270046
+00000000000700DD008F0000FFFF0071FFE3047F066602270048000000000007008D008B
+0000FFFF0071FFE3047F0666022700480000000000070043008B0000FFFF0071FFE3047F
+06660227004800000000000700D7008B0000FFFF0071FFE3047F06100227004800000000
+0007008E008B0000FFFF00900000026F0666022700D6000000000007008DFF1D0000FFFF
+FFC7000001A60666022700D60000000000070043FF1D0000FFFFFFDE0000025C06660227
+00D600000000000700D7FF1D0000FFFFFFF4000002460610022700D6000000000007008E
+FF1D0000FFFF00BA0000046406370227005100000000000700D800980000FFFF0071FFE3
+0475066602270052000000000007008D00730000FFFF0071FFE304750666022700520000
+00000007004300730000FFFF0071FFE3047506660227005200000000000700D700730000
+FFFF0071FFE30475061002270052000000000007008E00730000FFFF0071FFE304750637
+0227005200000000000700D800730000FFFF00AEFFE30458066602270058000000000007
+008D007B0000FFFF00AEFFE304580666022700580000000000070043007B0000FFFF00AE
+FFE3045806660227005800000000000700D7007B0000FFFF00AEFFE30458061002270058
+000000000007008E007B000000010039FF3B03C705D5000B002740140804B90A02008106
+C20C0359050157095907000C10D43CECFC3CEC310010E4F4D43CEC323001331121152111
+231121352101A8B0016FFE91B0FE91016F05D5FE5C99FBA3045D9900000200C30375033D
+05F0000B001A0020401106C315C400C30C911B095A125B035A181B10DCECFCEC310010F4
+ECFCEC300122061514163332363534262732161716161514062322263534360200506E6E
+50506E6F4F40762B2E2EB98687B4B8056F6F504F6D6D4F4F7081312E2D724284B7B48786
+BA00000200ACFEC704230598000600210051402B131614000F0C010B078608880B10860F
+880CB914160BB91D1F1CB8168C221C1500091E130B0F070412192210DCECD43CD43C3CEC
+3232310010E4F43CC4EC10C4FEF4EE10F5EE123911123911123930251106061514160115
+2626270336363715060607112311260011100037113313161602A693A4A402104A884401
+46894841894D66F1FEF70109F16601498983035812E2B8B9E203A1AC292A03FCA0052A27
+AA1E2307FEE4012014013301010102013216011FFEE10421000100810000046205F0001B
+00604021071608018600120AA914080C04A000941991100CA00E000D090B071C130F1511
+1C10DC3CCCCCFC3CC4D4C431002FEC32F4E4EC10D43CEE3210EE11393930014BB00C5458
+BD001CFFC00001001C001C00403811373859B43601360202005D01152E012322061D0121
+152111211521353311233533351036333216044E4C883D94740187FE79022DFC1FECC7C7
+D6E83D9705B4B629299BD4D78FFE2FAAAA01D18FEE0105F31F000002005CFF3D03A205F0
+000B003E0091403C2F302A0600171D3036040D278A260D8A0C2AC626C52310C60CC53C91
+233F2F0600173004131D2D0936031357392D572009570C221A3926220357333F10DCECE4
+C4D4E4ECD4EC10EE113911123911173939310010C4F4E4EC10E6EE10EE10EE1117393939
+11123930014BB00A544BB00B545B4BB00C545B4BB00E545B58BD003F00400001003F003F
+FFC03811373859010E01151416173E0135342613152E0123220615141716171E01151406
+071E0115140623222627351E0133323635342F012E01353436372E01353436333216017B
+3F3E8BFA3F3E8FCC538F38616CCE1A0ED3835C5D3E39CCAD499A5857943A6671DD19D680
+5D5B3B3BC8A6499903A82E5A2E4C85872D5B2E4B880293A4272750475A730F08779A655A
+8C35346D408EA81D1DA42727544C667B0E7899665B8F312C7045829F1D000001013301D1
+03850421000B0012B709C7030C065C000C10D4EC310010D4EC3001343633321615140623
+22260133AD7E7CABAC7D7DAC02FA7CABAB7C7DACAC000001009EFF3B043905D5000D0025
+4012080204C1008106020E00075D05035D010B0E10D4D4FCDCEC39310010C432F4EC1139
+300121112311231123112626353424027901C08DBE8ED7EB010405D5F966061FF9E1034E
+11DDB8BEE800000100BAFFE304AC0614002F009A40302D27210C04060D2000042A168617
+1AB9132AB90397138C2E0C090D1D2021270908242708061D082410162D081000463010FC
+C4FCCC10C6EED4EE10EE1139391239123931002FE4FEEE10FED5EE12173917393040400F
+050F060F070F270F288A0C8A0D070A060A070A0B0A0C0A0D0A1F0D200A210C220426190D
+191F19203A203A214D1F4D20492149226A1F6A20A506A507A620185D015D133436333216
+170E011514161F011E0115140623222627351E013332363534262F012E01353436372E01
+232206151123BAEFDAD0DB0397A83A4139A660E1D3408849508C4174783B655C6057A797
+0883718288BB0471C8DBE8E00873602F512A256A8E64ACB71918A41E1D5F5B3F543E373B
+875B7FAC1D67708B83FB93000004011B000006E505CD0017002F0038004C006040364542
+433F32C94830C9394A43CA0C39CA00C918C80CC924484533300431423C3F39364931604B
+3660433C5E12091E4B5E06091E5F2A4D10DCE4FCEC10FEFDC4EE10EE3211393912391217
+3931002FEEF6FEED10ED3210EED6EE391239393001220607060615141617161633323637
+363635342627262627320417161215140207060423222427260235341237362413231133
+32363534262732161514060716161717232726262323112311040083E25E5E60605E5EE2
+8384E35E5D5D5E5C5EE3849801076D6D6C6C6D6DFEF99898FEF96D6D6C6C6D6D01077D7B
+7B6E575866B0AE696018432E89AC813B4936429B05665E5E5EE58281E35E5E5F5F5E5DE2
+8385E35D5E5E676E6D6DFEFA9A98FEFB6D6D6E6E6D6D0105989A01066D6D6EFE62FEEC3E
+4B4C3F677779567011084D49DFD16033FE9C03440003011B000006E505CD0017002F0049
+004340263DCB3E3ACC41CA2431CB3034CC47CA18C900C824C90C3761443D305E2A090644
+5E1E0906124A10DCCCFCEC10FEED3210EE31002FEEF6FEFDEED6EE10FDEED6EE30013204
+171612151402070604232224272602353412373624172206070606151416171616333236
+373636353426272626171526262322061514163332363715060623222635343633321604
+009801076D6D6C6C6D6DFEF99898FEF96D6D6C6C6D6D01079883E25E5E60605E5EE28384
+E35E5D5D5E5C5EE3A742824295A7AB9B407A42438946D8FBFBD8498805CD6E6D6DFEFA9A
+98FEFB6D6D6E6E6D6D0105989A01066D6D6E675E5E5EE58281E35E5E5F5F5E5DE28385E3
+5D5E5EF5812120AF9D9FAE1F227F1D1CF4D0D1F21C00000201270393064605D5000C0014
+003E4021010607100A04120E090306C90D02008115010905620309620B0D630F62136311
+1510D4E4FCE4D4ECD4EC1139310010F43C3CEC1732D43C3CC41139300113133311231103
+23031123112315231123112335044AAEA4AA71C337CB7271CB72C905D5FF000100FDBE01
+E4FED1012FFE1C02425EFE1C01E45E000001017304EE0352066600030031400902B400B3
+040344010410D4EC310010F4EC30004BB009544BB00E545B58BD0004FFC0000100040004
+0040381137385901330123028BC7FEBA990666FE8800000200D705460329061000030007
+0092400E0602CE0400CD080164000564040810DCFCD4EC310010FC3CEC3230004BB00A54
+4BB00D545B58BD00080040000100080008FFC03811373859014BB00C544BB00D545B4BB0
+0E545B4BB017545B58BD0008FFC000010008000800403811373859014BB00F544BB01954
+5B58BD00080040000100080008FFC0381137385940116001600260056006700170027005
+7006085D0133152325331523025ECBCBFE79CBCB0610CACACA00000100D9002705DB04DD
+0013003E40220D0C0A0302CF04009C060CCF0E0A9C1206100814120E0D0C080403020809
+050F001410DC3CC4321739310010D43CCC32FC3CEC10FE3CEC3911123930132101170721
+1521072115210127372135213721D9030401007DAE012FFE48C3027BFCFAFEFE7DAEFED5
+01B6C3FD8703A2013B66D5A8F0AAFEC766D3AAF0000200080000074805D5000F00130087
+403911110E0F0E10110F0F0E0D110F0E0C110E0F0E420595030B95110195109500811107
+9503AD0D0911100F0D0C050E0A00040806021C120A0E1410D4D43CEC32D4C4C411121739
+31002F3CECECC4F4ECEC10EE10EE304B5358071005ED0705ED071005ED071005ED5922B2
+801501015D4013671177107711860C851096119015A015BF15095D011521112115211121
+15211121032301170121110735FD1B02C7FD3902F8FC3DFDF0A0CD02718BFEB601CB05D5
+AAFE46AAFDE3AA017FFE8105D59EFCF0031000030066FFBA05E5061700090013002B009E
+403C1D1F1A0D2B2C130A0100040D292620140D042A261E1A0495260D951A91268C2C2B2C
+2A141710201E23130A0100041D2910071F07192333101917102C10FCECFCECC011123939
+1739123939111239391139310010E4F4EC10EE10C010C011123939123912173912391112
+393930402A57005A15571955216A1565217B15761C7521094613590056136A006413641C
+6A287C007313761C7A280B5D015D09011E01333200113426272E01232200111416170726
+0235100021321617371707161215100021222627072704B6FD333EA15FDC010127793DA1
+5FDCFEFD2727864E4F0179013B82DD57A266AA4E50FE88FEC680DD5BA2670458FCB24043
+0148011A70B8B84043FEB8FEE570BC449E660108A0016201A54D4BBF59C667FEF69EFE9F
+FE5B4B4BBF58000300DD00DD05CF03EE000B0017002F00FF401D2D1B1509210300241804
+150F2721151B0F21300C00241812062A121E3010D4C4D4C41139393939310010D4C4D4C4
+10C01112173912391112393040BE05020503050400050006000705080509050A0A100F11
+0F120F130A1415021503150410051006100715081509150A1A0E1A0F1A101F111F121F13
+1A141A151A1624022403240420052006200724082409240A2A0E2A0F2A102F112F122F13
+2A142A152A1635023503350430053006300735083509350A3A0E3A0F3A103F113F123F13
+3A143A153A1645024503450440054006400745084509450A4A0E4A0F4A104F114F124F13
+4A144A154A1656B41FB020B021B022B026B027B028B429085D015D011E01333236353426
+232206072E01232206151416333236170E01232226353436333216173E01333216151406
+2322260393318654658076595285C4318555667F7659528690469D5E88BAA7865F994844
+9E6186BCA7865E95022F585A8769658687375858846A65868816877FDFA6AFD87E8A8A83
+E1A7AFD67700000200D9000005DB0504000B000F002E401805D007039C00D009010C9C0E
+0D02150400170C08150A061010D43CEC32FC3CEC3231002FECD43CECFC3CEC3001112115
+21112311213521110121152103AE022DFDD3A8FDD3022DFDD30502FAFE0504FE7DAAFE7D
+0183AA0183FBA6AA000200D9000005DB04A80006000A0054402E029C030403019C000104
+0403019C0201050605009C06054205040201000503D106A7079C0901080200240704230B
+10FC3CEC32323931002FECF4EC1739304B53580704ED071008ED071008ED071004ED5922
+0902150135010121152105DBFC4003C0FAFE0502FAFE0502FAFE03F8FEEBFEEEB20170AA
+016FFC02AA00000200D9000005DB04A80006000A0056402F069C0006030403059C040403
+009C010201069C05060202014206050302000504D101A7079C0806070224090400230B10
+FC3C3CEC323931002FECF4EC1739304B5358071008ED071004ED071004ED071008ED5922
+1335011501350101152135D90502FAFE03C10141FAFE03F8B0FE91AAFE90B20112FDC7AA
+AA0000010052000004C305D5001800C6404610021116110F020E0F1616110F02100F080D
+080E020D0D08420F0B090400D31706120BD31409100D81020C090E0305160F0315121003
+001166130065011C0D660A056507031910D43CEC32ECFCEC32EC12173912393911173931
+002FE432D43CEC32D43CEC32111239304B5358071005ED071008ED071008ED071005ED59
+22014BB00C5458BD0019FFC0000100190019004038113738594028860F900FA60FA00FB5
+0F05270C270D270E291028112812370E3910870C8812A60DA50EAA10A9110E5D005D0121
+1123112135213527213521013309013301211521071521048DFE63C9FE6001A054FEB401
+08FEC3BE017B0179BFFEC20108FEB554019F01C7FE3901C77B339B7B024AFD4402BCFDB6
+7B9B3300000100AEFE5604E504600020004D402513191F03160603090C0301120F06871C
+168C0A01BC00BD2119091209080B4E1F020800462110FCEC32F4ECC41239310010E4E432
+F43CECDCC41117391112173930B61F226022CF2203015D13113311141633323635113311
+141633323637150E01232226270E012322262711AEB88A879495B8232509201C29492345
+520F329162668F2AFE56060AFD489194A8A8028DFCA23C390B0C9417164E504F4F4E4EFD
+D70000020068FFE703C1052D001D002900624019002721091B062715060F211B0F15D52A
+0C2403001E1224182A10D4CCDCCC39391139310010E4CCDCCC10CE10CE11123911123930
+014BB00C544BB00B545B4BB00E545B4BB010545B4BB014545B58BD002A00400001002A00
+2AFFC03811373859013E0135342623220623222635343633321211100023222635341233
+321607342623220215141633321202F40F0F494837902424309065B4D6FEDFD598CBDDA2
+65820B574F6D8D56506D8D026D57A34B8183742C1F3E62FECAFEF9FEB1FE46D8A3C60101
+5BE0747DFEFECF747B01040000010019FE77053B05C1000B005D40140A040C0205070200
+070C0A05040301000606080C10D4C41739310010C4D4CC10CE1112393930403051035605
+50055A0A730370037604750570057A0A800380050C5A097F027F03700570067B09740B8F
+028F03800580060B5D015D1321152109012115213509013704EAFC4102A0FD4A03EFFADE
+02D5FD4905C1C1FD33FD04C095032102E3000001009CFE77057105C10007001E400F0602
+D704D600AF080367010567000810D4ECD4EC310010FCECEC323013211123112111239C04
+D5F0FD0AEF05C1F8B6067DF983000001FFE1FFF004AA042F002300CB40310B02151F1E03
+0008DA0F1A1600D922D80FD5180C1E1B1A19181706241201000B020423161505221F120C
+23126805231F2410D4D4D4EC12391112391239391117391112173931002F3CE4F4EC3232
+10EE111739393930014BB00A5458BD0024FFC0000100240024004038113738594056181E
+181F02090009010D020D030F040F050F060F070F080F090F0A0F0B0F0C0F0D0F0E0F0F0F
+100F110F120F130E140D1509160B1708180F180D19081A09231100110116021603171416
+15111617171C181C191123285D005D0123030E0115141633323637070E01232226353436
+37132103231323220607233E0133210487B6690F0F2F37112E251E1E371A7679152250FE
+BAC2B5C329363C09A01C8FA503790391FE194A5C163A3105058D080866642E90A10178FC
+6F03914045A67D000001002FFE8D03FA060E00250026401420DB001A0DDB131ADC07B126
+0A69176A1D69042610DCECFCEC310010FCECDCE410DEE430013213363712123332161514
+062322262726262322030607020223222635343633321617161601376A0E02010CBECA50
+6440372A380C0609106B0E040411BDC44F65443D21300F0A0AFEFA02B06C39020301BC54
+41363F26230F48FD95C16EFE21FE625341383F1D1C1253000003007301D5033B05F00003
+001E0029005F4033280725041F12181002E3001FDD1000E125DD050A19DF18DE15DD0AE0
+1C912A00180D1F10220602012811066B046C18226B0D2A10DCECCCFCEC3232C0C0111239
+39111239310010F4E4FCF4EC10C4EEEDD6EE10EE11123912391139393013211521011123
+35060623222635343633333534262322060735363633321605220615141633323635358B
+02B0FD5002AE952C905D8098BFBCB675753E8844499145B7B3FEECA17E6252688202507B
+02B8FE40703F448771878A045B5B22227F1C1CB0F0434F404D90721D0003006001D50364
+05F00003000F001B002E401902E300E116DD0AE010DD04911C00130D01196B076C136B0D
+1C10DCECFCEC39111239310010F4ECF4ECFCEC3013211521013216151406232226353436
+1722061514163332363534268B02B0FD500158B3CECEB3B3D0D0B3697E7F68697D7C0250
+7B041BDDBFBFDBDCBEBFDD73A18885A0A08589A00001004E000005CF05E7001F00404022
+09E51991120F030300E51001112016130F0C1F06020100026D061C1C0F6D0C1C162010D4
+ECECD4ECECC0C011123911123911123931002F3CEC1732F4EC3025152135361235340023
+2200151412171521352126023510002120001114020705CFFDA8B1C6FEF8D8D8FEF7C7B2
+FDA8013F9E91017F0131012F01818EA1B2B2B261014CCAF00122FEDDEFCAFEB461B2B28B
+012AB8013E018AFE77FECBC2FED88D000003007BFFE3076F047B00060033003E01034043
+272D253D0E0D0034A925168615881200A90E3A12B91C192E862DBA2A03B90EBB07310AB8
+1F198C253F343726060F0025371C07260F1500080D3D26080F2D370822453F10FCECCCD4
+FC3CD4ECC4111239391139111239111239310010C4E432F43CC4E4FC3CF4EC10C4EE3210
+EE10F4EE10EE11391139111239304081302B302C302D302E302F3030402B402C402D402E
+402F4030502B502C502D502E502F5030852B853080409040A040B040C040D040E040E040
+F0401D3F003F063F0D3F0E3F0F05302C302D302E302F402C402D402E402F502C502D502E
+502F6F006F066F0D6F0E6F0F602C602D602E602F702C702D702E702F802C802D802E802F
+1D5D71015D012E0123220607033E013332001D01211E0133323637150E01232226270E01
+232226353436332135342623220607353E013332160322061514163332363D0106B601A5
+8999B90E444AD484E20108FCB20CCCB768C86464D06AA7F84D49D88FBDD2FDFB0102A797
+60B65465BE5A8ED5EFDFAC816F99B9029497B4AE9E01305A5EFEDDFA5ABFC83535AE2A2C
+79777878BBA8BDC0127F8B2E2EAA272760FE18667B6273D9B42900030048FFA2049C04BC
+00090013002B00E4403C2B2C261F1D1A130A0100040D292620140D042A261E1A04B9260D
+B91AB8268C2C2B2C2A141710201E23130A01000410071F1D0712235129101217452C10FC
+EC32F4EC32C011121739123939111239391139310010E4F4EC10EE10C010C01112393912
+3912173911393911123930407028013F2D5914561C551D56206A1566217F007B047F057F
+067F077F087F097F0A7F0B7F0C7B0D7A157B1A7F1B7F1C7F1D7F1E7F1F7F207B217F227F
+237F247F257B269B199525A819A02DF02D2659005613551D5A2869006613651C6A287A00
+7413761C7A28891E95189A24A218AD24115D015D09011E01333236353426272E01232206
+15141617072E01351000333216173717071E011510002322262707270389FE1929674193
+AC145C2A673E97A913147D36360111F15D9F438B5F923536FEEEF060A13F8B600321FDB0
+2A28E8C84F759A2929EBD3486E2E974DC577011401383334A84FB34DC678FEEDFEC73433
+A84E0002008FFFE303AC05D5002000240086402F201A05020406190010860F880C002183
+230C95138C23812506221916090501001A2209001C01221C21260F091C162510DCECD4FC
+ECD4EC1112391112391112391239310010E4F4EC10FECD10F4EE123939173930014BB010
+544BB012545B4BB013545B58BD0025FFC000010025002500403811373859400B74047405
+74067407761C055D01331514060F010E0115141633323637150E012322263534363F013E
+01373E01351323353301F4BE375A5A3A33836D4EB4605EC067B8E04959583026080706C4
+CACA04449C65825758355E31596E4643BC3938C29F4C8956562F3519153C36010EFE0002
+01350000020005D5000300090062400F07008302810408070400030501000A10FC3CEC32
+393931002FF4FCCC30014BB00B5458BD000A00400001000A000AFFC03811373859014BB0
+0F544BB010545B4BB013545B58BD000AFFC00001000A000A00403811373859B6000B200B
+500B035D012335331123111333130200CBCBCB15A21404D7FEFA2B028F0165FE9B000001
+00D9011F05DB035E00050017400A049C020006031701000610DCD4EC310010D4C4EC3013
+2111231121D90502A8FBA6035EFDC10195000001003DFFD70519067D000A002A40180A09
+080706050B020402000B0A090706050403000801080B10D4CC1739310010D4CCC4111217
+39300133152301230107272501045CBD73FDAE42FEC17D19011B0100067D60F9BA03732D
+5062FD3B0001001FFE56050206140023008A40400E0D020F0C11191E190B0A0908040711
+1E1E1942190C130A071E011A0AA908138A12E616A90F018A00E604A921970F1C08241E1D
+1B1A190C0B0908070A00122410D4CC1739310010C432C4FCECF4EC10EEF6EE10EE321239
+3911123939304B5358071005ED1732071005ED1117395922014BB00C5458BD0024FFC000
+01002400240040381137385901152E01232206070321152103020623222627351E013332
+363713233521133E01333216050226502C6072193C011FFEC37F3ABCBA3A642F34612F61
+6D2289F801173F24C697356405F0A41D1C7A84FEC98FFD85FEE3D31516A6212189A602AD
+8F014AB7C312000200D9011005DB03F4001D003B003F401F2E1F392A002D221301101B0C
+1E2A9C31399C22049C1B0C9C133C1E002D0F3C10D43CC432310010D4ECD4ECDCFCD4ECC0
+111239391112393911123939300115060623222726272627262322060735363633321716
+171617163332361315060623222726272627262322060735363633321716171617163332
+3605DB69B3616E920A07060F9B5E58AC6269B3616E930B05060F9B5E56A96769B3616E92
+0A07060F9B5E58AC6269B3616E930A05070F9B5E56A9026FB34E453B040302063D4C54B3
+4E453B050202063D4B01DAB24F453B040302063D4C53B24E453B040203063D4B0002FFFA
+0000056005C1000200060038400F00030103050403020100050705060710D4CC11173931
+002FC4CC113930401463016D02700178027F0279057606076E007F00025D015D09012101
+33012102ACFE5E0344FDEFE00243FA9A04EEFBC4050FFA3F0002009E008D042504230006
+000D0086404903E804050402E8010205050402E8030206000601E80000060AE80B0C0B09
+E808090C0C0B09E80A090D070D08E807070D4209020B04E70700A60E090C05020703006F
+050A076F0C6E0E10FCFC3CD4EC321139111239310010F43CEC323939304B5358071004ED
+071008ED071008ED071004ED071004ED071008ED071008ED071004ED5922011501011501
+35131501011501350425FED3012DFE2B23FED3012DFE2B0423BFFEF4FEF4BF01A25201A2
+BFFEF4FEF4BF01A25200000200C1008D044804230006000D008640490CE80D0C090A090B
+E80A0A090DE80708070CE80B0C08080705E8060502030204E803030206E800010005E804
+05010100420C050A03E70700A60E0C08010500086F0A07016F0300700E10FC3CFCD43CEC
+1239111239310010F43CEC323939304B5358071008ED071004ED071004ED071008ED0710
+08ED071004ED071004ED071008ED59221301150135010125011501350101C101D5FE2B01
+2DFED301B201D5FE2B012DFED30423FE5E52FE5EBF010C010CBFFE5E52FE5EBF010C010C
+000300EC0000071400FE00030007000B00234011080400830A0602041905001901091908
+0C10D4FCD4ECD4EC31002F3C3CEC3232302533152325331523253315230396D4D402A9D5
+D5FAADD5D5FEFEFEFEFEFE00FFFF001000000568076B02270024000000000007010600BC
+0175FFFF001000000568075E02270024000000000007010500BC0175FFFF0073FFE305D9
+075E02270032000000000007010501270175000200730000080C05D500100019003B401F
+059503110195008118079503AD091812100A1506021C1100040815190D101A10FCECD4C4
+C4D4EC32123939393931002FECEC32F4EC3210EE30011521112115211121152120001110
+002117232000111000213307FAFD1A02C7FD3902F8FBD7FE4FFE4101BF01B16781FEBFFE
+C0014001418105D5AAFE46AAFDE3AA017C0170016D017CAAFEE1FEE0FEDFFEDF00030071
+FFE307C3047B0006002700330084403107080010860F880C00A9082E0CB916132803B908
+BB22251FB819138C340600162231090F0008074B311209512B121C453410FCECF4FCF4EC
+C4111239391239310010E432F43CC4E4EC3210C4EE3210EE10F4EE1112393040253F355F
+3570359F35CF35D035F035073F003F063F073F083F09056F006F066F076F086F09055D71
+015D012E01232206070515211E0133323637150E01232226270E01232200111000333216
+173E01333200252206151416333236353426070A02A48999B90E0348FCB20CCCB76AC862
+64D06AA0F25147D18CF1FEEF0111F18CD3424EE88FE20108FAB094ACAB9593ACAC029498
+B3AE9E355ABEC73434AE2A2C6E6D6E6D01390113011401386F6C6B70FEDD87E7C9C9E7E8
+C8C7E9000001000001E90400027900030010B602A900E90401002FC6310010FCEC301121
+15210400FC00027990000001000001E9080002790003000FB502A9000401002FCC310010
+D4EC30112115210800F800027990000200AE03E9036D05D50005000B0027401306009E09
+03810C090A0619070304070019010C10DCFCCCD4CC10FED4CE310010F43CEC3230012335
+1333030523351333030181D3A48152019AD3A4815203E9AD013FFEC1ADAD013FFEC10002
+00AE03E9036D05D50005000B0027401309039E0600810C090A0719060103040119000C10
+DCECD4CC10DCEED4CE310010F43CEC32300133150323132533150323130100D3A4815201
+9AD3A4815205D5ACFEC00140ACACFEC00140000100AE03E901D305D500050018400B009E
+03810603040019010610DCFCD4CC310010F4EC300123351333030181D3A4815203E9AD01
+3FFEC100000100B203FE01D705D500050018400B039E00810603040171000610DCECD4CC
+310010F4EC300133150323130104D3A4815205D598FEC1013F00000300D9009605DB046F
+00030007000B0029401400EA0206EA0402089C040A0C090501720400080C10DCD43CFC3C
+C4310010D4C4FCC410EE10EE3001331523113315230121152102DFF6F6F6F6FDFA0502FA
+FE046FF6FE12F50241AA00020006FE2303EE067500030007002240110206000804060806
+04030201000605070810D4CC1739310010D4CC1139123930090701FAFE7F01810181FE7F
+01F4FE0CFE0C0581FCCFFCC703390425FBDBFBD3042DFFFF003DFE56047F06100227005C
+000000000007008E005E0000FFFFFFFC000004E7074E0227003C00000000000701030073
+01750001FE89FFE302CD05F00003002B4013000F010201020F03000342028C0091040103
+0410D4CC310010E4E4304B5358071005ED071005ED592201330123022DA0FC5CA005F0F9
+F3000002005E005204BC04B20023002F0083404903091B15042D1E00271C02211D0C122D
+140B0A03130F011D2DB913EB0FEC27B91DEB21301E0C0012042A2414301C151B2A1D131C
+180903240B0A0103022428027306742A281C73183010DCE4ECF4E4EC1217391239391112
+393912393911123911121739310010D4E4ECF4E4EC10C011121739123939111239391139
+391217393001371707161615140607170727060623222627072737262635343637273717
+3636333216133426232206151416333236037BCF72CE25242628D172CF3B743D3A783DCF
+71CF25252626CF73CF3774403C755C9B72709E9D71719C03E1D173CE3B773E3F7339CF71
+CF28262525CF73CE3E763A407438CE73CF272524FE7C709A9A70729C9D000001009E008D
+0273042300060047402503E804050402E8010205050402E8030206000601E80006420204
+E700A6070203006F056E0710FCEC3239310010F4EC39304B53580704ED071008ED071008
+ED071004ED5922011501011501350273FED3012DFE2B0423BFFEF4FEF4BF01A252000001
+00C1008D0296042300060049402605E8060502030204E803030206E800010005E8040501
+0100420503E700A60705016F0300700710FC3CEC39310010F4EC39304B5358071008ED07
+1004ED071004ED071008ED592213011501350101C101D5FE2B012DFED30423FE5E52FE5E
+BF010C010C000002002F0000044A061400150019009B40280B14180703A90010870E18BE
+16B10E970900BC0501110E0F04160208000F1404080817000A064C1A10FC3CC432C4FC3C
+C410EE321112393931002F3CE632EEFEEE10EE10EE3212393930014BB00A5458BD001AFF
+C00001001A001A00403811373859014BB00E5458BD001A00400001001A001AFFC0381137
+3859401A101610171018101904301B501B800F8010801BA01BD01BEF1B085D005D011123
+11211123112335333534363B01152322061D0101331523044AB9FE07B9B0B0ADB3B9B063
+4D01F9B9B90460FBA003D1FC2F03D18F4EB7AF9950686301B2E90001002F0000044A0614
+0015008440210813040F0BA909048700971109BC0D0205000A080308010A0C0808100112
+0E4C1610FC3CC4C4FC3CC410EE1112393931002F3CE632FEEE10EE3212393930014BB00A
+5458BD0016FFC000010016001600403811373859014BB00E5458BD001600400001001600
+16FFC03811373859401130175017800A800B8017A017D017EF17085D0121112311212206
+1D01211521112311233533353436024A0200B9FEB7634D012FFED1B9B0B0AE0614F9EC05
+7B5068638FFC2F03D18F4EBBAB0000010039FF3B03C705D50013003E40201206B9001008
+B90A0400020E0A0C8102C2140F0059110D01570905590B07031410D43C3CEC32FC3C3CEC
+32310010E4F4C43210C43210EE3210EE3230252111231121352111213521113311211521
+112103C7FE91B0FE91016FFE91016FB0016FFE91016FDFFE5C01A49A021F9901A4FE5C99
+FDE1000100DB024801AE034600030012B7028300040119000410D4EC310010D4EC301333
+1523DBD3D30346FE000100AEFF1201D300FE00050018400B039E00830603040119000610
+D4ECD4CC310010FCEC302533150323130100D3A48152FEACFEC00140000200AEFF12036D
+00FE0005000B0027401309039E0600830C030401190007090A0719060C10DCECD4CC10DC
+EED4CE310010FC3CEC3230253315032313253315032313029AD3A48152FE66D3A48152FE
+ACFEC00140ACACFEC001400000070071FFE30A4C05F0000B0017002300270033003F004B
+00AE4044240F252625260F272427424000920C2E921E8D289218460692340C8D3A26128C
+2418914C25494327312B430D3D090D0F0E030D15310D1B3D0E490D15372B0D1B0E210B4C
+10FCE4ECD4C4ECE410EE10EEF6EE10EE111239111239310010E432F43C3CE432EC3210EE
+F6EE10EE32304B5358071005ED071005ED5922014BB014544BB009545B4BB00B545B4BB0
+0C545B4BB00D545B4BB00E545B58BD004C00400001004C004CFFC0381137385901220615
+141633323635342627321615140623222635343601321615140623222635343621330123
+132206151416333236353426013216151406232226353436172206151416333236353426
+08F457646457556363559EBABB9DA0BABBF9749EBCBB9F9FB9BA0425A0FC5AA01F566362
+5757636403B29EBABB9DA0BABB9F57636357556363029194848295958283957FDCBBBBDB
+DBBBBCDB02E0DBBBBDDADBBCBADCF9F3058E9582849494848196FD9FDCBBBBDBDBBBBCDB
+7F948482959582839500FFFF001000000568076D02270024000000000007010700BC0175
+FFFF00C90000048B076D022700280000000000070107009E0175FFFF001000000568076B
+02270024000000000007010400BC0175FFFF00C90000048B074E02270028000000000007
+0103009E0175FFFF00C90000048B076B022700280000000000070106009E0175FFFF00A2
+0000021F076B0227002C0000000000070104FF2F0175FFFFFFFE00000260076D0227002C
+0000000000070107FF2F0175FFFF000600000258074E0227002C0000000000070103FF2F
+0175FFFF003B000001BA076B0227002C0000000000070106FF2F0175FFFF0073FFE305D9
+076B02270032000000000007010401270175FFFF0073FFE305D9076D0227003200000000
+0007010701270175FFFF0073FFE305D9076B02270032000000000007010601270175FFFF
+00B2FFE30529076B02270038000000000007010400EE0175FFFF00B2FFE30529076D0227
+0038000000000007010700EE0175FFFF00B2FFE30529076B022700380000000000070106
+00EE0175000100C100000179046000030020B700BF02010800460410FCEC31002FEC3040
+0B1005400550056005700505015D13331123C1B8B80460FBA000000100C104EE033F0666
+00060037400C040502B400B307040275060710DCEC39310010F4EC323930004BB009544B
+B00E545B58BD0007FFC0000100070007004038113738590133132327072301B694F58BB4
+B48B0666FE88F5F5000100B6051D034A0637001B006340240012070E0B040112070F0B04
+12C3190704C3150BED1C0F010E000715561677075608761C10F4ECFCEC11393939393100
+10FC3CFCD43CEC11123911123911123911123930004BB009544BB00C545B58BD001CFFC0
+0001001C001C0040381137385901272E0123220607233E013332161F011E013332363733
+0E0123222601FC3916210D2624027D02665B2640253916210D2624027D02665B2640055A
+371413495287931C21371413495287931C00000100D50562032B05F60003002FB702EF00
+EE0401000410D4CC310010FCEC30004BB009544BB00E545B58BD0004FFC0000100040004
+0040381137385913211521D50256FDAA05F69400000100C7052903390648000D0057400E
+0BF0040700B30E0756080156000E10DCECD4EC310010F43CD4EC30004BB0095458BD000E
+FFC00001000E000E00403811373859004BB00F544BB010545B4BB011545B58BD000E0040
+0001000E000EFFC0381137385913331E0133323637330E01232226C7760B615756600D76
+0A9E91919E06484B4B4A4C8F90900001019A0544026606100003002C400902CE00CD0401
+64000410D4EC310010FCEC30004BB0095458BD0004FFC000010004000400403811373859
+01331523019ACCCC0610CC00000200EE04E103120706000B0017005F401103C115F209C1
+0FF11800560C780656121810D4ECF4EC310010F4ECF4EC30004BB009544BB00C545B58BD
+0018FFC000010018001800403811373859014BB00A544BB00B545B4BB00C545B58BD0018
+FFC000010018001800403811373859013426232206151416333236371406232226353436
+333216029858404157574140587A9F73739F9F73739F05F43F5857404157584073A0A073
+739F9F0000010123FE7502C100000013001F400E09060A0DF306001300102703091410DC
+D4ECD4CC31002FD4FCC41239302116161514062322262735161633323635342627025437
+3678762E572B224A2F3B3C2B2D3E6930595B0C0C83110F302E1E573D000200F004EE03AE
+066600030007004240110602B40400B3080407030005010305070810D4DCD4CC11391112
+39310010F43CEC3230004BB009544BB00E545B58BD0008FFC00001000800080040381137
+3859013303230333032302FCB2F88781AADF890666FE880178FE88000001014CFE7502C1
+000000130020400F0B0E0A07F30EF40001000A0427111410D4ECC4D4CC31002FFCFCC412
+3930213306061514163332363715060623222635343601B8772D2B3736203E1F26441E7A
+73353D581F2E2E0F0F850A0A575D3069000100C104EE033F066600060037400C0300B404
+01B307030575010710DCEC39310010F43CEC3930004BB009544BB00E545B58BD0007FFC0
+000100070007004038113738590103331737330301B6F58BB4B48BF504EE0178F5F5FE88
+0001FFF20000047505D5000D003F401E0C0B0A040302060006950081080304010B0E0004
+05011C0C073A0900790E10F43CECC4FC3CC411123911123931002FE4EC11173930B4300F
+500F02015D1333112517011121152111072737D3CB013950FE7702D7FC5E944DE105D5FD
+98DB6FFEEEFDE3AA023B6A6E9E0000010002000002480614000B005E401A0A0908040302
+06009706030401090A00047A0501080A7A07000C10D43CE4FC3CE411123911123931002F
+EC173930014BB0105458BD000C00400001000C000CFFC038113738594013100D400D500D
+600D73047A0A700DE00DF00D095D133311371707112311072737C7B87D4CC9B87B4AC506
+14FDA65A6A8DFCE3029A586A8D00FFFF0087FFE304A2076D022700360000000000070108
+008B0175FFFF006FFFE303C706660227005600000000000700E000170000FFFF005C0000
+051F076D0227003D000000000007010800BE0175FFFF0058000003DB06660227005D0000
+0000000700E0001B000000020104FEA201AE059800030007001C400D01F50004F5050804
+000506020810DC3CEC32310010D4ECD4EC30011123111311231101AEAAAAAA0198FD0A02
+F60400FD0A02F6000002000A000005BA05D5000C0019006740201009A90B0D9500811295
+0E0B0707011913040F0D161904320A110D1C0800791A10F43CEC32C4F4EC10C417393100
+2FC632EEF6EE10EE32304028201B7F1BB01B039F099F0A9F0B9F0C9F0E9F0F9F109F11BF
+09BF0ABF0BBF0CBF0EBF0FBF10BF11105D015D1321200011100029011123353313112115
+211133200011100021D301A001B10196FE69FE50FE60C9C9CB0150FEB0F30135011FFEE1
+FECB05D5FE97FE80FE7EFE9602BC9001E3FE1D90FDEA0118012E012C011700020071FFE3
+04750614000E00280127405E257B26251E231E247B23231E0F7B231E287B27281E231E26
+2728272524252828272223221F201F2120201F42282726252221201F08231E030F2303B9
+1B09B9158C1B23B1292627120C212018282523221F051E0F060C121251061218452910FC
+ECF4EC113939173912393911123939310010ECC4F4EC10EE12391239121739304B535807
+100EC9071008C9071008C907100EC9071008ED070EED071005ED071008ED5922B23F2A01
+015D407616252B1F28222F232F2429252D262D272A283625462558205821602060216622
+752075217522132523252426262627272836243625462445255A205A21622062217F007F
+017F027A037B097F0A7F0B7F0C7F0D7F0E7F0F7F107F117F127F137F147B157A1B7A1C7F
+1D7F1E762076217822A02AF02A275D005D012E0123220615141633323635342613161215
+140023220035340033321617270527252733172517050346325829A7B9AE9291AE36097E
+72FEE4E6E7FEE50114DD12342A9FFEC1210119B5E47F014D21FED903931110D8C3BCDEDE
+BC7ABC01268FFEE0ADFFFEC90137FFFA01370505B46B635CCC916F616200FFFFFFFC0000
+04E7076B0227003C000000000007010400730175FFFF003DFE56047F06660227005C0000
+00000007008D005E0000000200C90000048D05D5000C0015003D401B0E95090D9502F600
+810B150F090304011219063F0D0A011C00041610FCEC3232FCEC11173931002FF4FCECD4
+EC3040090F171F173F175F1704015D1333113332041514042B0111231311333236353426
+23C9CAFEFB0101FEFFFBFECACAFE8D9A998E05D5FEF8E1DCDCE2FEAE0427FDD192868691
+000200BAFE5604A406140010001C003E401B14B905081AB9000E8C08B801BD03971D1112
+0B471704000802461D10FCEC3232F4EC310010ECE4E4F4C4EC10C6EE304009601E801EA0
+1EE01E04015D2511231133113E0133321211100223222601342623220615141633323601
+73B9B93AB17BCCFFFFCC7BB10238A79292A7A79292A7A8FDAE07BEFDA26461FEBCFEF8FE
+F8FEBC6101EBCBE7E7CBCBE7E700000100D9022D05DB02D700030011B6009C0204010004
+10D4C4310010D4EC3013211521D90502FAFE02D7AA0000010119003F059C04C5000B0085
+404D0A9C0B0A070807099C080807049C0304070706059C060706049C0504010201039C02
+02010B9C0001000A9C090A010100420A080706040201000805030B090C0B0A0907050403
+0108020008060C10D43CCC321739310010D43CCC321739304B5358071008ED071005ED07
+1005ED071008ED071005ED071008ED071005ED071008ED59220902070101270101370101
+059CFE3701C977FE35FE357601C8FE387601CB01CB044CFE35FE377901CBFE357901C901
+CB79FE3501CB00010089029C02C505DF000A002C40180700DD0903DD0402DD09F705910B
+087C065D037C017C000B10DCF4E4FCE4310010F4ECECD4EC10EE32301333110735373311
+3315219CCCDFE689CDFDD7030A0263297427FD2B6E000001005E029C02B405F00018004A
+4024007D060400177D060604420402000EDD0F00DD02F70BDD0F129119000E087E01150E
+031910DCC4D4C4EC1139310010F4C4ECFCEC10EE111239304B5358071005ED17320705ED
+592201211521353637003534262322060735363633321615140106010C01A8FDAA223F01
+586855347A484D853991AEFEB538030E726E1F3801315E425123237B1C1C846C8BFEE430
+00010062028D02CD05F00028004840270015130ADD091FDD2013DD150DDD09F806F71CDD
+20F823912916130014197E26107E03141F092910DCC4C4D4ECD4EC11393939310010F4E4
+ECFCE4ECD4EC10EE10EE1112393001161615140623222627351616333236353426232335
+33323635342623220607353636333216151406020C5C65BEB1397D463477436D786F6C56
+5E5E61645F28665149803790A95A0460126D527C861514791B1A4F464A4C6C3F3C3A3D12
+1773111276634560FFFF0089FFE3077F05F0002700F000000000002700BC033500000007
+0109048BFD64FFFF0089FFE3073F05F0002700F000000000002700BC03350000000700F1
+048BFD64FFFF0062FFE3077F05F0002700F200000000002700BC0335000000070109048B
+FD64FFFF0073FFE3058B076D0227002A000000000007010A011B0175FFFF0071FE56045A
+06480227004A00000000000700DA008B0000FFFF00C90000019507500227002C00000000
+0007010BFF2F0175FFFF0087FE7504A205F00227003600000000000700DD008B0000FFFF
+006FFE7503C7047B0227005600000000000700DD00170000FFFF0073FFE30527076B0227
+00260000000000070104012D0175FFFF0071FFE303E7066602270046000000000007008D
+00890000FFFF0073FFE30527076D022700260000000000070108012D0175FFFF0071FFE3
+03E706660227004600000000000700E00089000000020071FFE304F4061400180024004A
+40240703D30901F922B900161CB90D108C16B805970B021F0C04030008080A0647191213
+452510FCECF43CC4FC173CC431002FECE4F4C4EC10C4EEFD3CEE3230B660268026A02603
+015D01112135213533153315231123350E01232202111012333216011416333236353426
+23220603A2FEBA0146B89A9AB83AB17CCBFFFFCB7CB1FDC7A79292A8A89292A703B6014E
+7D93937DFAFCA86461014401080108014461FE15CBE7E7CBCBE7E7000001006401DF027F
+028300030011B6009C020401000410DCCC310010D4EC301321152164021BFDE50283A400
+000100DB024801AE034600030012B7028300040119000410D4EC310010D4EC3013331523
+DBD3D30346FE00010000FFE3048F05F00031011C403A2012D322102B07D30919A11AAE16
+951D01A100AE04952F911D8C2909322B222129232612100A030D0911082C202613071108
+110D1C1900262A212F3CD4C432FCC4C41239391239391112391117391239391139393100
+10C432E4F4ECF4EC10EEF6EE10EE32DD3CEE3230014BB009544BB00C545B4BB00D545B4B
+B00F545B4BB017545B4BB018545B58BD0032FFC000010032003200403811373859407A0E
+000E010B020B315414690C6C0E6E0F6F106F116F126F1369146B1F6F206F216F226F236E
+246C256927692D9F079F089F099F0A9F0B9F0C9F0D9F0E9F0F9F109F119F129F13961F9F
+209F219F229F239F249F259F269F279F289F299F2A9F2B9F2C9D2D320008000910081009
+200820095515531E6A15671F0A5D005D01152E01232206072107210E0115141617210721
+1E0133323637150E01232200032337333426353436352337331200333216048F5BA9669D
+CA20024137FDE60201010201BE38FE8A20CA9D66A95B59B960EDFECB28D3378B0101C237
+9C280136EC62B90562D5695AC8BB7B182E23202E187BBBCA5A69D34848012201037B172F
+20232F177B0101012247000200D7050E032905D90003000700A5400D0400CE0602080164
+000564040810D4FCDCEC310010D43CEC3230004BB00E544BB011545B58BD000800400001
+00080008FFC03811373859014BB00E544BB00D545B4BB017545B58BD0008FFC000010008
+000800403811373859014BB011544BB019545B58BD00080040000100080008FFC0381137
+3859004BB0185458BD0008FFC00001000800080040381137385940116001600260056006
+700170027005700608015D0133152325331523025ECBCBFE79CBCB05D9CBCBCB00010173
+04EE02F005F60003007F40110203000301000003420002FA040103030410C410C0310010
+F4CC304B5358071005C9071005C95922004BB00C5458BD0004FFC0000100040004004038
+11373859004BB00E5458BD00040040000100040004FFC038113738594020060215022501
+25023602460256026A016702090F000F011F001F012F002F01065D015D013303230237B9
+E49905F6FEF8000100B6050E034A05E9001D0075402116100F03130C0701000308170CC3
+0413C31B08FA1E10010F00071656180756091E10D4ECD4EC1139393939310010F43CECD4
+EC321217391112173930004BB00C5458BD001EFFC00001001E001E00403811373859004B
+B00E5458BD001E00400001001E001EFFC03811373859B4100B1F1A025D01272E01232206
+1D012334363332161F011E013332363D01330E0123222601FC39191F0C24287D6756243D
+303917220F20287D026754223B0539210E0B322D066576101B1E0D0C3329066477100001
+010C04EE028B05F60003008940110102030200030302420001FA040103030410C410C031
+0010F4CC304B5358071005C9071005C95922004BB00C5458BD0004FFC000010004000400
+403811373859004BB00E5458BD00040040000100040004FFC03811373859402A06000601
+160012012400240135014301550055019F009F01AF00AF010E0F000F031F001F032F002F
+03065D015D0113230301C7C499E605F6FEF80108000100CF04EE033105F800060077400A
+04000502FA070402060710D4C439310010F43CC43930004BB00C5458BD0007FFC0000100
+07000700403811373859004BB00E5458BD00070040000100070007FFC03811373859014B
+B00E5458BD0007FFC00001000700070040381137385940130F000F010C041F001F011D04
+2F002F012D0409005D0133132327072301A2BCD38BA6A68B05F8FEF6B2B2000100CF04EE
+033105F800060086400A03040100FA070305010710D4C439310010F4C4323930004BB00C
+544BB009545B4BB00A545B4BB00B545B58BD0007FFC00001000700070040381137385900
+4BB00E5458BD00070040000100070007FFC03811373859014BB00E5458BD0007FFC00001
+0007000700403811373859401300000303000610001203100620002203200609005D0103
+331737330301A2D38BA6A68BD304EE010AB2B2FEF6000002003F029C02F405DF0002000D
+00D4401600030B07DD050109F703910E010C0A005D0608040C0E10DCD43CC4EC32113931
+0010F4FCD43CEC32123930014BB00E544BB00F545B4BB010545B4BB011545B4BB00B545B
+4BB00A545B58BD000E00400001000E000EFFC03811373859004BB011544BB00E545B58BD
+000EFFC00001000E000E0040381137385940540B011D012F01390149014603590369038B
+03AB03BB030B01000F010F020F050F060F070F080F0B0F0C0F0D13001F011F021F051F06
+1F071F081F0B1F0C1F0D2200350047004B0D53005B0D65008400A500B5001E5D015D0901
+21033311331523152335213501DDFECB013516A6878790FE620566FE5D021CFDE46DBABA
+7900000100C70506033905F8000D006A400E070004C30BFA0E0756080156000E10D4ECD4
+EC310010F4FCC43230004BB00C5458BD000EFFC00001000E000E00403811373859004BB0
+0E5458BD000E00400001000E000EFFC03811373859014BB00E544BB00F545B58BD000EFF
+C00001000E000E0040381137385913331E0133323637330E01232226C7760D6353526110
+760AA08F909F05F836393738777B7A000001019A050E026605DB00030011B60002FA0401
+000410D4CC310010F4CC3001331523019ACCCC05DBCD0000000000020001000000000014
+000300010000011A00000106000001000000000000000103000000020000000000000000
+00000000000000010000030405060708090A0B0C0D0E0F101112131415161718191A1B1C
+1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F40
+4142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F6061006263
+6465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F8081828384858687
+88898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAAB
+ACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF
+D0D100D2D3D4D5D6D7D8D9DADBDCDDDEDFE00004023E0000003A00200004001A007E00FF
+01070111011F01310142015301610178017E019202C702DD03A903C020262030203A20AC
+21222206221E222B2248226525CAFB02FFFF0000002000A00106010C011E013001410152
+015E0178017D019202C602D803A903C020132030203920AC21222202220F222B22482260
+25CAFB01FFFFFFE30000FFF50000FFD80000FFA0FF5E0000FF43FF68FF1400000000FCF6
+FCDB0000E096E085E056DF6A00000000DE71DE5F0000DAEF05BF000100000038000000F4
+000000FC0000000000FA00000000000000FA00FC00000000010200000000000000000120
+012800000000014200000000000000AC00A30084008500BD009600E70086008E008B009D
+00A900A40100008A00D90083009300F100F2008D0097008800C300DD00F0009E00AA00F3
+00F400F500A200AD00C900C700AE006200630090006400CB006500C800CA00CF00CC00CD
+00CE00E8006600D200D000D100AF006700EF009100D500D300D4006800EA00EC0089006A
+0069006B006D006C006E00A0006F0071007000720073007500740076007700E90078007A
+0079007B007D007C00B800A1007F007E0080008100EB00ED00BA00FD00FE000000000000
+00FF00F800D600F900FA00E300E400D700E000DA00DB00DC00DF00D800DE00B200B30000
+0000000000B600B700C4000000B400B500C50000008200C2008700000000000000AB0098
+00000000000000A8009A0000009900EE0000000000BC000000000000010100A500000000
+00000092008F0000000000000094009504CD006600000000028B0000028B000003350135
+03AE00C506B4009E051700AA079A0071063D0081023300C5031F00B0031F00A40400003D
+06B400D9028B009E02E30064028B00DB02B2000005170087051700E1051700960517009C
+051700640517009E0517008F051700A80517008B0517008102B200F002B2009E06B400D9
+06B400D906B400D9043F00930800008705790010057D00C905960073062900C9050E00C9
+049A00C906330073060400C9025C00C9025CFF96053F00C9047500C906E700C905FC00C9
+064C007304D300C9064C0073058F00C90514008704E3FFFA05DB00B20579001007E90044
+057B003D04E3FFFC057B005C031F00B002B20000031F00C706B400D90400FFEC040000AA
+04E7007B051400BA046600710514007104EC007102D1002F05140071051200BA023900C1
+0239FFDB04A200BA023900C107CB00BA051200BA04E50071051400BA05140071034A00BA
+042B006F03230037051200AE04BC003D068B005604BC003B04BC003D0433005805170100
+02B201040517010006B400D9057900100579001005960073050E00C905FC00C9064C0073
+05DB00B204E7007B04E7007B04E7007B04E7007B04E7007B04E7007B0466007104EC0071
+04EC007104EC007104EC0071023900900239FFC70239FFDE0239FFF4051200BA04E50071
+04E5007104E5007104E5007104E50071051200AE051200AE051200AE051200AE04000039
+040000C3051700AC051700810400005C04B801330517009E050A00BA0800011B0800011B
+0800012704000173040000D706B400D907CB0008064C006606AA00DD06B400D906B400D9
+06B400D905170052051700AE0423006805640019060E009C04B6FFE1042B002F03C50073
+03C50060061D004E07DB007B04E50048043F008F0335013506B400D90519003D0517001F
+06B400D9055AFFFA04E5009E04E500C1080000EC051700000579001005790010064C0073
+088F0073082F00710400000008000000042500AE042500AE028B00AE028B00B206B400D9
+03F4000604BC003D04E3FFFC0156FE890517005E0333009E033300C1050A002F050A002F
+04000039028B00DB028B00AE042500AE0ABC007105790010050E00C905790010050E00C9
+050E00C9025C00A2025CFFFE025C0006025C003B064C0073064C0073064C007305DB00B2
+05DB00B205DB00B2023900C1040000C1040000B6040000D5040000C70400019A040000EE
+04000123040000F00400014C040000C1047FFFF20246000205140087042B006F057B005C
+0433005802B201040633000A04E5007104E3FFFC04BC003D04D700C9051400BA06B400D9
+06B40119033500890335005E0335006207C1008907C1008907C100620633007305140071
+025C00C905140087042B006F059600730466007105960073046600710514007102E30064
+028B00DB05170000040000D704000173040000B60400010C040000CF040000CF0335003F
+040000C70400019A0002000000000000FF2B008F00000000000000000000000000000000
+00000000010C0000000100020003000400050006000700080009000A000B000C000D000E
+000F0010001100120013001400150016001700180019001A001B001C001D001E001F0020
+002100220023002400250026002700280029002A002B002C002D002E002F003000310032
+0033003400350036003700380039003A003B003C003D003E003F00400041004200430044
+00450046004700480049004A004B004C004D004E004F0050005100520053005400550056
+005700580059005A005B005C005D005E005F006000610062006300640065006600670068
+0069006A006B006C006D006E006F0070007100720073007400750076007700780079007A
+007B007C007D007E007F0080008100820083008400850086008700880089008A008B008C
+008D008E008F0090009100920093009400950096009700980099009A009B009C009D009E
+009F00A000A100A200A300A400A500A600A700A800A900AA00AB00AC00AD00AE00AF00B0
+00B100B200B300B400B500B600B700B800B900BA00BB00BC00BD00BE00BF00C000C100C2
+00C300C400C500C600C700C800C900CA00CB00CC00CD00CE00CF00D000D100D300D400D5
+00D600D700D800D900DA00DB00DC00DD00DE00DF00E000E100E200E300E400E500E600E7
+00E800E900EA00EB00EC00ED00EE00EF00F000F100F200F300F500F400F600F800F900FA
+00FB00FC00FD00FE00FF0100010101020103010401050106010701080109010A010B010C
+010D0973667468797068656E0E706572696F6463656E7465726564044575726F05633634
+353905633634363005633634363105633634363205633634363305633634363605633634
+36370563363436380563363436390000000000220022002200220058009300FF01B6024F
+038303B203F60421046E049804B404CA04DE0503054505820605067E06E1074C07B707FC
+086508CF08EE09160952097309AE0A1F0ADF0B580BB00BFB0C3A0C690C930CE60D140D3D
+0D7A0E0D0E2F0EAC0F000F450F850FEB107510F11129117011E012BD138A13EB1450148B
+14B114E115031518154015D61622166D16B91723177B17DF181B1843188018F819161977
+19B31A041A521AA11AD81B871BC41C001C9D1DBA1E871F771FE8205B207220F321352142
+21E221EF21FC2209221622232230223D224A225722642271227E228B229822A522B222BF
+22CC22D922E622F32300230D231A232723342341234E235B2368239423CF2434248F2533
+25532581261426BA274B279027B72813285828C3295F2A252A5C2AA32AE92B7A2BD32C44
+2C8F2CB12D502DA02E0E2E522EAA2F87304130BD31053121315031CF3248327A32DF3346
+33703370337D338A339733E6347A348F34A334D134FF351C353935673591359E35AB35CF
+365B369336CD374337A937EB3800381C384A390F391C3929393639433950395D396A3977
+39843991399E39AB39B839C539D239EF3A1C3A7B3AA03AE53B083B5E3B8E3BC43BF43C22
+3C5F3CA73CB43CC13CCE3CDB3CFE3D633E3B3E483E553E983EE73EFD3F613F8D3FDC403A
+404B405C406D407A4087409440A140AE40BB40C840D540E241404156416B424542AA42F7
+435F43B243FF445544DB452A453F00000000000100002D86000107941800000A15780010
+0024FFD300100025FFB70010002600000010002700000010002900000010002A004B0010
+002B00000010002D00720010002E00000010002F00000010003200390010003300000010
+0034004B00100035000000100037FF4400100039FF880010003AFFAD0010003BFF9A0010
+003CFF0D0010003D00000010004900000010005100000010005200260010005500000010
+0059FFC90010005A00000010005CFFDC00100062FFD30010006400000010006700390010
+007800000010007900260010007A00260010007B00260010007C00260010007D00260010
+00890000001000900000001000ADFFD3001000AEFFD3001000AF0039001000BAFFDC0010
+00BBFF0D001000C7FFD3001000C9FFD3001000D00039001000D10039001000D200390010
+00E50000001000E90000001000EAFF0D001000EBFFDC001000EC0000001000F6004B0010
+00FB0000001000FD000000240010FFD300240011FFDC0024001DFFDC0024002400390024
+0026FFDC0024002AFFDC00240032FFDC00240034FFDC00240036000000240037FF610024
+0038000000240039FF7D0024003AFF900024003B00000024003CFF6100240046FFDC0024
+0047FFDC00240048FFDC00240049FFB700240052FFDC00240054FFDC00240057FFDC0024
+0058000000240059FF880024005AFFAD0024005CFF7500240062003900240064FFDC0024
+0067FFDC0024006800000024006FFFDC00240070FFDC00240071FFDC00240072FFDC0024
+0073FFDC00240079FFDC0024007AFFDC0024007BFFDC0024007CFFDC0024007DFFDC0024
+007E00000024007F0000002400800000002400810000002400A9FFB7002400AA00000024
+00AD0039002400AE0039002400AFFFDC002400B4FEF8002400B5FF03002400BAFF750024
+00BBFF61002400C5002F002400C70039002400C90039002400D0FFDC002400D1FFDC0024
+00D2FFDC002400D30000002400D40000002400D50000002400E30000002400EAFF610024
+00EBFF75002400F6FFDC002400F90000002400FBFFDC002400FCFFDC002400FDFFDC0024
+00FEFFDC00250010000000250026FFDC0025002AFFDC00250032FFDC00250036FFDC0025
+0039FFC10025003AFFB70025003CFF9000250064FFDC00250067FFDC002500A9FFC10025
+00AAFFDC002500AFFFDC002500B4FF90002500B5FF90002500BBFF90002500C5FFAD0025
+00D0FFDC002500D1FFDC002500D2FFDC002500E3FFDC002500EAFF90002500F6FFDC0025
+00F9FFDC002500FBFFDC002500FDFFDC0026001000000026002400000026003600000026
+003CFFDC002600620000002600A9FFDC002600AAFFDC002600AD0000002600AE00000026
+00B40000002600B50026002600BBFFDC002600C50000002600C70000002600C900000026
+00E30000002600EAFFDC002600F9000000270010000000270024FFDC00270039FFDC0027
+003A00000027003CFF9000270062FFDC002700A9FFDC002700AAFFDC002700ADFFDC0027
+00AEFFDC002700B4FFD3002700B5FFC9002700BBFF90002700C5FF44002700C7FFDC0027
+00C9FFDC002700EAFF9000290010000000290011FEB70029001DFF6100290024FF440029
+0036FFDC00290037FFDC00290044FF4400290048FF900029004CFF6B00290052FFB70029
+0055FF6B00290058FF900029005CFF4400290062FF4400290069FF440029006AFF440029
+006BFF440029006CFF440029006DFF440029006EFF4400290070FF9000290071FF900029
+0072FF9000290073FF9000290079FFB70029007AFFB70029007BFFB70029007CFFB70029
+007DFFB70029007EFF900029007FFF9000290080FF9000290081FF90002900A900000029
+00AA0000002900ADFF44002900AEFF44002900B4FFD3002900B50000002900BAFF440029
+00C5FE88002900C7FF44002900C9FF44002900E3FFDC002900EBFF44002900F9FFDC002A
+00100000002A00240000002A0037FFB7002A003A0000002A003CFF9A002A00620000002A
+00A9FFDC002A00AAFFDC002A00AD0000002A00AE0000002A00B4FFD3002A00B5FFD3002A
+00BBFF9A002A00C5FFC9002A00C70000002A00C90000002A00EAFF9A002B00100000002B
+0011FFDC002B001D0000002B00A90000002B00AA0000002B00B4FFB7002B00B5FFC1002B
+00C5FFB7002D0010FFB7002D0024FFDC002D0062FFDC002D00A9FFDC002D00AAFFDC002D
+00ADFFDC002D00AEFFDC002D00B4FFB7002D00B5FFC1002D00C5FF90002D00C7FFDC002D
+00C9FFDC002E0010FF29002E0024FFDC002E0026FF90002E0032FF90002E0037FF61002E
+0038FFC9002E003AFFB7002E003CFFB7002E0044FFDC002E0048FF9A002E0052FF9A002E
+0058FF9A002E005CFF6B002E0062FFDC002E0064FF90002E0067FF90002E0068FFC9002E
+0069FFDC002E006AFFDC002E006BFFDC002E006CFFDC002E006DFFDC002E006EFFDC002E
+0070FF9A002E0071FF9A002E0072FF9A002E0073FF9A002E0079FF9A002E007AFF9A002E
+007BFF9A002E007CFF9A002E007DFF9A002E007EFF9A002E007FFF9A002E0080FF9A002E
+0081FF9A002E00A9FF7D002E00AA0000002E00ADFFDC002E00AEFFDC002E00AFFF90002E
+00B4FFC1002E00B5FFC1002E00BAFF6B002E00BBFFB7002E00C50000002E00C7FFDC002E
+00C9FFDC002E00D0FF90002E00D1FF90002E00D2FF90002E00D3FFC9002E00D4FFC9002E
+00D5FFC9002E00EAFFB7002E00EBFF6B002E00FBFF90002E00FDFF90002F0010FFDC002F
+0024002F002F0032FFB7002F0037FEE6002F0038FF9A002F0039FF1F002F003AFF44002F
+003CFEF0002F00440000002F0048FFDC002F0052FFDC002F0058FFDC002F005CFF44002F
+0062002F002F0067FFB7002F0068FF9A002F00690000002F006A0000002F006B0000002F
+006C0000002F006D0000002F006E0000002F0070FFDC002F0071FFDC002F0072FFDC002F
+0073FFDC002F0079FFDC002F007AFFDC002F007BFFDC002F007CFFDC002F007DFFDC002F
+007EFFDC002F007FFFDC002F0080FFDC002F0081FFDC002F00A90000002F00AA0000002F
+00AD002F002F00AE002F002F00AFFFB7002F00B4FE61002F00B5FDE6002F00BAFF44002F
+00BBFEF0002F00C50000002F00C7002F002F00C9002F002F00D0FFB7002F00D1FFB7002F
+00D2FFB7002F00D3FF9A002F00D4FF9A002F00D5FF9A002F00EAFEF0002F00EBFF440032
+0010003900320011FFAD0032001DFFDC00320024FFDC00320039FFDC0032003BFF7D0032
+003CFF9000320062FFDC003200A9FFDC003200AA0000003200ADFFDC003200AEFFDC0032
+00B4FFD3003200B5FFDC003200BBFF90003200C5FF44003200C7FFDC003200C9FFDC0032
+00EAFF9000330010FFD300330011FEC10033001D000000330024FF7D0033003800000033
+003A00000033003CFFD300330044FFA400330048FFB70033004CFFD300330051FFDC0033
+0052FFB700330055FFDC00330056FFDC00330058FFDC0033005C000000330062FF7D0033
+0068000000330069FFA40033006AFFA40033006BFFA40033006CFFA40033006DFFA40033
+006EFFA400330070FFB700330071FFB700330072FFB700330073FFB700330078FFDC0033
+0079FFB70033007AFFB70033007BFFB70033007CFFB70033007DFFB70033007EFFDC0033
+007FFFDC00330080FFDC00330081FFDC003300A9FFDC003300AA0000003300ADFF7D0033
+00AEFF7D003300B40026003300B50026003300BA0000003300BBFFD3003300C5FEB70033
+00C7FF7D003300C9FF7D003300D30000003300D40000003300D50000003300E4FFDC0033
+00EAFFD3003300EB0000003300FAFFDC003400100039003400A90000003400AA00000034
+00B4FFD3003400B5FFDC003400C5FF7D00350010FFAD00350011FFB70035001DFFC10035
+0024FFAD00350026FF9A00350037FF6B00350039FF900035003AFFAD0035003CFF7D0035
+0044FFD300350048FFA400350052FFA400350058FFA40035005CFF9000350062FFAD0035
+0064FF9A00350069FFD30035006AFFD30035006BFFD30035006CFFD30035006DFFD30035
+006EFFD300350070FFA400350071FFA400350072FFA400350073FFA400350079FFA40035
+007AFFA40035007BFFA40035007CFFA40035007DFFA40035007EFFA40035007FFFA40035
+0080FFA400350081FFA4003500A9FF90003500AAFFDC003500ADFFAD003500AEFFAD0035
+00B4FF6B003500B5FF7D003500BAFF90003500BBFF7D003500C5FFDC003500C7FFAD0035
+00C9FFAD003500EAFF7D003500EBFF90003500FBFF9A003500FDFF9A0036002400260036
+002600000036002A00000036003200000036003400000036003600000036006200260036
+00640000003600670000003600AD0026003600AE0026003600AF0000003600C700260036
+00C90026003600D00000003600D10000003600D20000003600E30000003600F600000036
+00F90000003600FB0000003600FD000000370010FF4400370011FF0D0037001DFF1F0037
+0024FF6100370026FF8800370037FFDC00370044FEAD00370046FEA400370048FEA40037
+004CFFC100370052FEA400370055FED300370056FEAD00370058FEC90037005AFEAD0037
+005CFEC100370062FF6100370064FF8800370069FEAD0037006AFEAD0037006BFEAD0037
+006CFEAD0037006DFEAD0037006EFEAD0037006FFEA400370070FEA400370071FEA40037
+0072FEA400370073FEA400370079FEA40037007AFEA40037007BFEA40037007CFEA40037
+007DFEA40037007EFEC90037007FFEC900370080FEC900370081FEC9003700A9FF440037
+00AAFF90003700ADFF61003700AEFF61003700B40000003700B5FFD3003700BAFEC10037
+00C5FEF8003700C7FF61003700C9FF61003700E4FEAD003700EBFEC1003700FAFEAD0037
+00FBFF88003700FCFEA4003700FDFF88003700FEFEA40038002400000038002D00000038
+003DFFDC003800620000003800AD0000003800AE0000003800C70000003800C900000038
+00E5FFDC00390010FF8800390011FEF80039001DFF5900390024FF7D00390032FFDC0039
+0044FF6100390048FF610039004CFFD300390052FF6100390058FF750039005CFFC90039
+0062FF7D00390067FFDC00390069FF610039006AFF610039006BFF610039006CFF610039
+006DFF610039006EFF6100390070FF6100390071FF6100390072FF6100390073FF610039
+0079FF610039007AFF610039007BFF610039007CFF610039007DFF610039007EFF750039
+007FFF7500390080FF7500390081FF75003900A9FF4E003900AAFF90003900ADFF7D0039
+00AEFF7D003900AFFFDC003900B40000003900B50000003900BAFFC9003900C5FEE60039
+00C7FF7D003900C9FF7D003900D0FFDC003900D1FFDC003900D2FFDC003900EBFFC9003A
+0010FFAD003A0011FF15003A001DFF88003A0024FF90003A0044FF7D003A0048FF88003A
+004CFFD3003A0052FF88003A0055FFA4003A0058FFB7003A005CFFDC003A0062FF90003A
+0069FF7D003A006AFF7D003A006BFF7D003A006CFF7D003A006DFF7D003A006EFF7D003A
+0070FF88003A0071FF88003A0072FF88003A0073FF88003A0079FF88003A007AFF88003A
+007BFF88003A007CFF88003A007DFF88003A007EFFB7003A007FFFB7003A0080FFB7003A
+0081FFB7003A00A9FF90003A00AAFFDC003A00ADFF90003A00AEFF90003A00B4FFDC003A
+00B50000003A00BAFFDC003A00C5FEF8003A00C7FF90003A00C9FF90003A00EBFFDC003B
+0010FF9A003B00240000003B0026FF6B003B0032FF7D003B0037FFDC003B0048FFA4003B
+00620000003B0064FF6B003B0067FF7D003B0070FFA4003B0071FFA4003B0072FFA4003B
+0073FFA4003B00A9FF90003B00AA0000003B00AD0000003B00AE0000003B00AFFF7D003B
+00B4FF61003B00B5FFAD003B00C5FFD3003B00C70000003B00C90000003B00D0FF7D003B
+00D1FF7D003B00D2FF7D003B00FBFF6B003B00FDFF6B003C0010FF0D003C0011FE61003C
+001DFEF0003C0024FF61003C0026FF90003C0032FF90003C0044FEE6003C0048FEF0003C
+004CFFB7003C0052FEF0003C0058FF15003C0062FF61003C0064FF90003C0067FF90003C
+0069FEE6003C006AFEE6003C006BFEE6003C006CFEE6003C006DFEE6003C006EFEE6003C
+0070FEF0003C0071FEF0003C0072FEF0003C0073FEF0003C0079FEF0003C007AFEF0003C
+007BFEF0003C007CFEF0003C007DFEF0003C007EFF15003C007FFF15003C0080FF15003C
+0081FF15003C00A9FF1F003C00AAFF6B003C00ADFF61003C00AEFF61003C00AFFF90003C
+00B4FF90003C00B5FFDC003C00C5FEF8003C00C7FF61003C00C9FF61003C00D0FF90003C
+00D1FF90003C00D2FF90003C00FBFF90003C00FDFF90003D0010FFDC003D00A90000003D
+00AA0000003D00B4FFDC003D00B5FFDC003D00C5FFDC0048005BFFDC00490010FF900049
+0011FF6B0049001DFFB700490057FFDC0049005AFFDC0049005CFFDC004900A9FFB70049
+00AAFFDC004900B40041004900B50000004900BAFFDC004900C5FF15004900EBFFDC004E
+0044FFDC004E0048FFB7004E0052FFB7004E0058FFC1004E005CFFB7004E0069FFDC004E
+006AFFDC004E006BFFDC004E006CFFDC004E006DFFDC004E006EFFDC004E0070FFB7004E
+0071FFB7004E0072FFB7004E0073FFB7004E0079FFB7004E007AFFB7004E007BFFB7004E
+007CFFB7004E007DFFB7004E007EFFC1004E007FFFC1004E0080FFC1004E0081FFC1004E
+00BAFFB7004E00EBFFB70051001000000051001100000051001D0000005100A900000051
+00AA0000005100B4FF6B005100B5FF90005100C5FFA400520010002600520011FFDC0052
+001D00000052005BFFC1005200A90000005200AA0000005200B4FF6B005200B5FFB70052
+00C5FF7D00550010FF7D00550011FF440055001DFFDC00550046FFD300550047FFDC0055
+0048FFD30055004900000055004AFFDC0055004BFFDC00550050FFDC00550051FFDC0055
+0052FFD300550054FFDC00550055FFDC0055005800000055005900000055005A00000055
+005BFFC90055005C00000055005D00000055006FFFD300550070FFD300550071FFD30055
+0072FFD300550073FFD300550078FFDC00550079FFD30055007AFFD30055007BFFD30055
+007CFFD30055007DFFD30055007E00000055007F00000055008000000055008100000055
+00A9FFB7005500AA0000005500B40000005500B50056005500BA0000005500C5FEC90055
+00E60000005500EB0000005500F7FFDC005500FCFFD3005500FEFFD300590010FFC90059
+0011FF610059001DFF90005900A9FFDC005900AAFFDC005900B40000005900B5FFDC0059
+00C5FEF0005A00100000005A0011FF44005A001DFF90005A00A9FFDC005A00AAFFDC005A
+00B40000005A00B50000005A00C5FF29005B0046FFDC005B0048FFC1005B0052FFC1005B
+006FFFDC005B0070FFC1005B0071FFC1005B0072FFC1005B0073FFC1005B0079FFC1005B
+007AFFC1005B007BFFC1005B007CFFC1005B007DFFC1005B00FCFFDC005B00FEFFDC005C
+0010FFDC005C0011FEDC005C001DFF6B005C00A9FFDC005C00AAFFDC005C00B40000005C
+00B50000005C00C5FED300620010FFD300620011FFDC0062001DFFDC0062002400390062
+0026FFDC0062002AFFDC00620032FFDC00620034FFDC00620036000000620037FF610062
+0038000000620039FF7D0062003AFF900062003B00000062003CFF6100620046FFDC0062
+0047FFDC00620048FFDC00620049FFB700620052FFDC00620054FFDC00620057FFDC0062
+0058000000620059FF880062005AFFAD0062005CFF7500620062003900620064FFDC0062
+0067FFDC0062006800000062006FFFDC00620070FFDC00620071FFDC00620072FFDC0062
+0073FFDC00620079FFDC0062007AFFDC0062007BFFDC0062007CFFDC0062007DFFDC0062
+007E00000062007F0000006200800000006200810000006200A9FFB7006200AA00000062
+00AD0039006200AE0039006200AFFFDC006200B4FEF8006200B5FF03006200BAFF750062
+00BBFF61006200C5002F006200C70039006200C90039006200D0FFDC006200D1FFDC0062
+00D2FFDC006200D30000006200D40000006200D50000006200E30000006200EAFF610062
+00EBFF75006200F6FFDC006200F90000006200FBFFDC006200FCFFDC006200FDFFDC0062
+00FEFFDC0064001000000064002400000064003600000064003CFFDC0064006200000064
+00A9FFDC006400AAFFDC006400AD0000006400AE0000006400B40000006400B500260064
+00BBFFDC006400C50000006400C70000006400C90000006400E30000006400EAFFDC0064
+00F9000000670010003900670011FFAD0067001DFFDC00670024FFDC00670039FFDC0067
+003BFF7D0067003CFF9000670062FFDC006700A9FFDC006700AA0000006700ADFFDC0067
+00AEFFDC006700B4FFD3006700B5FFDC006700BBFF90006700C5FF44006700C7FFDC0067
+00C9FFDC006700EAFF900068002400000068002D00000068003DFFDC0068006200000068
+00AD0000006800AE0000006800C70000006800C90000006800E5FFDC0070005BFFDC0071
+005BFFDC0072005BFFDC0073005BFFDC0078001000000078001100000078001D00000078
+00A90000007800AA0000007800B4FF6B007800B5FF90007800C5FFA40079001000260079
+0011FFDC0079001D00000079005BFFC1007900A90000007900AA0000007900B4FF6B0079
+00B5FFB7007900C5FF7D007A00100026007A0011FFDC007A001D0000007A005BFFC1007A
+00A90000007A00AA0000007A00B4FF6B007A00B5FFB7007A00C5FF7D007B00100026007B
+0011FFDC007B001D0000007B005BFFC1007B00A90000007B00AA0000007B00B4FF6B007B
+00B5FFB7007B00C5FF7D007C00100026007C0011FFDC007C001D0000007C005BFFC1007C
+00A90000007C00AA0000007C00B4FF6B007C00B5FFB7007C00C5FF7D007D00100026007D
+0011FFDC007D001D0000007D005BFFC1007D00A90000007D00AA0000007D00B4FF6B007D
+00B5FFB7007D00C5FF7D008900100026008900A90000008900AA0000008900B4FF900089
+00B5FF90008900C5FFAD009000100000009000A90000009000AA0000009000B4FFAD0090
+00B5FFA4009000C5FF9000A90024000000A90025FFDC00A90026FFDC00A90027FFDC00A9
+0029000000A9002AFFDC00A9002B000000A9002DFFDC00A9002E000000A9002F000000A9
+0032000000A90033000000A90034000000A90035000000A90037FF9000A90039FF9000A9
+003AFFDC00A9003B000000A9003CFF6B00A9003D000000A90049000000A90051000000A9
+0052000000A90055000000A90059FFDC00A9005AFFDC00A9005CFFDC00A90062000000A9
+0064FFDC00A90067000000A90078000000A90079000000A9007A000000A9007B000000A9
+007C000000A9007D000000A90089000000A90090009700A900AD000000A900AE000000A9
+00AF000000A900BAFFDC00A900BBFF6B00A900C7000000A900C9000000A900D0000000A9
+00D1000000A900D2000000A900E5000000A900E9000000A900EAFF6B00A900EBFFDC00A9
+00EC000000A900F6FFDC00A900FBFFDC00A900FDFFDC00AA0024FFB700AA0025FFB700AA
+0026FFDC00AA0027FFDC00AA0029000000AA002A000000AA002B000000AA002DFFDC00AA
+002E000000AA002F000000AA0032FFDC00AA0033000000AA0034000000AA0035000000AA
+0037FF4400AA0039FF4E00AA003AFF9000AA003BFF9000AA003CFF1F00AA003D000000AA
+0049000000AA0051000000AA0052000000AA0055000000AA0059FFDC00AA005AFFDC00AA
+005CFFDC00AA0062FFB700AA0064FFDC00AA0067FFDC00AA0078000000AA0079000000AA
+007A000000AA007B000000AA007C000000AA007D000000AA0089000000AA0090000000AA
+00ADFFB700AA00AEFFB700AA00AFFFDC00AA00BAFFDC00AA00BBFF1F00AA00C7FFB700AA
+00C9FFB700AA00D0FFDC00AA00D1FFDC00AA00D2FFDC00AA00E5000000AA00E9000000AA
+00EAFF1F00AA00EBFFDC00AA00EC000000AA00F6000000AA00FBFFDC00AA00FDFFDC00AD
+0010FFD300AD0011FFDC00AD001DFFDC00AD0024003900AD0026FFDC00AD002AFFDC00AD
+0032FFDC00AD0034FFDC00AD0036000000AD0037FF6100AD0038000000AD0039FF7D00AD
+003AFF9000AD003B000000AD003CFF6100AD0046FFDC00AD0047FFDC00AD0048FFDC00AD
+0049FFB700AD0052FFDC00AD0054FFDC00AD0057FFDC00AD0058000000AD0059FF8800AD
+005AFFAD00AD005CFF7500AD0062003900AD0064FFDC00AD0067FFDC00AD0068000000AD
+006FFFDC00AD0070FFDC00AD0071FFDC00AD0072FFDC00AD0073FFDC00AD0079FFDC00AD
+007AFFDC00AD007BFFDC00AD007CFFDC00AD007DFFDC00AD007E000000AD007F000000AD
+0080000000AD0081000000AD00A9FFB700AD00AA000000AD00AD003900AD00AE003900AD
+00AFFFDC00AD00B4FEF800AD00B5FF0300AD00BAFF7500AD00BBFF6100AD00C5002F00AD
+00C7003900AD00C9003900AD00D0FFDC00AD00D1FFDC00AD00D2FFDC00AD00D3000000AD
+00D4000000AD00D5000000AD00E3000000AD00EAFF6100AD00EBFF7500AD00F6FFDC00AD
+00F9000000AD00FBFFDC00AD00FCFFDC00AD00FDFFDC00AD00FEFFDC00AE0010FFD300AE
+0011FFDC00AE001DFFDC00AE0024003900AE0026FFDC00AE002AFFDC00AE0032FFDC00AE
+0034FFDC00AE0036000000AE0037FF6100AE0038000000AE0039FF7D00AE003AFF9000AE
+003B000000AE003CFF6100AE0046FFDC00AE0047FFDC00AE0048FFDC00AE0049FFB700AE
+0052FFDC00AE0054FFDC00AE0057FFDC00AE0058000000AE0059FF8800AE005AFFAD00AE
+005CFF7500AE0062003900AE0064FFDC00AE0067FFDC00AE0068000000AE006FFFDC00AE
+0070FFDC00AE0071FFDC00AE0072FFDC00AE0073FFDC00AE0079FFDC00AE007AFFDC00AE
+007BFFDC00AE007CFFDC00AE007DFFDC00AE007E000000AE007F000000AE0080000000AE
+0081000000AE00A9FFB700AE00AA000000AE00AD003900AE00AE003900AE00AFFFDC00AE
+00B4FEF800AE00B5FF0300AE00BAFF7500AE00BBFF6100AE00C5002F00AE00C7003900AE
+00C9003900AE00D0FFDC00AE00D1FFDC00AE00D2FFDC00AE00D3000000AE00D4000000AE
+00D5000000AE00E3000000AE00EAFF6100AE00EBFF7500AE00F6FFDC00AE00F9000000AE
+00FBFFDC00AE00FCFFDC00AE00FDFFDC00AE00FEFFDC00AF0010003900AF0011FFAD00AF
+001DFFDC00AF0024FFDC00AF0039FFDC00AF003BFF7D00AF003CFF9000AF0062FFDC00AF
+00A9FFDC00AF00AA000000AF00ADFFDC00AF00AEFFDC00AF00B4FFD300AF00B5FFDC00AF
+00BBFF9000AF00C5FF4400AF00C7FFDC00AF00C9FFDC00AF00EAFF9000B40024FEF800B4
+0025FFC100B40026FFB700B40027FFC100B40029FFC100B4002AFFB700B4002BFFC100B4
+002DFFC100B4002EFFC100B4002FFFC100B40032FFB700B40033FFC100B40034FFB700B4
+0035FFC100B40037000000B40039000000B4003A000000B4003BFF8800B4003C000000B4
+003DFFDC00B40049FFB700B40051FF9000B40052FF6B00B40055FF9000B40059FFB700B4
+005AFFB700B4005CFFB700B40062FEF800B40064FFB700B40067FFB700B40078FF9000B4
+0079FF6B00B4007AFF6B00B4007BFF6B00B4007CFF6B00B4007DFF6B00B40089FFC100B4
+0090FE7D00B400ADFEF800B400AEFEF800B400AFFFB700B400BAFFB700B400BB000000B4
+00C7FEF800B400C9FEF800B400D0FFB700B400D1FFB700B400D2FFB700B400E5FFDC00B4
+00E9FFB700B400EA000000B400EBFFB700B400ECFFC100B400F6FFB700B400FBFFB700B4
+00FDFFB700BA0010FFDC00BA0011FEDC00BA001DFF6B00BA00A9FFDC00BA00AAFFDC00BA
+00B4000000BA00B5000000BA00C5FED300BB0010FF0D00BB0011FE6100BB001DFEF000BB
+0024FF6100BB0026FF9000BB0032FF9000BB0044FEE600BB0048FEF000BB004CFFB700BB
+0052FEF000BB0058FF1500BB0062FF6100BB0064FF9000BB0067FF9000BB0069FEE600BB
+006AFEE600BB006BFEE600BB006CFEE600BB006DFEE600BB006EFEE600BB0070FEF000BB
+0071FEF000BB0072FEF000BB0073FEF000BB0079FEF000BB007AFEF000BB007BFEF000BB
+007CFEF000BB007DFEF000BB007EFF1500BB007FFF1500BB0080FF1500BB0081FF1500BB
+00A9FF1F00BB00AAFF6B00BB00ADFF6100BB00AEFF6100BB00AFFF9000BB00B4FF9000BB
+00B5FFDC00BB00C5FEF800BB00C7FF6100BB00C9FF6100BB00D0FF9000BB00D1FF9000BB
+00D2FF9000BB00FBFF9000BB00FDFF9000C50024002600C50025FFB700C50026FF9000C5
+0027FFB700C50029FFB700C5002AFFB700C5002BFFB700C5002D002F00C5002EFFB700C5
+002FFFB700C50032FF9000C50033FFB700C50034FF9000C50035FFB700C50037FEE600C5
+0039FE8800C5003AFF0300C5003BFFB700C5003CFE8800C5003D000000C50049FFDC00C5
+0051FFB700C50052FFB700C50055FFB700C50059FF1500C5005AFF3C00C5005CFF9000C5
+0062002600C50064FF9000C50067FF9000C50078FFB700C50079FFB700C5007AFFB700C5
+007BFFB700C5007CFFB700C5007DFFB700C50089FFB700C50090002600C500AD002600C5
+00AE002600C500AFFF9000C500BAFF9000C500BBFE8800C500C7002600C500C9002600C5
+00D0FF9000C500D1FF9000C500D2FF9000C500E5000000C500E9FFB700C500EAFE8800C5
+00EBFF9000C500ECFFB700C500F6FFB700C500FBFF9000C500FDFF9000C70010FFD300C7
+0011FFDC00C7001DFFDC00C70024003900C70026FFDC00C7002AFFDC00C70032FFDC00C7
+0034FFDC00C70036000000C70037FF6100C70038000000C70039FF7D00C7003AFF9000C7
+003B000000C7003CFF6100C70046FFDC00C70047FFDC00C70048FFDC00C70049FFB700C7
+0052FFDC00C70054FFDC00C70057FFDC00C70058000000C70059FF8800C7005AFFAD00C7
+005CFF7500C70062003900C70064FFDC00C70067FFDC00C70068000000C7006FFFDC00C7
+0070FFDC00C70071FFDC00C70072FFDC00C70073FFDC00C70079FFDC00C7007AFFDC00C7
+007BFFDC00C7007CFFDC00C7007DFFDC00C7007E000000C7007F000000C70080000000C7
+0081000000C700A9FFB700C700AA000000C700AD003900C700AE003900C700AFFFDC00C7
+00B4FEF800C700B5FF0300C700BAFF7500C700BBFF6100C700C5002F00C700C7003900C7
+00C9003900C700D0FFDC00C700D1FFDC00C700D2FFDC00C700D3000000C700D4000000C7
+00D5000000C700E3000000C700EAFF6100C700EBFF7500C700F6FFDC00C700F9000000C7
+00FBFFDC00C700FCFFDC00C700FDFFDC00C700FEFFDC00C90010FFD300C90011FFDC00C9
+001DFFDC00C90024003900C90026FFDC00C9002AFFDC00C90032FFDC00C90034FFDC00C9
+0036000000C90037FF6100C90038000000C90039FF7D00C9003AFF9000C9003B000000C9
+003CFF6100C90046FFDC00C90047FFDC00C90048FFDC00C90049FFB700C90052FFDC00C9
+0054FFDC00C90057FFDC00C90058000000C90059FF8800C9005AFFAD00C9005CFF7500C9
+0062003900C90064FFDC00C90067FFDC00C90068000000C9006FFFDC00C90070FFDC00C9
+0071FFDC00C90072FFDC00C90073FFDC00C90079FFDC00C9007AFFDC00C9007BFFDC00C9
+007CFFDC00C9007DFFDC00C9007E000000C9007F000000C90080000000C90081000000C9
+00A9FFB700C900AA000000C900AD003900C900AE003900C900AFFFDC00C900B4FEF800C9
+00B5FF0300C900BAFF7500C900BBFF6100C900C5002F00C900C7003900C900C9003900C9
+00D0FFDC00C900D1FFDC00C900D2FFDC00C900D3000000C900D4000000C900D5000000C9
+00E3000000C900EAFF6100C900EBFF7500C900F6FFDC00C900F9000000C900FBFFDC00C9
+00FCFFDC00C900FDFFDC00C900FEFFDC00D00010003900D00011FFAD00D0001DFFDC00D0
+0024FFDC00D00039FFDC00D0003BFF7D00D0003CFF9000D00062FFDC00D000A9FFDC00D0
+00AA000000D000ADFFDC00D000AEFFDC00D000B4FFD300D000B5FFDC00D000BBFF9000D0
+00C5FF4400D000C7FFDC00D000C9FFDC00D000EAFF9000D10010003900D10011FFAD00D1
+001DFFDC00D10024FFDC00D10039FFDC00D1003BFF7D00D1003CFF9000D10062FFDC00D1
+00A9FFDC00D100AA000000D100ADFFDC00D100AEFFDC00D100B4FFD300D100B5FFDC00D1
+00BBFF9000D100C5FF4400D100C7FFDC00D100C9FFDC00D100EAFF9000D20010003900D2
+0011FFAD00D2001DFFDC00D20024FFDC00D20039FFDC00D2003BFF7D00D2003CFF9000D2
+0062FFDC00D200A9FFDC00D200AA000000D200ADFFDC00D200AEFFDC00D200B4FFD300D2
+00B5FFDC00D200BBFF9000D200C5FF4400D200C7FFDC00D200C9FFDC00D200EAFF9000D3
+0024000000D3002D000000D3003DFFDC00D30062000000D300AD000000D300AE000000D3
+00C7000000D300C9000000D300E5FFDC00D40024000000D4002D000000D4003DFFDC00D4
+0062000000D400AD000000D400AE000000D400C7000000D400C9000000D400E5FFDC00D5
+0024000000D5002D000000D5003DFFDC00D50062000000D500AD000000D500AE000000D5
+00C7000000D500C9000000D500E5FFDC00E30024002600E30026000000E3002A000000E3
+0032000000E30034000000E30036000000E30062002600E30064000000E30067000000E3
+00AD002600E300AE002600E300AF000000E300C7002600E300C9002600E300D0000000E3
+00D1000000E300D2000000E300E3000000E300F6000000E300F9000000E300FB000000E3
+00FD000000E50010FFDC00E500A9000000E500AA000000E500B4FFDC00E500B5FFDC00E5
+00C5FFDC00E90010000000E900A9000000E900AA000000E900B4FFA400E900B5FF9000E9
+00C5FFB700EA0010FF0D00EA0011FE6100EA001DFEF000EA0024FF6100EA0026FF9000EA
+0032FF9000EA0044FEE600EA0048FEF000EA004CFFB700EA0052FEF000EA0058FF1500EA
+0062FF6100EA0064FF9000EA0067FF9000EA0069FEE600EA006AFEE600EA006BFEE600EA
+006CFEE600EA006DFEE600EA006EFEE600EA0070FEF000EA0071FEF000EA0072FEF000EA
+0073FEF000EA0079FEF000EA007AFEF000EA007BFEF000EA007CFEF000EA007DFEF000EA
+007EFF1500EA007FFF1500EA0080FF1500EA0081FF1500EA00A9FF1F00EA00AAFF6B00EA
+00ADFF6100EA00AEFF6100EA00AFFF9000EA00B4FF9000EA00B5FFDC00EA00C5FEF800EA
+00C7FF6100EA00C9FF6100EA00D0FF9000EA00D1FF9000EA00D2FF9000EA00FBFF9000EA
+00FDFF9000EB0010FFDC00EB0011FEDC00EB001DFF6B00EB00A9FFDC00EB00AAFFDC00EB
+00B4000000EB00B5000000EB00C5FED300EC0010000000EC0011FF6B00EC001DFFB700EC
+00A9000000EC00AA000000EC00B4FFDC00EC00B5000000EC00C5FF4400F60010000000F6
+0024000000F60037FFB700F6003A000000F6003CFF9A00F60062000000F600A9FFDC00F6
+00AAFFDC00F600AD000000F600AE000000F600B4FFD300F600B5FFD300F600BBFF9A00F6
+00C5FFC900F600C7000000F600C9000000F600EAFF9A00F90024002600F90026000000F9
+002A000000F90032000000F90034000000F90036000000F90062002600F90064000000F9
+0067000000F900AD002600F900AE002600F900AF000000F900C7002600F900C9002600F9
+00D0000000F900D1000000F900D2000000F900E3000000F900F6000000F900F9000000F9
+00FB000000F900FD000000FB0010000000FB0024000000FB0036000000FB003CFFDC00FB
+0062000000FB00A9FFDC00FB00AAFFDC00FB00AD000000FB00AE000000FB00B4000000FB
+00B5002600FB00BBFFDC00FB00C5000000FB00C7000000FB00C9000000FB00E3000000FB
+00EAFFDC00FB00F9000000FD0010000000FD0024000000FD0036000000FD003CFFDC00FD
+0062000000FD00A9FFDC00FD00AAFFDC00FD00AD000000FD00AE000000FD00B4000000FD
+00B5002600FD00BBFFDC00FD00C5000000FD00C7000000FD00C9000000FD00E3000000FD
+00EAFFDC00FD00F90000000000010000010C004D00070042000400020010004000070000
+041505680003000100010000076DFE1D00000ABCFE89FE890A4C00010000000000000000
+000000000000010C0001040E019000050004054704CC0000FE42054704CC00000253008F
+02660802020B0603030804020204800000AF1000204A0000000000000000426974730040
+0020FB020614FE14019A076D01E3000000010000000000000001000042001DB1028B0460
+0000236305D500005665726153616E730000000000000000FFFFFFFF36FFFFFE36323852
+30300000400000000000001400000110090C050003030304080609080204040508030303
+03060606060606060606060303080808050A060707070606070703030605080707060706
+070507060706050504030408050506060606060306060303050309060606060405040605
+070505060503050806060706070707060606060606060606060603030303060606060606
+060606060505060605050606090909050508090708080808060605060705050404070906
+05030806060806060609060606070A090509050503030804050502060404060605030305
+0C0606060606030303030707070707070305050505050505050505050307050506030706
+050506060808040404090909070603070507060706060303060505050505050405050000
+0A0D06000303040508060A09030404050803040303060606060606060606060303080808
+050B07070808070608080303070609080807080707050807090607060403040805050606
+050606040606020205020A06060606040504060608060605060306080707080708080806
+06060606060506060606020202020606060606060606060605050606050606060A0A0A05
+05080A0808080808060705070806050505080A060504080606080706060A060707080B0A
+050A0505030308050607020604040606050303050D070707070703030303080808080808
+02050505050505050505050602070506050308060706070608080404040A0A0A08060307
+05080508050604030605050505050504050500000B0F07000303030509070A0A03040406
+0904040404070707070707070707070404090909060C0708080807060908030307060908
+0907090708070807090707090404040906060707060707040707030306030B0707070705
+070407060906060507040709070708070809080707070707070607070707030303030707
+070707070707070706060707060607070B0B0B0606090B09090909090707060708060605
+05080B070603090707090707070B070707090C0B060B0606040409050607020704040707
+060404060F07070707070303030309090908080803060606060606060606060603080709
+050408070706070709090404040B0B0B0907030807080608060704040706060606060604
+060600000C100700040405050A080B0A030505060A040404040808080808080808080804
+040A0A0A060D0808080908070909030307060A0909080908080709080B0907090504050A
+06060808070808040808030307030B080808080507050806090606050804080A08080808
+090909080808080808070808080803030303080808080808080808080606080806070808
+0C0C0C06060A0C090A0A0A0A080806080907060606090C0806050A08080A0807070C0808
+08090D0D060C060604040A06060702080505070706040406100808080808030303030909
+090909090306060606060606060606060308070905040908070608080A0A0505050C0C0C
+0908030807080708070804040806060606060605060600000D110800040405050B080C0B
+030505070B040504040808080808080808080804040B0B0B070D0909090A08070A0A0303
+08070B0A0A080A0809070A090B0A070A0504050B07070808070808040808030307030D08
+0808080507050807090707070804080B090909080A0A0A08080808080807080808080303
+03030808080808080808080807070808070808080D0D0D07070B0D0A0B0B0B0B08080709
+0A080706060A0D0807050B08080B0908080D0809090A0E0D070D070704040B0607070208
+0505080807040407110908090808030303030A0A0A0A0A0A030707070707070707070707
+0309070A07040A08070708080B0B0505050D0D0D0A080309070907090708050408070707
+07070705070700000E130800040405050C090D0C030505070C0405040509090909090909
+09090905050C0C0C070E090A0A0B09080B0A030309070C0A0B090B0A09090A090D0B090A
+0505050C07070809080909040909030308030D0909090905080509070B0707080905090C
+09090A090A0B0A0808080808080809090909030303030909090909090909090907070909
+070809090E0E0E07070C0E0B0C0C0C0C090907090B080707070B0E0907050C09090C0909
+090E0909090B0F0F070E070704040C070709020906060808070404071309090909090303
+03030B0B0B0A0A0A0307070707070707070707070309080A08050B09090709090C0C0606
+060E0E0E0B090309080A080A080905040907070707070706070700000F14090005050606
+0D0A0E0B030606080D050505050A0A0A0A0A0A0A0A0A0A05050D0D0D080F0A0A0A0B0909
+0C0B03030A080D0B0C090C0A0A090B0A0F0A090B0605060D080809090809090509090303
+08030F0909090906080609080D0A08080A050A0D0A0A0A090B0C0B090909090909080909
+0909030303030909090909090909090908080A0A08090A090F0F0F08080D0F0C0D0D0D0D
+0A09080A0B090807070B0F0908060D0A0A0D0A09090F0A0A0A0C100F080F080805050D07
+0809030A0606090908050508140A090A0909030303030C0C0C0B0B0B0308080808080808
+08080808030A080B08050C09090809090D0D0606060F0F0F0C09030A080A080A08090505
+0A080808080808060808000010150A00050506060D0A0F0C030606080D050605050A0A0A
+0A0A0A0A0A0A0A05050D0D0D09100B0B0B0C0A090C0C05050A090D0C0D0A0D0B0A090C0B
+110B090C0605060D0808090A090A09060A0A030309030F0A0A0A0A0709060A090D0A0909
+0A050A0D0B0B0B0A0C0D0C0909090909090909090909030303030A0A0A0A0A0A0A0A0A0A
+08080A0A08090A0A10101008080D100D0D0D0D0D0A0A080B0C090808080C100A09060D0A
+0A0D0B0A0A100A0B0B0D110F0810080805050D080909030A06060A0A08050508150B0A0B
+0A0A050505050D0D0D0C0C0C030808080808080808080809040A090C09050D0A09090A0A
+0D0D0606061010100C0A050A090B090B090A06050A080808080808060808000011170A00
+050507080E0B100D050707090E050605060B0B0B0B0B0B0B0B0B0B06060E0E0E09110B0C
+0C0D0B0A0D0D06060C090F0D0D0A0D0C0B0A0D0B120D0A0C0706070E09090A0A080A0A06
+0A0B05050A05110B0A0A0A0708070B0A0F0A0A080B060B0E0B0B0C0B0D0D0D0A0A0A0A0A
+0A080A0A0A0A050505050B0A0A0A0A0A0B0B0B0B09090B0B090A0B0B11111109090E100D
+0E0E0E0E0B0B090B0D0A0908080D100A09070E0B0B0E0B0A0A110B0B0B0D121109110909
+05050E080A0A030B07070A0A09050509170B0B0B0B0B060606060D0D0D0D0D0D05090909
+090909090909090A050B080C08060D0A0A0A0A0A0E0E0707071010100D0A060B080C080C
+080A06050B090909090909070909000012180B00060607080F0B110D040707090F060706
+060B0B0B0B0B0B0B0B0B0B06060F0F0F0A120C0C0D0E0B0A0E0E06060C0A100E0E0B0E0D
+0B0C0E0C130D0C0D0706070F09090A0B090B0B060B0B05050A05110B0B0B0B0808070B0B
+100B0B090B060B0F0C0C0D0B0E0E0E0A0A0A0A0A0A090B0B0B0B050505050B0B0B0B0B0B
+0B0B0B0B09090B0B090B0B0B12121209090F110E0F0F0F0F0B0B090C0E0B0908080E110B
+0A070F0B0B0F0C0B0B120B0C0C0E13130912090906060F090B0C030B07070B0B09060609
+180C0B0C0B0B060606060E0E0E0E0E0E05090909090909090909090A050B080D09060E0B
+0C0B0B0B0F0F0707071111110E0B060B080D090D090B07060B0909090909090709090000
+131A0B0006060808100C120E0407070A10060706060C0C0C0C0C0C0C0C0C0C0606101010
+0A130D0D0D0F0C0B0F0E06060C0B100E0F0C0F0D0C0C0E0D140E0C0D070607100A0A0B0B
+090B0B060B0C05050B05110C0B0B0B0809080C0B110B0B0B0C060C100D0D0D0C0E0F0E0B
+0B0B0B0B0B090B0B0B0B050505050C0B0B0B0B0B0C0C0C0C0A0A0C0C0A0B0C0C1313130A
+0A10120F101010100C0C0A0D0E0B0A09090F120B0A08100C0C100D0C0C130C0D0D0F1413
+0A130A0A060610090B0C030C08080B0B0A06060A1A0D0C0D0C0C060606060F0F0F0E0E0E
+050A0A0A0A0A0A0A0A0A0A0B050C090D0B060F0B0C0B0C0B10100808081212120F0B060C
+090D090D090B07060C0A0A0A0A0A0A080A0A0000141B0C000606080A110D130F0608080A
+11060706070D0D0D0D0D0D0D0D0D0D07071111110B140E0E0E0F0D0C100F06060D0B110F
+100C100E0D0C0F0E140E0C0E080708110A0A0C0D0B0D0C070D0D06060C06140D0C0D0D08
+0A080D0B110B0B0B0D070D110E0E0E0D0F100F0C0C0C0C0C0C0B0C0C0C0C060606060D0C
+0C0C0C0C0D0D0D0D0A0A0D0D0A0C0D0D1414140A0A111410111111110D0D0A0D0F0C0A09
+090F130C0B08110D0D110D0C0C140D0E0E1015140A140A0A0606110A0B0C030D08080D0D
+0A06060A1B0E0D0E0D0D060606061010100F0F0F060A0A0A0A0A0A0A0A0A0A0B060D0A0E
+0B070F0C0C0B0C0D1111080808131313100D060D0A0E0B0E0B0D07060D0A0A0A0A0A0A08
+0A0A0000151C0D000707080A120D14100608080B12070807070D0D0D0D0D0D0D0D0D0D07
+071212120B150E0E0F100D0C101006060E0C1210110D110F0D0D0F0E150E0D0E08070812
+0B0B0D0D0C0D0D070D0D06060C06140E0D0D0D090B080E0B110D0D0B0D070D120E0E0F0D
+10110F0D0D0D0D0D0D0C0D0D0D0D060606060E0D0D0D0D0D0E0E0E0E0B0B0D0D0B0C0D0D
+1515150B0B121411121212120D0E0B0E100C0B0A0A10140D0B08120D0D120E0D0D150D0E
+0E1116160B150B0B0707120A0D0D040D08080D0D0B07070B1C0E0D0E0D0D060606061111
+110F0F0F060B0B0B0B0B0B0B0B0B0B0C060D0B0E0B07100D0D0D0D0D1212080808141414
+100D060D0B0F0C0F0C0D08070D0B0B0B0B0B0B080B0B0000161E0D000707090A120E1511
+0609090B12070807070E0E0E0E0E0E0E0E0E0E07071212120C160F0F0F110E0D11110606
+0E0C1310110D110F0E0D100F160F0D0F090709120B0B0D0E0C0E0D080E0E06060D06160E
+0D0E0E090B090E0E120E0E0C0E070E120F0F0F0E1011100D0D0D0D0D0D0C0D0D0D0D0606
+06060E0D0D0D0D0D0E0E0E0E0B0B0E0E0B0D0E0E1616160B0B121511121212120E0E0B0F
+110D0B0A0A11150D0C09120E0E120F0D0D160E0F0F1118160B160B0B0707120B0E0D040E
+09090D0D0B07070B1E0F0E0F0E0E06060606111111101010060B0B0B0B0B0B0B0B0B0B0C
+060E0B0F0C07110D0D0E0D0E1212090909151515110E060E0B0F0C0F0C0E08070E0B0B0B
+0B0B0B090B0B0000171F0E000707090B130F16120609090C13070807080F0F0F0F0F0F0F
+0F0F0F08081313130C17101010120F0D121107070F0D1411120E12100F0E111017100E10
+090809130C0C0E0F0D0F0E080F0F06060D06160F0E0E0E090C090F0E130E0E0C0F080F13
+1010100F1112110E0E0E0E0E0E0D0E0E0E0E060606060F0E0E0E0E0E0F0F0F0F0C0C0F0F
+0C0E0F0E1717170C0C131612131313130F0F0C10110E0C0B0B12150E0C09130F0F130F0E
+0E170F10101219180C170C0C0707130B0E0E040F09090F0F0C07070C1F100F100F0F0707
+0707121212111111060C0C0C0C0C0C0C0C0C0C0D060F0C100C08120E0E0E0E0E13130909
+09161616120F070F0C100D100D0F08070F0C0C0C0C0C0C090C0C000018200E0008080A0B
+140F17130709090C14080908080F0F0F0F0F0F0F0F0F0F08081414140D18101011120F0E
+13120707100D1512130E13110F0F121018100F10090809140C0C0E0F0D0F0E080F0F0707
+0E06180F0E0F0F0A0C090F0F140F0F0D0F080F141010110F1213120E0E0E0E0E0E0D0E0E
+0E0E070707070F0E0E0E0E0E0F0F0F0F0C0C0F0F0C0E0F0F1818180C0C14171314141414
+0F0F0C10120E0D0B0B12170E0D0A140F0F14100F0F180F1010131A180C180C0C0808140C
+0F0F040F0A0A0F0F0C08080C20100F100F0F07070707131313121212070C0C0C0C0C0C0C
+0C0C0C0D060F0C100D08130E0F0F0F0F14140A0A0A171717130F070F0C110D110D0F0908
+0F0C0C0C0C0C0C0A0C0C000019220F0008080A0C15101814070A0A0D1508090808101010
+1010101010101008081515150D1911111113100E13130707100E1613140F1411100F1211
+19110F110A080A150D0D0F100E100F09101007070E0718100F10100A0D0A100F140F0F0D
+10081015111111101314120F0F0F0F0F0F0E0F0F0F0F07070707100F0F0F0F0F10101010
+0D0D10100D0F10101919190D0D1518141515151510100D11130F0D0C0C13190F0D0A1510
+1015110F0F19101111141B1A0D190D0D0808150C0F0F04100A0A10100D08080D22111011
+101007070707141414121212070D0D0D0D0D0D0D0D0D0D0E07100D110D08130F0F0F0F10
+15150A0A0A181818131007100D110E110E100908100D0D0D0D0D0D0A0D0D00001A231000
+08080A0C16111914070A0A0D16080908091111111111111111111109091616160E1A1212
+1214100F14140808110E161314101412111013121A1210120A090A160D0D10110E111009
+111007070F0719101011110B0E0A100F150F0F0E11091116121212101314131010101010
+100E1010101007070707101010101010101010100D0D11110D0F11101A1A1A0D0D161914
+1616161611110D12140F0E0C0C141A100E0A161111161110101A111212141C1B0D1A0D0D
+0808160D0F1004110A0A10100D08080D23121012101008080808141414131313070D0D0D
+0D0D0D0D0D0D0D0F07110E120E091410100F101116160A0A0A191919141108110E120E12
+0E110908110D0D0D0D0D0D0A0D0D00001B24100009090B0C17111A15070B0B0E17090A09
+091111111111111111111109091717170E1B12131315111015140808120F171415101513
+111114121B1311130B090B170E0E11110F11110A1111080810081A111111110B0E0B1110
+1610100E11091117121213111415141111111111110F1111111108080808111111111111
+111111110E0E11110E1011111B1B1B0E0E171A151617171711110E1214100E0D0D151B11
+0E0B171111171211111B111212151D1C0E1B0E0E0909170D101105110B0B11110E09090E>
+<24121112111108080808151515141414080E0E0E0E0E0E0E0E0E0E0F08110E130E091511
+1110101117170B0B0B1A1A1A151108110E130F130F110A09110E0E0E0E0E0E0B0E0E0000
+1C26110009090B0D17121B16080B0B0E17090A0909121212121212121212120909171717
+0F1C131314161210161508081210181516111613121115131C1311130B090B170E0E1112
+0F12110A1212080810081B121112120C0F0B12111711110F120912171313141215161511
+11111111110F1111111108080808121111111111121212120E0E12120E1112121C1C1C0E
+0E171B161717171712120E1315100F0D0D151C110F0B171212171311111C121313161E1D
+0E1C0F0F0909170E111105120B0B12120E09090F26131213121208080808161616151515
+080E0E0E0E0E0E0E0E0E0E1008120F130F0916111111111217170B0B0B1B1B1B16120812
+0F140F140F120A09120E0E0E0E0E0E0B0E0E00000000000200080002FFFF000300010000
+000200000C500AEC5F0F3CF5001F080000000000BAB9F0B800000000BAC26791FE89FE1D
+0A4C076D00000008000100000000000000>
+] def
+/CharStrings 268 dict dup begin
+/.notdef 0 def /.null 1 def /nonmarkingreturn 2 def /space 3 def /exclam 4 def
+/quotedbl 5 def /numbersign 6 def /dollar 7 def /percent 8 def
+/ampersand 9 def /quotesingle 10 def /parenleft 11 def /parenright 12 def
+/asterisk 13 def /plus 14 def /comma 15 def /hyphen 16 def
+/period 17 def /slash 18 def /zero 19 def /one 20 def
+/two 21 def /three 22 def /four 23 def /five 24 def
+/six 25 def /seven 26 def /eight 27 def /nine 28 def
+/colon 29 def /semicolon 30 def /less 31 def /equal 32 def
+/greater 33 def /question 34 def /at 35 def /A 36 def
+/B 37 def /C 38 def /D 39 def /E 40 def
+/F 41 def /G 42 def /H 43 def /I 44 def
+/J 45 def /K 46 def /L 47 def /M 48 def
+/N 49 def /O 50 def /P 51 def /Q 52 def
+/R 53 def /S 54 def /T 55 def /U 56 def
+/V 57 def /W 58 def /X 59 def /Y 60 def
+/Z 61 def /bracketleft 62 def /backslash 63 def /bracketright 64 def
+/asciicircum 65 def /underscore 66 def /grave 67 def /a 68 def
+/b 69 def /c 70 def /d 71 def /e 72 def
+/f 73 def /g 74 def /h 75 def /i 76 def
+/j 77 def /k 78 def /l 79 def /m 80 def
+/n 81 def /o 82 def /p 83 def /q 84 def
+/r 85 def /s 86 def /t 87 def /u 88 def
+/v 89 def /w 90 def /x 91 def /y 92 def
+/z 93 def /braceleft 94 def /bar 95 def /braceright 96 def
+/asciitilde 97 def /Adieresis 98 def /Aring 99 def /Ccedilla 100 def
+/Eacute 101 def /Ntilde 102 def /Odieresis 103 def /Udieresis 104 def
+/aacute 105 def /agrave 106 def /acircumflex 107 def /adieresis 108 def
+/atilde 109 def /aring 110 def /ccedilla 111 def /eacute 112 def
+/egrave 113 def /ecircumflex 114 def /edieresis 115 def /iacute 116 def
+/igrave 117 def /icircumflex 118 def /idieresis 119 def /ntilde 120 def
+/oacute 121 def /ograve 122 def /ocircumflex 123 def /odieresis 124 def
+/otilde 125 def /uacute 126 def /ugrave 127 def /ucircumflex 128 def
+/udieresis 129 def /dagger 130 def /degree 131 def /cent 132 def
+/sterling 133 def /section 134 def /bullet 135 def /paragraph 136 def
+/germandbls 137 def /registered 138 def /copyright 139 def /trademark 140 def
+/acute 141 def /dieresis 142 def /notequal 143 def /AE 144 def
+/Oslash 145 def /infinity 146 def /plusminus 147 def /lessequal 148 def
+/greaterequal 149 def /yen 150 def /mu 151 def /partialdiff 152 def
+/summation 153 def /product 154 def /pi 155 def /integral 156 def
+/ordfeminine 157 def /ordmasculine 158 def /Omega 159 def /ae 160 def
+/oslash 161 def /questiondown 162 def /exclamdown 163 def /logicalnot 164 def
+/radical 165 def /florin 166 def /approxequal 167 def /Delta 168 def
+/guillemotleft 169 def /guillemotright 170 def /ellipsis 171 def /nonbreakingspace 172 def
+/Agrave 173 def /Atilde 174 def /Otilde 175 def /OE 176 def
+/oe 177 def /endash 178 def /emdash 179 def /quotedblleft 180 def
+/quotedblright 181 def /quoteleft 182 def /quoteright 183 def /divide 184 def
+/lozenge 185 def /ydieresis 186 def /Ydieresis 187 def /fraction 188 def
+/currency 189 def /guilsinglleft 190 def /guilsinglright 191 def /fi 192 def
+/fl 193 def /daggerdbl 194 def /periodcentered 195 def /quotesinglbase 196 def
+/quotedblbase 197 def /perthousand 198 def /Acircumflex 199 def /Ecircumflex 200 def
+/Aacute 201 def /Edieresis 202 def /Egrave 203 def /Iacute 204 def
+/Icircumflex 205 def /Idieresis 206 def /Igrave 207 def /Oacute 208 def
+/Ocircumflex 209 def /Ograve 210 def /Uacute 211 def /Ucircumflex 212 def
+/Ugrave 213 def /dotlessi 214 def /circumflex 215 def /tilde 216 def
+/macron 217 def /breve 218 def /dotaccent 219 def /ring 220 def
+/cedilla 221 def /hungarumlaut 222 def /ogonek 223 def /caron 224 def
+/Lslash 225 def /lslash 226 def /Scaron 227 def /scaron 228 def
+/Zcaron 229 def /zcaron 230 def /brokenbar 231 def /Eth 232 def
+/eth 233 def /Yacute 234 def /yacute 235 def /Thorn 236 def
+/thorn 237 def /minus 238 def /multiply 239 def /onesuperior 240 def
+/twosuperior 241 def /threesuperior 242 def /onequarter 243 def /onehalf 244 def
+/threequarters 245 def /Gbreve 246 def /gbreve 247 def /Idotaccent 248 def
+/Scedilla 249 def /scedilla 250 def /Cacute 251 def /cacute 252 def
+/Ccaron 253 def /ccaron 254 def /dcroat 255 def /sfthyphen 256 def
+/periodcentered 257 def /Euro 258 def /c6459 259 def /c6460 260 def
+/c6461 261 def /c6462 262 def /c6463 263 def /c6466 264 def
+/c6467 265 def /c6468 266 def /c6469 267 def 
+end readonly def
+FontName currentdict end definefont pop
+%%EndFont
+%%EndProlog
+mpldict begin
+18 180 translate
+576 432 0 0 clipbox
+% polygon
+1.000 setgray
+1.000 setlinewidth
+0 setlinejoin
+2 setlinecap
+[] 0 setdash
+0 0 m
+0 432 l
+576 432 l
+576 0 l
+closepath
+gsave
+fill
+grestore
+stroke
+% polygon
+0.000 setgray
+57.6 231.709 m
+57.6 388.8 l
+214.691 388.8 l
+214.691 231.709 l
+closepath
+gsave
+1.000 setgray
+fill
+grestore
+stroke
+% line
+0.500 setlinewidth
+0 setlinecap
+63.418 231.709 m 63.418 235.709 l
+stroke
+% line
+63.418 231.709 m 63.418 235.709 l
+stroke
+% line
+63.418 384.800 m 63.418 388.800 l
+stroke
+% line
+63.418 384.800 m 63.418 388.800 l
+stroke
+% text
+/BitstreamVeraSans-Roman findfont
+12.000 scalefont
+setfont
+60.418 218.709 m
+(0) show
+% line
+208.873 231.709 m 208.873 235.709 l
+stroke
+% line
+208.873 231.709 m 208.873 235.709 l
+stroke
+% line
+208.873 384.800 m 208.873 388.800 l
+stroke
+% line
+208.873 384.800 m 208.873 388.800 l
+stroke
+% text
+201.873 218.709 m
+(25) show
+% line
+57.600 237.527 m 61.600 237.527 l
+stroke
+% line
+57.600 237.527 m 61.600 237.527 l
+stroke
+% line
+210.691 237.527 m 214.691 237.527 l
+stroke
+% line
+210.691 237.527 m 214.691 237.527 l
+stroke
+% text
+47.6 233.027 m
+(0) show
+% line
+57.600 382.982 m 61.600 382.982 l
+stroke
+% line
+57.600 382.982 m 61.600 382.982 l
+stroke
+% line
+210.691 382.982 m 214.691 382.982 l
+stroke
+% line
+210.691 382.982 m 214.691 382.982 l
+stroke
+% text
+39.6 378.482 m
+(25) show
+% polygon
+1.000 setlinewidth
+2 setlinecap
+gsave
+157.091 157.091 57.600 231.709 clipbox
+63.418 288.105 m
+63.418 332.864 l
+139.048 332.864 l
+139.048 288.105 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+157.091 157.091 57.600 231.709 clipbox
+63.418 237.527 m
+63.418 282.286 l
+139.048 282.286 l
+139.048 237.527 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+157.091 157.091 57.600 231.709 clipbox
+144.866 237.527 m
+144.866 332.864 l
+180.373 332.864 l
+180.373 237.527 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+157.091 157.091 57.600 231.709 clipbox
+63.418 338.682 m
+63.418 367.626 l
+180.373 367.626 l
+180.373 338.682 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+157.091 157.091 57.600 231.709 clipbox
+186.191 237.527 m
+186.191 367.626 l
+212.211 367.626 l
+212.211 237.527 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% text
+101.233 310.484 m
+(1) show
+% text
+101.233 259.907 m
+(2) show
+% text
+162.62 285.196 m
+(3) show
+% text
+121.896 353.154 m
+(4) show
+% text
+199.201 302.577 m
+(5) show
+% polygon
+246.109 231.709 m
+246.109 388.8 l
+403.2 388.8 l
+403.2 231.709 l
+closepath
+gsave
+1.000 setgray
+fill
+grestore
+stroke
+% line
+0.500 setlinewidth
+0 setlinecap
+251.927 231.709 m 251.927 235.709 l
+stroke
+% line
+251.927 231.709 m 251.927 235.709 l
+stroke
+% line
+251.927 384.800 m 251.927 388.800 l
+stroke
+% line
+251.927 384.800 m 251.927 388.800 l
+stroke
+% text
+248.927 218.709 m
+(0) show
+% line
+397.382 231.709 m 397.382 235.709 l
+stroke
+% line
+397.382 231.709 m 397.382 235.709 l
+stroke
+% line
+397.382 384.800 m 397.382 388.800 l
+stroke
+% line
+397.382 384.800 m 397.382 388.800 l
+stroke
+% text
+390.382 218.709 m
+(25) show
+% line
+246.109 237.527 m 250.109 237.527 l
+stroke
+% line
+246.109 237.527 m 250.109 237.527 l
+stroke
+% line
+399.200 237.527 m 403.200 237.527 l
+stroke
+% line
+399.200 237.527 m 403.200 237.527 l
+stroke
+% text
+236.109 233.027 m
+(0) show
+% line
+246.109 382.982 m 250.109 382.982 l
+stroke
+% line
+246.109 382.982 m 250.109 382.982 l
+stroke
+% line
+399.200 382.982 m 403.200 382.982 l
+stroke
+% line
+399.200 382.982 m 403.200 382.982 l
+stroke
+% text
+228.109 378.482 m
+(25) show
+% polygon
+1.000 setlinewidth
+2 setlinecap
+gsave
+157.091 157.091 246.109 231.709 clipbox
+251.927 288.16 m
+251.927 306.085 l
+289.696 306.085 l
+289.696 288.16 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+157.091 157.091 246.109 231.709 clipbox
+251.927 237.527 m
+251.927 282.341 l
+289.696 282.341 l
+289.696 237.527 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+157.091 157.091 246.109 231.709 clipbox
+295.514 237.527 m
+295.514 306.085 l
+335.015 306.085 l
+335.015 237.527 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+157.091 157.091 246.109 231.709 clipbox
+251.927 311.903 m
+251.927 373.016 l
+335.015 373.016 l
+335.015 311.903 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+157.091 157.091 246.109 231.709 clipbox
+340.833 237.527 m
+340.833 373.016 l
+390.802 373.016 l
+390.802 237.527 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% text
+270.812 297.122 m
+(1) show
+% text
+270.812 259.934 m
+(2) show
+% text
+315.264 271.806 m
+(3) show
+% text
+293.471 342.46 m
+(4) show
+% text
+365.818 305.272 m
+(5) show
+% polygon
+57.6 43.2 m
+57.6 200.291 l
+214.691 200.291 l
+214.691 43.2 l
+closepath
+gsave
+1.000 setgray
+fill
+grestore
+stroke
+% line
+0.500 setlinewidth
+0 setlinecap
+63.418 43.200 m 63.418 47.200 l
+stroke
+% line
+63.418 43.200 m 63.418 47.200 l
+stroke
+% line
+63.418 196.291 m 63.418 200.291 l
+stroke
+% line
+63.418 196.291 m 63.418 200.291 l
+stroke
+% text
+60.418 30.2 m
+(0) show
+% line
+208.873 43.200 m 208.873 47.200 l
+stroke
+% line
+208.873 43.200 m 208.873 47.200 l
+stroke
+% line
+208.873 196.291 m 208.873 200.291 l
+stroke
+% line
+208.873 196.291 m 208.873 200.291 l
+stroke
+% text
+201.873 30.2 m
+(25) show
+% line
+57.600 49.018 m 61.600 49.018 l
+stroke
+% line
+57.600 49.018 m 61.600 49.018 l
+stroke
+% line
+210.691 49.018 m 214.691 49.018 l
+stroke
+% line
+210.691 49.018 m 214.691 49.018 l
+stroke
+% text
+47.6 44.518 m
+(0) show
+% line
+57.600 194.473 m 61.600 194.473 l
+stroke
+% line
+57.600 194.473 m 61.600 194.473 l
+stroke
+% line
+210.691 194.473 m 214.691 194.473 l
+stroke
+% line
+210.691 194.473 m 214.691 194.473 l
+stroke
+% text
+39.6 189.973 m
+(25) show
+% polygon
+1.000 setlinewidth
+2 setlinecap
+gsave
+157.091 157.091 57.600 43.200 clipbox
+63.418 86.468 m
+63.418 157.639 l
+149.032 157.639 l
+149.032 86.468 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+157.091 157.091 57.600 43.200 clipbox
+63.418 49.018 m
+63.418 80.65 l
+149.032 80.65 l
+149.032 49.018 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+157.091 157.091 57.600 43.200 clipbox
+154.85 49.018 m
+154.85 157.639 l
+179.782 157.639 l
+179.782 49.018 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+157.091 157.091 57.600 43.200 clipbox
+63.418 163.457 m
+63.418 186.73 l
+179.782 186.73 l
+179.782 163.457 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+157.091 157.091 57.600 43.200 clipbox
+185.6 59.692 m
+185.6 176.056 l
+208.873 176.056 l
+208.873 59.692 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% text
+106.225 122.053 m
+(1) show
+% text
+106.225 64.834 m
+(2) show
+% text
+167.316 103.329 m
+(3) show
+% text
+121.6 175.094 m
+(4) show
+% text
+197.236 117.874 m
+(5) show
+% polygon
+246.109 43.2 m
+246.109 200.291 l
+403.2 200.291 l
+403.2 43.2 l
+closepath
+gsave
+1.000 setgray
+fill
+grestore
+stroke
+% line
+0.500 setlinewidth
+0 setlinecap
+251.927 43.200 m 251.927 47.200 l
+stroke
+% line
+251.927 43.200 m 251.927 47.200 l
+stroke
+% line
+251.927 196.291 m 251.927 200.291 l
+stroke
+% line
+251.927 196.291 m 251.927 200.291 l
+stroke
+% text
+248.927 30.2 m
+(0) show
+% line
+397.382 43.200 m 397.382 47.200 l
+stroke
+% line
+397.382 43.200 m 397.382 47.200 l
+stroke
+% line
+397.382 196.291 m 397.382 200.291 l
+stroke
+% line
+397.382 196.291 m 397.382 200.291 l
+stroke
+% text
+390.382 30.2 m
+(25) show
+% line
+246.109 49.018 m 250.109 49.018 l
+stroke
+% line
+246.109 49.018 m 250.109 49.018 l
+stroke
+% line
+399.200 49.018 m 403.200 49.018 l
+stroke
+% line
+399.200 49.018 m 403.200 49.018 l
+stroke
+% text
+236.109 44.518 m
+(0) show
+% line
+246.109 194.473 m 250.109 194.473 l
+stroke
+% line
+246.109 194.473 m 250.109 194.473 l
+stroke
+% line
+399.200 194.473 m 403.200 194.473 l
+stroke
+% line
+399.200 194.473 m 403.200 194.473 l
+stroke
+% text
+228.109 189.973 m
+(25) show
+% polygon
+1.000 setlinewidth
+2 setlinecap
+gsave
+157.091 157.091 246.109 43.200 clipbox
+270.813 107.755 m
+270.813 119.391 l
+328.995 119.391 l
+328.995 107.755 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+157.091 157.091 246.109 43.200 clipbox
+251.927 49.018 m
+251.927 101.936 l
+347.881 101.936 l
+347.881 49.018 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+157.091 157.091 246.109 43.200 clipbox
+353.699 51.177 m
+353.699 117.233 l
+364.283 117.233 l
+364.283 51.177 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+157.091 157.091 246.109 43.200 clipbox
+251.927 125.209 m
+251.927 185.467 l
+364.283 185.467 l
+364.283 125.209 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+157.091 157.091 246.109 43.200 clipbox
+370.101 49.018 m
+370.101 185.467 l
+397.39 185.467 l
+397.39 49.018 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+% text
+299.904 113.573 m
+(1) show
+% text
+299.904 75.477 m
+(2) show
+% text
+358.991 84.205 m
+(3) show
+% text
+308.105 155.338 m
+(4) show
+% text
+383.746 117.242 m
+(5) show
+
+end
+showpage
diff --git a/doc/figures/normappr.eps b/doc/figures/normappr.eps
new file mode 100644
index 0000000..039ac6c
--- /dev/null
+++ b/doc/figures/normappr.eps
@@ -0,0 +1,6818 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Title: /home/vandenbe/src/python/examples/normappr/normappr.eps
+%%Creator: matplotlib version 0.83.2, http://matplotlib.sourceforge.net/
+%%CreationDate: Thu Oct 13 16:06:23 2005
+%%BoundingBox: 18 180 594 612
+%%EndComments
+%%BeginProlog
+/mpldict 7 dict def
+mpldict begin
+/m { moveto } bind def
+/l { lineto } bind def
+/r { rlineto } bind def
+/box {
+m
+1 index 0 r
+0 exch r
+neg 0 r
+closepath
+} bind def
+/clipbox {
+box
+clip
+newpath
+} bind def
+/ellipse {
+newpath
+matrix currentmatrix 7 1 roll
+translate
+scale
+0 0 1 5 3 roll arc
+setmatrix
+closepath
+} bind def
+%%BeginFont: BitstreamVeraSans-Roman
+%!PS-TrueType-1.0-2.0
+8 dict begin
+/FontName /BitstreamVeraSans-Roman def
+/FontMatrix [1 0 0 1 0 0] def
+/FontType 42 def
+/Encoding StandardEncoding def
+/FontBBox [-375 -483 2636 1901] def
+/PaintType 0 def
+/FontInfo 7 dict dup begin
+/Notice (Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.) def
+/FamilyName (Bitstream Vera Sans) def
+/FullName (Bitstream Vera Sans) def
+/version (Release 1.10) def
+/isFixedPitch false def
+/UnderlinePosition -213 def
+/UnderlineThickness 143 def
+end readonly def
+/sfnts [
+<0001000000110100000400104F532F32B45FF4630000EB700000005650434C54D18A5E97
+0000EBC800000036636D6170A4C3E8A00000B16C0000035863767420FFD31D3900001EFC
+000001FC6670676DE7B4F1C4000026600000008B6761737000070007000101480000000C
+676C79660C7441CF000026EC00008A7E68646D7834F0210E0000EC000000154868656164
+DD84A2D00001015400000036686865611045086F0000EB4C00000024686D747809C68EB2
+0000B4C4000004306B65726EDC52D5990000BDA000002D8A6C6F6361F3CBD23D0000BB84
+0000021A6D6178700547063A0000EB2C000000206E616D65D9BCC8B50000011C00001DDF
+706F7374B45A2FBB0000B8F40000028E707265703B07F100000020F80000056800000016
+010E0001000000000000003A000000010000000000010013003A00010000000000020005
+005F00010000000000030013003A00010000000000040013003A0001000000000005000C
+006400010000000000060017004D0001000000000007003000AD0001000000000008000E
+086C000100000000000B00180983000100000000000D0913007000030001040900000074
+099B000300010409000100260A0F0003000104090002000A0A5900030001040900030026
+0A0F000300010409000400260A0F000300010409000500180A630003000104090006002E
+0A35000300010409000700600AF50003000104090008001C1A73000300010409000B0030
+1CA1000300010409000D12260A7B436F7079726967687420286329203230303320627920
+42697473747265616D2C20496E632E20416C6C205269676874732052657365727665642E
+42697473747265616D20566572612053616E7342697473747265616D5665726153616E73
+2D526F6D616E52656C6561736520312E3130436F70797269676874202863292032303033
+2062792042697473747265616D2C20496E632E0D0A416C6C205269676874732052657365
+727665642E0D0A42697473747265616D205665726120697320612074726164656D61726B
+206F662042697473747265616D2C20496E632E0D0A0D0A5065726D697373696F6E206973
+20686572656279206772616E7465642C2066726565206F66206368617267652C20746F20
+616E7920706572736F6E206F627461696E696E67206120636F7079206F66207468652066
+6F6E7473206163636F6D70616E79696E672074686973206C6963656E7365202822466F6E
+7473222920616E64206173736F63696174656420646F63756D656E746174696F6E206669
+6C657320287468652022466F6E7420536F66747761726522292C20746F20726570726F64
+75636520616E6420646973747269627574652074686520466F6E7420536F667477617265
+2C20696E636C7564696E6720776974686F7574206C696D69746174696F6E207468652072
+696768747320746F207573652C20636F70792C206D657267652C207075626C6973682C20
+646973747269627574652C20616E642F6F722073656C6C20636F70696573206F66207468
+6520466F6E7420536F6674776172652C20616E6420746F207065726D697420706572736F
+6E7320746F2077686F6D2074686520466F6E7420536F667477617265206973206675726E
+697368656420746F20646F20736F2C207375626A65637420746F2074686520666F6C6C6F
+77696E6720636F6E646974696F6E733A0D0A0D0A5468652061626F766520636F70797269
+67687420616E642074726164656D61726B206E6F746963657320616E6420746869732070
+65726D697373696F6E206E6F74696365207368616C6C20626520696E636C756465642069
+6E20616C6C20636F70696573206F66206F6E65206F72206D6F7265206F66207468652046
+6F6E7420536F667477617265207479706566616365732E0D0A0D0A54686520466F6E7420
+536F667477617265206D6179206265206D6F6469666965642C20616C74657265642C206F
+7220616464656420746F2C20616E6420696E20706172746963756C617220746865206465
+7369676E73206F6620676C79706873206F72206368617261637465727320696E20746865
+20466F6E7473206D6179206265206D6F64696669656420616E64206164646974696F6E61
+6C20676C79706873206F722063686172616374657273206D617920626520616464656420
+746F2074686520466F6E74732C206F6E6C792069662074686520666F6E74732061726520
+72656E616D656420746F206E616D6573206E6F7420636F6E7461696E696E672065697468
+65722074686520776F726473202242697473747265616D22206F722074686520776F7264
+202256657261222E0D0A0D0A54686973204C6963656E7365206265636F6D6573206E756C
+6C20616E6420766F696420746F2074686520657874656E74206170706C696361626C6520
+746F20466F6E7473206F7220466F6E7420536F6674776172652074686174206861732062
+65656E206D6F64696669656420616E6420697320646973747269627574656420756E6465
+7220746865202242697473747265616D205665726122206E616D65732E0D0A0D0A546865
+20466F6E7420536F667477617265206D617920626520736F6C642061732070617274206F
+662061206C617267657220736F667477617265207061636B61676520627574206E6F2063
+6F7079206F66206F6E65206F72206D6F7265206F662074686520466F6E7420536F667477
+61726520747970656661636573206D617920626520736F6C6420627920697473656C662E
+0D0A0D0A54484520464F4E5420534F4654574152452049532050524F5649444544202241
+53204953222C20574954484F55542057415252414E5459204F4620414E59204B494E442C
+2045585052455353204F5220494D504C4945442C20494E434C5544494E4720425554204E
+4F54204C494D4954454420544F20414E592057415252414E54494553204F46204D455243
+48414E544142494C4954592C204649544E45535320464F52204120504152544943554C41
+5220505552504F534520414E44204E4F4E494E4652494E47454D454E54204F4620434F50
+5952494748542C20504154454E542C2054524144454D41524B2C204F52204F5448455220
+52494748542E20494E204E4F204556454E54205348414C4C2042495453545245414D204F
+522054484520474E4F4D4520464F554E444154494F4E204245204C4941424C4520464F52
+20414E5920434C41494D2C2044414D41474553204F52204F54484552204C494142494C49
+54592C20494E434C5544494E4720414E592047454E4552414C2C205350454349414C2C20
+494E4449524543542C20494E434944454E54414C2C204F5220434F4E53455155454E5449
+414C2044414D414745532C205748455448455220494E20414E20414354494F4E204F4620
+434F4E54524143542C20544F5254204F52204F54484552574953452C2041524953494E47
+2046524F4D2C204F5554204F462054484520555345204F5220494E4142494C4954592054
+4F205553452054484520464F4E5420534F465457415245204F522046524F4D204F544845
+52204445414C494E475320494E2054484520464F4E5420534F4654574152452E0D0A0D0A
+45786365707420617320636F6E7461696E656420696E2074686973206E6F746963652C20
+746865206E616D6573206F6620476E6F6D652C2074686520476E6F6D6520466F756E6461
+74696F6E2C20616E642042697473747265616D20496E632E2C207368616C6C206E6F7420
+6265207573656420696E206164766572746973696E67206F72206F746865727769736520
+746F2070726F6D6F7465207468652073616C652C20757365206F72206F74686572206465
+616C696E677320696E207468697320466F6E7420536F66747761726520776974686F7574
+207072696F72207772697474656E20617574686F72697A6174696F6E2066726F6D207468
+6520476E6F6D6520466F756E646174696F6E206F722042697473747265616D20496E632E
+2C20726573706563746976656C792E20466F72206675727468657220696E666F726D6174
+696F6E2C20636F6E746163743A20666F6E747320617420676E6F6D6520646F74206F7267
+2E687474703A2F2F7777772E62697473747265616D2E636F6D0043006F00700079007200
+690067006800740020002800630029002000320030003000330020006200790020004200
+69007400730074007200650061006D002C00200049006E0063002E00200041006C006C00
+20005200690067006800740073002000520065007300650072007600650064002E004200
+69007400730074007200650061006D00200056006500720061002000530061006E007300
+420069007400730074007200650061006D005600650072006100530061006E0073002D00
+52006F006D0061006E00520065006C006500610073006500200031002E00310030004300
+6F0070007900720069006700680074002000280063002900200032003000300033002000
+620079002000420069007400730074007200650061006D002C00200049006E0063002E00
+0D000A0041006C006C002000520069006700680074007300200052006500730065007200
+7600650064002E000D000A00420069007400730074007200650061006D00200056006500
+72006100200069007300200061002000740072006100640065006D00610072006B002000
+6F0066002000420069007400730074007200650061006D002C00200049006E0063002E00
+0D000A000D000A005000650072006D0069007300730069006F006E002000690073002000
+68006500720065006200790020006700720061006E007400650064002C00200066007200
+6500650020006F00660020006300680061007200670065002C00200074006F0020006100
+6E007900200070006500720073006F006E0020006F0062007400610069006E0069006E00
+670020006100200063006F007000790020006F0066002000740068006500200066006F00
+6E007400730020006100630063006F006D00700061006E00790069006E00670020007400
+68006900730020006C006900630065006E007300650020002800220046006F006E007400
+730022002900200061006E00640020006100730073006F00630069006100740065006400
+200064006F00630075006D0065006E0074006100740069006F006E002000660069006C00
+65007300200028007400680065002000220046006F006E007400200053006F0066007400
+7700610072006500220029002C00200074006F00200072006500700072006F0064007500
+63006500200061006E006400200064006900730074007200690062007500740065002000
+740068006500200046006F006E007400200053006F006600740077006100720065002C00
+200069006E0063006C007500640069006E006700200077006900740068006F0075007400
+20006C0069006D00690074006100740069006F006E002000740068006500200072006900
+6700680074007300200074006F0020007500730065002C00200063006F00700079002C00
+20006D0065007200670065002C0020007000750062006C006900730068002C0020006400
+6900730074007200690062007500740065002C00200061006E0064002F006F0072002000
+730065006C006C00200063006F00700069006500730020006F0066002000740068006500
+200046006F006E007400200053006F006600740077006100720065002C00200061006E00
+6400200074006F0020007000650072006D0069007400200070006500720073006F006E00
+7300200074006F002000770068006F006D002000740068006500200046006F006E007400
+200053006F0066007400770061007200650020006900730020006600750072006E006900
+7300680065006400200074006F00200064006F00200073006F002C002000730075006200
+6A00650063007400200074006F002000740068006500200066006F006C006C006F007700
+69006E006700200063006F006E0064006900740069006F006E0073003A000D000A000D00
+0A005400680065002000610062006F0076006500200063006F0070007900720069006700
+68007400200061006E0064002000740072006100640065006D00610072006B0020006E00
+6F0074006900630065007300200061006E00640020007400680069007300200070006500
+72006D0069007300730069006F006E0020006E006F007400690063006500200073006800
+61006C006C00200062006500200069006E0063006C007500640065006400200069006E00
+200061006C006C00200063006F00700069006500730020006F00660020006F006E006500
+20006F00720020006D006F007200650020006F0066002000740068006500200046006F00
+6E007400200053006F006600740077006100720065002000740079007000650066006100
+6300650073002E000D000A000D000A00540068006500200046006F006E00740020005300
+6F0066007400770061007200650020006D006100790020006200650020006D006F006400
+690066006900650064002C00200061006C00740065007200650064002C0020006F007200
+200061006400640065006400200074006F002C00200061006E006400200069006E002000
+70006100720074006900630075006C006100720020007400680065002000640065007300
+690067006E00730020006F006600200067006C00790070006800730020006F0072002000
+6300680061007200610063007400650072007300200069006E0020007400680065002000
+46006F006E007400730020006D006100790020006200650020006D006F00640069006600
+690065006400200061006E00640020006100640064006900740069006F006E0061006C00
+200067006C00790070006800730020006F00720020006300680061007200610063007400
+65007200730020006D006100790020006200650020006100640064006500640020007400
+6F002000740068006500200046006F006E00740073002C0020006F006E006C0079002000
+690066002000740068006500200066006F006E0074007300200061007200650020007200
+65006E0061006D0065006400200074006F0020006E0061006D006500730020006E006F00
+7400200063006F006E007400610069006E0069006E006700200065006900740068006500
+72002000740068006500200077006F007200640073002000220042006900740073007400
+7200650061006D00220020006F0072002000740068006500200077006F00720064002000
+2200560065007200610022002E000D000A000D000A00540068006900730020004C006900
+630065006E007300650020006200650063006F006D006500730020006E0075006C006C00
+200061006E006400200076006F0069006400200074006F00200074006800650020006500
+7800740065006E00740020006100700070006C0069006300610062006C00650020007400
+6F00200046006F006E007400730020006F007200200046006F006E007400200053006F00
+660074007700610072006500200074006800610074002000680061007300200062006500
+65006E0020006D006F00640069006600690065006400200061006E006400200069007300
+200064006900730074007200690062007500740065006400200075006E00640065007200
+200074006800650020002200420069007400730074007200650061006D00200056006500
+72006100220020006E0061006D00650073002E000D000A000D000A005400680065002000
+46006F006E007400200053006F0066007400770061007200650020006D00610079002000
+62006500200073006F006C0064002000610073002000700061007200740020006F006600
+2000610020006C0061007200670065007200200073006F00660074007700610072006500
+20007000610063006B00610067006500200062007500740020006E006F00200063006F00
+7000790020006F00660020006F006E00650020006F00720020006D006F00720065002000
+6F0066002000740068006500200046006F006E007400200053006F006600740077006100
+72006500200074007900700065006600610063006500730020006D006100790020006200
+6500200073006F006C006400200062007900200069007400730065006C0066002E000D00
+0A000D000A00540048004500200046004F004E005400200053004F004600540057004100
+520045002000490053002000500052004F00560049004400450044002000220041005300
+20004900530022002C00200057004900540048004F005500540020005700410052005200
+41004E005400590020004F004600200041004E00590020004B0049004E0044002C002000
+450058005000520045005300530020004F005200200049004D0050004C00490045004400
+2C00200049004E0043004C005500440049004E004700200042005500540020004E004F00
+540020004C0049004D004900540045004400200054004F00200041004E00590020005700
+41005200520041004E00540049004500530020004F00460020004D004500520043004800
+41004E0054004100420049004C004900540059002C0020004600490054004E0045005300
+5300200046004F00520020004100200050004100520054004900430055004C0041005200
+200050005500520050004F0053004500200041004E00440020004E004F004E0049004E00
+4600520049004E00470045004D0045004E00540020004F004600200043004F0050005900
+520049004700480054002C00200050004100540045004E0054002C002000540052004100
+440045004D00410052004B002C0020004F00520020004F00540048004500520020005200
+49004700480054002E00200049004E0020004E004F0020004500560045004E0054002000
+5300480041004C004C002000420049005400530054005200450041004D0020004F005200
+2000540048004500200047004E004F004D004500200046004F0055004E00440041005400
+49004F004E0020004200450020004C004900410042004C004500200046004F0052002000
+41004E005900200043004C00410049004D002C002000440041004D004100470045005300
+20004F00520020004F00540048004500520020004C0049004100420049004C0049005400
+59002C00200049004E0043004C005500440049004E004700200041004E00590020004700
+45004E004500520041004C002C0020005300500045004300490041004C002C0020004900
+4E004400490052004500430054002C00200049004E0043004900440045004E0054004100
+4C002C0020004F005200200043004F004E00530045005100550045004E00540049004100
+4C002000440041004D0041004700450053002C0020005700480045005400480045005200
+200049004E00200041004E00200041004300540049004F004E0020004F00460020004300
+4F004E00540052004100430054002C00200054004F005200540020004F00520020004F00
+540048004500520057004900530045002C002000410052004900530049004E0047002000
+460052004F004D002C0020004F005500540020004F004600200054004800450020005500
+5300450020004F005200200049004E004100420049004C00490054005900200054004F00
+20005500530045002000540048004500200046004F004E005400200053004F0046005400
+570041005200450020004F0052002000460052004F004D0020004F005400480045005200
+20004400450041004C0049004E0047005300200049004E00200054004800450020004600
+4F004E005400200053004F004600540057004100520045002E000D000A000D000A004500
+78006300650070007400200061007300200063006F006E007400610069006E0065006400
+200069006E002000740068006900730020006E006F0074006900630065002C0020007400
+6800650020006E0061006D006500730020006F006600200047006E006F006D0065002C00
+2000740068006500200047006E006F006D006500200046006F0075006E00640061007400
+69006F006E002C00200061006E0064002000420069007400730074007200650061006D00
+200049006E0063002E002C0020007300680061006C006C0020006E006F00740020006200
+650020007500730065006400200069006E00200061006400760065007200740069007300
+69006E00670020006F00720020006F007400680065007200770069007300650020007400
+6F002000700072006F006D006F007400650020007400680065002000730061006C006500
+2C00200075007300650020006F00720020006F0074006800650072002000640065006100
+6C0069006E0067007300200069006E0020007400680069007300200046006F006E007400
+200053006F00660074007700610072006500200077006900740068006F00750074002000
+7000720069006F00720020007700720069007400740065006E0020006100750074006800
+6F00720069007A006100740069006F006E002000660072006F006D002000740068006500
+200047006E006F006D006500200046006F0075006E0064006100740069006F006E002000
+6F0072002000420069007400730074007200650061006D00200049006E0063002E002C00
+200072006500730070006500630074006900760065006C0079002E00200046006F007200
+20006600750072007400680065007200200069006E0066006F0072006D00610074006900
+6F006E002C00200063006F006E0074006100630074003A00200066006F006E0074007300
+200061007400200067006E006F006D006500200064006F00740020006F00720067002E00
+68007400740070003A002F002F007700770077002E006200690074007300740072006500
+61006D002E0063006F006D00013500B800CB00CB00C100AA009C01A600B8006600000071
+00CB00A002B20085007500B800C301CB0189022D00CB00A600F000D300AA008700CB03AA
+0400014A003300CB000000D9050200F4015400B4009C01390114013907060400044E04B4
+045204B804E704CD0037047304CD04600473013303A2055605A60556053903C5021200C9
+001F00B801DF007300BA03E9033303BC0444040E00DF03CD03AA00E503AA0404000000CB
+008F00A4007B00B80014016F007F027B0252008F00C705CD009A009A006F00CB00CD019E
+01D300F000BA018300D5009803040248009E01D500C100CB00F600830354027F00000333
+026600D300C700A400CD008F009A0073040005D5010A00FE022B00A400B4009C00000062
+009C0000001D032D05D505D505D505F0007F007B005400A406B80614072301D300B800CB
+00A601C301EC069300A000D3035C037103DB0185042304A80448008F0139011401390360
+008F05D5019A0614072306660179046004600460047B009C00000277046001AA00E90460
+0762007B00C5007F027B000000B4025205CD006600BC00660077061000CD013B01850389
+008F007B0000001D00CD074A042F009C009C0000077D006F0000006F0335006A006F007B
+00AE00B2002D0396008F027B00F600830354063705F6008F009C04E10266008F018D02F6
+00CD03440029006604EE007300001400B8028040FFFBFE03FA1403F92503F83203F79603
+F60E03F5FE03F4FE03F32503F20E03F19603F02503EF8A4105EFFE03EE9603ED9603ECFA
+03EBFA03EAFE03E93A03E84203E7FE03E63203E5E45305E59603E48A4105E45303E3E22F
+05E3FA03E22F03E1FE03E0FE03DF3203DE1403DD9603DCFE03DB1203DA7D03D9BB03D8FE
+03D68A4105D67D03D5D44705D57D03D44703D3D21B05D3FE03D21B03D1FE03D0FE03CFFE
+03CEFE03CD9603CCCB1E05CCFE03CB1E03CA3203C9FE03C6851105C61C03C51603C4FE03
+C3FE03C2FE03C1FE03C0FE03BFFE03BEFE03BDFE03BCFE03BBFE03BA1103B9862505B9FE
+03B8B7BB05B8FE03B7B65D05B7BB03B78004B6B52505B65D40FF03B64004B52503B4FE03
+B39603B2FE03B1FE03B0FE03AFFE03AE6403AD0E03ACAB2505AC6403ABAA1205AB2503AA
+1203A98A4105A9FA03A8FE03A7FE03A6FE03A51203A4FE03A3A20E05A33203A20E03A164
+03A08A4105A096039FFE039E9D0C059EFE039D0C039C9B19059C64039B9A10059B19039A
+1003990A0398FE0397960D0597FE03960D03958A410595960394930E05942803930E0392
+FA039190BB0591FE03908F5D0590BB039080048F8E25058F5D038F40048E25038DFE038C
+8B2E058CFE038B2E038A8625058A410389880B05891403880B0387862505876403868511
+0586250385110384FE038382110583FE0382110381FE0380FE037FFE0340FF7E7D7D057E
+FE037D7D037C64037B5415057B25037AFE0379FE03780E03770C03760A0375FE0374FA03
+73FA0372FA0371FA0370FE036FFE036EFE036C21036BFE036A1142056A530369FE03687D
+036711420566FE0365FE0364FE0363FE0362FE03613A0360FA035E0C035DFE035BFE035A
+FE0359580A0559FA03580A035716190557320356FE035554150555420354150353011005
+531803521403514A130551FE03500B034FFE034E4D10054EFE034D10034CFE034B4A1305
+4BFE034A4910054A1303491D0D05491003480D0347FE0346960345960344FE0343022D05
+43FA0342BB03414B0340FE033FFE033E3D12053E14033D3C0F053D12033C3B0D053C40FF
+0F033B0D033AFE0339FE033837140538FA033736100537140336350B05361003350B0334
+1E03330D0332310B0532FE03310B03302F0B05300D032F0B032E2D09052E10032D09032C
+32032B2A25052B64032A2912052A25032912032827250528410327250326250B05260F03
+250B0324FE0323FE03220F03210110052112032064031FFA031E1D0D051E64031D0D031C
+1142051CFE031BFA031A42031911420519FE031864031716190517FE0316011005161903
+15FE0314FE0313FE031211420512FE0311022D05114203107D030F64030EFE030D0C1605
+0DFE030C0110050C16030BFE030A100309FE0308022D0508FE0307140306640304011005
+04FE03401503022D0503FE0302011005022D0301100300FE0301B80164858D012B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B002B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B1DB6060504
+030201002C2010B002254964B040515820C859212D2CB002254964B040515820C859212D
+2C20100720B00050B00D7920B8FFFF5058041B0559B0051CB0032508B0042523E120B000
+50B00D7920B8FFFF5058041B0559B0051CB0032508E12D2C4B505820B0FD454459212D2C
+B002254560442D2C4B5358B00225B0022545445921212D2C45442D0000020066FE960466
+05A400030007001A400C04FB0006FB0108057F0204002FC4D4EC310010D4ECD4EC301311
+211125211121660400FC73031BFCE5FE96070EF8F2720629000201350000020005D50003
+00090040400F07008304810208070501030400000A10FC3CEC32393931002FE4FCCC3001
+4BB00B5458BD000A00400001000A000AFFC03811373859B6000B200B500B035D25331523
+1133110323030135CBCBCB14A215FEFE05D5FD71FE9B0165000200C503AA02E905D50003
+0007004D400F05018404008108040506000502040810FCFCDCEC310010F43CEC3230014B
+B012544BB013545B58BD00080040000100080008FFC03811373859400F30094009500960
+097009A009BF09075D0111231121112311016FAA0224AA05D5FDD5022BFDD5022B000002
+009E0000061705BE0003001F006040311B0B008707041D0905190D028717130F15111F1E
+1C1B1A17161514131211100E0D0C090807060504030201001A0A18062010FCCC17393100
+2F3CD43C3CFC3C3CD43C3CC432EC32323040110B010B020B0C0B0D14041A111A12141F08
+015D012103210B0121133303211521032115210323132103231321352113213521130417
+FEDD5401254468012469A0670138FEA152013EFE9B68A067FEDB67A168FEC5016054FEBE
+0169660385FEB20387FE61019FFE619AFEB299FE62019EFE62019E99014E9A019F000003
+00AAFED3046D061400210028002F00D5405522020A0B0A27012628020B0B0A1D011E1C02
+2F292F1B0229292F42131110220A1B29041706092A21050217861606860511231A8A1689
+10002A8A0589022D08160A1E07291A1203000922100903010726080D05063010FC3CECF4
+173CFC173CF4E4EC31002FE4ECC4D4E4EC32C410EE10EE11123911391112173911123930
+4B5358071004ED07100EED11173907100EED111739071004ED5922014BB0095458BD0030
+0040000100300030FFC03811373859014BB00C544BB010545B4BB00F545B58BD0030FFC0
+000100300030004038113738590123032E0127351E0117112E01353436373533151E0117
+152E0127111E011514060703110E0115141617113E0135342602B4640169D26A66D16FDD
+C9DACC645DAE5353AF5CE3D6E3D664747A71E17F817BFED3012D022D2DB440410101C824
+AC96A3BC0EEBE8041F1BAF2A2E04FE5523B49CA9C30F0300019A0D6A585660D5FE4F116E
+5A58680000050071FFE3072905F0000B001700230027003300954036240F252625260F27
+24274200920C1E922E8D18922406920C8D26128C2824913427211B2509030D150E090D0F
+210D2B0E1B0D0F310B3410FCC4ECF4EC10EEF6EE1139111239310010E432F43CE4EC10EE
+F6EE10EE304B5358071005ED071005ED5922014BB009544BB00B545B4BB00C545B4BB014
+545B4BB00E545B4BB00D545B58BD00340040000100340034FFC038113738590122061514
+163332363534262732161514062322263534360122061514163332363534262533012313
+321615140623222635343605D157636357556363559EBABB9DA0BABBFC97566362575763
+640331A0FC5AA01F9EBCBB9F9FB9BA029194848295958283957FDCBBBBDBDBBBBCDB0261
+95828494948481967FF9F3060DDBBBBDDADBBCBADC0000020081FFE305FE05F000090030
+01CD40960D010E0C861112110B860A0B1212110986000915161507010608861616150201
+0301861D1E1D008609001E1E1D201F02211E110A130A17161503181411130A0708020609
+1113130A0201020300110A130A171602181511130A141113130A42120B090306000A1E03
+28150E0628270695182B9527942491188C0E130A2E0B0E09002E1215270E1E032E122721
+0E110F132103121B103110FCECC4D4D4EC10C6EE1139111239391139391139113931002F
+C6E4F6E6EE10EE10C6111239111739111739304B5358071005ED0705ED111739071005ED
+111739071005ED1117390705ED111739071005ED111739071008ED07100EED1117390710
+0EED111739071008ED071008ED07100EED1117395922B20F3201015D40B2070B05220929
+1C001C011F02170B2A002A0126123A003412440B5E0059015A0A55125A1A5A1F5930671E
+7B009B009A0199029708950B931595169522992D1F090B090C08110C270C2818021B0919
+0B190C19111C141C15161D1F3227002701290923122A132A1428152F323B09341239133F
+324A094C144B1546194F3256015A09590C551259135C1F5F326A0C691160327501790C7A
+1193009301970295059C079C089F089A099B0B9A0C9032A032B032395D005D010E011514
+163332363709013E0137330602070123270E01232200353436372E013534363332161715
+2E0123220615141601F25B55D4A05FA649FE7B01FC3B4206BA0C685D0117FC8F68E483F1
+FECE86863032DEB853A555579E4469833B032351A15892C23F40028FFDF859CB7284FEFE
+7EFEE39359570113D780E1633F7D3CA2C52424B62F316F583367000100C503AA016F05D5
+00030042400A0184008104000502040410FCEC310010F4EC30014BB012544BB013545B58
+BD00040040000100040004FFC03811373859400D40055005600570059005A005065D0111
+2311016FAA05D5FDD5022B00000100B0FEF2027B0612000D004F400F069800970E0D0700
+03120600130A0E10DCE432EC113939310010FCEC30014BB0135458BD000E00400001000E
+000EFFC03811373859014BB00F5458BD000EFFC00001000E000E00403811373859010602
+1514121723260235341237027B86828385A0969594970612E6FE3EE7E7FE3BE5EB01C6E0
+DF01C4EC000100A4FEF2026F0612000D001F400F079800970E0701000B12041308000E10
+DC3CF4EC113939310010FCEC301333161215140207233612353402A4A096959596A08583
+830612ECFE3CDFE0FE3AEBE501C5E7E701C20001003D024A03C305F00011004E402C100D
+0B00040C090704020408039905110C990A010E9112080C0A030906110301030200140F04
+0B09140D061210D43CE432DC3CE432173911121739310010F4D43CEC32C4EC3217391217
+393001050507251123110527252537051133112503C3FE9901673AFEB072FEB03A0167FE
+993A015072015004DFC2C362CBFE870179CB62C3C263CB0179FE87CB000100D9000005DB
+0504000B002340110009019C07030502150400170A0615080C10DCFC3CFC3CEC31002FD4
+3CFC3CC43001112115211123112135211103AE022DFDD3A8FDD3022D0504FDD3AAFDD302
+2DAA022D0001009EFF1201C300FE00050019400C039E0083060304011900180610FCECD4
+CC310010FCEC30373315032313F0D3A48152FEACFEC001400001006401DF027F02830003
+0011B6009C020401000410DCCC310010D4EC301321152164021BFDE50283A400000100DB
+000001AE00FE00030011B7008302011900180410FCEC31002FEC3037331523DBD3D3FEFE
+00010000FF4202B205D50003002D4014001A010201021A03000342029F00810402000103
+2FC43939310010F4EC304B5358071005ED071005ED5922013301230208AAFDF8AA05D5F9
+6D0000020087FFE3048F05F0000B00170023401306A01200A00C91128C18091C0F1E031C
+151B1810FCECF4EC310010E4F4EC10EE3001220211101233321211100227320011100023
+2200111000028B9C9D9D9C9D9D9D9DFB0109FEF7FBFBFEF701090550FECDFECCFECDFECD
+0133013301340133A0FE73FE86FE87FE73018D0179017A018D00000100E10000045A05D5
+000A004B40154203A00402A005810700A009081F061C03001F010B10D4ECC4FCEC31002F
+EC32F4ECD4EC304B53585922014BB00F5458BD000BFFC00001000B000B00403811373859
+B40F030F04025D3721110535253311211521FE014AFE990165CA014AFCA4AA047348B848
+FAD5AA00000100960000044A05F0001C00A54027191A1B03181C11050400110505044210
+A111940DA014910400A00200100A02010A1C171003061D10FCC4D4ECC0C011123931002F
+EC32F4ECF4EC304B5358071005ED0705ED1117395922014BB015544BB016545B4BB01454
+5B58BD001D00400001001D001DFFC0381137385940325504560556077A047A05761B8719
+0704000419041A041B051C74007606751A731B741C82008619821A821B821CA800A81B11
+5D005D25211521353600373E0135342623220607353E01333204151406070600018902C1
+FC4C73018D33614DA7865FD3787AD458E80114455B19FEF4AAAAAA7701913A6D97497796
+4243CC3132E8C25CA5701DFEEB000001009CFFE3047305F00028007B402E0015130A8609
+1F862013A0150DA00993061CA020932391068C15A329161C13000314191C2620101C0314
+1F09062910FCC4C4D4ECF4EC11173939310010ECE4F4E4EC10E6EE10EE10EE10EE111239
+30014BB016544BB014545B58BD00290040000100290029FFC038113738594009641E611F
+6120642104005D011E0115140421222627351E013332363534262B013533323635342623
+220607353E01333204151406033F91A3FED0FEE85EC76A54C86DBEC7B9A5AEB6959EA398
+53BE7273C959E6010C8E03251FC490DDF22525C33132968F8495A67770737B2426B42020
+D1B27CAB00020064000004A405D50002000D008C401D010D030D0003030D4200030B07A0
+0501038109010C0A001C0608040C0E10DCD43CC4EC32113931002FE4D43CEC321239304B
+5358071004C9071005C95922014BB00B544BB00D545B58BD000E00400001000E000EFFC0
+3811373859402A0B002A0048005900690077008A000716012B0026012B0336014E014F0C
+4F0D5601660175017A0385010D5D005D09012103331133152311231121350306FE0201FE
+35FED5D5C9FD5E0525FCE303CDFC33A8FEA00160C3000001009EFFE3046405D5001D0075
+4023041A071186101D1AA00714A010890D02A000810D8C07A41E171C010A031C000A1006
+1E10FCC4D4EC10C4EE310010E4E4F4EC10E6EE10FEC410EE11123930014BB016544BB014
+545B58BD001E00400001001E001EFFC03811373859014BB00F5458BD001EFFC00001001E
+001E0040381137385913211521113E0133320015140021222627351E0133323635342623
+220607DD0319FDA02C582CFA0124FED4FEEF5EC3685AC06BADCACAAD51A15405D5AAFE92
+0F0FFEEEEAF1FEF52020CB3130B69C9CB62426000002008FFFE3049605F0000B00240058
+40241306000D860C00A01606A01C16A510A00C8922911C8C250C22091C191E131C03211F
+1B2510FCECECF4ECE4310010E4F4E4FCE410EE10EE10EE111239304014CB00CB01CD02CD
+03CD04CB05CB0607A41EB21E025D015D01220615141633323635342601152E0123220203
+3E0133320015140023200011100021321602A4889F9F88889F9F01094C9B4CC8D30F3BB2
+6BE10105FEF0E2FEFDFEEE0150011B4C9B033BBAA2A1BBBBA1A2BA0279B82426FEF2FEEF
+575DFEEFEBE6FEEA018D0179016201A51E00000100A80000046805D50006006340180511
+02030203110405044205A0008103050301040100060710FCCCC411393931002FF4EC304B
+5358071005ED071005ED5922014BB0165458BD00070040000100070007FFC03811373859
+401258020106031A05390548056703B000B006075D005D13211501230121A803C0FDE2D3
+01FEFD3305D556FA81052B000003008BFFE3048B05F0000B0023002F00434025180C00A0
+2706A01E2DA012911E8C27A330180C242A1C15241C0F091C151B1E031C0F211B3010FCC4
+ECF4C4EC10EE10EE113939310010ECE4F4EC10EE10EE3939300122061514163332363534
+262526263534363332161514060716161514042322243534361314163332363534262322
+06028B90A5A59090A6A5FEA58291FFDEDFFE918192A3FEF7F7F7FEF7A448918382939382
+839102C59A87879A9B86879A5620B280B3D0D0B380B22022C68FD9E8E8D98FC601617482
+82747482820000020081FFE3048705F00018002400584023071F1901860019A00AA504A0
+0089161FA01091168C25071C1C21131E0022221C0D1B2510FCECE4F4ECEC310010E4F4EC
+10E6FEF5EE10EE111239304016C419C21AC01BC01CC01DC21EC41F07AA12BC12E912035D
+015D37351E01333212130E01232200353400332000111000212226013236353426232206
+151416E14C9C4BC8D30F3AB26CE0FEFB0110E201030111FEB1FEE54C9C013E889F9F8888
+9F9F1FB82426010D0112565C010FEBE60116FE73FE86FE9FFE5B1E0297BAA2A1BBBBA1A2
+BA00000200F0000001C3042300030007001C400E068304A60083020501030400180810FC
+3CEC3231002FECF4EC303733152311331523F0D3D3D3D3FEFE0423FE0002009EFF1201C3
+04230003000900254013028300079E048300A60A07080501190400180A10FC3CEC32D4CC
+310010E4FCEC10EE3013331523113315032313F0D3D3D3A481520423FEFDD9ACFEC00140
+000100D9005E05DB04A60006004D402A029C030403019C0001040403019C020105060500
+9C06054205040201000503A806A7070102002404230710FCEC3239310010F4EC1739304B
+53580704ED071008ED071008ED071004ED592209021501350105DBFBF80408FAFE050203
+F0FE91FE93B601D1A601D100000200D9016005DB03A200030007001C400D009C02069C04
+0805010400230810FC3CC432310010D4ECD4EC301321152115211521D90502FAFE0502FA
+FE03A2A8F0AA000100D9005E05DB04A60006004F402B069C0006030403059C040403009C
+010201069C05060202014206050302000504A801A7070602240400230710FC3CEC393100
+10F4EC1739304B5358071008ED071004ED071004ED071008ED592213350115013501D905
+02FAFE040603F0B6FE2FA6FE2FB6016D00020093000003B005F0000300240070402B241E
+0906040A1D13040014861388109517910083021D1A0D0905040A1E010D1C1A041C050103
+00261A132510DCC4FCECD4EC10EE11393911123911123931002FEEF6FEF4EE10CD113939
+173930014BB00C5458BD00250040000100250025FFC03811373859B679097A0A7A20035D
+2533152313233534363F013E0135342623220607353E013332161514060F010E01070E01
+150187CBCBC5BF385A5A3933836C4FB3615EC167B8DF485A582F27080606FEFE01919A65
+825659355E31596E4643BC3938C29F4C8956562F3519153C340000020087FE9C077105A2
+000B004C00954032180C0309A919151B03A94C0F34330FAC30A93715AC24A937434D3334
+1E1A00281206180C281A2B1E2849122B2A28492C3D4D10DCECFCEC10FEFDFE3CC610EE11
+123939310010D4C4FCEC10FEEDD4C610C5EE3210C4EE11393930004BB009544BB00C545B
+4BB010545B4BB013545B4BB014545B58BD004DFFC00001004D004D004038113738594009
+0F4E1F4E2F4E3F4E04015D011416333236353426232206010E0123222635343633321617
+3533113E0135342627262423220607060215141217160433323637170604232224272602
+353412373624333204171E011510000502FA8E7C7B8D907A798F02213C9B67ACD7D8AB67
+9C3B8F92A53F4068FED5B07BE2609DB1736D6901149D81F9685A7DFED998B9FEB8808086
+887E810152BDD4016B7B4B4FFEC2FEE802198FA3A48E8CA5A4FE484D49F9C8C8FA4B4C83
+FD2016DFB16BBC50838B414066FEB5C19FFEEA6A686D57516F6167837D7D0149BDB6014A
+7D7F87AEA062E67BFEF9FED00600000200100000056805D50002000A00BA404100110100
+040504021105050401110A030A0011020003030A0711050406110505040911030A08110A
+030A4200030795010381090509080706040302010009050A0B10D4C4173931002F3CE4D4
+EC1239304B5358071005ED0705ED071005ED0705ED071008ED071005ED071005ED071008
+ED5922B2200C01015D403A0F005800760070008C00050701080206030904160119025601
+5802500C67016802780176027C0372047707780887018802800C980299039604175D005D
+090121013301230321032302BCFEEE0225FE7BE50239D288FD5F88D5050EFD1903AEFA2B
+017FFE81000300C9000004EC05D5000800110020004340231900950A0995128101950AAD
+1F110B080213191F05000E1C1605191C2E09001C12042110FCEC32FCECD4EC1117393939
+31002FECECF4EC10EE3930B20F2201015D01112132363534262301112132363534262325
+213216151406071E01151404232101930144A39D9DA3FEBC012B94919194FE0B0204E7FA
+807C95A5FEF0FBFDE802C9FDDD878B8C850266FE3E6F727170A6C0B189A21420CB98C8DA
+00010073FFE3052705F000190036401A0DA10EAE0A951101A100AE04951791118C1A0719
+0D003014101A10FCEC32EC310010E4F4ECF4EC10EEF6EE30B40F1B1F1B02015D01152E01
+23200011100021323637150E01232000111000213216052766E782FF00FEF00110010082
+E7666AED84FEADFE7A0186015386ED0562D55F5EFEC7FED8FED9FEC75E5FD34848019F01
+670168019F47000200C9000005B005D500080011002E4015009509810195100802100A00
+05190D32001C09041210FCECF4EC113939393931002FECF4EC30B2601301015D01113320
+00111000212521200011100029010193F40135011FFEE1FECBFE42019F01B20196FE68FE
+50FE61052FFB770118012E012C0117A6FE97FE80FE7EFE96000100C90000048B05D5000B
+002E401506950402950081089504AD0A05010907031C00040C10FCEC32D4C4C431002FEC
+ECF4EC10EE30B21F0D01015D132115211121152111211521C903B0FD1A02C7FD3902F8FC
+3E05D5AAFE46AAFDE3AA000100C90000042305D50009002940120695040295008104AD08
+050107031C00040A10FCEC32D4C431002FECF4EC10EE30B20F0B01015D13211521112115
+211123C9035AFD700250FDB0CA05D5AAFE48AAFD370000010073FFE3058B05F0001D0039
+402000051B0195031B950812A111AE15950E91088C1E02001C1134043318190B101E10FC
+ECFCE4FCC4310010E4F4ECF4EC10FED4EE11393930251121352111060423200011100021
+32041715262623200011100021323604C3FEB6021275FEE6A0FEA2FE75018B015E920107
+6F70FC8BFEEEFEED011301126BA8D50191A6FD7F53550199016D016E01994846D75F60FE
+CEFED1FED2FECE25000100C90000053B05D5000B002C4014089502AD0400810A0607031C
+053809011C00040C10FCEC32FCEC3231002F3CE432FCEC30B2500D01015D133311211133
+112311211123C9CA02DECACAFD22CA05D5FD9C0264FA2B02C7FD3900000100C900000193
+05D500030039B700AF02011C00040410FCEC31002FEC30014BB0105458BD0004FFC00001
+0004000400403811373859400D30054005500560058F059F05065D13331123C9CACA05D5
+FA2B0001FF96FE66019305D5000B004D40130B0200079505B000810C05080639011C0004
+0C10FCECE43939310010E4FCEC11393930014BB0105458BD000CFFC00001000C000C0040
+3811373859400D300D400D500D600D8F0D9F0D065D13331110062B013533323635C9CACD
+E34D3F866E05D5FA93FEF2F4AA96C200000100C90000056A05D5000A00EF402808110506
+0507110606050311040504021105050442080502030300AF09060501040608011C00040B
+10FCEC32D4C4113931002F3CEC321739304B5358071004ED071005ED071005ED071004ED
+5922B2080301015D40921402010402090816022805280837023605340847024605430855
+02670276027705830288058F0894029B08E702150603090509061B031907050A030A0718
+0328052B062A073604360536063507300C41034004450540064007400C62036004680567
+077705700C8B038B058E068F078F0C9A039D069D07B603B507C503C507D703D607E803E9
+04E805EA06F703F805F9062C5D71005D711333110121090121011123C9CA029E0104FD1B
+031AFEF6FD33CA05D5FD890277FD48FCE302CFFD3100000100C90000046A05D500050025
+400C0295008104011C033A00040610FCECEC31002FE4EC30400930075007800380040401
+5D133311211521C9CA02D7FC5F05D5FAD5AA000100C90000061F05D5000C00BF40340311
+0708070211010208080702110302090A0901110A0A09420A070203080300AF080B050908
+030201050A061C043E0A1C00040D10FCECFCEC11173931002F3CC4EC32111739304B5358
+071005ED071008ED071008ED071005ED5922B2700E01015D405603070F080F09020A1502
+1407130A260226072007260A200A3407350A69027C027B07790A80028207820A90021604
+010B0313011B0323012C032708280934013C035608590965086A097608790981018D0395
+019B03145D005D13210901211123110123011123C9012D017D017F012DC5FE7FCBFE7FC4
+05D5FC0803F8FA2B051FFC000400FAE1000100C90000053305D500090079401E07110102
+0102110607064207020300AF0805060107021C0436071C00040A10FCECFCEC1139393100
+2F3CEC323939304B5358071004ED071004ED5922B21F0B01015D40303602380748024707
+690266078002070601090615011A06460149065701580665016906790685018A0695019A
+069F0B105D005D13210111331121011123C901100296C4FEF0FD6AC405D5FB1F04E1FA2B
+04E1FB1F00020073FFE305D905F0000B00170023401306951200950C91128C1809190F33
+031915101810FCECFCEC310010E4F4EC10EE300122001110003332001110002720001110
+002120001110000327DCFEFD0103DCDC0101FEFFDC013A0178FE88FEC6FEC5FE87017905
+4CFEB8FEE5FEE6FEB80148011A011B0148A4FE5BFE9EFE9FFE5B01A40162016201A50002
+00C90000048D05D500080013003A40180195100095098112100A0802040005190D3F1100
+1C09041410FCEC32FCEC11173931002FF4ECD4EC30400B0F151F153F155F15AF1505015D
+011133323635342623252132041514042B0111230193FE8D9A9A8DFE3801C8FB0101FEFF
+FBFECA052FFDCF92878692A6E3DBDDE2FDA800020073FEF805D905F0000B001D0052402A
+1110020F010C0D0C0E010D0D0C420F1E0C06951200951891128C0D1E0D1B0F0C0309191B
+33031915101E10FCECFCEC1139391139310010C4E4F4EC10EE391239304B5358071005ED
+071005ED1739592201220011100033320011100013012327060623200011100021200011
+10020327DCFEFD0103DCDC0101FEFF3F010AF4DD212310FEC5FE870179013B013A0178D1
+054CFEB8FEE5FEE6FEB80148011A011B0148FACFFEDDEF020201A50161016201A5FE5BFE
+9EFEFCFE8E00000200C90000055405D50013001C00B14035090807030A06110304030511
+0404034206040015030415950914950D810B040506031109001C160E050A191904113F14
+0A1C0C041D10FCEC32FCC4EC1117391139393931002F3CF4ECD4EC123912391239304B53
+58071005ED071005ED1117395922B2401E01015D40427A13010500050105020603070415
+00150114021603170425002501250226032706260726082609201E360136024601460268
+0575047505771388068807980698071F5D005D011E01171323032E012B01112311212016
+151406011133323635342623038D417B3ECDD9BF4A8B78DCCA01C80100FC83FD89FE9295
+959202BC16907EFE68017F9662FD8905D5D6D88DBA024FFDEE878383850000010087FFE3
+04A205F00027007E403C0D0C020E0B021E1F1E080902070A021F1F1E420A0B1E1F041501
+0015A11494189511049500942591118C281E0A0B1F1B0700221B190E2D071914222810DC
+C4ECFCECE4111239393939310010E4F4E4EC10EEF6EE10C6111739304B535807100EED11
+173907100EED1117395922B20F2901015DB61F292F294F29035D01152E01232206151416
+1F011E0115140421222627351E013332363534262F012E01353424333216044873CC5FA5
+B377A67AE2D7FEDDFEE76AEF807BEC72ADBC879A7BE2CA0117F569DA05A4C53736807663
+651F192BD9B6D9E0302FD04546887E6E7C1F182DC0ABC6E426000001FFFA000004E905D5
+0007004A400E0602950081040140031C0040050810D4E4FCE431002FF4EC3230014BB00A
+5458BD00080040000100080008FFC03811373859401300091F00100110021F0710094009
+70099F09095D03211521112311210604EFFDEECBFDEE05D5AAFAD5052B00000100B2FFE3
+052905D50011004B40160802110B0005950E8C09008112081C0A38011C00411210FCECFC
+EC310010E432F4EC113939393930014BB0105458BD00120040000100120012FFC0381137
+3859B61F138F139F13035D133311141633323635113311100021200011B2CBAEC3C2AECB
+FEDFFEE6FEE5FEDF05D5FC75F0D3D3F0038BFC5CFEDCFED6012A01240001001000000568
+05D5000600B7402704110506050311020306060503110403000100021101010042030401
+AF0006040302000505010710D4C4173931002FEC3239304B5358071005ED071008ED0710
+08ED071005ED5922B2500801015D406200032A03470447055A037D038303070600070208
+040906150114021A041A052A002601260229042905250620083800330133023C043C0537
+06480045014502490449054706590056066602690469057A007601760279047905750680
+0898009706295D005D21013309013301024AFDC6D301D901DAD2FDC705D5FB1704E9FA2B
+00010044000007A605D5000C017B4049051A0605090A09041A0A09031A0A0B0A021A0102
+0B0B0A061107080705110405080807021103020C000C011100000C420A050203060300AF
+0B080C0B0A09080605040302010B07000D10D4CC173931002F3CEC32321739304B535807
+1005ED071008ED071008ED071005ED071008ED071005ED0705ED071008ED5922B2000E01
+015D40F206020605020A000A000A120A2805240A200A3E023E05340A300A4C024D05420A
+400A59026A026B05670A600A7B027F027C057F05800A960295051D070009020803000406
+050005000601070408000807090009040A0A0C000E1A0315041508190C100E2004210520
+06200720082309240A250B200E200E3C023A033504330530083609390B3F0C300E460046
+014A0240044505400542064207420840084009440A4D0C400E400E58025608590C500E66
+026703610462056006600760086409640A640B770076017B027803770474057906790777
+087008780C7F0C7F0E860287038804890585098A0B8F0E97049F0EAF0E5B5D005D133309
+0133090133012309012344CC013A0139E3013A0139CDFE89FEFEC5FEC2FE05D5FB1204EE
+FB1204EEFA2B0510FAF00001003D0000053B05D5000B015D404609110A0B0A081107080B
+0B0A081109080506050711060605031104050402110102050504021103020B000B011100
+000B420B080502040300AF09060B08050204000406000A0C10D4C4DCC411173931002F3C
+EC321739304B5358071005ED071008ED071008ED071005ED071005ED071008ED071008ED
+071005ED5922014BB00C544BB00D545B4BB00E545B58BD000CFFC00001000C000C004038
+1137385940B80702080816021908170B2708270B34023808360B4B0858055B0866026B08
+7702770B8602800287058B08850B9402900297059D08960B1B0601090308070709160119
+0319071709100D260128022903260528072709290B200D350034013C033B043A063B0734
+09340A380B3F0D48094F0D580B5F0D650065016A036A046805690669076C096C0A780379
+06790778087D097F0A780B800080018302880385058408830B8F0D900090019402970597
+069508930B9F0DAF0D405D005D13330901330901230901230181D901730175D9FE200200
+D9FE5CFE59DA021505D5FDD5022BFD33FCF8027BFD85031D0001FFFC000004E705D50008
+0094402803110405040211010205050402110302080008011100000842020300AF060207
+0440051C0040070910D4E4FCE4123931002FEC3239304B5358071005ED071008ED071008
+ED071005ED5922B2000A01015D403C050214023502300230053008460240024005400851
+02510551086502840293021016011A031F0A2601290337013803400A670168037803700A
+9F0A0D5D005D03330901330111231104D9019E019BD9FDF0CB05D5FD9A0266FCF2FD3902
+C7000001005C0000051F05D50009009B401B031107080708110203024208950081039505
+08030001420400060A10DCC4D4E411393931002FECF4EC304B5358071005ED071005ED59
+22014BB009544BB00A545B58BD000A00400001000A000AFFC03811373859404005020A07
+18072902260738074802470748080905030B08000B16031A08100B2F0B350339083F0B47
+034A084F0B55035908660369086F0B770378087F0B9F0B165D005D132115012115213501
+21730495FC5003C7FB3D03B0FC6705D59AFB6FAA9A049100000100B0FEF2025806140007
+0053400F04A906B202A900B10805010343000810DCFCCC32310010FCECF4EC30014BB00C
+5458BD0008FFC000010008000800403811373859014BB012544BB013545B58BD00080040
+000100080008FFC038113738591321152311331521B001A8F0F0FE5806148FF9FC8F0001
+0000FF4202B205D50003002D4014021A010100001A03030242019F008104020001032FC4
+3939310010F4EC304B5358071005ED071005ED592213012301AA0208AAFDF805D5F96D06
+9300000100C7FEF2026F06140007003C401003A901B205A900B1080043040602040810FC
+3CDCEC310010FCECF4EC30014BB00F544BB010545B58BD0008FFC0000100080008004038
+113738590111213533112335026FFE58EFEF0614F8DE8F06048F000100D903A805DB05D5
+00060018400A0304010081070301050710DCCC39310010F4CC3239300101230101230103
+BC021FC9FE48FE48C9021F05D5FDD3018BFE75022D000001FFECFE1D0414FEAC0003000F
+B500A90100020410C4C43100D4EC30011521350414FBD8FEAC8F8F00000100AA04F00289
+066600030031400901B400B3040344010410DCEC310010F4EC30004BB009544BB00E545B
+58BD0004FFC00001000400040040381137385909012301016F011A99FEBA0666FE8A0176
+0002007BFFE3042D047B000A002500BC4027191F0B17090E00A91706B90E1120861FBA1C
+B923B8118C170C001703180D09080B1F030814452610FCECCCD4EC323211393931002FC4
+E4F4FCF4EC10C6EE10EE11391139123930406E301D301E301F3020302130223F27401D40
+1E401F402040214022501D501E501F50205021502250277027851D871E871F8720872185
+229027A027F0271E301E301F30203021401E401F40204021501E501F50205021601E601F
+60206021701E701F70207021801E801F80208021185D015D0122061514163332363D0137
+1123350E01232226353436332135342623220607353E0133321602BEDFAC816F99B9B8B8
+3FBC88ACCBFDFB0102A79760B65465BE5AF3F00233667B6273D9B4294CFD81AA6661C1A2
+BDC0127F8B2E2EAA2727FC00000200BAFFE304A40614000B001C0038401903B90C0F09B9
+18158C0FB81B971900121247180C06081A461D10FCEC3232F4EC31002FECE4F4C4EC10C6
+EE30B6601E801EA01E03015D013426232206151416333236013E01333212111002232226
+271523113303E5A79292A7A79292A7FD8E3AB17BCCFFFFCC7BB13AB9B9022FCBE7E7CBCB
+E7E702526461FEBCFEF8FEF8FEBC6164A806140000010071FFE303E7047B0019003F401B
+00860188040E860D880AB91104B917B8118C1A07120D004814451A10FCE432EC310010E4
+F4EC10FEF4EE10F5EE30400B0F1B101B801B901BA01B05015D01152E0123220615141633
+323637150E0123220011100021321603E74E9D50B3C6C6B3509D4E4DA55DFDFED6012D01
+0655A20435AC2B2BE3CDCDE32B2BAA2424013E010E0112013A2300020071FFE3045A0614
+0010001C003840191AB9000E14B905088C0EB801970317040008024711120B451D10FCEC
+F4EC323231002FECE4F4C4EC10C4EE30B6601E801EA01E03015D0111331123350E012322
+0211101233321601141633323635342623220603A2B8B83AB17CCBFFFFCB7CB1FDC7A792
+92A8A89292A703B6025EF9ECA86461014401080108014461FE15CBE7E7CBCBE7E7000002
+0071FFE3047F047B0014001B00704024001501098608880515A90105B90C01BB18B912B8
+0C8C1C1B1502081508004B02120F451C10FCECF4ECC4111239310010E4F4ECE410EE10EE
+10F4EE1112393040293F1D701DA01DD01DF01D053F003F013F023F153F1B052C072F082F
+092C0A6F006F016F026F156F1B095D71015D0115211E0133323637150E01232000111000
+333200072E0123220607047FFCB20CCDB76AC76263D06BFEF4FEC70129FCE20107B802A5
+889AB90E025E5ABEC73434AE2A2C0138010A01130143FEDDC497B4AE9E000001002F0000
+02F8061400130070401C0510010C08A906018700970E06BC0A02130700070905080D0F0B
+4C1410FC3CC4FC3CC4C412393931002FE432FCEC10EE3212393930014BB00A5458BD0014
+FFC000010014001400403811373859014BB00E5458BD00140040000100140014FFC03811
+373859B640155015A015035D01152322061D012115211123112335333534363302F8B063
+4D012FFED1B9B0B0AEBD0614995068638FFC2F03D18F4EBBAB0000020071FE56045A047B
+000B0028004A4023190C1D0912861316B90F03B92623B827BC09B90FBD1A1D261900080C
+4706121220452910FCC4ECF4EC323231002FC4E4ECE4F4C4EC10FED5EE1112393930B660
+2A802AA02A03015D01342623220615141633323617100221222627351E013332363D010E
+0123220211101233321617353303A2A59594A5A59495A5B8FEFEFA61AC51519E52B5B439
+B27CCEFCFCCE7CB239B8023DC8DCDCC8C7DCDCEBFEE2FEE91D1EB32C2ABDBF5B6362013A
+01030104013A6263AA00000100BA000004640614001300344019030900030E0106870E11
+B80C970A010208004E0D09080B461410FCEC32F4EC31002F3CECF4C4EC1112173930B260
+1501015D0111231134262322061511231133113E013332160464B87C7C95ACB9B942B375
+C1C602A4FD5C029E9F9EBEA4FD870614FD9E6564EF00000200C100000179061400030007
+002B400E06BE04B100BC020501080400460810FC3CEC3231002FE4FCEC30400B10094009
+50096009700905015D1333112311331523C1B8B8B8B80460FBA00614E9000002FFDBFE56
+01790614000B000F0044401C0B0207000EBE0C078705BD00BC0CB110081005064F0D0108
+0C00461010FC3CEC32E4391239310010ECE4F4EC10EE1112393930400B10114011501160
+11701105015D13331114062B01353332363511331523C1B8A3B54631694CB8B80460FB8C
+D6C09C61990628E9000100BA0000049C0614000A00BC4029081105060507110606050311
+0405040211050504420805020303BC009709060501040608010800460B10FCEC32D4C411
+3931002F3CECE41739304B5358071004ED071005ED071005ED071004ED5922B2100C0101
+5D405F04020A081602270229052B0856026602670873027705820289058E089302960597
+08A3021209050906020B030A072803270428052B062B07400C6803600C8903850489058D
+068F079A039707AA03A705B607C507D607F703F003F704F0041A5D71005D133311013309
+0123011123BAB90225EBFDAE026BF0FDC7B90614FC6901E3FDF4FDAC0223FDDD000100C1
+00000179061400030022B7009702010800460410FCEC31002FEC30400D10054005500560
+057005F00506015D13331123C1B8B80614F9EC00000100BA0000071D047B0022005A4026
+061209180F00061D07150C871D2003B81BBC19100700110F0808065011080F501C18081A
+462310FCEC32FCFCFCEC11123931002F3C3CE4F43CC4EC32111217393040133024502470
+249024A024A024BF24DF24FF2409015D013E013332161511231134262322061511231134
+262322061511231133153E01333216042945C082AFBEB972758FA6B972778DA6B9B93FB0
+797AAB03897C76F5E2FD5C029EA19CBEA4FD87029EA29BBFA3FD870460AE67627C000001
+00BA00000464047B001300364019030900030E0106870E11B80CBC0A010208004E0D0908
+0B461410FCEC32F4EC31002F3CE4F4C4EC1112173930B46015CF1502015D011123113426
+2322061511231133153E013332160464B87C7C95ACB9B942B375C1C602A4FD5C029E9F9E
+BEA4FD870460AE6564EF00020071FFE30475047B000B0017004A401306B91200B90CB812
+8C1809120F51031215451810FCECF4EC310010E4F4EC10EE3040233F197B007B067F077F
+087F097F0A7F0B7B0C7F0D7F0E7F0F7F107F117B12A019F01911015D0122061514163332
+36353426273200111000232200111000027394ACAB9593ACAC93F00112FEEEF0F1FEEF01
+1103DFE7C9C9E7E8C8C7E99CFEC8FEECFEEDFEC70139011301140138000200BAFE5604A4
+047B0010001C003E401B1AB9000E14B90508B80E8C01BD03BC1D11120B47170400080246
+1D10FCEC3232F4EC310010E4E4E4F4C4EC10C4EE304009601E801EA01EE01E04015D2511
+231133153E013332121110022322260134262322061514163332360173B9B93AB17BCCFF
+FFCC7BB10238A79292A7A79292A7A8FDAE060AAA6461FEBCFEF8FEF8FEBC6101EBCBE7E7
+CBCBE7E700020071FE56045A047B000B001C003E401B03B90C0F09B91815B80F8C1BBD19
+BC1D180C06081A47001212451D10FCECF4EC3232310010E4E4E4F4C4EC10C6EE30400960
+1E801EA01EE01E04015D011416333236353426232206010E012322021110123332161735
+331123012FA79292A8A89292A702733AB17CCBFFFFCB7CB13AB8B8022FCBE7E7CBCBE7E7
+FDAE646101440108010801446164AAF9F600000100BA0000034A047B001100304014060B
+0700110B03870EB809BC070A06080008461210FCC4EC3231002FE4F4ECC4D4CC11123930
+B450139F1302015D012E012322061511231133153E0133321617034A1F492C9CA7B9B93A
+BA85132E1C03B41211CBBEFDB20460AE666305050001006FFFE303C7047B002700E7403C
+0D0C020E0B531F1E080902070A531E1F1E420A0B1E1F041500860189041486158918B911
+04B925B8118C281E0A0B1F1B0700521B080E07081422452810FCC4ECD4ECE41112393939
+39310010E4F4EC10FEF5EE10F5EE121739304B535807100EED111739070EED1117395922
+B2002701015D406D1C0A1C0B1C0C2E092C0A2C0B2C0C3B093B0A3B0B3B0C0B2000200124
+02280A280B2A132F142F152A16281E281F292029212427860A860B860C860D1200000001
+0202060A060B030C030D030E030F03100319031A031B031C041D09272F293F295F297F29
+80299029A029F029185D005D7101152E012322061514161F011E0115140623222627351E
+013332363534262F012E01353436333216038B4EA85A898962943FC4A5F7D85AC36C66C6
+61828C65AB40AB98E0CE66B4043FAE282854544049210E2A99899CB62323BE353559514B
+50250F2495829EAC1E0000010037000002F2059E0013003840190E05080F03A9001101BC
+08870A0B08090204000810120E461410FC3CC4FC3CC432393931002FECF43CC4EC321139
+3930B2AF1501015D01112115211114163B01152322263511233533110177017BFE854B73
+BDBDD5A28787059EFEC28FFDA0894E9A9FD202608F013E00000100AEFFE3045804600013
+00364019030900030E0106870E118C0A01BC0C0D09080B4E020800461410FCECF4EC3231
+002FE432F4C4EC1112173930B46015CF1502015D1311331114163332363511331123350E
+01232226AEB87C7C95ADB8B843B175C1C801BA02A6FD619F9FBEA4027BFBA0AC6663F000
+0001003D0000047F04600006011240270311040504021101020505040211030206000601
+1100000642020300BF0506050302010504000710D4C4173931002FEC3239304B53580710
+05ED071008ED071008ED071005ED5922014BB00A5458BD0007FFC0000100070007004038
+11373859014BB014544BB015545B58BD00070040000100070007FFC03811373859408E48
+026A027B027F02860280029102A402080600060109030904150015011A031A0426002601
+290329042008350035013A033A0430084600460149034904460548064008560056015903
+590450086600660169036904670568066008750074017B037B0475057A06850085018903
+8904890586069600960197029A03980498059706A805A706B008C008DF08FF083E5D005D
+133309013301233DC3015E015EC3FE5CFA0460FC5403ACFBA00000010056000006350460
+000C0201404905550605090A0904550A0903550A0B0A025501020B0B0A06110708070511
+0405080807021103020C000C011100000C420A050203060300BF0B080C0B0A0908060504
+0302010B07000D10D4CC173931002F3CEC32321739304B5358071005ED071008ED071008
+ED071005ED071008ED071005ED0705ED071008ED5922014BB00A544BB011545B4BB01254
+5B4BB013545B4BB00B545B58BD000DFFC00001000D000D00403811373859014BB00C544B
+B00D545B4BB010545B58BD000D00400001000D000DFFC0381137385940FF050216021605
+220A350A49024905460A400A5B025B05550A500A6E026E05660A79027F0279057F058702
+99029805940ABC02BC05CE02C703CF051D0502090306040B050A080B09040B050C150219
+0316041A051B081B09140B150C2500250123022703210425052206220725082709240A21
+0B230C390336043608390C300E460248034604400442054006400740084409440A440B40
+0E400E560056015602500451055206520750085309540A550B6300640165026A0365046A
+056A066A076E09610B670C6F0E7500750179027D0378047D057A067F067A077F07780879
+097F097B0A760B7D0C870288058F0E97009701940293039C049B05980698079908402F96
+0C9F0EA600A601A402A403AB04AB05A906A907AB08A40CAF0EB502B103BD04BB05B809BF
+0EC402C303CC04CA05795D005D13331B01331B013301230B012356B8E6E5D9E6E5B8FEDB
+D9F1F2D90460FC96036AFC96036AFBA00396FC6A0001003B000004790460000B015A4046
+0511060706041103040707060411050401020103110202010B110001000A11090A010100
+0A110B0A0708070911080807420A070401040800BF05020A0704010408000208060C10D4
+C4D4C411173931002F3CEC321739304B5358071005ED071008ED071008ED071005ED0710
+05ED071008ED071008ED071005ED5922014BB00A544BB00F545B4BB010545B4BB011545B
+58BD000CFFC00001000C000C00403811373859014BB0145458BD000C00400001000C000C
+FFC0381137385940980A04040A1A04150A260A3D04310A55045707580A660A76017A0476
+07740A8D04820A99049F049707920A900AA601A904AF04A507A30AA00A1C0A0304050509
+0A0B1A03150515091A0B2903260525092A0B200D3A013903370534073609390B300D4903
+460545094A0B400D590056015902590357055606590756085609590B500D6F0D78017F0D
+9B019407AB01A407B00DCF0DDF0DFF0D2F5D005D09022309012309013309010464FE6B01
+AAD9FEBAFEBAD901B3FE72D9012901290460FDDFFDC101B8FE48024A0216FE71018F0001
+003DFE56047F0460000F01A240430708020911000F0A110B0A00000F0E110F000F0D110C
+0D00000F0D110E0D0A0B0A0C110B0B0A420D0B0910000B058703BD0E0BBC100E0D0C0A09
+060300080F040F0B1010D4C4C4111739310010E432F4EC113911391239304B5358071005
+ED071008ED071008ED071005ED071008ED0705ED17325922014BB00A544BB008545B58BD
+0010FFC000010010001000403811373859014BB0145458BD00100040000100100010FFC0
+381137385940F0060005080609030D160A170D100D230D350D490A4F0A4E0D5A095A0A6A
+0A870D800D930D120A000A09060B050C0B0E0B0F1701150210041005170A140B140C1A0E
+1A0F2700240124022004200529082809250A240B240C270D2A0E2A0F2011370035013502
+30043005380A360B360C380D390E390F3011410040014002400340044005400640074008
+4209450A470D490E490F40115400510151025503500450055606550756085709570A550B
+550C590E590F501166016602680A690E690F60117B08780E780F89008A09850B850C890D
+890E890F9909950B950C9A0E9A0FA40BA40CAB0EAB0FB011CF11DF11FF11655D005D050E
+012B01353332363F01013309013302934E947C936C4C543321FE3BC3015E015EC368C87A
+9A488654044EFC94036C00010058000003DB0460000900B4401A08110203020311070807
+4208A900BC03A905080301000401060A10DCC432C411393931002FECF4EC304B53580710
+05ED071005ED5922014BB00B544BB00C545B58BD000A00400001000A000AFFC038113738
+59014BB0135458BD000AFFC00001000A000A004038113738594042050216022602470249
+07050B080F0B18031B082B08200B36033908300B40014002450340044005430857035908
+5F0B6001600266036004600562087F0B800BAF0B1B5D005D132115012115213501217103
+6AFD4C02B4FC7D02B4FD650460A8FCDB93A8032500010100FEB204170614002400824034
+190F150B0625091A10151D0B05202103000BA90900A901C00915A913B1250C090A052416
+19001D0A05130214002019430A0F052510D43CC4FC3CC432393911123911123939111239
+39310010FCECC4F4EC10EE12173912391139391112391112393930014BB00C5458BD0025
+FFC000010025002500403811373859B20026015D05152322263D0134262B01353332363D
+0134363B01152322061D011406071E011D0114163304173EF9A96C8E3D3D8F6BA9F93E44
+8D565B6E6F5A568DBE9094DDEF97748F7395F0DD938F588DF89D8E191B8E9CF88D580001
+0104FE1D01AE061D00030012B70100B1040005020410D4EC310010FCCC300111231101AE
+AA061DF80008000000010100FEB2041706140024009E40361F251B160C0F081B0B15190F
+040520030019A91B00A923C01B0FA911B1251C191A150F010400081A15231204001A1F15
+4310000B042510D43CC432FC3CC4111239391112391112393911123939310010FCECC4F4
+EC10EE12173911123939113911393911123930014BB00A5458BD00250040000100250025
+FFC03811373859014BB00E5458BD0025FFC000010025002500403811373859B20026015D
+053332363D013436372E013D0134262B01353332161D0114163B01152322061D0114062B
+010100468C555A6F6F5A558C463FF9A76C8E3E3E8E6CA7F93FBE568FF89C8E1B198E9DF8
+8E578F93DDF095738F7497EFDD94000100D901D305DB0331001D0023401001101B0C0013
+049C1B139C0C1E000F1E10D4C4310010D4FCD4EC10C01112393930011506062322272627
+26272623220607353636333217161716171633323605DB69B3616E920B05070F9B5E58AC
+6269B3616E930A05080E9B5E56A90331B24F443B040203053E4D53B24F453C040203053E
+4C00FFFF001000000568074E02270024000000000007010300BC01750003001000000568
+076D000B000E002100CB40540C110D0C1B1C1B0E111C1B1E111C1B1D111C1C1B0D11210F
+210C110E0C0F0F2120110F211F11210F21420C1B0F0D0903C115091E950D098E201C1E1D
+1C18201F210D12060E180C061B0056181C0F0656121C212210D4C4D4EC3210D4EE321139
+11391112391139391112393931002F3CE6D6EE10D4EE1112393939304B5358071005ED07
+05ED071008ED071005ED071005ED0705ED0705ED071008ED5922B2202301015D40201A0C
+730C9B0C03070F081B5023660D690E750D7B0E791C791D7620762180230C5D005D013426
+232206151416333236030121012E01353436333216151406070123032103230354593F40
+57583F3F5998FEF00221FE583D3E9F7372A13F3C0214D288FD5F88D5065A3F5957413F58
+58FEF3FD19034E29734973A0A172467629FA8B017FFE8100FFFF0073FE75052705F00227
+002600000000000700DD012D0000FFFF00C90000048B076B022700280000000000070104
+009E0175FFFF00C900000533075E02270031000000000007010500FE0175FFFF0073FFE3
+05D9074E02270032000000000007010301270175FFFF00B2FFE30529074E022700380000
+00000007010300EE0175FFFF007BFFE3042D066602270044000000000007008D00520000
+FFFF007BFFE3042D066602270044000000000007004300520000FFFF007BFFE3042D0666
+0227004400000000000700D700520000FFFF007BFFE3042D061002270044000000000007
+008E00520000FFFF007BFFE3042D06370227004400000000000700D800520000FFFF007B
+FFE3042D07060227004400000000000700DC00520000FFFF0071FE7503E7047B02270046
+00000000000700DD008F0000FFFF0071FFE3047F066602270048000000000007008D008B
+0000FFFF0071FFE3047F0666022700480000000000070043008B0000FFFF0071FFE3047F
+06660227004800000000000700D7008B0000FFFF0071FFE3047F06100227004800000000
+0007008E008B0000FFFF00900000026F0666022700D6000000000007008DFF1D0000FFFF
+FFC7000001A60666022700D60000000000070043FF1D0000FFFFFFDE0000025C06660227
+00D600000000000700D7FF1D0000FFFFFFF4000002460610022700D6000000000007008E
+FF1D0000FFFF00BA0000046406370227005100000000000700D800980000FFFF0071FFE3
+0475066602270052000000000007008D00730000FFFF0071FFE304750666022700520000
+00000007004300730000FFFF0071FFE3047506660227005200000000000700D700730000
+FFFF0071FFE30475061002270052000000000007008E00730000FFFF0071FFE304750637
+0227005200000000000700D800730000FFFF00AEFFE30458066602270058000000000007
+008D007B0000FFFF00AEFFE304580666022700580000000000070043007B0000FFFF00AE
+FFE3045806660227005800000000000700D7007B0000FFFF00AEFFE30458061002270058
+000000000007008E007B000000010039FF3B03C705D5000B002740140804B90A02008106
+C20C0359050157095907000C10D43CECFC3CEC310010E4F4D43CEC323001331121152111
+231121352101A8B0016FFE91B0FE91016F05D5FE5C99FBA3045D9900000200C30375033D
+05F0000B001A0020401106C315C400C30C911B095A125B035A181B10DCECFCEC310010F4
+ECFCEC300122061514163332363534262732161716161514062322263534360200506E6E
+50506E6F4F40762B2E2EB98687B4B8056F6F504F6D6D4F4F7081312E2D724284B7B48786
+BA00000200ACFEC704230598000600210051402B131614000F0C010B078608880B10860F
+880CB914160BB91D1F1CB8168C221C1500091E130B0F070412192210DCECD43CD43C3CEC
+3232310010E4F43CC4EC10C4FEF4EE10F5EE123911123911123930251106061514160115
+2626270336363715060607112311260011100037113313161602A693A4A402104A884401
+46894841894D66F1FEF70109F16601498983035812E2B8B9E203A1AC292A03FCA0052A27
+AA1E2307FEE4012014013301010102013216011FFEE10421000100810000046205F0001B
+00604021071608018600120AA914080C04A000941991100CA00E000D090B071C130F1511
+1C10DC3CCCCCFC3CC4D4C431002FEC32F4E4EC10D43CEE3210EE11393930014BB00C5458
+BD001CFFC00001001C001C00403811373859B43601360202005D01152E012322061D0121
+152111211521353311233533351036333216044E4C883D94740187FE79022DFC1FECC7C7
+D6E83D9705B4B629299BD4D78FFE2FAAAA01D18FEE0105F31F000002005CFF3D03A205F0
+000B003E0091403C2F302A0600171D3036040D278A260D8A0C2AC626C52310C60CC53C91
+233F2F0600173004131D2D0936031357392D572009570C221A3926220357333F10DCECE4
+C4D4E4ECD4EC10EE113911123911173939310010C4F4E4EC10E6EE10EE10EE1117393939
+11123930014BB00A544BB00B545B4BB00C545B4BB00E545B58BD003F00400001003F003F
+FFC03811373859010E01151416173E0135342613152E0123220615141716171E01151406
+071E0115140623222627351E0133323635342F012E01353436372E01353436333216017B
+3F3E8BFA3F3E8FCC538F38616CCE1A0ED3835C5D3E39CCAD499A5857943A6671DD19D680
+5D5B3B3BC8A6499903A82E5A2E4C85872D5B2E4B880293A4272750475A730F08779A655A
+8C35346D408EA81D1DA42727544C667B0E7899665B8F312C7045829F1D000001013301D1
+03850421000B0012B709C7030C065C000C10D4EC310010D4EC3001343633321615140623
+22260133AD7E7CABAC7D7DAC02FA7CABAB7C7DACAC000001009EFF3B043905D5000D0025
+4012080204C1008106020E00075D05035D010B0E10D4D4FCDCEC39310010C432F4EC1139
+300121112311231123112626353424027901C08DBE8ED7EB010405D5F966061FF9E1034E
+11DDB8BEE800000100BAFFE304AC0614002F009A40302D27210C04060D2000042A168617
+1AB9132AB90397138C2E0C090D1D2021270908242708061D082410162D081000463010FC
+C4FCCC10C6EED4EE10EE1139391239123931002FE4FEEE10FED5EE12173917393040400F
+050F060F070F270F288A0C8A0D070A060A070A0B0A0C0A0D0A1F0D200A210C220426190D
+191F19203A203A214D1F4D20492149226A1F6A20A506A507A620185D015D133436333216
+170E011514161F011E0115140623222627351E013332363534262F012E01353436372E01
+232206151123BAEFDAD0DB0397A83A4139A660E1D3408849508C4174783B655C6057A797
+0883718288BB0471C8DBE8E00873602F512A256A8E64ACB71918A41E1D5F5B3F543E373B
+875B7FAC1D67708B83FB93000004011B000006E505CD0017002F0038004C006040364542
+433F32C94830C9394A43CA0C39CA00C918C80CC924484533300431423C3F39364931604B
+3660433C5E12091E4B5E06091E5F2A4D10DCE4FCEC10FEFDC4EE10EE3211393912391217
+3931002FEEF6FEED10ED3210EED6EE391239393001220607060615141617161633323637
+363635342627262627320417161215140207060423222427260235341237362413231133
+32363534262732161514060716161717232726262323112311040083E25E5E60605E5EE2
+8384E35E5D5D5E5C5EE3849801076D6D6C6C6D6DFEF99898FEF96D6D6C6C6D6D01077D7B
+7B6E575866B0AE696018432E89AC813B4936429B05665E5E5EE58281E35E5E5F5F5E5DE2
+8385E35D5E5E676E6D6DFEFA9A98FEFB6D6D6E6E6D6D0105989A01066D6D6EFE62FEEC3E
+4B4C3F677779567011084D49DFD16033FE9C03440003011B000006E505CD0017002F0049
+004340263DCB3E3ACC41CA2431CB3034CC47CA18C900C824C90C3761443D305E2A090644
+5E1E0906124A10DCCCFCEC10FEED3210EE31002FEEF6FEFDEED6EE10FDEED6EE30013204
+171612151402070604232224272602353412373624172206070606151416171616333236
+373636353426272626171526262322061514163332363715060623222635343633321604
+009801076D6D6C6C6D6DFEF99898FEF96D6D6C6C6D6D01079883E25E5E60605E5EE28384
+E35E5D5D5E5C5EE3A742824295A7AB9B407A42438946D8FBFBD8498805CD6E6D6DFEFA9A
+98FEFB6D6D6E6E6D6D0105989A01066D6D6E675E5E5EE58281E35E5E5F5F5E5DE28385E3
+5D5E5EF5812120AF9D9FAE1F227F1D1CF4D0D1F21C00000201270393064605D5000C0014
+003E4021010607100A04120E090306C90D02008115010905620309620B0D630F62136311
+1510D4E4FCE4D4ECD4EC1139310010F43C3CEC1732D43C3CC41139300113133311231103
+23031123112315231123112335044AAEA4AA71C337CB7271CB72C905D5FF000100FDBE01
+E4FED1012FFE1C02425EFE1C01E45E000001017304EE0352066600030031400902B400B3
+040344010410D4EC310010F4EC30004BB009544BB00E545B58BD0004FFC0000100040004
+0040381137385901330123028BC7FEBA990666FE8800000200D705460329061000030007
+0092400E0602CE0400CD080164000564040810DCFCD4EC310010FC3CEC3230004BB00A54
+4BB00D545B58BD00080040000100080008FFC03811373859014BB00C544BB00D545B4BB0
+0E545B4BB017545B58BD0008FFC000010008000800403811373859014BB00F544BB01954
+5B58BD00080040000100080008FFC0381137385940116001600260056006700170027005
+7006085D0133152325331523025ECBCBFE79CBCB0610CACACA00000100D9002705DB04DD
+0013003E40220D0C0A0302CF04009C060CCF0E0A9C1206100814120E0D0C080403020809
+050F001410DC3CC4321739310010D43CCC32FC3CEC10FE3CEC3911123930132101170721
+1521072115210127372135213721D9030401007DAE012FFE48C3027BFCFAFEFE7DAEFED5
+01B6C3FD8703A2013B66D5A8F0AAFEC766D3AAF0000200080000074805D5000F00130087
+403911110E0F0E10110F0F0E0D110F0E0C110E0F0E420595030B95110195109500811107
+9503AD0D0911100F0D0C050E0A00040806021C120A0E1410D4D43CEC32D4C4C411121739
+31002F3CECECC4F4ECEC10EE10EE304B5358071005ED0705ED071005ED071005ED5922B2
+801501015D4013671177107711860C851096119015A015BF15095D011521112115211121
+15211121032301170121110735FD1B02C7FD3902F8FC3DFDF0A0CD02718BFEB601CB05D5
+AAFE46AAFDE3AA017FFE8105D59EFCF0031000030066FFBA05E5061700090013002B009E
+403C1D1F1A0D2B2C130A0100040D292620140D042A261E1A0495260D951A91268C2C2B2C
+2A141710201E23130A0100041D2910071F07192333101917102C10FCECFCECC011123939
+1739123939111239391139310010E4F4EC10EE10C010C011123939123912173912391112
+393930402A57005A15571955216A1565217B15761C7521094613590056136A006413641C
+6A287C007313761C7A280B5D015D09011E01333200113426272E01232200111416170726
+0235100021321617371707161215100021222627072704B6FD333EA15FDC010127793DA1
+5FDCFEFD2727864E4F0179013B82DD57A266AA4E50FE88FEC680DD5BA2670458FCB24043
+0148011A70B8B84043FEB8FEE570BC449E660108A0016201A54D4BBF59C667FEF69EFE9F
+FE5B4B4BBF58000300DD00DD05CF03EE000B0017002F00FF401D2D1B1509210300241804
+150F2721151B0F21300C00241812062A121E3010D4C4D4C41139393939310010D4C4D4C4
+10C01112173912391112393040BE05020503050400050006000705080509050A0A100F11
+0F120F130A1415021503150410051006100715081509150A1A0E1A0F1A101F111F121F13
+1A141A151A1624022403240420052006200724082409240A2A0E2A0F2A102F112F122F13
+2A142A152A1635023503350430053006300735083509350A3A0E3A0F3A103F113F123F13
+3A143A153A1645024503450440054006400745084509450A4A0E4A0F4A104F114F124F13
+4A144A154A1656B41FB020B021B022B026B027B028B429085D015D011E01333236353426
+232206072E01232206151416333236170E01232226353436333216173E01333216151406
+2322260393318654658076595285C4318555667F7659528690469D5E88BAA7865F994844
+9E6186BCA7865E95022F585A8769658687375858846A65868816877FDFA6AFD87E8A8A83
+E1A7AFD67700000200D9000005DB0504000B000F002E401805D007039C00D009010C9C0E
+0D02150400170C08150A061010D43CEC32FC3CEC3231002FECD43CECFC3CEC3001112115
+21112311213521110121152103AE022DFDD3A8FDD3022DFDD30502FAFE0504FE7DAAFE7D
+0183AA0183FBA6AA000200D9000005DB04A80006000A0054402E029C030403019C000104
+0403019C0201050605009C06054205040201000503D106A7079C0901080200240704230B
+10FC3CEC32323931002FECF4EC1739304B53580704ED071008ED071008ED071004ED5922
+0902150135010121152105DBFC4003C0FAFE0502FAFE0502FAFE03F8FEEBFEEEB20170AA
+016FFC02AA00000200D9000005DB04A80006000A0056402F069C0006030403059C040403
+009C010201069C05060202014206050302000504D101A7079C0806070224090400230B10
+FC3C3CEC323931002FECF4EC1739304B5358071008ED071004ED071004ED071008ED5922
+1335011501350101152135D90502FAFE03C10141FAFE03F8B0FE91AAFE90B20112FDC7AA
+AA0000010052000004C305D5001800C6404610021116110F020E0F1616110F02100F080D
+080E020D0D08420F0B090400D31706120BD31409100D81020C090E0305160F0315121003
+001166130065011C0D660A056507031910D43CEC32ECFCEC32EC12173912393911173931
+002FE432D43CEC32D43CEC32111239304B5358071005ED071008ED071008ED071005ED59
+22014BB00C5458BD0019FFC0000100190019004038113738594028860F900FA60FA00FB5
+0F05270C270D270E291028112812370E3910870C8812A60DA50EAA10A9110E5D005D0121
+1123112135213527213521013309013301211521071521048DFE63C9FE6001A054FEB401
+08FEC3BE017B0179BFFEC20108FEB554019F01C7FE3901C77B339B7B024AFD4402BCFDB6
+7B9B3300000100AEFE5604E504600020004D402513191F03160603090C0301120F06871C
+168C0A01BC00BD2119091209080B4E1F020800462110FCEC32F4ECC41239310010E4E432
+F43CECDCC41117391112173930B61F226022CF2203015D13113311141633323635113311
+141633323637150E01232226270E012322262711AEB88A879495B8232509201C29492345
+520F329162668F2AFE56060AFD489194A8A8028DFCA23C390B0C9417164E504F4F4E4EFD
+D70000020068FFE703C1052D001D002900624019002721091B062715060F211B0F15D52A
+0C2403001E1224182A10D4CCDCCC39391139310010E4CCDCCC10CE10CE11123911123930
+014BB00C544BB00B545B4BB00E545B4BB010545B4BB014545B58BD002A00400001002A00
+2AFFC03811373859013E0135342623220623222635343633321211100023222635341233
+321607342623220215141633321202F40F0F494837902424309065B4D6FEDFD598CBDDA2
+65820B574F6D8D56506D8D026D57A34B8183742C1F3E62FECAFEF9FEB1FE46D8A3C60101
+5BE0747DFEFECF747B01040000010019FE77053B05C1000B005D40140A040C0205070200
+070C0A05040301000606080C10D4C41739310010C4D4CC10CE1112393930403051035605
+50055A0A730370037604750570057A0A800380050C5A097F027F03700570067B09740B8F
+028F03800580060B5D015D1321152109012115213509013704EAFC4102A0FD4A03EFFADE
+02D5FD4905C1C1FD33FD04C095032102E3000001009CFE77057105C10007001E400F0602
+D704D600AF080367010567000810D4ECD4EC310010FCECEC323013211123112111239C04
+D5F0FD0AEF05C1F8B6067DF983000001FFE1FFF004AA042F002300CB40310B02151F1E03
+0008DA0F1A1600D922D80FD5180C1E1B1A19181706241201000B020423161505221F120C
+23126805231F2410D4D4D4EC12391112391239391117391112173931002F3CE4F4EC3232
+10EE111739393930014BB00A5458BD0024FFC0000100240024004038113738594056181E
+181F02090009010D020D030F040F050F060F070F080F090F0A0F0B0F0C0F0D0F0E0F0F0F
+100F110F120F130E140D1509160B1708180F180D19081A09231100110116021603171416
+15111617171C181C191123285D005D0123030E0115141633323637070E01232226353436
+37132103231323220607233E0133210487B6690F0F2F37112E251E1E371A7679152250FE
+BAC2B5C329363C09A01C8FA503790391FE194A5C163A3105058D080866642E90A10178FC
+6F03914045A67D000001002FFE8D03FA060E00250026401420DB001A0DDB131ADC07B126
+0A69176A1D69042610DCECFCEC310010FCECDCE410DEE430013213363712123332161514
+062322262726262322030607020223222635343633321617161601376A0E02010CBECA50
+6440372A380C0609106B0E040411BDC44F65443D21300F0A0AFEFA02B06C39020301BC54
+41363F26230F48FD95C16EFE21FE625341383F1D1C1253000003007301D5033B05F00003
+001E0029005F4033280725041F12181002E3001FDD1000E125DD050A19DF18DE15DD0AE0
+1C912A00180D1F10220602012811066B046C18226B0D2A10DCECCCFCEC3232C0C0111239
+39111239310010F4E4FCF4EC10C4EEEDD6EE10EE11123912391139393013211521011123
+35060623222635343633333534262322060735363633321605220615141633323635358B
+02B0FD5002AE952C905D8098BFBCB675753E8844499145B7B3FEECA17E6252688202507B
+02B8FE40703F448771878A045B5B22227F1C1CB0F0434F404D90721D0003006001D50364
+05F00003000F001B002E401902E300E116DD0AE010DD04911C00130D01196B076C136B0D
+1C10DCECFCEC39111239310010F4ECF4ECFCEC3013211521013216151406232226353436
+1722061514163332363534268B02B0FD500158B3CECEB3B3D0D0B3697E7F68697D7C0250
+7B041BDDBFBFDBDCBEBFDD73A18885A0A08589A00001004E000005CF05E7001F00404022
+09E51991120F030300E51001112016130F0C1F06020100026D061C1C0F6D0C1C162010D4
+ECECD4ECECC0C011123911123911123931002F3CEC1732F4EC3025152135361235340023
+2200151412171521352126023510002120001114020705CFFDA8B1C6FEF8D8D8FEF7C7B2
+FDA8013F9E91017F0131012F01818EA1B2B2B261014CCAF00122FEDDEFCAFEB461B2B28B
+012AB8013E018AFE77FECBC2FED88D000003007BFFE3076F047B00060033003E01034043
+272D253D0E0D0034A925168615881200A90E3A12B91C192E862DBA2A03B90EBB07310AB8
+1F198C253F343726060F0025371C07260F1500080D3D26080F2D370822453F10FCECCCD4
+FC3CD4ECC4111239391139111239111239310010C4E432F43CC4E4FC3CF4EC10C4EE3210
+EE10F4EE10EE11391139111239304081302B302C302D302E302F3030402B402C402D402E
+402F4030502B502C502D502E502F5030852B853080409040A040B040C040D040E040E040
+F0401D3F003F063F0D3F0E3F0F05302C302D302E302F402C402D402E402F502C502D502E
+502F6F006F066F0D6F0E6F0F602C602D602E602F702C702D702E702F802C802D802E802F
+1D5D71015D012E0123220607033E013332001D01211E0133323637150E01232226270E01
+232226353436332135342623220607353E013332160322061514163332363D0106B601A5
+8999B90E444AD484E20108FCB20CCCB768C86464D06AA7F84D49D88FBDD2FDFB0102A797
+60B65465BE5A8ED5EFDFAC816F99B9029497B4AE9E01305A5EFEDDFA5ABFC83535AE2A2C
+79777878BBA8BDC0127F8B2E2EAA272760FE18667B6273D9B42900030048FFA2049C04BC
+00090013002B00E4403C2B2C261F1D1A130A0100040D292620140D042A261E1A04B9260D
+B91AB8268C2C2B2C2A141710201E23130A01000410071F1D0712235129101217452C10FC
+EC32F4EC32C011121739123939111239391139310010E4F4EC10EE10C010C01112393912
+3912173911393911123930407028013F2D5914561C551D56206A1566217F007B047F057F
+067F077F087F097F0A7F0B7F0C7B0D7A157B1A7F1B7F1C7F1D7F1E7F1F7F207B217F227F
+237F247F257B269B199525A819A02DF02D2659005613551D5A2869006613651C6A287A00
+7413761C7A28891E95189A24A218AD24115D015D09011E01333236353426272E01232206
+15141617072E01351000333216173717071E011510002322262707270389FE1929674193
+AC145C2A673E97A913147D36360111F15D9F438B5F923536FEEEF060A13F8B600321FDB0
+2A28E8C84F759A2929EBD3486E2E974DC577011401383334A84FB34DC678FEEDFEC73433
+A84E0002008FFFE303AC05D5002000240086402F201A05020406190010860F880C002183
+230C95138C23812506221916090501001A2209001C01221C21260F091C162510DCECD4FC
+ECD4EC1112391112391112391239310010E4F4EC10FECD10F4EE123939173930014BB010
+544BB012545B4BB013545B58BD0025FFC000010025002500403811373859400B74047405
+74067407761C055D01331514060F010E0115141633323637150E012322263534363F013E
+01373E01351323353301F4BE375A5A3A33836D4EB4605EC067B8E04959583026080706C4
+CACA04449C65825758355E31596E4643BC3938C29F4C8956562F3519153C36010EFE0002
+01350000020005D5000300090062400F07008302810408070400030501000A10FC3CEC32
+393931002FF4FCCC30014BB00B5458BD000A00400001000A000AFFC03811373859014BB0
+0F544BB010545B4BB013545B58BD000AFFC00001000A000A00403811373859B6000B200B
+500B035D012335331123111333130200CBCBCB15A21404D7FEFA2B028F0165FE9B000001
+00D9011F05DB035E00050017400A049C020006031701000610DCD4EC310010D4C4EC3013
+2111231121D90502A8FBA6035EFDC10195000001003DFFD70519067D000A002A40180A09
+080706050B020402000B0A090706050403000801080B10D4CC1739310010D4CCC4111217
+39300133152301230107272501045CBD73FDAE42FEC17D19011B0100067D60F9BA03732D
+5062FD3B0001001FFE56050206140023008A40400E0D020F0C11191E190B0A0908040711
+1E1E1942190C130A071E011A0AA908138A12E616A90F018A00E604A921970F1C08241E1D
+1B1A190C0B0908070A00122410D4CC1739310010C432C4FCECF4EC10EEF6EE10EE321239
+3911123939304B5358071005ED1732071005ED1117395922014BB00C5458BD0024FFC000
+01002400240040381137385901152E01232206070321152103020623222627351E013332
+363713233521133E01333216050226502C6072193C011FFEC37F3ABCBA3A642F34612F61
+6D2289F801173F24C697356405F0A41D1C7A84FEC98FFD85FEE3D31516A6212189A602AD
+8F014AB7C312000200D9011005DB03F4001D003B003F401F2E1F392A002D221301101B0C
+1E2A9C31399C22049C1B0C9C133C1E002D0F3C10D43CC432310010D4ECD4ECDCFCD4ECC0
+111239391112393911123939300115060623222726272627262322060735363633321716
+171617163332361315060623222726272627262322060735363633321716171617163332
+3605DB69B3616E920A07060F9B5E58AC6269B3616E930B05060F9B5E56A96769B3616E92
+0A07060F9B5E58AC6269B3616E930A05070F9B5E56A9026FB34E453B040302063D4C54B3
+4E453B050202063D4B01DAB24F453B040302063D4C53B24E453B040203063D4B0002FFFA
+0000056005C1000200060038400F00030103050403020100050705060710D4CC11173931
+002FC4CC113930401463016D02700178027F0279057606076E007F00025D015D09012101
+33012102ACFE5E0344FDEFE00243FA9A04EEFBC4050FFA3F0002009E008D042504230006
+000D0086404903E804050402E8010205050402E8030206000601E80000060AE80B0C0B09
+E808090C0C0B09E80A090D070D08E807070D4209020B04E70700A60E090C05020703006F
+050A076F0C6E0E10FCFC3CD4EC321139111239310010F43CEC323939304B5358071004ED
+071008ED071008ED071004ED071004ED071008ED071008ED071004ED5922011501011501
+35131501011501350425FED3012DFE2B23FED3012DFE2B0423BFFEF4FEF4BF01A25201A2
+BFFEF4FEF4BF01A25200000200C1008D044804230006000D008640490CE80D0C090A090B
+E80A0A090DE80708070CE80B0C08080705E8060502030204E803030206E800010005E804
+05010100420C050A03E70700A60E0C08010500086F0A07016F0300700E10FC3CFCD43CEC
+1239111239310010F43CEC323939304B5358071008ED071004ED071004ED071008ED0710
+08ED071004ED071004ED071008ED59221301150135010125011501350101C101D5FE2B01
+2DFED301B201D5FE2B012DFED30423FE5E52FE5EBF010C010CBFFE5E52FE5EBF010C010C
+000300EC0000071400FE00030007000B00234011080400830A0602041905001901091908
+0C10D4FCD4ECD4EC31002F3C3CEC3232302533152325331523253315230396D4D402A9D5
+D5FAADD5D5FEFEFEFEFEFE00FFFF001000000568076B02270024000000000007010600BC
+0175FFFF001000000568075E02270024000000000007010500BC0175FFFF0073FFE305D9
+075E02270032000000000007010501270175000200730000080C05D500100019003B401F
+059503110195008118079503AD091812100A1506021C1100040815190D101A10FCECD4C4
+C4D4EC32123939393931002FECEC32F4EC3210EE30011521112115211121152120001110
+002117232000111000213307FAFD1A02C7FD3902F8FBD7FE4FFE4101BF01B16781FEBFFE
+C0014001418105D5AAFE46AAFDE3AA017C0170016D017CAAFEE1FEE0FEDFFEDF00030071
+FFE307C3047B0006002700330084403107080010860F880C00A9082E0CB916132803B908
+BB22251FB819138C340600162231090F0008074B311209512B121C453410FCECF4FCF4EC
+C4111239391239310010E432F43CC4E4EC3210C4EE3210EE10F4EE1112393040253F355F
+3570359F35CF35D035F035073F003F063F073F083F09056F006F066F076F086F09055D71
+015D012E01232206070515211E0133323637150E01232226270E01232200111000333216
+173E01333200252206151416333236353426070A02A48999B90E0348FCB20CCCB76AC862
+64D06AA0F25147D18CF1FEEF0111F18CD3424EE88FE20108FAB094ACAB9593ACAC029498
+B3AE9E355ABEC73434AE2A2C6E6D6E6D01390113011401386F6C6B70FEDD87E7C9C9E7E8
+C8C7E9000001000001E90400027900030010B602A900E90401002FC6310010FCEC301121
+15210400FC00027990000001000001E9080002790003000FB502A9000401002FCC310010
+D4EC30112115210800F800027990000200AE03E9036D05D50005000B0027401306009E09
+03810C090A0619070304070019010C10DCFCCCD4CC10FED4CE310010F43CEC3230012335
+1333030523351333030181D3A48152019AD3A4815203E9AD013FFEC1ADAD013FFEC10002
+00AE03E9036D05D50005000B0027401309039E0600810C090A0719060103040119000C10
+DCECD4CC10DCEED4CE310010F43CEC32300133150323132533150323130100D3A4815201
+9AD3A4815205D5ACFEC00140ACACFEC00140000100AE03E901D305D500050018400B009E
+03810603040019010610DCFCD4CC310010F4EC300123351333030181D3A4815203E9AD01
+3FFEC100000100B203FE01D705D500050018400B039E00810603040171000610DCECD4CC
+310010F4EC300133150323130104D3A4815205D598FEC1013F00000300D9009605DB046F
+00030007000B0029401400EA0206EA0402089C040A0C090501720400080C10DCD43CFC3C
+C4310010D4C4FCC410EE10EE3001331523113315230121152102DFF6F6F6F6FDFA0502FA
+FE046FF6FE12F50241AA00020006FE2303EE067500030007002240110206000804060806
+04030201000605070810D4CC1739310010D4CC1139123930090701FAFE7F01810181FE7F
+01F4FE0CFE0C0581FCCFFCC703390425FBDBFBD3042DFFFF003DFE56047F06100227005C
+000000000007008E005E0000FFFFFFFC000004E7074E0227003C00000000000701030073
+01750001FE89FFE302CD05F00003002B4013000F010201020F03000342028C0091040103
+0410D4CC310010E4E4304B5358071005ED071005ED592201330123022DA0FC5CA005F0F9
+F3000002005E005204BC04B20023002F0083404903091B15042D1E00271C02211D0C122D
+140B0A03130F011D2DB913EB0FEC27B91DEB21301E0C0012042A2414301C151B2A1D131C
+180903240B0A0103022428027306742A281C73183010DCE4ECF4E4EC1217391239391112
+393912393911123911121739310010D4E4ECF4E4EC10C011121739123939111239391139
+391217393001371707161615140607170727060623222627072737262635343637273717
+3636333216133426232206151416333236037BCF72CE25242628D172CF3B743D3A783DCF
+71CF25252626CF73CF3774403C755C9B72709E9D71719C03E1D173CE3B773E3F7339CF71
+CF28262525CF73CE3E763A407438CE73CF272524FE7C709A9A70729C9D000001009E008D
+0273042300060047402503E804050402E8010205050402E8030206000601E80006420204
+E700A6070203006F056E0710FCEC3239310010F4EC39304B53580704ED071008ED071008
+ED071004ED5922011501011501350273FED3012DFE2B0423BFFEF4FEF4BF01A252000001
+00C1008D0296042300060049402605E8060502030204E803030206E800010005E8040501
+0100420503E700A60705016F0300700710FC3CEC39310010F4EC39304B5358071008ED07
+1004ED071004ED071008ED592213011501350101C101D5FE2B012DFED30423FE5E52FE5E
+BF010C010C000002002F0000044A061400150019009B40280B14180703A90010870E18BE
+16B10E970900BC0501110E0F04160208000F1404080817000A064C1A10FC3CC432C4FC3C
+C410EE321112393931002F3CE632EEFEEE10EE10EE3212393930014BB00A5458BD001AFF
+C00001001A001A00403811373859014BB00E5458BD001A00400001001A001AFFC0381137
+3859401A101610171018101904301B501B800F8010801BA01BD01BEF1B085D005D011123
+11211123112335333534363B01152322061D0101331523044AB9FE07B9B0B0ADB3B9B063
+4D01F9B9B90460FBA003D1FC2F03D18F4EB7AF9950686301B2E90001002F0000044A0614
+0015008440210813040F0BA909048700971109BC0D0205000A080308010A0C0808100112
+0E4C1610FC3CC4C4FC3CC410EE1112393931002F3CE632FEEE10EE3212393930014BB00A
+5458BD0016FFC000010016001600403811373859014BB00E5458BD001600400001001600
+16FFC03811373859401130175017800A800B8017A017D017EF17085D0121112311212206
+1D01211521112311233533353436024A0200B9FEB7634D012FFED1B9B0B0AE0614F9EC05
+7B5068638FFC2F03D18F4EBBAB0000010039FF3B03C705D50013003E40201206B9001008
+B90A0400020E0A0C8102C2140F0059110D01570905590B07031410D43C3CEC32FC3C3CEC
+32310010E4F4C43210C43210EE3210EE3230252111231121352111213521113311211521
+112103C7FE91B0FE91016FFE91016FB0016FFE91016FDFFE5C01A49A021F9901A4FE5C99
+FDE1000100DB024801AE034600030012B7028300040119000410D4EC310010D4EC301333
+1523DBD3D30346FE000100AEFF1201D300FE00050018400B039E00830603040119000610
+D4ECD4CC310010FCEC302533150323130100D3A48152FEACFEC00140000200AEFF12036D
+00FE0005000B0027401309039E0600830C030401190007090A0719060C10DCECD4CC10DC
+EED4CE310010FC3CEC3230253315032313253315032313029AD3A48152FE66D3A48152FE
+ACFEC00140ACACFEC001400000070071FFE30A4C05F0000B0017002300270033003F004B
+00AE4044240F252625260F272427424000920C2E921E8D289218460692340C8D3A26128C
+2418914C25494327312B430D3D090D0F0E030D15310D1B3D0E490D15372B0D1B0E210B4C
+10FCE4ECD4C4ECE410EE10EEF6EE10EE111239111239310010E432F43C3CE432EC3210EE
+F6EE10EE32304B5358071005ED071005ED5922014BB014544BB009545B4BB00B545B4BB0
+0C545B4BB00D545B4BB00E545B58BD004C00400001004C004CFFC0381137385901220615
+141633323635342627321615140623222635343601321615140623222635343621330123
+132206151416333236353426013216151406232226353436172206151416333236353426
+08F457646457556363559EBABB9DA0BABBF9749EBCBB9F9FB9BA0425A0FC5AA01F566362
+5757636403B29EBABB9DA0BABB9F57636357556363029194848295958283957FDCBBBBDB
+DBBBBCDB02E0DBBBBDDADBBCBADCF9F3058E9582849494848196FD9FDCBBBBDBDBBBBCDB
+7F948482959582839500FFFF001000000568076D02270024000000000007010700BC0175
+FFFF00C90000048B076D022700280000000000070107009E0175FFFF001000000568076B
+02270024000000000007010400BC0175FFFF00C90000048B074E02270028000000000007
+0103009E0175FFFF00C90000048B076B022700280000000000070106009E0175FFFF00A2
+0000021F076B0227002C0000000000070104FF2F0175FFFFFFFE00000260076D0227002C
+0000000000070107FF2F0175FFFF000600000258074E0227002C0000000000070103FF2F
+0175FFFF003B000001BA076B0227002C0000000000070106FF2F0175FFFF0073FFE305D9
+076B02270032000000000007010401270175FFFF0073FFE305D9076D0227003200000000
+0007010701270175FFFF0073FFE305D9076B02270032000000000007010601270175FFFF
+00B2FFE30529076B02270038000000000007010400EE0175FFFF00B2FFE30529076D0227
+0038000000000007010700EE0175FFFF00B2FFE30529076B022700380000000000070106
+00EE0175000100C100000179046000030020B700BF02010800460410FCEC31002FEC3040
+0B1005400550056005700505015D13331123C1B8B80460FBA000000100C104EE033F0666
+00060037400C040502B400B307040275060710DCEC39310010F4EC323930004BB009544B
+B00E545B58BD0007FFC0000100070007004038113738590133132327072301B694F58BB4
+B48B0666FE88F5F5000100B6051D034A0637001B006340240012070E0B040112070F0B04
+12C3190704C3150BED1C0F010E000715561677075608761C10F4ECFCEC11393939393100
+10FC3CFCD43CEC11123911123911123911123930004BB009544BB00C545B58BD001CFFC0
+0001001C001C0040381137385901272E0123220607233E013332161F011E013332363733
+0E0123222601FC3916210D2624027D02665B2640253916210D2624027D02665B2640055A
+371413495287931C21371413495287931C00000100D50562032B05F60003002FB702EF00
+EE0401000410D4CC310010FCEC30004BB009544BB00E545B58BD0004FFC0000100040004
+0040381137385913211521D50256FDAA05F69400000100C7052903390648000D0057400E
+0BF0040700B30E0756080156000E10DCECD4EC310010F43CD4EC30004BB0095458BD000E
+FFC00001000E000E00403811373859004BB00F544BB010545B4BB011545B58BD000E0040
+0001000E000EFFC0381137385913331E0133323637330E01232226C7760B615756600D76
+0A9E91919E06484B4B4A4C8F90900001019A0544026606100003002C400902CE00CD0401
+64000410D4EC310010FCEC30004BB0095458BD0004FFC000010004000400403811373859
+01331523019ACCCC0610CC00000200EE04E103120706000B0017005F401103C115F209C1
+0FF11800560C780656121810D4ECF4EC310010F4ECF4EC30004BB009544BB00C545B58BD
+0018FFC000010018001800403811373859014BB00A544BB00B545B4BB00C545B58BD0018
+FFC000010018001800403811373859013426232206151416333236371406232226353436
+333216029858404157574140587A9F73739F9F73739F05F43F5857404157584073A0A073
+739F9F0000010123FE7502C100000013001F400E09060A0DF306001300102703091410DC
+D4ECD4CC31002FD4FCC41239302116161514062322262735161633323635342627025437
+3678762E572B224A2F3B3C2B2D3E6930595B0C0C83110F302E1E573D000200F004EE03AE
+066600030007004240110602B40400B3080407030005010305070810D4DCD4CC11391112
+39310010F43CEC3230004BB009544BB00E545B58BD0008FFC00001000800080040381137
+3859013303230333032302FCB2F88781AADF890666FE880178FE88000001014CFE7502C1
+000000130020400F0B0E0A07F30EF40001000A0427111410D4ECC4D4CC31002FFCFCC412
+3930213306061514163332363715060623222635343601B8772D2B3736203E1F26441E7A
+73353D581F2E2E0F0F850A0A575D3069000100C104EE033F066600060037400C0300B404
+01B307030575010710DCEC39310010F43CEC3930004BB009544BB00E545B58BD0007FFC0
+000100070007004038113738590103331737330301B6F58BB4B48BF504EE0178F5F5FE88
+0001FFF20000047505D5000D003F401E0C0B0A040302060006950081080304010B0E0004
+05011C0C073A0900790E10F43CECC4FC3CC411123911123931002FE4EC11173930B4300F
+500F02015D1333112517011121152111072737D3CB013950FE7702D7FC5E944DE105D5FD
+98DB6FFEEEFDE3AA023B6A6E9E0000010002000002480614000B005E401A0A0908040302
+06009706030401090A00047A0501080A7A07000C10D43CE4FC3CE411123911123931002F
+EC173930014BB0105458BD000C00400001000C000CFFC038113738594013100D400D500D
+600D73047A0A700DE00DF00D095D133311371707112311072737C7B87D4CC9B87B4AC506
+14FDA65A6A8DFCE3029A586A8D00FFFF0087FFE304A2076D022700360000000000070108
+008B0175FFFF006FFFE303C706660227005600000000000700E000170000FFFF005C0000
+051F076D0227003D000000000007010800BE0175FFFF0058000003DB06660227005D0000
+0000000700E0001B000000020104FEA201AE059800030007001C400D01F50004F5050804
+000506020810DC3CEC32310010D4ECD4EC30011123111311231101AEAAAAAA0198FD0A02
+F60400FD0A02F6000002000A000005BA05D5000C0019006740201009A90B0D9500811295
+0E0B0707011913040F0D161904320A110D1C0800791A10F43CEC32C4F4EC10C417393100
+2FC632EEF6EE10EE32304028201B7F1BB01B039F099F0A9F0B9F0C9F0E9F0F9F109F11BF
+09BF0ABF0BBF0CBF0EBF0FBF10BF11105D015D1321200011100029011123353313112115
+211133200011100021D301A001B10196FE69FE50FE60C9C9CB0150FEB0F30135011FFEE1
+FECB05D5FE97FE80FE7EFE9602BC9001E3FE1D90FDEA0118012E012C011700020071FFE3
+04750614000E00280127405E257B26251E231E247B23231E0F7B231E287B27281E231E26
+2728272524252828272223221F201F2120201F42282726252221201F08231E030F2303B9
+1B09B9158C1B23B1292627120C212018282523221F051E0F060C121251061218452910FC
+ECF4EC113939173912393911123939310010ECC4F4EC10EE12391239121739304B535807
+100EC9071008C9071008C907100EC9071008ED070EED071005ED071008ED5922B23F2A01
+015D407616252B1F28222F232F2429252D262D272A283625462558205821602060216622
+752075217522132523252426262627272836243625462445255A205A21622062217F007F
+017F027A037B097F0A7F0B7F0C7F0D7F0E7F0F7F107F117F127F137F147B157A1B7A1C7F
+1D7F1E762076217822A02AF02A275D005D012E0123220615141633323635342613161215
+140023220035340033321617270527252733172517050346325829A7B9AE9291AE36097E
+72FEE4E6E7FEE50114DD12342A9FFEC1210119B5E47F014D21FED903931110D8C3BCDEDE
+BC7ABC01268FFEE0ADFFFEC90137FFFA01370505B46B635CCC916F616200FFFFFFFC0000
+04E7076B0227003C000000000007010400730175FFFF003DFE56047F06660227005C0000
+00000007008D005E0000000200C90000048D05D5000C0015003D401B0E95090D9502F600
+810B150F090304011219063F0D0A011C00041610FCEC3232FCEC11173931002FF4FCECD4
+EC3040090F171F173F175F1704015D1333113332041514042B0111231311333236353426
+23C9CAFEFB0101FEFFFBFECACAFE8D9A998E05D5FEF8E1DCDCE2FEAE0427FDD192868691
+000200BAFE5604A406140010001C003E401B14B905081AB9000E8C08B801BD03971D1112
+0B471704000802461D10FCEC3232F4EC310010ECE4E4F4C4EC10C6EE304009601E801EA0
+1EE01E04015D2511231133113E0133321211100223222601342623220615141633323601
+73B9B93AB17BCCFFFFCC7BB10238A79292A7A79292A7A8FDAE07BEFDA26461FEBCFEF8FE
+F8FEBC6101EBCBE7E7CBCBE7E700000100D9022D05DB02D700030011B6009C0204010004
+10D4C4310010D4EC3013211521D90502FAFE02D7AA0000010119003F059C04C5000B0085
+404D0A9C0B0A070807099C080807049C0304070706059C060706049C0504010201039C02
+02010B9C0001000A9C090A010100420A080706040201000805030B090C0B0A0907050403
+0108020008060C10D43CCC321739310010D43CCC321739304B5358071008ED071005ED07
+1005ED071008ED071005ED071008ED071005ED071008ED59220902070101270101370101
+059CFE3701C977FE35FE357601C8FE387601CB01CB044CFE35FE377901CBFE357901C901
+CB79FE3501CB00010089029C02C505DF000A002C40180700DD0903DD0402DD09F705910B
+087C065D037C017C000B10DCF4E4FCE4310010F4ECECD4EC10EE32301333110735373311
+3315219CCCDFE689CDFDD7030A0263297427FD2B6E000001005E029C02B405F00018004A
+4024007D060400177D060604420402000EDD0F00DD02F70BDD0F129119000E087E01150E
+031910DCC4D4C4EC1139310010F4C4ECFCEC10EE111239304B5358071005ED17320705ED
+592201211521353637003534262322060735363633321615140106010C01A8FDAA223F01
+586855347A484D853991AEFEB538030E726E1F3801315E425123237B1C1C846C8BFEE430
+00010062028D02CD05F00028004840270015130ADD091FDD2013DD150DDD09F806F71CDD
+20F823912916130014197E26107E03141F092910DCC4C4D4ECD4EC11393939310010F4E4
+ECFCE4ECD4EC10EE10EE1112393001161615140623222627351616333236353426232335
+33323635342623220607353636333216151406020C5C65BEB1397D463477436D786F6C56
+5E5E61645F28665149803790A95A0460126D527C861514791B1A4F464A4C6C3F3C3A3D12
+1773111276634560FFFF0089FFE3077F05F0002700F000000000002700BC033500000007
+0109048BFD64FFFF0089FFE3073F05F0002700F000000000002700BC03350000000700F1
+048BFD64FFFF0062FFE3077F05F0002700F200000000002700BC0335000000070109048B
+FD64FFFF0073FFE3058B076D0227002A000000000007010A011B0175FFFF0071FE56045A
+06480227004A00000000000700DA008B0000FFFF00C90000019507500227002C00000000
+0007010BFF2F0175FFFF0087FE7504A205F00227003600000000000700DD008B0000FFFF
+006FFE7503C7047B0227005600000000000700DD00170000FFFF0073FFE30527076B0227
+00260000000000070104012D0175FFFF0071FFE303E7066602270046000000000007008D
+00890000FFFF0073FFE30527076D022700260000000000070108012D0175FFFF0071FFE3
+03E706660227004600000000000700E00089000000020071FFE304F4061400180024004A
+40240703D30901F922B900161CB90D108C16B805970B021F0C04030008080A0647191213
+452510FCECF43CC4FC173CC431002FECE4F4C4EC10C4EEFD3CEE3230B660268026A02603
+015D01112135213533153315231123350E01232202111012333216011416333236353426
+23220603A2FEBA0146B89A9AB83AB17CCBFFFFCB7CB1FDC7A79292A8A89292A703B6014E
+7D93937DFAFCA86461014401080108014461FE15CBE7E7CBCBE7E7000001006401DF027F
+028300030011B6009C020401000410DCCC310010D4EC301321152164021BFDE50283A400
+000100DB024801AE034600030012B7028300040119000410D4EC310010D4EC3013331523
+DBD3D30346FE00010000FFE3048F05F00031011C403A2012D322102B07D30919A11AAE16
+951D01A100AE04952F911D8C2909322B222129232612100A030D0911082C202613071108
+110D1C1900262A212F3CD4C432FCC4C41239391239391112391117391239391139393100
+10C432E4F4ECF4EC10EEF6EE10EE32DD3CEE3230014BB009544BB00C545B4BB00D545B4B
+B00F545B4BB017545B4BB018545B58BD0032FFC000010032003200403811373859407A0E
+000E010B020B315414690C6C0E6E0F6F106F116F126F1369146B1F6F206F216F226F236E
+246C256927692D9F079F089F099F0A9F0B9F0C9F0D9F0E9F0F9F109F119F129F13961F9F
+209F219F229F239F249F259F269F279F289F299F2A9F2B9F2C9D2D320008000910081009
+200820095515531E6A15671F0A5D005D01152E01232206072107210E0115141617210721
+1E0133323637150E01232200032337333426353436352337331200333216048F5BA9669D
+CA20024137FDE60201010201BE38FE8A20CA9D66A95B59B960EDFECB28D3378B0101C237
+9C280136EC62B90562D5695AC8BB7B182E23202E187BBBCA5A69D34848012201037B172F
+20232F177B0101012247000200D7050E032905D90003000700A5400D0400CE0602080164
+000564040810D4FCDCEC310010D43CEC3230004BB00E544BB011545B58BD000800400001
+00080008FFC03811373859014BB00E544BB00D545B4BB017545B58BD0008FFC000010008
+000800403811373859014BB011544BB019545B58BD00080040000100080008FFC0381137
+3859004BB0185458BD0008FFC00001000800080040381137385940116001600260056006
+700170027005700608015D0133152325331523025ECBCBFE79CBCB05D9CBCBCB00010173
+04EE02F005F60003007F40110203000301000003420002FA040103030410C410C0310010
+F4CC304B5358071005C9071005C95922004BB00C5458BD0004FFC0000100040004004038
+11373859004BB00E5458BD00040040000100040004FFC038113738594020060215022501
+25023602460256026A016702090F000F011F001F012F002F01065D015D013303230237B9
+E49905F6FEF8000100B6050E034A05E9001D0075402116100F03130C0701000308170CC3
+0413C31B08FA1E10010F00071656180756091E10D4ECD4EC1139393939310010F43CECD4
+EC321217391112173930004BB00C5458BD001EFFC00001001E001E00403811373859004B
+B00E5458BD001E00400001001E001EFFC03811373859B4100B1F1A025D01272E01232206
+1D012334363332161F011E013332363D01330E0123222601FC39191F0C24287D6756243D
+303917220F20287D026754223B0539210E0B322D066576101B1E0D0C3329066477100001
+010C04EE028B05F60003008940110102030200030302420001FA040103030410C410C031
+0010F4CC304B5358071005C9071005C95922004BB00C5458BD0004FFC000010004000400
+403811373859004BB00E5458BD00040040000100040004FFC03811373859402A06000601
+160012012400240135014301550055019F009F01AF00AF010E0F000F031F001F032F002F
+03065D015D0113230301C7C499E605F6FEF80108000100CF04EE033105F800060077400A
+04000502FA070402060710D4C439310010F43CC43930004BB00C5458BD0007FFC0000100
+07000700403811373859004BB00E5458BD00070040000100070007FFC03811373859014B
+B00E5458BD0007FFC00001000700070040381137385940130F000F010C041F001F011D04
+2F002F012D0409005D0133132327072301A2BCD38BA6A68B05F8FEF6B2B2000100CF04EE
+033105F800060086400A03040100FA070305010710D4C439310010F4C4323930004BB00C
+544BB009545B4BB00A545B4BB00B545B58BD0007FFC00001000700070040381137385900
+4BB00E5458BD00070040000100070007FFC03811373859014BB00E5458BD0007FFC00001
+0007000700403811373859401300000303000610001203100620002203200609005D0103
+331737330301A2D38BA6A68BD304EE010AB2B2FEF6000002003F029C02F405DF0002000D
+00D4401600030B07DD050109F703910E010C0A005D0608040C0E10DCD43CC4EC32113931
+0010F4FCD43CEC32123930014BB00E544BB00F545B4BB010545B4BB011545B4BB00B545B
+4BB00A545B58BD000E00400001000E000EFFC03811373859004BB011544BB00E545B58BD
+000EFFC00001000E000E0040381137385940540B011D012F01390149014603590369038B
+03AB03BB030B01000F010F020F050F060F070F080F0B0F0C0F0D13001F011F021F051F06
+1F071F081F0B1F0C1F0D2200350047004B0D53005B0D65008400A500B5001E5D015D0901
+21033311331523152335213501DDFECB013516A6878790FE620566FE5D021CFDE46DBABA
+7900000100C70506033905F8000D006A400E070004C30BFA0E0756080156000E10D4ECD4
+EC310010F4FCC43230004BB00C5458BD000EFFC00001000E000E00403811373859004BB0
+0E5458BD000E00400001000E000EFFC03811373859014BB00E544BB00F545B58BD000EFF
+C00001000E000E0040381137385913331E0133323637330E01232226C7760D6353526110
+760AA08F909F05F836393738777B7A000001019A050E026605DB00030011B60002FA0401
+000410D4CC310010F4CC3001331523019ACCCC05DBCD0000000000020001000000000014
+000300010000011A00000106000001000000000000000103000000020000000000000000
+00000000000000010000030405060708090A0B0C0D0E0F101112131415161718191A1B1C
+1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F40
+4142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F6061006263
+6465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F8081828384858687
+88898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAAB
+ACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF
+D0D100D2D3D4D5D6D7D8D9DADBDCDDDEDFE00004023E0000003A00200004001A007E00FF
+01070111011F01310142015301610178017E019202C702DD03A903C020262030203A20AC
+21222206221E222B2248226525CAFB02FFFF0000002000A00106010C011E013001410152
+015E0178017D019202C602D803A903C020132030203920AC21222202220F222B22482260
+25CAFB01FFFFFFE30000FFF50000FFD80000FFA0FF5E0000FF43FF68FF1400000000FCF6
+FCDB0000E096E085E056DF6A00000000DE71DE5F0000DAEF05BF000100000038000000F4
+000000FC0000000000FA00000000000000FA00FC00000000010200000000000000000120
+012800000000014200000000000000AC00A30084008500BD009600E70086008E008B009D
+00A900A40100008A00D90083009300F100F2008D0097008800C300DD00F0009E00AA00F3
+00F400F500A200AD00C900C700AE006200630090006400CB006500C800CA00CF00CC00CD
+00CE00E8006600D200D000D100AF006700EF009100D500D300D4006800EA00EC0089006A
+0069006B006D006C006E00A0006F0071007000720073007500740076007700E90078007A
+0079007B007D007C00B800A1007F007E0080008100EB00ED00BA00FD00FE000000000000
+00FF00F800D600F900FA00E300E400D700E000DA00DB00DC00DF00D800DE00B200B30000
+0000000000B600B700C4000000B400B500C50000008200C2008700000000000000AB0098
+00000000000000A8009A0000009900EE0000000000BC000000000000010100A500000000
+00000092008F0000000000000094009504CD006600000000028B0000028B000003350135
+03AE00C506B4009E051700AA079A0071063D0081023300C5031F00B0031F00A40400003D
+06B400D9028B009E02E30064028B00DB02B2000005170087051700E1051700960517009C
+051700640517009E0517008F051700A80517008B0517008102B200F002B2009E06B400D9
+06B400D906B400D9043F00930800008705790010057D00C905960073062900C9050E00C9
+049A00C906330073060400C9025C00C9025CFF96053F00C9047500C906E700C905FC00C9
+064C007304D300C9064C0073058F00C90514008704E3FFFA05DB00B20579001007E90044
+057B003D04E3FFFC057B005C031F00B002B20000031F00C706B400D90400FFEC040000AA
+04E7007B051400BA046600710514007104EC007102D1002F05140071051200BA023900C1
+0239FFDB04A200BA023900C107CB00BA051200BA04E50071051400BA05140071034A00BA
+042B006F03230037051200AE04BC003D068B005604BC003B04BC003D0433005805170100
+02B201040517010006B400D9057900100579001005960073050E00C905FC00C9064C0073
+05DB00B204E7007B04E7007B04E7007B04E7007B04E7007B04E7007B0466007104EC0071
+04EC007104EC007104EC0071023900900239FFC70239FFDE0239FFF4051200BA04E50071
+04E5007104E5007104E5007104E50071051200AE051200AE051200AE051200AE04000039
+040000C3051700AC051700810400005C04B801330517009E050A00BA0800011B0800011B
+0800012704000173040000D706B400D907CB0008064C006606AA00DD06B400D906B400D9
+06B400D905170052051700AE0423006805640019060E009C04B6FFE1042B002F03C50073
+03C50060061D004E07DB007B04E50048043F008F0335013506B400D90519003D0517001F
+06B400D9055AFFFA04E5009E04E500C1080000EC051700000579001005790010064C0073
+088F0073082F00710400000008000000042500AE042500AE028B00AE028B00B206B400D9
+03F4000604BC003D04E3FFFC0156FE890517005E0333009E033300C1050A002F050A002F
+04000039028B00DB028B00AE042500AE0ABC007105790010050E00C905790010050E00C9
+050E00C9025C00A2025CFFFE025C0006025C003B064C0073064C0073064C007305DB00B2
+05DB00B205DB00B2023900C1040000C1040000B6040000D5040000C70400019A040000EE
+04000123040000F00400014C040000C1047FFFF20246000205140087042B006F057B005C
+0433005802B201040633000A04E5007104E3FFFC04BC003D04D700C9051400BA06B400D9
+06B40119033500890335005E0335006207C1008907C1008907C100620633007305140071
+025C00C905140087042B006F059600730466007105960073046600710514007102E30064
+028B00DB05170000040000D704000173040000B60400010C040000CF040000CF0335003F
+040000C70400019A0002000000000000FF2B008F00000000000000000000000000000000
+00000000010C0000000100020003000400050006000700080009000A000B000C000D000E
+000F0010001100120013001400150016001700180019001A001B001C001D001E001F0020
+002100220023002400250026002700280029002A002B002C002D002E002F003000310032
+0033003400350036003700380039003A003B003C003D003E003F00400041004200430044
+00450046004700480049004A004B004C004D004E004F0050005100520053005400550056
+005700580059005A005B005C005D005E005F006000610062006300640065006600670068
+0069006A006B006C006D006E006F0070007100720073007400750076007700780079007A
+007B007C007D007E007F0080008100820083008400850086008700880089008A008B008C
+008D008E008F0090009100920093009400950096009700980099009A009B009C009D009E
+009F00A000A100A200A300A400A500A600A700A800A900AA00AB00AC00AD00AE00AF00B0
+00B100B200B300B400B500B600B700B800B900BA00BB00BC00BD00BE00BF00C000C100C2
+00C300C400C500C600C700C800C900CA00CB00CC00CD00CE00CF00D000D100D300D400D5
+00D600D700D800D900DA00DB00DC00DD00DE00DF00E000E100E200E300E400E500E600E7
+00E800E900EA00EB00EC00ED00EE00EF00F000F100F200F300F500F400F600F800F900FA
+00FB00FC00FD00FE00FF0100010101020103010401050106010701080109010A010B010C
+010D0973667468797068656E0E706572696F6463656E7465726564044575726F05633634
+353905633634363005633634363105633634363205633634363305633634363605633634
+36370563363436380563363436390000000000220022002200220058009300FF01B6024F
+038303B203F60421046E049804B404CA04DE0503054505820605067E06E1074C07B707FC
+086508CF08EE09160952097309AE0A1F0ADF0B580BB00BFB0C3A0C690C930CE60D140D3D
+0D7A0E0D0E2F0EAC0F000F450F850FEB107510F11129117011E012BD138A13EB1450148B
+14B114E115031518154015D61622166D16B91723177B17DF181B1843188018F819161977
+19B31A041A521AA11AD81B871BC41C001C9D1DBA1E871F771FE8205B207220F321352142
+21E221EF21FC2209221622232230223D224A225722642271227E228B229822A522B222BF
+22CC22D922E622F32300230D231A232723342341234E235B2368239423CF2434248F2533
+25532581261426BA274B279027B72813285828C3295F2A252A5C2AA32AE92B7A2BD32C44
+2C8F2CB12D502DA02E0E2E522EAA2F87304130BD31053121315031CF3248327A32DF3346
+33703370337D338A339733E6347A348F34A334D134FF351C353935673591359E35AB35CF
+365B369336CD374337A937EB3800381C384A390F391C3929393639433950395D396A3977
+39843991399E39AB39B839C539D239EF3A1C3A7B3AA03AE53B083B5E3B8E3BC43BF43C22
+3C5F3CA73CB43CC13CCE3CDB3CFE3D633E3B3E483E553E983EE73EFD3F613F8D3FDC403A
+404B405C406D407A4087409440A140AE40BB40C840D540E241404156416B424542AA42F7
+435F43B243FF445544DB452A453F00000000000100002D86000107941800000A15780010
+0024FFD300100025FFB70010002600000010002700000010002900000010002A004B0010
+002B00000010002D00720010002E00000010002F00000010003200390010003300000010
+0034004B00100035000000100037FF4400100039FF880010003AFFAD0010003BFF9A0010
+003CFF0D0010003D00000010004900000010005100000010005200260010005500000010
+0059FFC90010005A00000010005CFFDC00100062FFD30010006400000010006700390010
+007800000010007900260010007A00260010007B00260010007C00260010007D00260010
+00890000001000900000001000ADFFD3001000AEFFD3001000AF0039001000BAFFDC0010
+00BBFF0D001000C7FFD3001000C9FFD3001000D00039001000D10039001000D200390010
+00E50000001000E90000001000EAFF0D001000EBFFDC001000EC0000001000F6004B0010
+00FB0000001000FD000000240010FFD300240011FFDC0024001DFFDC0024002400390024
+0026FFDC0024002AFFDC00240032FFDC00240034FFDC00240036000000240037FF610024
+0038000000240039FF7D0024003AFF900024003B00000024003CFF6100240046FFDC0024
+0047FFDC00240048FFDC00240049FFB700240052FFDC00240054FFDC00240057FFDC0024
+0058000000240059FF880024005AFFAD0024005CFF7500240062003900240064FFDC0024
+0067FFDC0024006800000024006FFFDC00240070FFDC00240071FFDC00240072FFDC0024
+0073FFDC00240079FFDC0024007AFFDC0024007BFFDC0024007CFFDC0024007DFFDC0024
+007E00000024007F0000002400800000002400810000002400A9FFB7002400AA00000024
+00AD0039002400AE0039002400AFFFDC002400B4FEF8002400B5FF03002400BAFF750024
+00BBFF61002400C5002F002400C70039002400C90039002400D0FFDC002400D1FFDC0024
+00D2FFDC002400D30000002400D40000002400D50000002400E30000002400EAFF610024
+00EBFF75002400F6FFDC002400F90000002400FBFFDC002400FCFFDC002400FDFFDC0024
+00FEFFDC00250010000000250026FFDC0025002AFFDC00250032FFDC00250036FFDC0025
+0039FFC10025003AFFB70025003CFF9000250064FFDC00250067FFDC002500A9FFC10025
+00AAFFDC002500AFFFDC002500B4FF90002500B5FF90002500BBFF90002500C5FFAD0025
+00D0FFDC002500D1FFDC002500D2FFDC002500E3FFDC002500EAFF90002500F6FFDC0025
+00F9FFDC002500FBFFDC002500FDFFDC0026001000000026002400000026003600000026
+003CFFDC002600620000002600A9FFDC002600AAFFDC002600AD0000002600AE00000026
+00B40000002600B50026002600BBFFDC002600C50000002600C70000002600C900000026
+00E30000002600EAFFDC002600F9000000270010000000270024FFDC00270039FFDC0027
+003A00000027003CFF9000270062FFDC002700A9FFDC002700AAFFDC002700ADFFDC0027
+00AEFFDC002700B4FFD3002700B5FFC9002700BBFF90002700C5FF44002700C7FFDC0027
+00C9FFDC002700EAFF9000290010000000290011FEB70029001DFF6100290024FF440029
+0036FFDC00290037FFDC00290044FF4400290048FF900029004CFF6B00290052FFB70029
+0055FF6B00290058FF900029005CFF4400290062FF4400290069FF440029006AFF440029
+006BFF440029006CFF440029006DFF440029006EFF4400290070FF9000290071FF900029
+0072FF9000290073FF9000290079FFB70029007AFFB70029007BFFB70029007CFFB70029
+007DFFB70029007EFF900029007FFF9000290080FF9000290081FF90002900A900000029
+00AA0000002900ADFF44002900AEFF44002900B4FFD3002900B50000002900BAFF440029
+00C5FE88002900C7FF44002900C9FF44002900E3FFDC002900EBFF44002900F9FFDC002A
+00100000002A00240000002A0037FFB7002A003A0000002A003CFF9A002A00620000002A
+00A9FFDC002A00AAFFDC002A00AD0000002A00AE0000002A00B4FFD3002A00B5FFD3002A
+00BBFF9A002A00C5FFC9002A00C70000002A00C90000002A00EAFF9A002B00100000002B
+0011FFDC002B001D0000002B00A90000002B00AA0000002B00B4FFB7002B00B5FFC1002B
+00C5FFB7002D0010FFB7002D0024FFDC002D0062FFDC002D00A9FFDC002D00AAFFDC002D
+00ADFFDC002D00AEFFDC002D00B4FFB7002D00B5FFC1002D00C5FF90002D00C7FFDC002D
+00C9FFDC002E0010FF29002E0024FFDC002E0026FF90002E0032FF90002E0037FF61002E
+0038FFC9002E003AFFB7002E003CFFB7002E0044FFDC002E0048FF9A002E0052FF9A002E
+0058FF9A002E005CFF6B002E0062FFDC002E0064FF90002E0067FF90002E0068FFC9002E
+0069FFDC002E006AFFDC002E006BFFDC002E006CFFDC002E006DFFDC002E006EFFDC002E
+0070FF9A002E0071FF9A002E0072FF9A002E0073FF9A002E0079FF9A002E007AFF9A002E
+007BFF9A002E007CFF9A002E007DFF9A002E007EFF9A002E007FFF9A002E0080FF9A002E
+0081FF9A002E00A9FF7D002E00AA0000002E00ADFFDC002E00AEFFDC002E00AFFF90002E
+00B4FFC1002E00B5FFC1002E00BAFF6B002E00BBFFB7002E00C50000002E00C7FFDC002E
+00C9FFDC002E00D0FF90002E00D1FF90002E00D2FF90002E00D3FFC9002E00D4FFC9002E
+00D5FFC9002E00EAFFB7002E00EBFF6B002E00FBFF90002E00FDFF90002F0010FFDC002F
+0024002F002F0032FFB7002F0037FEE6002F0038FF9A002F0039FF1F002F003AFF44002F
+003CFEF0002F00440000002F0048FFDC002F0052FFDC002F0058FFDC002F005CFF44002F
+0062002F002F0067FFB7002F0068FF9A002F00690000002F006A0000002F006B0000002F
+006C0000002F006D0000002F006E0000002F0070FFDC002F0071FFDC002F0072FFDC002F
+0073FFDC002F0079FFDC002F007AFFDC002F007BFFDC002F007CFFDC002F007DFFDC002F
+007EFFDC002F007FFFDC002F0080FFDC002F0081FFDC002F00A90000002F00AA0000002F
+00AD002F002F00AE002F002F00AFFFB7002F00B4FE61002F00B5FDE6002F00BAFF44002F
+00BBFEF0002F00C50000002F00C7002F002F00C9002F002F00D0FFB7002F00D1FFB7002F
+00D2FFB7002F00D3FF9A002F00D4FF9A002F00D5FF9A002F00EAFEF0002F00EBFF440032
+0010003900320011FFAD0032001DFFDC00320024FFDC00320039FFDC0032003BFF7D0032
+003CFF9000320062FFDC003200A9FFDC003200AA0000003200ADFFDC003200AEFFDC0032
+00B4FFD3003200B5FFDC003200BBFF90003200C5FF44003200C7FFDC003200C9FFDC0032
+00EAFF9000330010FFD300330011FEC10033001D000000330024FF7D0033003800000033
+003A00000033003CFFD300330044FFA400330048FFB70033004CFFD300330051FFDC0033
+0052FFB700330055FFDC00330056FFDC00330058FFDC0033005C000000330062FF7D0033
+0068000000330069FFA40033006AFFA40033006BFFA40033006CFFA40033006DFFA40033
+006EFFA400330070FFB700330071FFB700330072FFB700330073FFB700330078FFDC0033
+0079FFB70033007AFFB70033007BFFB70033007CFFB70033007DFFB70033007EFFDC0033
+007FFFDC00330080FFDC00330081FFDC003300A9FFDC003300AA0000003300ADFF7D0033
+00AEFF7D003300B40026003300B50026003300BA0000003300BBFFD3003300C5FEB70033
+00C7FF7D003300C9FF7D003300D30000003300D40000003300D50000003300E4FFDC0033
+00EAFFD3003300EB0000003300FAFFDC003400100039003400A90000003400AA00000034
+00B4FFD3003400B5FFDC003400C5FF7D00350010FFAD00350011FFB70035001DFFC10035
+0024FFAD00350026FF9A00350037FF6B00350039FF900035003AFFAD0035003CFF7D0035
+0044FFD300350048FFA400350052FFA400350058FFA40035005CFF9000350062FFAD0035
+0064FF9A00350069FFD30035006AFFD30035006BFFD30035006CFFD30035006DFFD30035
+006EFFD300350070FFA400350071FFA400350072FFA400350073FFA400350079FFA40035
+007AFFA40035007BFFA40035007CFFA40035007DFFA40035007EFFA40035007FFFA40035
+0080FFA400350081FFA4003500A9FF90003500AAFFDC003500ADFFAD003500AEFFAD0035
+00B4FF6B003500B5FF7D003500BAFF90003500BBFF7D003500C5FFDC003500C7FFAD0035
+00C9FFAD003500EAFF7D003500EBFF90003500FBFF9A003500FDFF9A0036002400260036
+002600000036002A00000036003200000036003400000036003600000036006200260036
+00640000003600670000003600AD0026003600AE0026003600AF0000003600C700260036
+00C90026003600D00000003600D10000003600D20000003600E30000003600F600000036
+00F90000003600FB0000003600FD000000370010FF4400370011FF0D0037001DFF1F0037
+0024FF6100370026FF8800370037FFDC00370044FEAD00370046FEA400370048FEA40037
+004CFFC100370052FEA400370055FED300370056FEAD00370058FEC90037005AFEAD0037
+005CFEC100370062FF6100370064FF8800370069FEAD0037006AFEAD0037006BFEAD0037
+006CFEAD0037006DFEAD0037006EFEAD0037006FFEA400370070FEA400370071FEA40037
+0072FEA400370073FEA400370079FEA40037007AFEA40037007BFEA40037007CFEA40037
+007DFEA40037007EFEC90037007FFEC900370080FEC900370081FEC9003700A9FF440037
+00AAFF90003700ADFF61003700AEFF61003700B40000003700B5FFD3003700BAFEC10037
+00C5FEF8003700C7FF61003700C9FF61003700E4FEAD003700EBFEC1003700FAFEAD0037
+00FBFF88003700FCFEA4003700FDFF88003700FEFEA40038002400000038002D00000038
+003DFFDC003800620000003800AD0000003800AE0000003800C70000003800C900000038
+00E5FFDC00390010FF8800390011FEF80039001DFF5900390024FF7D00390032FFDC0039
+0044FF6100390048FF610039004CFFD300390052FF6100390058FF750039005CFFC90039
+0062FF7D00390067FFDC00390069FF610039006AFF610039006BFF610039006CFF610039
+006DFF610039006EFF6100390070FF6100390071FF6100390072FF6100390073FF610039
+0079FF610039007AFF610039007BFF610039007CFF610039007DFF610039007EFF750039
+007FFF7500390080FF7500390081FF75003900A9FF4E003900AAFF90003900ADFF7D0039
+00AEFF7D003900AFFFDC003900B40000003900B50000003900BAFFC9003900C5FEE60039
+00C7FF7D003900C9FF7D003900D0FFDC003900D1FFDC003900D2FFDC003900EBFFC9003A
+0010FFAD003A0011FF15003A001DFF88003A0024FF90003A0044FF7D003A0048FF88003A
+004CFFD3003A0052FF88003A0055FFA4003A0058FFB7003A005CFFDC003A0062FF90003A
+0069FF7D003A006AFF7D003A006BFF7D003A006CFF7D003A006DFF7D003A006EFF7D003A
+0070FF88003A0071FF88003A0072FF88003A0073FF88003A0079FF88003A007AFF88003A
+007BFF88003A007CFF88003A007DFF88003A007EFFB7003A007FFFB7003A0080FFB7003A
+0081FFB7003A00A9FF90003A00AAFFDC003A00ADFF90003A00AEFF90003A00B4FFDC003A
+00B50000003A00BAFFDC003A00C5FEF8003A00C7FF90003A00C9FF90003A00EBFFDC003B
+0010FF9A003B00240000003B0026FF6B003B0032FF7D003B0037FFDC003B0048FFA4003B
+00620000003B0064FF6B003B0067FF7D003B0070FFA4003B0071FFA4003B0072FFA4003B
+0073FFA4003B00A9FF90003B00AA0000003B00AD0000003B00AE0000003B00AFFF7D003B
+00B4FF61003B00B5FFAD003B00C5FFD3003B00C70000003B00C90000003B00D0FF7D003B
+00D1FF7D003B00D2FF7D003B00FBFF6B003B00FDFF6B003C0010FF0D003C0011FE61003C
+001DFEF0003C0024FF61003C0026FF90003C0032FF90003C0044FEE6003C0048FEF0003C
+004CFFB7003C0052FEF0003C0058FF15003C0062FF61003C0064FF90003C0067FF90003C
+0069FEE6003C006AFEE6003C006BFEE6003C006CFEE6003C006DFEE6003C006EFEE6003C
+0070FEF0003C0071FEF0003C0072FEF0003C0073FEF0003C0079FEF0003C007AFEF0003C
+007BFEF0003C007CFEF0003C007DFEF0003C007EFF15003C007FFF15003C0080FF15003C
+0081FF15003C00A9FF1F003C00AAFF6B003C00ADFF61003C00AEFF61003C00AFFF90003C
+00B4FF90003C00B5FFDC003C00C5FEF8003C00C7FF61003C00C9FF61003C00D0FF90003C
+00D1FF90003C00D2FF90003C00FBFF90003C00FDFF90003D0010FFDC003D00A90000003D
+00AA0000003D00B4FFDC003D00B5FFDC003D00C5FFDC0048005BFFDC00490010FF900049
+0011FF6B0049001DFFB700490057FFDC0049005AFFDC0049005CFFDC004900A9FFB70049
+00AAFFDC004900B40041004900B50000004900BAFFDC004900C5FF15004900EBFFDC004E
+0044FFDC004E0048FFB7004E0052FFB7004E0058FFC1004E005CFFB7004E0069FFDC004E
+006AFFDC004E006BFFDC004E006CFFDC004E006DFFDC004E006EFFDC004E0070FFB7004E
+0071FFB7004E0072FFB7004E0073FFB7004E0079FFB7004E007AFFB7004E007BFFB7004E
+007CFFB7004E007DFFB7004E007EFFC1004E007FFFC1004E0080FFC1004E0081FFC1004E
+00BAFFB7004E00EBFFB70051001000000051001100000051001D0000005100A900000051
+00AA0000005100B4FF6B005100B5FF90005100C5FFA400520010002600520011FFDC0052
+001D00000052005BFFC1005200A90000005200AA0000005200B4FF6B005200B5FFB70052
+00C5FF7D00550010FF7D00550011FF440055001DFFDC00550046FFD300550047FFDC0055
+0048FFD30055004900000055004AFFDC0055004BFFDC00550050FFDC00550051FFDC0055
+0052FFD300550054FFDC00550055FFDC0055005800000055005900000055005A00000055
+005BFFC90055005C00000055005D00000055006FFFD300550070FFD300550071FFD30055
+0072FFD300550073FFD300550078FFDC00550079FFD30055007AFFD30055007BFFD30055
+007CFFD30055007DFFD30055007E00000055007F00000055008000000055008100000055
+00A9FFB7005500AA0000005500B40000005500B50056005500BA0000005500C5FEC90055
+00E60000005500EB0000005500F7FFDC005500FCFFD3005500FEFFD300590010FFC90059
+0011FF610059001DFF90005900A9FFDC005900AAFFDC005900B40000005900B5FFDC0059
+00C5FEF0005A00100000005A0011FF44005A001DFF90005A00A9FFDC005A00AAFFDC005A
+00B40000005A00B50000005A00C5FF29005B0046FFDC005B0048FFC1005B0052FFC1005B
+006FFFDC005B0070FFC1005B0071FFC1005B0072FFC1005B0073FFC1005B0079FFC1005B
+007AFFC1005B007BFFC1005B007CFFC1005B007DFFC1005B00FCFFDC005B00FEFFDC005C
+0010FFDC005C0011FEDC005C001DFF6B005C00A9FFDC005C00AAFFDC005C00B40000005C
+00B50000005C00C5FED300620010FFD300620011FFDC0062001DFFDC0062002400390062
+0026FFDC0062002AFFDC00620032FFDC00620034FFDC00620036000000620037FF610062
+0038000000620039FF7D0062003AFF900062003B00000062003CFF6100620046FFDC0062
+0047FFDC00620048FFDC00620049FFB700620052FFDC00620054FFDC00620057FFDC0062
+0058000000620059FF880062005AFFAD0062005CFF7500620062003900620064FFDC0062
+0067FFDC0062006800000062006FFFDC00620070FFDC00620071FFDC00620072FFDC0062
+0073FFDC00620079FFDC0062007AFFDC0062007BFFDC0062007CFFDC0062007DFFDC0062
+007E00000062007F0000006200800000006200810000006200A9FFB7006200AA00000062
+00AD0039006200AE0039006200AFFFDC006200B4FEF8006200B5FF03006200BAFF750062
+00BBFF61006200C5002F006200C70039006200C90039006200D0FFDC006200D1FFDC0062
+00D2FFDC006200D30000006200D40000006200D50000006200E30000006200EAFF610062
+00EBFF75006200F6FFDC006200F90000006200FBFFDC006200FCFFDC006200FDFFDC0062
+00FEFFDC0064001000000064002400000064003600000064003CFFDC0064006200000064
+00A9FFDC006400AAFFDC006400AD0000006400AE0000006400B40000006400B500260064
+00BBFFDC006400C50000006400C70000006400C90000006400E30000006400EAFFDC0064
+00F9000000670010003900670011FFAD0067001DFFDC00670024FFDC00670039FFDC0067
+003BFF7D0067003CFF9000670062FFDC006700A9FFDC006700AA0000006700ADFFDC0067
+00AEFFDC006700B4FFD3006700B5FFDC006700BBFF90006700C5FF44006700C7FFDC0067
+00C9FFDC006700EAFF900068002400000068002D00000068003DFFDC0068006200000068
+00AD0000006800AE0000006800C70000006800C90000006800E5FFDC0070005BFFDC0071
+005BFFDC0072005BFFDC0073005BFFDC0078001000000078001100000078001D00000078
+00A90000007800AA0000007800B4FF6B007800B5FF90007800C5FFA40079001000260079
+0011FFDC0079001D00000079005BFFC1007900A90000007900AA0000007900B4FF6B0079
+00B5FFB7007900C5FF7D007A00100026007A0011FFDC007A001D0000007A005BFFC1007A
+00A90000007A00AA0000007A00B4FF6B007A00B5FFB7007A00C5FF7D007B00100026007B
+0011FFDC007B001D0000007B005BFFC1007B00A90000007B00AA0000007B00B4FF6B007B
+00B5FFB7007B00C5FF7D007C00100026007C0011FFDC007C001D0000007C005BFFC1007C
+00A90000007C00AA0000007C00B4FF6B007C00B5FFB7007C00C5FF7D007D00100026007D
+0011FFDC007D001D0000007D005BFFC1007D00A90000007D00AA0000007D00B4FF6B007D
+00B5FFB7007D00C5FF7D008900100026008900A90000008900AA0000008900B4FF900089
+00B5FF90008900C5FFAD009000100000009000A90000009000AA0000009000B4FFAD0090
+00B5FFA4009000C5FF9000A90024000000A90025FFDC00A90026FFDC00A90027FFDC00A9
+0029000000A9002AFFDC00A9002B000000A9002DFFDC00A9002E000000A9002F000000A9
+0032000000A90033000000A90034000000A90035000000A90037FF9000A90039FF9000A9
+003AFFDC00A9003B000000A9003CFF6B00A9003D000000A90049000000A90051000000A9
+0052000000A90055000000A90059FFDC00A9005AFFDC00A9005CFFDC00A90062000000A9
+0064FFDC00A90067000000A90078000000A90079000000A9007A000000A9007B000000A9
+007C000000A9007D000000A90089000000A90090009700A900AD000000A900AE000000A9
+00AF000000A900BAFFDC00A900BBFF6B00A900C7000000A900C9000000A900D0000000A9
+00D1000000A900D2000000A900E5000000A900E9000000A900EAFF6B00A900EBFFDC00A9
+00EC000000A900F6FFDC00A900FBFFDC00A900FDFFDC00AA0024FFB700AA0025FFB700AA
+0026FFDC00AA0027FFDC00AA0029000000AA002A000000AA002B000000AA002DFFDC00AA
+002E000000AA002F000000AA0032FFDC00AA0033000000AA0034000000AA0035000000AA
+0037FF4400AA0039FF4E00AA003AFF9000AA003BFF9000AA003CFF1F00AA003D000000AA
+0049000000AA0051000000AA0052000000AA0055000000AA0059FFDC00AA005AFFDC00AA
+005CFFDC00AA0062FFB700AA0064FFDC00AA0067FFDC00AA0078000000AA0079000000AA
+007A000000AA007B000000AA007C000000AA007D000000AA0089000000AA0090000000AA
+00ADFFB700AA00AEFFB700AA00AFFFDC00AA00BAFFDC00AA00BBFF1F00AA00C7FFB700AA
+00C9FFB700AA00D0FFDC00AA00D1FFDC00AA00D2FFDC00AA00E5000000AA00E9000000AA
+00EAFF1F00AA00EBFFDC00AA00EC000000AA00F6000000AA00FBFFDC00AA00FDFFDC00AD
+0010FFD300AD0011FFDC00AD001DFFDC00AD0024003900AD0026FFDC00AD002AFFDC00AD
+0032FFDC00AD0034FFDC00AD0036000000AD0037FF6100AD0038000000AD0039FF7D00AD
+003AFF9000AD003B000000AD003CFF6100AD0046FFDC00AD0047FFDC00AD0048FFDC00AD
+0049FFB700AD0052FFDC00AD0054FFDC00AD0057FFDC00AD0058000000AD0059FF8800AD
+005AFFAD00AD005CFF7500AD0062003900AD0064FFDC00AD0067FFDC00AD0068000000AD
+006FFFDC00AD0070FFDC00AD0071FFDC00AD0072FFDC00AD0073FFDC00AD0079FFDC00AD
+007AFFDC00AD007BFFDC00AD007CFFDC00AD007DFFDC00AD007E000000AD007F000000AD
+0080000000AD0081000000AD00A9FFB700AD00AA000000AD00AD003900AD00AE003900AD
+00AFFFDC00AD00B4FEF800AD00B5FF0300AD00BAFF7500AD00BBFF6100AD00C5002F00AD
+00C7003900AD00C9003900AD00D0FFDC00AD00D1FFDC00AD00D2FFDC00AD00D3000000AD
+00D4000000AD00D5000000AD00E3000000AD00EAFF6100AD00EBFF7500AD00F6FFDC00AD
+00F9000000AD00FBFFDC00AD00FCFFDC00AD00FDFFDC00AD00FEFFDC00AE0010FFD300AE
+0011FFDC00AE001DFFDC00AE0024003900AE0026FFDC00AE002AFFDC00AE0032FFDC00AE
+0034FFDC00AE0036000000AE0037FF6100AE0038000000AE0039FF7D00AE003AFF9000AE
+003B000000AE003CFF6100AE0046FFDC00AE0047FFDC00AE0048FFDC00AE0049FFB700AE
+0052FFDC00AE0054FFDC00AE0057FFDC00AE0058000000AE0059FF8800AE005AFFAD00AE
+005CFF7500AE0062003900AE0064FFDC00AE0067FFDC00AE0068000000AE006FFFDC00AE
+0070FFDC00AE0071FFDC00AE0072FFDC00AE0073FFDC00AE0079FFDC00AE007AFFDC00AE
+007BFFDC00AE007CFFDC00AE007DFFDC00AE007E000000AE007F000000AE0080000000AE
+0081000000AE00A9FFB700AE00AA000000AE00AD003900AE00AE003900AE00AFFFDC00AE
+00B4FEF800AE00B5FF0300AE00BAFF7500AE00BBFF6100AE00C5002F00AE00C7003900AE
+00C9003900AE00D0FFDC00AE00D1FFDC00AE00D2FFDC00AE00D3000000AE00D4000000AE
+00D5000000AE00E3000000AE00EAFF6100AE00EBFF7500AE00F6FFDC00AE00F9000000AE
+00FBFFDC00AE00FCFFDC00AE00FDFFDC00AE00FEFFDC00AF0010003900AF0011FFAD00AF
+001DFFDC00AF0024FFDC00AF0039FFDC00AF003BFF7D00AF003CFF9000AF0062FFDC00AF
+00A9FFDC00AF00AA000000AF00ADFFDC00AF00AEFFDC00AF00B4FFD300AF00B5FFDC00AF
+00BBFF9000AF00C5FF4400AF00C7FFDC00AF00C9FFDC00AF00EAFF9000B40024FEF800B4
+0025FFC100B40026FFB700B40027FFC100B40029FFC100B4002AFFB700B4002BFFC100B4
+002DFFC100B4002EFFC100B4002FFFC100B40032FFB700B40033FFC100B40034FFB700B4
+0035FFC100B40037000000B40039000000B4003A000000B4003BFF8800B4003C000000B4
+003DFFDC00B40049FFB700B40051FF9000B40052FF6B00B40055FF9000B40059FFB700B4
+005AFFB700B4005CFFB700B40062FEF800B40064FFB700B40067FFB700B40078FF9000B4
+0079FF6B00B4007AFF6B00B4007BFF6B00B4007CFF6B00B4007DFF6B00B40089FFC100B4
+0090FE7D00B400ADFEF800B400AEFEF800B400AFFFB700B400BAFFB700B400BB000000B4
+00C7FEF800B400C9FEF800B400D0FFB700B400D1FFB700B400D2FFB700B400E5FFDC00B4
+00E9FFB700B400EA000000B400EBFFB700B400ECFFC100B400F6FFB700B400FBFFB700B4
+00FDFFB700BA0010FFDC00BA0011FEDC00BA001DFF6B00BA00A9FFDC00BA00AAFFDC00BA
+00B4000000BA00B5000000BA00C5FED300BB0010FF0D00BB0011FE6100BB001DFEF000BB
+0024FF6100BB0026FF9000BB0032FF9000BB0044FEE600BB0048FEF000BB004CFFB700BB
+0052FEF000BB0058FF1500BB0062FF6100BB0064FF9000BB0067FF9000BB0069FEE600BB
+006AFEE600BB006BFEE600BB006CFEE600BB006DFEE600BB006EFEE600BB0070FEF000BB
+0071FEF000BB0072FEF000BB0073FEF000BB0079FEF000BB007AFEF000BB007BFEF000BB
+007CFEF000BB007DFEF000BB007EFF1500BB007FFF1500BB0080FF1500BB0081FF1500BB
+00A9FF1F00BB00AAFF6B00BB00ADFF6100BB00AEFF6100BB00AFFF9000BB00B4FF9000BB
+00B5FFDC00BB00C5FEF800BB00C7FF6100BB00C9FF6100BB00D0FF9000BB00D1FF9000BB
+00D2FF9000BB00FBFF9000BB00FDFF9000C50024002600C50025FFB700C50026FF9000C5
+0027FFB700C50029FFB700C5002AFFB700C5002BFFB700C5002D002F00C5002EFFB700C5
+002FFFB700C50032FF9000C50033FFB700C50034FF9000C50035FFB700C50037FEE600C5
+0039FE8800C5003AFF0300C5003BFFB700C5003CFE8800C5003D000000C50049FFDC00C5
+0051FFB700C50052FFB700C50055FFB700C50059FF1500C5005AFF3C00C5005CFF9000C5
+0062002600C50064FF9000C50067FF9000C50078FFB700C50079FFB700C5007AFFB700C5
+007BFFB700C5007CFFB700C5007DFFB700C50089FFB700C50090002600C500AD002600C5
+00AE002600C500AFFF9000C500BAFF9000C500BBFE8800C500C7002600C500C9002600C5
+00D0FF9000C500D1FF9000C500D2FF9000C500E5000000C500E9FFB700C500EAFE8800C5
+00EBFF9000C500ECFFB700C500F6FFB700C500FBFF9000C500FDFF9000C70010FFD300C7
+0011FFDC00C7001DFFDC00C70024003900C70026FFDC00C7002AFFDC00C70032FFDC00C7
+0034FFDC00C70036000000C70037FF6100C70038000000C70039FF7D00C7003AFF9000C7
+003B000000C7003CFF6100C70046FFDC00C70047FFDC00C70048FFDC00C70049FFB700C7
+0052FFDC00C70054FFDC00C70057FFDC00C70058000000C70059FF8800C7005AFFAD00C7
+005CFF7500C70062003900C70064FFDC00C70067FFDC00C70068000000C7006FFFDC00C7
+0070FFDC00C70071FFDC00C70072FFDC00C70073FFDC00C70079FFDC00C7007AFFDC00C7
+007BFFDC00C7007CFFDC00C7007DFFDC00C7007E000000C7007F000000C70080000000C7
+0081000000C700A9FFB700C700AA000000C700AD003900C700AE003900C700AFFFDC00C7
+00B4FEF800C700B5FF0300C700BAFF7500C700BBFF6100C700C5002F00C700C7003900C7
+00C9003900C700D0FFDC00C700D1FFDC00C700D2FFDC00C700D3000000C700D4000000C7
+00D5000000C700E3000000C700EAFF6100C700EBFF7500C700F6FFDC00C700F9000000C7
+00FBFFDC00C700FCFFDC00C700FDFFDC00C700FEFFDC00C90010FFD300C90011FFDC00C9
+001DFFDC00C90024003900C90026FFDC00C9002AFFDC00C90032FFDC00C90034FFDC00C9
+0036000000C90037FF6100C90038000000C90039FF7D00C9003AFF9000C9003B000000C9
+003CFF6100C90046FFDC00C90047FFDC00C90048FFDC00C90049FFB700C90052FFDC00C9
+0054FFDC00C90057FFDC00C90058000000C90059FF8800C9005AFFAD00C9005CFF7500C9
+0062003900C90064FFDC00C90067FFDC00C90068000000C9006FFFDC00C90070FFDC00C9
+0071FFDC00C90072FFDC00C90073FFDC00C90079FFDC00C9007AFFDC00C9007BFFDC00C9
+007CFFDC00C9007DFFDC00C9007E000000C9007F000000C90080000000C90081000000C9
+00A9FFB700C900AA000000C900AD003900C900AE003900C900AFFFDC00C900B4FEF800C9
+00B5FF0300C900BAFF7500C900BBFF6100C900C5002F00C900C7003900C900C9003900C9
+00D0FFDC00C900D1FFDC00C900D2FFDC00C900D3000000C900D4000000C900D5000000C9
+00E3000000C900EAFF6100C900EBFF7500C900F6FFDC00C900F9000000C900FBFFDC00C9
+00FCFFDC00C900FDFFDC00C900FEFFDC00D00010003900D00011FFAD00D0001DFFDC00D0
+0024FFDC00D00039FFDC00D0003BFF7D00D0003CFF9000D00062FFDC00D000A9FFDC00D0
+00AA000000D000ADFFDC00D000AEFFDC00D000B4FFD300D000B5FFDC00D000BBFF9000D0
+00C5FF4400D000C7FFDC00D000C9FFDC00D000EAFF9000D10010003900D10011FFAD00D1
+001DFFDC00D10024FFDC00D10039FFDC00D1003BFF7D00D1003CFF9000D10062FFDC00D1
+00A9FFDC00D100AA000000D100ADFFDC00D100AEFFDC00D100B4FFD300D100B5FFDC00D1
+00BBFF9000D100C5FF4400D100C7FFDC00D100C9FFDC00D100EAFF9000D20010003900D2
+0011FFAD00D2001DFFDC00D20024FFDC00D20039FFDC00D2003BFF7D00D2003CFF9000D2
+0062FFDC00D200A9FFDC00D200AA000000D200ADFFDC00D200AEFFDC00D200B4FFD300D2
+00B5FFDC00D200BBFF9000D200C5FF4400D200C7FFDC00D200C9FFDC00D200EAFF9000D3
+0024000000D3002D000000D3003DFFDC00D30062000000D300AD000000D300AE000000D3
+00C7000000D300C9000000D300E5FFDC00D40024000000D4002D000000D4003DFFDC00D4
+0062000000D400AD000000D400AE000000D400C7000000D400C9000000D400E5FFDC00D5
+0024000000D5002D000000D5003DFFDC00D50062000000D500AD000000D500AE000000D5
+00C7000000D500C9000000D500E5FFDC00E30024002600E30026000000E3002A000000E3
+0032000000E30034000000E30036000000E30062002600E30064000000E30067000000E3
+00AD002600E300AE002600E300AF000000E300C7002600E300C9002600E300D0000000E3
+00D1000000E300D2000000E300E3000000E300F6000000E300F9000000E300FB000000E3
+00FD000000E50010FFDC00E500A9000000E500AA000000E500B4FFDC00E500B5FFDC00E5
+00C5FFDC00E90010000000E900A9000000E900AA000000E900B4FFA400E900B5FF9000E9
+00C5FFB700EA0010FF0D00EA0011FE6100EA001DFEF000EA0024FF6100EA0026FF9000EA
+0032FF9000EA0044FEE600EA0048FEF000EA004CFFB700EA0052FEF000EA0058FF1500EA
+0062FF6100EA0064FF9000EA0067FF9000EA0069FEE600EA006AFEE600EA006BFEE600EA
+006CFEE600EA006DFEE600EA006EFEE600EA0070FEF000EA0071FEF000EA0072FEF000EA
+0073FEF000EA0079FEF000EA007AFEF000EA007BFEF000EA007CFEF000EA007DFEF000EA
+007EFF1500EA007FFF1500EA0080FF1500EA0081FF1500EA00A9FF1F00EA00AAFF6B00EA
+00ADFF6100EA00AEFF6100EA00AFFF9000EA00B4FF9000EA00B5FFDC00EA00C5FEF800EA
+00C7FF6100EA00C9FF6100EA00D0FF9000EA00D1FF9000EA00D2FF9000EA00FBFF9000EA
+00FDFF9000EB0010FFDC00EB0011FEDC00EB001DFF6B00EB00A9FFDC00EB00AAFFDC00EB
+00B4000000EB00B5000000EB00C5FED300EC0010000000EC0011FF6B00EC001DFFB700EC
+00A9000000EC00AA000000EC00B4FFDC00EC00B5000000EC00C5FF4400F60010000000F6
+0024000000F60037FFB700F6003A000000F6003CFF9A00F60062000000F600A9FFDC00F6
+00AAFFDC00F600AD000000F600AE000000F600B4FFD300F600B5FFD300F600BBFF9A00F6
+00C5FFC900F600C7000000F600C9000000F600EAFF9A00F90024002600F90026000000F9
+002A000000F90032000000F90034000000F90036000000F90062002600F90064000000F9
+0067000000F900AD002600F900AE002600F900AF000000F900C7002600F900C9002600F9
+00D0000000F900D1000000F900D2000000F900E3000000F900F6000000F900F9000000F9
+00FB000000F900FD000000FB0010000000FB0024000000FB0036000000FB003CFFDC00FB
+0062000000FB00A9FFDC00FB00AAFFDC00FB00AD000000FB00AE000000FB00B4000000FB
+00B5002600FB00BBFFDC00FB00C5000000FB00C7000000FB00C9000000FB00E3000000FB
+00EAFFDC00FB00F9000000FD0010000000FD0024000000FD0036000000FD003CFFDC00FD
+0062000000FD00A9FFDC00FD00AAFFDC00FD00AD000000FD00AE000000FD00B4000000FD
+00B5002600FD00BBFFDC00FD00C5000000FD00C7000000FD00C9000000FD00E3000000FD
+00EAFFDC00FD00F90000000000010000010C004D00070042000400020010004000070000
+041505680003000100010000076DFE1D00000ABCFE89FE890A4C00010000000000000000
+000000000000010C0001040E019000050004054704CC0000FE42054704CC00000253008F
+02660802020B0603030804020204800000AF1000204A0000000000000000426974730040
+0020FB020614FE14019A076D01E3000000010000000000000001000042001DB1028B0460
+0000236305D500005665726153616E730000000000000000FFFFFFFF36FFFFFE36323852
+30300000400000000000001400000110090C050003030304080609080204040508030303
+03060606060606060606060303080808050A060707070606070703030605080707060706
+070507060706050504030408050506060606060306060303050309060606060405040605
+070505060503050806060706070707060606060606060606060603030303060606060606
+060606060505060605050606090909050508090708080808060605060705050404070906
+05030806060806060609060606070A090509050503030804050502060404060605030305
+0C0606060606030303030707070707070305050505050505050505050307050506030706
+050506060808040404090909070603070507060706060303060505050505050405050000
+0A0D06000303040508060A09030404050803040303060606060606060606060303080808
+050B07070808070608080303070609080807080707050807090607060403040805050606
+050606040606020205020A06060606040504060608060605060306080707080708080806
+06060606060506060606020202020606060606060606060605050606050606060A0A0A05
+05080A0808080808060705070806050505080A060504080606080706060A060707080B0A
+050A0505030308050607020604040606050303050D070707070703030303080808080808
+02050505050505050505050602070506050308060706070608080404040A0A0A08060307
+05080508050604030605050505050504050500000B0F07000303030509070A0A03040406
+0904040404070707070707070707070404090909060C0708080807060908030307060908
+0907090708070807090707090404040906060707060707040707030306030B0707070705
+070407060906060507040709070708070809080707070707070607070707030303030707
+070707070707070706060707060607070B0B0B0606090B09090909090707060708060605
+05080B070603090707090707070B070707090C0B060B0606040409050607020704040707
+060404060F07070707070303030309090908080803060606060606060606060603080709
+050408070706070709090404040B0B0B0907030807080608060704040706060606060604
+060600000C100700040405050A080B0A030505060A040404040808080808080808080804
+040A0A0A060D0808080908070909030307060A0909080908080709080B0907090504050A
+06060808070808040808030307030B080808080507050806090606050804080A08080808
+090909080808080808070808080803030303080808080808080808080606080806070808
+0C0C0C06060A0C090A0A0A0A080806080907060606090C0806050A08080A0807070C0808
+08090D0D060C060604040A06060702080505070706040406100808080808030303030909
+090909090306060606060606060606060308070905040908070608080A0A0505050C0C0C
+0908030807080708070804040806060606060605060600000D110800040405050B080C0B
+030505070B040504040808080808080808080804040B0B0B070D0909090A08070A0A0303
+08070B0A0A080A0809070A090B0A070A0504050B07070808070808040808030307030D08
+0808080507050807090707070804080B090909080A0A0A08080808080807080808080303
+03030808080808080808080807070808070808080D0D0D07070B0D0A0B0B0B0B08080709
+0A080706060A0D0807050B08080B0908080D0809090A0E0D070D070704040B0607070208
+0505080807040407110908090808030303030A0A0A0A0A0A030707070707070707070707
+0309070A07040A08070708080B0B0505050D0D0D0A080309070907090708050408070707
+07070705070700000E130800040405050C090D0C030505070C0405040509090909090909
+09090905050C0C0C070E090A0A0B09080B0A030309070C0A0B090B0A09090A090D0B090A
+0505050C07070809080909040909030308030D0909090905080509070B0707080905090C
+09090A090A0B0A0808080808080809090909030303030909090909090909090907070909
+070809090E0E0E07070C0E0B0C0C0C0C090907090B080707070B0E0907050C09090C0909
+090E0909090B0F0F070E070704040C070709020906060808070404071309090909090303
+03030B0B0B0A0A0A0307070707070707070707070309080A08050B09090709090C0C0606
+060E0E0E0B090309080A080A080905040907070707070706070700000F14090005050606
+0D0A0E0B030606080D050505050A0A0A0A0A0A0A0A0A0A05050D0D0D080F0A0A0A0B0909
+0C0B03030A080D0B0C090C0A0A090B0A0F0A090B0605060D080809090809090509090303
+08030F0909090906080609080D0A08080A050A0D0A0A0A090B0C0B090909090909080909
+0909030303030909090909090909090908080A0A08090A090F0F0F08080D0F0C0D0D0D0D
+0A09080A0B090807070B0F0908060D0A0A0D0A09090F0A0A0A0C100F080F080805050D07
+0809030A0606090908050508140A090A0909030303030C0C0C0B0B0B0308080808080808
+08080808030A080B08050C09090809090D0D0606060F0F0F0C09030A080A080A08090505
+0A080808080808060808000010150A00050506060D0A0F0C030606080D050605050A0A0A
+0A0A0A0A0A0A0A05050D0D0D09100B0B0B0C0A090C0C05050A090D0C0D0A0D0B0A090C0B
+110B090C0605060D0808090A090A09060A0A030309030F0A0A0A0A0709060A090D0A0909
+0A050A0D0B0B0B0A0C0D0C0909090909090909090909030303030A0A0A0A0A0A0A0A0A0A
+08080A0A08090A0A10101008080D100D0D0D0D0D0A0A080B0C090808080C100A09060D0A
+0A0D0B0A0A100A0B0B0D110F0810080805050D080909030A06060A0A08050508150B0A0B
+0A0A050505050D0D0D0C0C0C030808080808080808080809040A090C09050D0A09090A0A
+0D0D0606061010100C0A050A090B090B090A06050A080808080808060808000011170A00
+050507080E0B100D050707090E050605060B0B0B0B0B0B0B0B0B0B06060E0E0E09110B0C
+0C0D0B0A0D0D06060C090F0D0D0A0D0C0B0A0D0B120D0A0C0706070E09090A0A080A0A06
+0A0B05050A05110B0A0A0A0708070B0A0F0A0A080B060B0E0B0B0C0B0D0D0D0A0A0A0A0A
+0A080A0A0A0A050505050B0A0A0A0A0A0B0B0B0B09090B0B090A0B0B11111109090E100D
+0E0E0E0E0B0B090B0D0A0908080D100A09070E0B0B0E0B0A0A110B0B0B0D121109110909
+05050E080A0A030B07070A0A09050509170B0B0B0B0B060606060D0D0D0D0D0D05090909
+090909090909090A050B080C08060D0A0A0A0A0A0E0E0707071010100D0A060B080C080C
+080A06050B090909090909070909000012180B00060607080F0B110D040707090F060706
+060B0B0B0B0B0B0B0B0B0B06060F0F0F0A120C0C0D0E0B0A0E0E06060C0A100E0E0B0E0D
+0B0C0E0C130D0C0D0706070F09090A0B090B0B060B0B05050A05110B0B0B0B0808070B0B
+100B0B090B060B0F0C0C0D0B0E0E0E0A0A0A0A0A0A090B0B0B0B050505050B0B0B0B0B0B
+0B0B0B0B09090B0B090B0B0B12121209090F110E0F0F0F0F0B0B090C0E0B0908080E110B
+0A070F0B0B0F0C0B0B120B0C0C0E13130912090906060F090B0C030B07070B0B09060609
+180C0B0C0B0B060606060E0E0E0E0E0E05090909090909090909090A050B080D09060E0B
+0C0B0B0B0F0F0707071111110E0B060B080D090D090B07060B0909090909090709090000
+131A0B0006060808100C120E0407070A10060706060C0C0C0C0C0C0C0C0C0C0606101010
+0A130D0D0D0F0C0B0F0E06060C0B100E0F0C0F0D0C0C0E0D140E0C0D070607100A0A0B0B
+090B0B060B0C05050B05110C0B0B0B0809080C0B110B0B0B0C060C100D0D0D0C0E0F0E0B
+0B0B0B0B0B090B0B0B0B050505050C0B0B0B0B0B0C0C0C0C0A0A0C0C0A0B0C0C1313130A
+0A10120F101010100C0C0A0D0E0B0A09090F120B0A08100C0C100D0C0C130C0D0D0F1413
+0A130A0A060610090B0C030C08080B0B0A06060A1A0D0C0D0C0C060606060F0F0F0E0E0E
+050A0A0A0A0A0A0A0A0A0A0B050C090D0B060F0B0C0B0C0B10100808081212120F0B060C
+090D090D090B07060C0A0A0A0A0A0A080A0A0000141B0C000606080A110D130F0608080A
+11060706070D0D0D0D0D0D0D0D0D0D07071111110B140E0E0E0F0D0C100F06060D0B110F
+100C100E0D0C0F0E140E0C0E080708110A0A0C0D0B0D0C070D0D06060C06140D0C0D0D08
+0A080D0B110B0B0B0D070D110E0E0E0D0F100F0C0C0C0C0C0C0B0C0C0C0C060606060D0C
+0C0C0C0C0D0D0D0D0A0A0D0D0A0C0D0D1414140A0A111410111111110D0D0A0D0F0C0A09
+090F130C0B08110D0D110D0C0C140D0E0E1015140A140A0A0606110A0B0C030D08080D0D
+0A06060A1B0E0D0E0D0D060606061010100F0F0F060A0A0A0A0A0A0A0A0A0A0B060D0A0E
+0B070F0C0C0B0C0D1111080808131313100D060D0A0E0B0E0B0D07060D0A0A0A0A0A0A08
+0A0A0000151C0D000707080A120D14100608080B12070807070D0D0D0D0D0D0D0D0D0D07
+071212120B150E0E0F100D0C101006060E0C1210110D110F0D0D0F0E150E0D0E08070812
+0B0B0D0D0C0D0D070D0D06060C06140E0D0D0D090B080E0B110D0D0B0D070D120E0E0F0D
+10110F0D0D0D0D0D0D0C0D0D0D0D060606060E0D0D0D0D0D0E0E0E0E0B0B0D0D0B0C0D0D
+1515150B0B121411121212120D0E0B0E100C0B0A0A10140D0B08120D0D120E0D0D150D0E
+0E1116160B150B0B0707120A0D0D040D08080D0D0B07070B1C0E0D0E0D0D060606061111
+110F0F0F060B0B0B0B0B0B0B0B0B0B0C060D0B0E0B07100D0D0D0D0D1212080808141414
+100D060D0B0F0C0F0C0D08070D0B0B0B0B0B0B080B0B0000161E0D000707090A120E1511
+0609090B12070807070E0E0E0E0E0E0E0E0E0E07071212120C160F0F0F110E0D11110606
+0E0C1310110D110F0E0D100F160F0D0F090709120B0B0D0E0C0E0D080E0E06060D06160E
+0D0E0E090B090E0E120E0E0C0E070E120F0F0F0E1011100D0D0D0D0D0D0C0D0D0D0D0606
+06060E0D0D0D0D0D0E0E0E0E0B0B0E0E0B0D0E0E1616160B0B121511121212120E0E0B0F
+110D0B0A0A11150D0C09120E0E120F0D0D160E0F0F1118160B160B0B0707120B0E0D040E
+09090D0D0B07070B1E0F0E0F0E0E06060606111111101010060B0B0B0B0B0B0B0B0B0B0C
+060E0B0F0C07110D0D0E0D0E1212090909151515110E060E0B0F0C0F0C0E08070E0B0B0B
+0B0B0B090B0B0000171F0E000707090B130F16120609090C13070807080F0F0F0F0F0F0F
+0F0F0F08081313130C17101010120F0D121107070F0D1411120E12100F0E111017100E10
+090809130C0C0E0F0D0F0E080F0F06060D06160F0E0E0E090C090F0E130E0E0C0F080F13
+1010100F1112110E0E0E0E0E0E0D0E0E0E0E060606060F0E0E0E0E0E0F0F0F0F0C0C0F0F
+0C0E0F0E1717170C0C131612131313130F0F0C10110E0C0B0B12150E0C09130F0F130F0E
+0E170F10101219180C170C0C0707130B0E0E040F09090F0F0C07070C1F100F100F0F0707
+0707121212111111060C0C0C0C0C0C0C0C0C0C0D060F0C100C08120E0E0E0E0E13130909
+09161616120F070F0C100D100D0F08070F0C0C0C0C0C0C090C0C000018200E0008080A0B
+140F17130709090C14080908080F0F0F0F0F0F0F0F0F0F08081414140D18101011120F0E
+13120707100D1512130E13110F0F121018100F10090809140C0C0E0F0D0F0E080F0F0707
+0E06180F0E0F0F0A0C090F0F140F0F0D0F080F141010110F1213120E0E0E0E0E0E0D0E0E
+0E0E070707070F0E0E0E0E0E0F0F0F0F0C0C0F0F0C0E0F0F1818180C0C14171314141414
+0F0F0C10120E0D0B0B12170E0D0A140F0F14100F0F180F1010131A180C180C0C0808140C
+0F0F040F0A0A0F0F0C08080C20100F100F0F07070707131313121212070C0C0C0C0C0C0C
+0C0C0C0D060F0C100D08130E0F0F0F0F14140A0A0A171717130F070F0C110D110D0F0908
+0F0C0C0C0C0C0C0A0C0C000019220F0008080A0C15101814070A0A0D1508090808101010
+1010101010101008081515150D1911111113100E13130707100E1613140F1411100F1211
+19110F110A080A150D0D0F100E100F09101007070E0718100F10100A0D0A100F140F0F0D
+10081015111111101314120F0F0F0F0F0F0E0F0F0F0F07070707100F0F0F0F0F10101010
+0D0D10100D0F10101919190D0D1518141515151510100D11130F0D0C0C13190F0D0A1510
+1015110F0F19101111141B1A0D190D0D0808150C0F0F04100A0A10100D08080D22111011
+101007070707141414121212070D0D0D0D0D0D0D0D0D0D0E07100D110D08130F0F0F0F10
+15150A0A0A181818131007100D110E110E100908100D0D0D0D0D0D0A0D0D00001A231000
+08080A0C16111914070A0A0D16080908091111111111111111111109091616160E1A1212
+1214100F14140808110E161314101412111013121A1210120A090A160D0D10110E111009
+111007070F0719101011110B0E0A100F150F0F0E11091116121212101314131010101010
+100E1010101007070707101010101010101010100D0D11110D0F11101A1A1A0D0D161914
+1616161611110D12140F0E0C0C141A100E0A161111161110101A111212141C1B0D1A0D0D
+0808160D0F1004110A0A10100D08080D23121012101008080808141414131313070D0D0D
+0D0D0D0D0D0D0D0F07110E120E091410100F101116160A0A0A191919141108110E120E12
+0E110908110D0D0D0D0D0D0A0D0D00001B24100009090B0C17111A15070B0B0E17090A09
+091111111111111111111109091717170E1B12131315111015140808120F171415101513
+111114121B1311130B090B170E0E11110F11110A1111080810081A111111110B0E0B1110
+1610100E11091117121213111415141111111111110F1111111108080808111111111111
+111111110E0E11110E1011111B1B1B0E0E171A151617171711110E1214100E0D0D151B11
+0E0B171111171211111B111212151D1C0E1B0E0E0909170D101105110B0B11110E09090E>
+<24121112111108080808151515141414080E0E0E0E0E0E0E0E0E0E0F08110E130E091511
+1110101117170B0B0B1A1A1A151108110E130F130F110A09110E0E0E0E0E0E0B0E0E0000
+1C26110009090B0D17121B16080B0B0E17090A0909121212121212121212120909171717
+0F1C131314161210161508081210181516111613121115131C1311130B090B170E0E1112
+0F12110A1212080810081B121112120C0F0B12111711110F120912171313141215161511
+11111111110F1111111108080808121111111111121212120E0E12120E1112121C1C1C0E
+0E171B161717171712120E1315100F0D0D151C110F0B171212171311111C121313161E1D
+0E1C0F0F0909170E111105120B0B12120E09090F26131213121208080808161616151515
+080E0E0E0E0E0E0E0E0E0E1008120F130F0916111111111217170B0B0B1B1B1B16120812
+0F140F140F120A09120E0E0E0E0E0E0B0E0E00000000000200080002FFFF000300010000
+000200000C500AEC5F0F3CF5001F080000000000BAB9F0B800000000BAC26791FE89FE1D
+0A4C076D00000008000100000000000000>
+] def
+/CharStrings 268 dict dup begin
+/.notdef 0 def /.null 1 def /nonmarkingreturn 2 def /space 3 def /exclam 4 def
+/quotedbl 5 def /numbersign 6 def /dollar 7 def /percent 8 def
+/ampersand 9 def /quotesingle 10 def /parenleft 11 def /parenright 12 def
+/asterisk 13 def /plus 14 def /comma 15 def /hyphen 16 def
+/period 17 def /slash 18 def /zero 19 def /one 20 def
+/two 21 def /three 22 def /four 23 def /five 24 def
+/six 25 def /seven 26 def /eight 27 def /nine 28 def
+/colon 29 def /semicolon 30 def /less 31 def /equal 32 def
+/greater 33 def /question 34 def /at 35 def /A 36 def
+/B 37 def /C 38 def /D 39 def /E 40 def
+/F 41 def /G 42 def /H 43 def /I 44 def
+/J 45 def /K 46 def /L 47 def /M 48 def
+/N 49 def /O 50 def /P 51 def /Q 52 def
+/R 53 def /S 54 def /T 55 def /U 56 def
+/V 57 def /W 58 def /X 59 def /Y 60 def
+/Z 61 def /bracketleft 62 def /backslash 63 def /bracketright 64 def
+/asciicircum 65 def /underscore 66 def /grave 67 def /a 68 def
+/b 69 def /c 70 def /d 71 def /e 72 def
+/f 73 def /g 74 def /h 75 def /i 76 def
+/j 77 def /k 78 def /l 79 def /m 80 def
+/n 81 def /o 82 def /p 83 def /q 84 def
+/r 85 def /s 86 def /t 87 def /u 88 def
+/v 89 def /w 90 def /x 91 def /y 92 def
+/z 93 def /braceleft 94 def /bar 95 def /braceright 96 def
+/asciitilde 97 def /Adieresis 98 def /Aring 99 def /Ccedilla 100 def
+/Eacute 101 def /Ntilde 102 def /Odieresis 103 def /Udieresis 104 def
+/aacute 105 def /agrave 106 def /acircumflex 107 def /adieresis 108 def
+/atilde 109 def /aring 110 def /ccedilla 111 def /eacute 112 def
+/egrave 113 def /ecircumflex 114 def /edieresis 115 def /iacute 116 def
+/igrave 117 def /icircumflex 118 def /idieresis 119 def /ntilde 120 def
+/oacute 121 def /ograve 122 def /ocircumflex 123 def /odieresis 124 def
+/otilde 125 def /uacute 126 def /ugrave 127 def /ucircumflex 128 def
+/udieresis 129 def /dagger 130 def /degree 131 def /cent 132 def
+/sterling 133 def /section 134 def /bullet 135 def /paragraph 136 def
+/germandbls 137 def /registered 138 def /copyright 139 def /trademark 140 def
+/acute 141 def /dieresis 142 def /notequal 143 def /AE 144 def
+/Oslash 145 def /infinity 146 def /plusminus 147 def /lessequal 148 def
+/greaterequal 149 def /yen 150 def /mu 151 def /partialdiff 152 def
+/summation 153 def /product 154 def /pi 155 def /integral 156 def
+/ordfeminine 157 def /ordmasculine 158 def /Omega 159 def /ae 160 def
+/oslash 161 def /questiondown 162 def /exclamdown 163 def /logicalnot 164 def
+/radical 165 def /florin 166 def /approxequal 167 def /Delta 168 def
+/guillemotleft 169 def /guillemotright 170 def /ellipsis 171 def /nonbreakingspace 172 def
+/Agrave 173 def /Atilde 174 def /Otilde 175 def /OE 176 def
+/oe 177 def /endash 178 def /emdash 179 def /quotedblleft 180 def
+/quotedblright 181 def /quoteleft 182 def /quoteright 183 def /divide 184 def
+/lozenge 185 def /ydieresis 186 def /Ydieresis 187 def /fraction 188 def
+/currency 189 def /guilsinglleft 190 def /guilsinglright 191 def /fi 192 def
+/fl 193 def /daggerdbl 194 def /periodcentered 195 def /quotesinglbase 196 def
+/quotedblbase 197 def /perthousand 198 def /Acircumflex 199 def /Ecircumflex 200 def
+/Aacute 201 def /Edieresis 202 def /Egrave 203 def /Iacute 204 def
+/Icircumflex 205 def /Idieresis 206 def /Igrave 207 def /Oacute 208 def
+/Ocircumflex 209 def /Ograve 210 def /Uacute 211 def /Ucircumflex 212 def
+/Ugrave 213 def /dotlessi 214 def /circumflex 215 def /tilde 216 def
+/macron 217 def /breve 218 def /dotaccent 219 def /ring 220 def
+/cedilla 221 def /hungarumlaut 222 def /ogonek 223 def /caron 224 def
+/Lslash 225 def /lslash 226 def /Scaron 227 def /scaron 228 def
+/Zcaron 229 def /zcaron 230 def /brokenbar 231 def /Eth 232 def
+/eth 233 def /Yacute 234 def /yacute 235 def /Thorn 236 def
+/thorn 237 def /minus 238 def /multiply 239 def /onesuperior 240 def
+/twosuperior 241 def /threesuperior 242 def /onequarter 243 def /onehalf 244 def
+/threequarters 245 def /Gbreve 246 def /gbreve 247 def /Idotaccent 248 def
+/Scedilla 249 def /scedilla 250 def /Cacute 251 def /cacute 252 def
+/Ccaron 253 def /ccaron 254 def /dcroat 255 def /sfthyphen 256 def
+/periodcentered 257 def /Euro 258 def /c6459 259 def /c6460 260 def
+/c6461 261 def /c6462 262 def /c6463 263 def /c6466 264 def
+/c6467 265 def /c6468 266 def /c6469 267 def 
+end readonly def
+FontName currentdict end definefont pop
+%%EndFont
+%%EndProlog
+mpldict begin
+18 180 translate
+576 432 0 0 clipbox
+% polygon
+1.000 setgray
+1.000 setlinewidth
+0 setlinejoin
+2 setlinecap
+[] 0 setdash
+0 0 m
+0 432 l
+576 432 l
+576 0 l
+closepath
+gsave
+fill
+grestore
+stroke
+% polygon
+0.000 setgray
+72 287.153 m
+72 388.8 l
+518.4 388.8 l
+518.4 287.153 l
+closepath
+gsave
+1.000 setgray
+fill
+grestore
+stroke
+% text
+/BitstreamVeraSans-Roman findfont
+12.000 scalefont
+setfont
+61 274.153 m
+(-2.0) show
+% line
+0.500 setlinewidth
+0 setlinecap
+127.800 287.153 m 127.800 291.153 l
+stroke
+% line
+127.800 287.153 m 127.800 291.153 l
+stroke
+% line
+127.800 384.800 m 127.800 388.800 l
+stroke
+% line
+127.800 384.800 m 127.800 388.800 l
+stroke
+% text
+116.8 274.153 m
+(-1.5) show
+% line
+183.600 287.153 m 183.600 291.153 l
+stroke
+% line
+183.600 287.153 m 183.600 291.153 l
+stroke
+% line
+183.600 384.800 m 183.600 388.800 l
+stroke
+% line
+183.600 384.800 m 183.600 388.800 l
+stroke
+% text
+172.6 274.153 m
+(-1.0) show
+% line
+239.400 287.153 m 239.400 291.153 l
+stroke
+% line
+239.400 287.153 m 239.400 291.153 l
+stroke
+% line
+239.400 384.800 m 239.400 388.800 l
+stroke
+% line
+239.400 384.800 m 239.400 388.800 l
+stroke
+% text
+228.4 274.153 m
+(-0.5) show
+% line
+295.200 287.153 m 295.200 291.153 l
+stroke
+% line
+295.200 287.153 m 295.200 291.153 l
+stroke
+% line
+295.200 384.800 m 295.200 388.800 l
+stroke
+% line
+295.200 384.800 m 295.200 388.800 l
+stroke
+% text
+286.2 274.153 m
+(0.0) show
+% line
+351.000 287.153 m 351.000 291.153 l
+stroke
+% line
+351.000 287.153 m 351.000 291.153 l
+stroke
+% line
+351.000 384.800 m 351.000 388.800 l
+stroke
+% line
+351.000 384.800 m 351.000 388.800 l
+stroke
+% text
+342 274.153 m
+(0.5) show
+% line
+406.800 287.153 m 406.800 291.153 l
+stroke
+% line
+406.800 287.153 m 406.800 291.153 l
+stroke
+% line
+406.800 384.800 m 406.800 388.800 l
+stroke
+% line
+406.800 384.800 m 406.800 388.800 l
+stroke
+% text
+397.8 274.153 m
+(1.0) show
+% line
+462.600 287.153 m 462.600 291.153 l
+stroke
+% line
+462.600 287.153 m 462.600 291.153 l
+stroke
+% line
+462.600 384.800 m 462.600 388.800 l
+stroke
+% line
+462.600 384.800 m 462.600 388.800 l
+stroke
+% text
+453.6 274.153 m
+(1.5) show
+% text
+509.4 274.153 m
+(2.0) show
+% text
+62 282.653 m
+(0) show
+% line
+72.000 304.094 m 76.000 304.094 l
+stroke
+% line
+72.000 304.094 m 76.000 304.094 l
+stroke
+% line
+514.400 304.094 m 518.400 304.094 l
+stroke
+% line
+514.400 304.094 m 518.400 304.094 l
+stroke
+% text
+54 299.594 m
+(10) show
+% line
+72.000 321.035 m 76.000 321.035 l
+stroke
+% line
+72.000 321.035 m 76.000 321.035 l
+stroke
+% line
+514.400 321.035 m 518.400 321.035 l
+stroke
+% line
+514.400 321.035 m 518.400 321.035 l
+stroke
+% text
+54 316.535 m
+(20) show
+% line
+72.000 337.976 m 76.000 337.976 l
+stroke
+% line
+72.000 337.976 m 76.000 337.976 l
+stroke
+% line
+514.400 337.976 m 518.400 337.976 l
+stroke
+% line
+514.400 337.976 m 518.400 337.976 l
+stroke
+% text
+54 333.476 m
+(30) show
+% line
+72.000 354.918 m 76.000 354.918 l
+stroke
+% line
+72.000 354.918 m 76.000 354.918 l
+stroke
+% line
+514.400 354.918 m 518.400 354.918 l
+stroke
+% line
+514.400 354.918 m 518.400 354.918 l
+stroke
+% text
+54 350.418 m
+(40) show
+% line
+72.000 371.859 m 76.000 371.859 l
+stroke
+% line
+72.000 371.859 m 76.000 371.859 l
+stroke
+% line
+514.400 371.859 m 518.400 371.859 l
+stroke
+% line
+514.400 371.859 m 518.400 371.859 l
+stroke
+% text
+54 367.359 m
+(50) show
+% text
+54 384.3 m
+(60) show
+% polygon
+1.000 setlinewidth
+2 setlinecap
+gsave
+446.400 101.647 72.000 287.153 clipbox
+110.696 287.153 m
+110.696 371.859 l
+114.017 371.859 l
+114.017 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+114.386 287.153 m
+114.386 290.541 l
+117.707 290.541 l
+117.707 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+118.076 287.153 m
+118.076 293.929 l
+121.397 293.929 l
+121.397 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+121.766 287.153 m
+121.766 292.235 l
+125.087 292.235 l
+125.087 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+125.456 287.153 m
+125.456 292.235 l
+128.777 292.235 l
+128.777 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+129.146 287.153 m
+129.146 287.153 l
+132.467 287.153 l
+132.467 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+132.836 287.153 m
+132.836 290.541 l
+136.157 290.541 l
+136.157 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+136.526 287.153 m
+136.526 288.847 l
+139.847 288.847 l
+139.847 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+140.216 287.153 m
+140.216 288.847 l
+143.537 288.847 l
+143.537 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+143.906 287.153 m
+143.906 292.235 l
+147.227 292.235 l
+147.227 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+147.596 287.153 m
+147.596 295.624 l
+150.918 295.624 l
+150.918 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+151.287 287.153 m
+151.287 295.624 l
+154.608 295.624 l
+154.608 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+154.977 287.153 m
+154.977 293.929 l
+158.298 293.929 l
+158.298 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+158.667 287.153 m
+158.667 293.929 l
+161.988 293.929 l
+161.988 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+162.357 287.153 m
+162.357 295.624 l
+165.678 295.624 l
+165.678 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+166.047 287.153 m
+166.047 288.847 l
+169.368 288.847 l
+169.368 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+169.737 287.153 m
+169.737 293.929 l
+173.058 293.929 l
+173.058 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+173.427 287.153 m
+173.427 293.929 l
+176.748 293.929 l
+176.748 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+177.117 287.153 m
+177.117 292.235 l
+180.438 292.235 l
+180.438 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+180.807 287.153 m
+180.807 292.235 l
+184.128 292.235 l
+184.128 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+184.497 287.153 m
+184.497 290.541 l
+187.818 290.541 l
+187.818 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+188.187 287.153 m
+188.187 290.541 l
+191.509 290.541 l
+191.509 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+191.878 287.153 m
+191.878 293.929 l
+195.199 293.929 l
+195.199 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+195.568 287.153 m
+195.568 299.012 l
+198.889 299.012 l
+198.889 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+199.258 287.153 m
+199.258 297.318 l
+202.579 297.318 l
+202.579 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+202.948 287.153 m
+202.948 297.318 l
+206.269 297.318 l
+206.269 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+206.638 287.153 m
+206.638 292.235 l
+209.959 292.235 l
+209.959 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+210.328 287.153 m
+210.328 297.318 l
+213.649 297.318 l
+213.649 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+214.018 287.153 m
+214.018 295.624 l
+217.339 295.624 l
+217.339 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+217.708 287.153 m
+217.708 292.235 l
+221.029 292.235 l
+221.029 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+221.398 287.153 m
+221.398 300.706 l
+224.719 300.706 l
+224.719 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+225.088 287.153 m
+225.088 290.541 l
+228.409 290.541 l
+228.409 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+228.778 287.153 m
+228.778 295.624 l
+232.099 295.624 l
+232.099 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+232.469 287.153 m
+232.469 293.929 l
+235.79 293.929 l
+235.79 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+236.159 287.153 m
+236.159 297.318 l
+239.48 297.318 l
+239.48 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+239.849 287.153 m
+239.849 300.706 l
+243.17 300.706 l
+243.17 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+243.539 287.153 m
+243.539 288.847 l
+246.86 288.847 l
+246.86 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+247.229 287.153 m
+247.229 290.541 l
+250.55 290.541 l
+250.55 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+250.919 287.153 m
+250.919 292.235 l
+254.24 292.235 l
+254.24 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+254.609 287.153 m
+254.609 290.541 l
+257.93 290.541 l
+257.93 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+258.299 287.153 m
+258.299 292.235 l
+261.62 292.235 l
+261.62 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+261.989 287.153 m
+261.989 295.624 l
+265.31 295.624 l
+265.31 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+265.679 287.153 m
+265.679 299.012 l
+269 299.012 l
+269 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+269.369 287.153 m
+269.369 299.012 l
+272.69 299.012 l
+272.69 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+273.059 287.153 m
+273.059 295.624 l
+276.381 295.624 l
+276.381 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+276.75 287.153 m
+276.75 295.624 l
+280.071 295.624 l
+280.071 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+280.44 287.153 m
+280.44 295.624 l
+283.761 295.624 l
+283.761 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+284.13 287.153 m
+284.13 293.929 l
+287.451 293.929 l
+287.451 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+287.82 287.153 m
+287.82 297.318 l
+291.141 297.318 l
+291.141 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+291.51 287.153 m
+291.51 293.929 l
+294.831 293.929 l
+294.831 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+295.2 287.153 m
+295.2 292.235 l
+298.521 292.235 l
+298.521 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+298.89 287.153 m
+298.89 295.624 l
+302.211 295.624 l
+302.211 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+302.58 287.153 m
+302.58 302.4 l
+305.901 302.4 l
+305.901 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+306.27 287.153 m
+306.27 292.235 l
+309.591 292.235 l
+309.591 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+309.96 287.153 m
+309.96 297.318 l
+313.281 297.318 l
+313.281 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+313.65 287.153 m
+313.65 295.624 l
+316.972 295.624 l
+316.972 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+317.341 287.153 m
+317.341 290.541 l
+320.662 290.541 l
+320.662 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+321.031 287.153 m
+321.031 297.318 l
+324.352 297.318 l
+324.352 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+324.721 287.153 m
+324.721 295.624 l
+328.042 295.624 l
+328.042 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+328.411 287.153 m
+328.411 293.929 l
+331.732 293.929 l
+331.732 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+332.101 287.153 m
+332.101 299.012 l
+335.422 299.012 l
+335.422 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+335.791 287.153 m
+335.791 288.847 l
+339.112 288.847 l
+339.112 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+339.481 287.153 m
+339.481 293.929 l
+342.802 293.929 l
+342.802 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+343.171 287.153 m
+343.171 295.624 l
+346.492 295.624 l
+346.492 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+346.861 287.153 m
+346.861 297.318 l
+350.182 297.318 l
+350.182 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+350.551 287.153 m
+350.551 295.624 l
+353.872 295.624 l
+353.872 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+354.241 287.153 m
+354.241 292.235 l
+357.562 292.235 l
+357.562 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+357.931 287.153 m
+357.931 295.624 l
+361.253 295.624 l
+361.253 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+361.622 287.153 m
+361.622 293.929 l
+364.943 293.929 l
+364.943 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+365.312 287.153 m
+365.312 292.235 l
+368.633 292.235 l
+368.633 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+369.002 287.153 m
+369.002 292.235 l
+372.323 292.235 l
+372.323 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+372.692 287.153 m
+372.692 300.706 l
+376.013 300.706 l
+376.013 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+376.382 287.153 m
+376.382 299.012 l
+379.703 299.012 l
+379.703 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+380.072 287.153 m
+380.072 292.235 l
+383.393 292.235 l
+383.393 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+383.762 287.153 m
+383.762 292.235 l
+387.083 292.235 l
+387.083 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+387.452 287.153 m
+387.452 292.235 l
+390.773 292.235 l
+390.773 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+391.142 287.153 m
+391.142 292.235 l
+394.463 292.235 l
+394.463 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+394.832 287.153 m
+394.832 293.929 l
+398.153 293.929 l
+398.153 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+398.522 287.153 m
+398.522 292.235 l
+401.844 292.235 l
+401.844 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+402.213 287.153 m
+402.213 300.706 l
+405.534 300.706 l
+405.534 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+405.903 287.153 m
+405.903 293.929 l
+409.224 293.929 l
+409.224 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+409.593 287.153 m
+409.593 297.318 l
+412.914 297.318 l
+412.914 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+413.283 287.153 m
+413.283 299.012 l
+416.604 299.012 l
+416.604 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+416.973 287.153 m
+416.973 290.541 l
+420.294 290.541 l
+420.294 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+420.663 287.153 m
+420.663 293.929 l
+423.984 293.929 l
+423.984 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+424.353 287.153 m
+424.353 290.541 l
+427.674 290.541 l
+427.674 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+428.043 287.153 m
+428.043 295.624 l
+431.364 295.624 l
+431.364 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+431.733 287.153 m
+431.733 290.541 l
+435.054 290.541 l
+435.054 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+435.423 287.153 m
+435.423 293.929 l
+438.744 293.929 l
+438.744 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+439.113 287.153 m
+439.113 290.541 l
+442.435 290.541 l
+442.435 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+442.804 287.153 m
+442.804 292.235 l
+446.125 292.235 l
+446.125 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+446.494 287.153 m
+446.494 292.235 l
+449.815 292.235 l
+449.815 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+450.184 287.153 m
+450.184 293.929 l
+453.505 293.929 l
+453.505 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+453.874 287.153 m
+453.874 290.541 l
+457.195 290.541 l
+457.195 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+457.564 287.153 m
+457.564 295.624 l
+460.885 295.624 l
+460.885 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+461.254 287.153 m
+461.254 292.235 l
+464.575 292.235 l
+464.575 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+464.944 287.153 m
+464.944 290.541 l
+468.265 290.541 l
+468.265 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+468.634 287.153 m
+468.634 290.541 l
+471.955 290.541 l
+471.955 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+472.324 287.153 m
+472.324 292.235 l
+475.645 292.235 l
+475.645 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 287.153 clipbox
+476.014 287.153 m
+476.014 382.024 l
+479.335 382.024 l
+479.335 287.153 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+72 165.176 m
+72 266.824 l
+518.4 266.824 l
+518.4 165.176 l
+closepath
+gsave
+1.000 setgray
+fill
+grestore
+stroke
+% text
+67 152.176 m
+(-4) show
+% line
+0.500 setlinewidth
+0 setlinecap
+127.800 165.176 m 127.800 169.176 l
+stroke
+% line
+127.800 165.176 m 127.800 169.176 l
+stroke
+% line
+127.800 262.824 m 127.800 266.824 l
+stroke
+% line
+127.800 262.824 m 127.800 266.824 l
+stroke
+% text
+122.8 152.176 m
+(-3) show
+% line
+183.600 165.176 m 183.600 169.176 l
+stroke
+% line
+183.600 165.176 m 183.600 169.176 l
+stroke
+% line
+183.600 262.824 m 183.600 266.824 l
+stroke
+% line
+183.600 262.824 m 183.600 266.824 l
+stroke
+% text
+178.577 152.176 m
+(-2) show
+% line
+239.400 165.176 m 239.400 169.176 l
+stroke
+% line
+239.400 165.176 m 239.400 169.176 l
+stroke
+% line
+239.400 262.824 m 239.400 266.824 l
+stroke
+% line
+239.400 262.824 m 239.400 266.824 l
+stroke
+% text
+234.9 152.176 m
+(-1) show
+% line
+295.200 165.176 m 295.200 169.176 l
+stroke
+% line
+295.200 165.176 m 295.200 169.176 l
+stroke
+% line
+295.200 262.824 m 295.200 266.824 l
+stroke
+% line
+295.200 262.824 m 295.200 266.824 l
+stroke
+% text
+292.2 152.176 m
+(0) show
+% line
+351.000 165.176 m 351.000 169.176 l
+stroke
+% line
+351.000 165.176 m 351.000 169.176 l
+stroke
+% line
+351.000 262.824 m 351.000 266.824 l
+stroke
+% line
+351.000 262.824 m 351.000 266.824 l
+stroke
+% text
+348.5 152.176 m
+(1) show
+% line
+406.800 165.176 m 406.800 169.176 l
+stroke
+% line
+406.800 165.176 m 406.800 169.176 l
+stroke
+% line
+406.800 262.824 m 406.800 266.824 l
+stroke
+% line
+406.800 262.824 m 406.800 266.824 l
+stroke
+% text
+403.777 152.176 m
+(2) show
+% line
+462.600 165.176 m 462.600 169.176 l
+stroke
+% line
+462.600 165.176 m 462.600 169.176 l
+stroke
+% line
+462.600 262.824 m 462.600 266.824 l
+stroke
+% line
+462.600 262.824 m 462.600 266.824 l
+stroke
+% text
+459.6 152.176 m
+(3) show
+% text
+515.4 152.176 m
+(4) show
+% text
+62 160.676 m
+(0) show
+% line
+72.000 182.118 m 76.000 182.118 l
+stroke
+% line
+72.000 182.118 m 76.000 182.118 l
+stroke
+% line
+514.400 182.118 m 518.400 182.118 l
+stroke
+% line
+514.400 182.118 m 518.400 182.118 l
+stroke
+% text
+54 177.618 m
+(20) show
+% line
+72.000 199.059 m 76.000 199.059 l
+stroke
+% line
+72.000 199.059 m 76.000 199.059 l
+stroke
+% line
+514.400 199.059 m 518.400 199.059 l
+stroke
+% line
+514.400 199.059 m 518.400 199.059 l
+stroke
+% text
+54 194.559 m
+(40) show
+% line
+72.000 216.000 m 76.000 216.000 l
+stroke
+% line
+72.000 216.000 m 76.000 216.000 l
+stroke
+% line
+514.400 216.000 m 518.400 216.000 l
+stroke
+% line
+514.400 216.000 m 518.400 216.000 l
+stroke
+% text
+54 211.5 m
+(60) show
+% line
+72.000 232.941 m 76.000 232.941 l
+stroke
+% line
+72.000 232.941 m 76.000 232.941 l
+stroke
+% line
+514.400 232.941 m 518.400 232.941 l
+stroke
+% line
+514.400 232.941 m 518.400 232.941 l
+stroke
+% text
+54 228.441 m
+(80) show
+% line
+72.000 249.882 m 76.000 249.882 l
+stroke
+% line
+72.000 249.882 m 76.000 249.882 l
+stroke
+% line
+514.400 249.882 m 518.400 249.882 l
+stroke
+% line
+514.400 249.882 m 518.400 249.882 l
+stroke
+% text
+46 245.382 m
+(100) show
+% text
+46 262.324 m
+(120) show
+% polygon
+1.000 setlinewidth
+2 setlinecap
+gsave
+446.400 101.647 72.000 165.176 clipbox
+112.122 165.176 m
+112.122 166.024 l
+115.427 166.024 l
+115.427 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+115.794 165.176 m
+115.794 165.176 l
+119.098 165.176 l
+119.098 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+119.465 165.176 m
+119.465 165.176 l
+122.77 165.176 l
+122.77 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+123.137 165.176 m
+123.137 165.176 l
+126.442 165.176 l
+126.442 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+126.809 165.176 m
+126.809 165.176 l
+130.113 165.176 l
+130.113 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+130.48 165.176 m
+130.48 165.176 l
+133.785 165.176 l
+133.785 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+134.152 165.176 m
+134.152 165.176 l
+137.456 165.176 l
+137.456 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+137.824 165.176 m
+137.824 165.176 l
+141.128 165.176 l
+141.128 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+141.495 165.176 m
+141.495 166.871 l
+144.8 166.871 l
+144.8 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+145.167 165.176 m
+145.167 166.871 l
+148.471 166.871 l
+148.471 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+148.838 165.176 m
+148.838 165.176 l
+152.143 165.176 l
+152.143 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+152.51 165.176 m
+152.51 166.871 l
+155.815 166.871 l
+155.815 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+156.182 165.176 m
+156.182 166.024 l
+159.486 166.024 l
+159.486 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+159.853 165.176 m
+159.853 166.024 l
+163.158 166.024 l
+163.158 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+163.525 165.176 m
+163.525 166.024 l
+166.829 166.024 l
+166.829 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+167.197 165.176 m
+167.197 166.024 l
+170.501 166.024 l
+170.501 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+170.868 165.176 m
+170.868 166.024 l
+174.173 166.024 l
+174.173 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+174.54 165.176 m
+174.54 166.024 l
+177.844 166.024 l
+177.844 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+178.211 165.176 m
+178.211 166.024 l
+181.516 166.024 l
+181.516 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+181.883 165.176 m
+181.883 165.176 l
+185.188 165.176 l
+185.188 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+185.555 165.176 m
+185.555 165.176 l
+188.859 165.176 l
+188.859 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+189.226 165.176 m
+189.226 167.718 l
+192.531 167.718 l
+192.531 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+192.898 165.176 m
+192.898 165.176 l
+196.202 165.176 l
+196.202 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+196.57 165.176 m
+196.57 169.412 l
+199.874 169.412 l
+199.874 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+200.241 165.176 m
+200.241 166.024 l
+203.546 166.024 l
+203.546 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+203.913 165.176 m
+203.913 166.024 l
+207.217 166.024 l
+207.217 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+207.584 165.176 m
+207.584 169.412 l
+210.889 169.412 l
+210.889 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+211.256 165.176 m
+211.256 168.565 l
+214.561 168.565 l
+214.561 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+214.928 165.176 m
+214.928 171.106 l
+218.232 171.106 l
+218.232 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+218.599 165.176 m
+218.599 167.718 l
+221.904 167.718 l
+221.904 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+222.271 165.176 m
+222.271 167.718 l
+225.575 167.718 l
+225.575 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+225.943 165.176 m
+225.943 169.412 l
+229.247 169.412 l
+229.247 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+229.614 165.176 m
+229.614 169.412 l
+232.919 169.412 l
+232.919 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+233.286 165.176 m
+233.286 166.024 l
+236.59 166.024 l
+236.59 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+236.957 165.176 m
+236.957 169.412 l
+240.262 169.412 l
+240.262 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+240.629 165.176 m
+240.629 171.953 l
+243.934 171.953 l
+243.934 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+244.301 165.176 m
+244.301 171.953 l
+247.605 171.953 l
+247.605 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+247.972 165.176 m
+247.972 170.259 l
+251.277 170.259 l
+251.277 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+251.644 165.176 m
+251.644 171.106 l
+254.948 171.106 l
+254.948 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+255.316 165.176 m
+255.316 171.106 l
+258.62 171.106 l
+258.62 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+258.987 165.176 m
+258.987 171.106 l
+262.292 171.106 l
+262.292 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+262.659 165.176 m
+262.659 171.106 l
+265.963 171.106 l
+265.963 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+266.33 165.176 m
+266.33 170.259 l
+269.635 170.259 l
+269.635 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+270.002 165.176 m
+270.002 169.412 l
+273.307 169.412 l
+273.307 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+273.674 165.176 m
+273.674 173.647 l
+276.978 173.647 l
+276.978 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+277.345 165.176 m
+277.345 177.882 l
+280.65 177.882 l
+280.65 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+281.017 165.176 m
+281.017 175.341 l
+284.321 175.341 l
+284.321 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+284.689 165.176 m
+284.689 179.576 l
+287.993 179.576 l
+287.993 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+288.36 165.176 m
+288.36 177.035 l
+291.665 177.035 l
+291.665 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+292.032 165.176 m
+292.032 260.047 l
+295.336 260.047 l
+295.336 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+295.703 165.176 m
+295.703 175.341 l
+299.008 175.341 l
+299.008 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+299.375 165.176 m
+299.375 178.729 l
+302.68 178.729 l
+302.68 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+303.047 165.176 m
+303.047 171.953 l
+306.351 171.953 l
+306.351 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+306.718 165.176 m
+306.718 171.106 l
+310.023 171.106 l
+310.023 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+310.39 165.176 m
+310.39 173.647 l
+313.694 173.647 l
+313.694 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+314.062 165.176 m
+314.062 171.106 l
+317.366 171.106 l
+317.366 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+317.733 165.176 m
+317.733 172.8 l
+321.038 172.8 l
+321.038 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+321.405 165.176 m
+321.405 171.106 l
+324.709 171.106 l
+324.709 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+325.076 165.176 m
+325.076 169.412 l
+328.381 169.412 l
+328.381 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+328.748 165.176 m
+328.748 171.106 l
+332.053 171.106 l
+332.053 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+332.42 165.176 m
+332.42 172.8 l
+335.724 172.8 l
+335.724 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+336.091 165.176 m
+336.091 170.259 l
+339.396 170.259 l
+339.396 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+339.763 165.176 m
+339.763 171.106 l
+343.067 171.106 l
+343.067 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+343.435 165.176 m
+343.435 169.412 l
+346.739 169.412 l
+346.739 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+347.106 165.176 m
+347.106 171.106 l
+350.411 171.106 l
+350.411 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+350.778 165.176 m
+350.778 168.565 l
+354.082 168.565 l
+354.082 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+354.449 165.176 m
+354.449 171.106 l
+357.754 171.106 l
+357.754 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+358.121 165.176 m
+358.121 167.718 l
+361.426 167.718 l
+361.426 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+361.793 165.176 m
+361.793 170.259 l
+365.097 170.259 l
+365.097 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+365.464 165.176 m
+365.464 171.953 l
+368.769 171.953 l
+368.769 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+369.136 165.176 m
+369.136 166.871 l
+372.44 166.871 l
+372.44 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+372.808 165.176 m
+372.808 170.259 l
+376.112 170.259 l
+376.112 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+376.479 165.176 m
+376.479 166.024 l
+379.784 166.024 l
+379.784 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+380.151 165.176 m
+380.151 169.412 l
+383.455 169.412 l
+383.455 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+383.822 165.176 m
+383.822 168.565 l
+387.127 168.565 l
+387.127 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+387.494 165.176 m
+387.494 170.259 l
+390.799 170.259 l
+390.799 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+391.166 165.176 m
+391.166 166.871 l
+394.47 166.871 l
+394.47 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+394.837 165.176 m
+394.837 166.024 l
+398.142 166.024 l
+398.142 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+398.509 165.176 m
+398.509 167.718 l
+401.813 167.718 l
+401.813 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+402.181 165.176 m
+402.181 167.718 l
+405.485 167.718 l
+405.485 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+405.852 165.176 m
+405.852 167.718 l
+409.157 167.718 l
+409.157 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+409.524 165.176 m
+409.524 166.024 l
+412.828 166.024 l
+412.828 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+413.195 165.176 m
+413.195 168.565 l
+416.5 168.565 l
+416.5 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+416.867 165.176 m
+416.867 166.024 l
+420.172 166.024 l
+420.172 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+420.539 165.176 m
+420.539 166.024 l
+423.843 166.024 l
+423.843 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+424.21 165.176 m
+424.21 165.176 l
+427.515 165.176 l
+427.515 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+427.882 165.176 m
+427.882 166.871 l
+431.186 166.871 l
+431.186 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+431.554 165.176 m
+431.554 165.176 l
+434.858 165.176 l
+434.858 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+435.225 165.176 m
+435.225 165.176 l
+438.53 165.176 l
+438.53 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+438.897 165.176 m
+438.897 165.176 l
+442.201 165.176 l
+442.201 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+442.568 165.176 m
+442.568 165.176 l
+445.873 165.176 l
+445.873 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+446.24 165.176 m
+446.24 165.176 l
+449.545 165.176 l
+449.545 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+449.912 165.176 m
+449.912 166.024 l
+453.216 166.024 l
+453.216 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+453.583 165.176 m
+453.583 165.176 l
+456.888 165.176 l
+456.888 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+457.255 165.176 m
+457.255 165.176 l
+460.559 165.176 l
+460.559 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+460.927 165.176 m
+460.927 165.176 l
+464.231 165.176 l
+464.231 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+464.598 165.176 m
+464.598 165.176 l
+467.903 165.176 l
+467.903 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+468.27 165.176 m
+468.27 165.176 l
+471.574 165.176 l
+471.574 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+471.941 165.176 m
+471.941 165.176 l
+475.246 165.176 l
+475.246 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 165.176 clipbox
+475.613 165.176 m
+475.613 166.024 l
+478.918 166.024 l
+478.918 165.176 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+72 43.2 m
+72 144.847 l
+518.4 144.847 l
+518.4 43.2 l
+closepath
+gsave
+1.000 setgray
+fill
+grestore
+stroke
+% text
+67 30.2 m
+(-3) show
+% line
+0.500 setlinewidth
+0 setlinecap
+146.400 43.200 m 146.400 47.200 l
+stroke
+% line
+146.400 43.200 m 146.400 47.200 l
+stroke
+% line
+146.400 140.847 m 146.400 144.847 l
+stroke
+% line
+146.400 140.847 m 146.400 144.847 l
+stroke
+% text
+141.377 30.2 m
+(-2) show
+% line
+220.800 43.200 m 220.800 47.200 l
+stroke
+% line
+220.800 43.200 m 220.800 47.200 l
+stroke
+% line
+220.800 140.847 m 220.800 144.847 l
+stroke
+% line
+220.800 140.847 m 220.800 144.847 l
+stroke
+% text
+216.3 30.2 m
+(-1) show
+% line
+295.200 43.200 m 295.200 47.200 l
+stroke
+% line
+295.200 43.200 m 295.200 47.200 l
+stroke
+% line
+295.200 140.847 m 295.200 144.847 l
+stroke
+% line
+295.200 140.847 m 295.200 144.847 l
+stroke
+% text
+292.2 30.2 m
+(0) show
+% line
+369.600 43.200 m 369.600 47.200 l
+stroke
+% line
+369.600 43.200 m 369.600 47.200 l
+stroke
+% line
+369.600 140.847 m 369.600 144.847 l
+stroke
+% line
+369.600 140.847 m 369.600 144.847 l
+stroke
+% text
+367.1 30.2 m
+(1) show
+% line
+444.000 43.200 m 444.000 47.200 l
+stroke
+% line
+444.000 43.200 m 444.000 47.200 l
+stroke
+% line
+444.000 140.847 m 444.000 144.847 l
+stroke
+% line
+444.000 140.847 m 444.000 144.847 l
+stroke
+% text
+440.977 30.2 m
+(2) show
+% text
+515.4 30.2 m
+(3) show
+% text
+62 38.7 m
+(0) show
+% line
+72.000 54.494 m 76.000 54.494 l
+stroke
+% line
+72.000 54.494 m 76.000 54.494 l
+stroke
+% line
+514.400 54.494 m 518.400 54.494 l
+stroke
+% line
+514.400 54.494 m 518.400 54.494 l
+stroke
+% text
+62 49.994 m
+(5) show
+% line
+72.000 65.788 m 76.000 65.788 l
+stroke
+% line
+72.000 65.788 m 76.000 65.788 l
+stroke
+% line
+514.400 65.788 m 518.400 65.788 l
+stroke
+% line
+514.400 65.788 m 518.400 65.788 l
+stroke
+% text
+54 61.288 m
+(10) show
+% line
+72.000 77.082 m 76.000 77.082 l
+stroke
+% line
+72.000 77.082 m 76.000 77.082 l
+stroke
+% line
+514.400 77.082 m 518.400 77.082 l
+stroke
+% line
+514.400 77.082 m 518.400 77.082 l
+stroke
+% text
+54 72.582 m
+(15) show
+% line
+72.000 88.376 m 76.000 88.376 l
+stroke
+% line
+72.000 88.376 m 76.000 88.376 l
+stroke
+% line
+514.400 88.376 m 518.400 88.376 l
+stroke
+% line
+514.400 88.376 m 518.400 88.376 l
+stroke
+% text
+54 83.876 m
+(20) show
+% line
+72.000 99.671 m 76.000 99.671 l
+stroke
+% line
+72.000 99.671 m 76.000 99.671 l
+stroke
+% line
+514.400 99.671 m 518.400 99.671 l
+stroke
+% line
+514.400 99.671 m 518.400 99.671 l
+stroke
+% text
+54 95.171 m
+(25) show
+% line
+72.000 110.965 m 76.000 110.965 l
+stroke
+% line
+72.000 110.965 m 76.000 110.965 l
+stroke
+% line
+514.400 110.965 m 518.400 110.965 l
+stroke
+% line
+514.400 110.965 m 518.400 110.965 l
+stroke
+% text
+54 106.465 m
+(30) show
+% line
+72.000 122.259 m 76.000 122.259 l
+stroke
+% line
+72.000 122.259 m 76.000 122.259 l
+stroke
+% line
+514.400 122.259 m 518.400 122.259 l
+stroke
+% line
+514.400 122.259 m 518.400 122.259 l
+stroke
+% text
+54 117.759 m
+(35) show
+% line
+72.000 133.553 m 76.000 133.553 l
+stroke
+% line
+72.000 133.553 m 76.000 133.553 l
+stroke
+% line
+514.400 133.553 m 518.400 133.553 l
+stroke
+% line
+514.400 133.553 m 518.400 133.553 l
+stroke
+% text
+54 129.053 m
+(40) show
+% text
+54 140.347 m
+(45) show
+% polygon
+1.000 setlinewidth
+2 setlinecap
+gsave
+446.400 101.647 72.000 43.200 clipbox
+83.455 43.2 m
+83.455 45.459 l
+87.317 45.459 l
+87.317 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+87.746 43.2 m
+87.746 43.2 l
+91.608 43.2 l
+91.608 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+92.037 43.2 m
+92.037 43.2 l
+95.899 43.2 l
+95.899 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+96.328 43.2 m
+96.328 43.2 l
+100.191 43.2 l
+100.191 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+100.62 43.2 m
+100.62 43.2 l
+104.482 43.2 l
+104.482 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+104.911 43.2 m
+104.911 43.2 l
+108.773 43.2 l
+108.773 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+109.202 43.2 m
+109.202 45.459 l
+113.064 45.459 l
+113.064 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+113.494 43.2 m
+113.494 43.2 l
+117.356 43.2 l
+117.356 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+117.785 43.2 m
+117.785 45.459 l
+121.647 45.459 l
+121.647 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+122.076 43.2 m
+122.076 45.459 l
+125.938 45.459 l
+125.938 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+126.367 43.2 m
+126.367 45.459 l
+130.23 45.459 l
+130.23 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+130.659 43.2 m
+130.659 43.2 l
+134.521 43.2 l
+134.521 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+134.95 43.2 m
+134.95 45.459 l
+138.812 45.459 l
+138.812 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+139.241 43.2 m
+139.241 43.2 l
+143.103 43.2 l
+143.103 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+143.533 43.2 m
+143.533 45.459 l
+147.395 45.459 l
+147.395 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+147.824 43.2 m
+147.824 47.718 l
+151.686 47.718 l
+151.686 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+152.115 43.2 m
+152.115 45.459 l
+155.977 45.459 l
+155.977 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+156.406 43.2 m
+156.406 47.718 l
+160.269 47.718 l
+160.269 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+160.698 43.2 m
+160.698 43.2 l
+164.56 43.2 l
+164.56 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+164.989 43.2 m
+164.989 43.2 l
+168.851 43.2 l
+168.851 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+169.28 43.2 m
+169.28 45.459 l
+173.142 45.459 l
+173.142 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+173.572 43.2 m
+173.572 45.459 l
+177.434 45.459 l
+177.434 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+177.863 43.2 m
+177.863 47.718 l
+181.725 47.718 l
+181.725 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+182.154 43.2 m
+182.154 90.635 l
+186.016 90.635 l
+186.016 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+186.445 43.2 m
+186.445 45.459 l
+190.308 45.459 l
+190.308 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+190.737 43.2 m
+190.737 54.494 l
+194.599 54.494 l
+194.599 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+195.028 43.2 m
+195.028 49.976 l
+198.89 49.976 l
+198.89 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+199.319 43.2 m
+199.319 52.235 l
+203.181 52.235 l
+203.181 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+203.611 43.2 m
+203.611 54.494 l
+207.473 54.494 l
+207.473 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+207.902 43.2 m
+207.902 45.459 l
+211.764 45.459 l
+211.764 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+212.193 43.2 m
+212.193 49.976 l
+216.055 49.976 l
+216.055 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+216.484 43.2 m
+216.484 56.753 l
+220.347 56.753 l
+220.347 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+220.776 43.2 m
+220.776 59.012 l
+224.638 59.012 l
+224.638 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+225.067 43.2 m
+225.067 52.235 l
+228.929 52.235 l
+228.929 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+229.358 43.2 m
+229.358 52.235 l
+233.22 52.235 l
+233.22 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+233.65 43.2 m
+233.65 56.753 l
+237.512 56.753 l
+237.512 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+237.941 43.2 m
+237.941 120 l
+241.803 120 l
+241.803 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+242.232 43.2 m
+242.232 63.529 l
+246.094 63.529 l
+246.094 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+246.523 43.2 m
+246.523 52.235 l
+250.386 52.235 l
+250.386 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+250.815 43.2 m
+250.815 70.306 l
+254.677 70.306 l
+254.677 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+255.106 43.2 m
+255.106 59.012 l
+258.968 59.012 l
+258.968 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+259.397 43.2 m
+259.397 72.565 l
+263.259 72.565 l
+263.259 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+263.689 43.2 m
+263.689 65.788 l
+267.551 65.788 l
+267.551 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+267.98 43.2 m
+267.98 49.976 l
+271.842 49.976 l
+271.842 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+272.271 43.2 m
+272.271 70.306 l
+276.133 70.306 l
+276.133 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+276.562 43.2 m
+276.562 56.753 l
+280.425 56.753 l
+280.425 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+280.854 43.2 m
+280.854 74.824 l
+284.716 74.824 l
+284.716 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+285.145 43.2 m
+285.145 74.824 l
+289.007 74.824 l
+289.007 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+289.436 43.2 m
+289.436 74.824 l
+293.298 74.824 l
+293.298 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+293.728 43.2 m
+293.728 68.047 l
+297.59 68.047 l
+297.59 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+298.019 43.2 m
+298.019 74.824 l
+301.881 74.824 l
+301.881 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+302.31 43.2 m
+302.31 74.824 l
+306.172 74.824 l
+306.172 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+306.601 43.2 m
+306.601 49.976 l
+310.464 49.976 l
+310.464 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+310.893 43.2 m
+310.893 81.6 l
+314.755 81.6 l
+314.755 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+315.184 43.2 m
+315.184 70.306 l
+319.046 70.306 l
+319.046 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+319.475 43.2 m
+319.475 61.271 l
+323.337 61.271 l
+323.337 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+323.767 43.2 m
+323.767 59.012 l
+327.629 59.012 l
+327.629 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+328.058 43.2 m
+328.058 61.271 l
+331.92 61.271 l
+331.92 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+332.349 43.2 m
+332.349 63.529 l
+336.211 63.529 l
+336.211 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+336.64 43.2 m
+336.64 54.494 l
+340.503 54.494 l
+340.503 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+340.932 43.2 m
+340.932 63.529 l
+344.794 63.529 l
+344.794 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+345.223 43.2 m
+345.223 56.753 l
+349.085 56.753 l
+349.085 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+349.514 43.2 m
+349.514 140.329 l
+353.376 140.329 l
+353.376 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+353.806 43.2 m
+353.806 68.047 l
+357.668 68.047 l
+357.668 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+358.097 43.2 m
+358.097 59.012 l
+361.959 59.012 l
+361.959 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+362.388 43.2 m
+362.388 59.012 l
+366.25 59.012 l
+366.25 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+366.679 43.2 m
+366.679 54.494 l
+370.542 54.494 l
+370.542 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+370.971 43.2 m
+370.971 56.753 l
+374.833 56.753 l
+374.833 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+375.262 43.2 m
+375.262 47.718 l
+379.124 47.718 l
+379.124 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+379.553 43.2 m
+379.553 49.976 l
+383.415 49.976 l
+383.415 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+383.844 43.2 m
+383.844 49.976 l
+387.707 49.976 l
+387.707 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+388.136 43.2 m
+388.136 52.235 l
+391.998 52.235 l
+391.998 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+392.427 43.2 m
+392.427 54.494 l
+396.289 54.494 l
+396.289 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+396.718 43.2 m
+396.718 59.012 l
+400.58 59.012 l
+400.58 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+401.01 43.2 m
+401.01 52.235 l
+404.872 52.235 l
+404.872 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+405.301 43.2 m
+405.301 81.6 l
+409.163 81.6 l
+409.163 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+409.592 43.2 m
+409.592 45.459 l
+413.454 45.459 l
+413.454 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+413.883 43.2 m
+413.883 47.718 l
+417.746 47.718 l
+417.746 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+418.175 43.2 m
+418.175 45.459 l
+422.037 45.459 l
+422.037 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+422.466 43.2 m
+422.466 45.459 l
+426.328 45.459 l
+426.328 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+426.757 43.2 m
+426.757 45.459 l
+430.619 45.459 l
+430.619 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+431.049 43.2 m
+431.049 45.459 l
+434.911 45.459 l
+434.911 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+435.34 43.2 m
+435.34 47.718 l
+439.202 47.718 l
+439.202 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+439.631 43.2 m
+439.631 43.2 l
+443.493 43.2 l
+443.493 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+443.922 43.2 m
+443.922 43.2 l
+447.785 43.2 l
+447.785 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+448.214 43.2 m
+448.214 45.459 l
+452.076 45.459 l
+452.076 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+452.505 43.2 m
+452.505 47.718 l
+456.367 47.718 l
+456.367 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+456.796 43.2 m
+456.796 43.2 l
+460.658 43.2 l
+460.658 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+461.088 43.2 m
+461.088 45.459 l
+464.95 45.459 l
+464.95 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+465.379 43.2 m
+465.379 43.2 l
+469.241 43.2 l
+469.241 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+469.67 43.2 m
+469.67 45.459 l
+473.532 45.459 l
+473.532 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+473.961 43.2 m
+473.961 43.2 l
+477.824 43.2 l
+477.824 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+478.253 43.2 m
+478.253 43.2 l
+482.115 43.2 l
+482.115 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+482.544 43.2 m
+482.544 43.2 l
+486.406 43.2 l
+486.406 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+486.835 43.2 m
+486.835 43.2 l
+490.697 43.2 l
+490.697 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+491.127 43.2 m
+491.127 43.2 l
+494.989 43.2 l
+494.989 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+495.418 43.2 m
+495.418 43.2 l
+499.28 43.2 l
+499.28 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+499.709 43.2 m
+499.709 43.2 l
+503.571 43.2 l
+503.571 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+504 43.2 m
+504 43.2 l
+507.863 43.2 l
+507.863 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+% polygon
+gsave
+446.400 101.647 72.000 43.200 clipbox
+508.292 43.2 m
+508.292 45.459 l
+512.154 45.459 l
+512.154 43.2 l
+closepath
+gsave
+0.000 0.000 1.000 setrgbcolor
+fill
+grestore
+stroke
+grestore
+
+end
+showpage
diff --git a/doc/figures/portfolio1.eps b/doc/figures/portfolio1.eps
new file mode 100644
index 0000000..b296921
--- /dev/null
+++ b/doc/figures/portfolio1.eps
@@ -0,0 +1,2152 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Title: portfolio1.eps
+%%Creator: matplotlib version 0.87.2, http://matplotlib.sourceforge.net/
+%%CreationDate: Wed Sep 13 10:10:08 2006
+%%Orientation: portrait
+%%BoundingBox: 18 180 594 612
+%%EndComments
+%%BeginProlog
+/mpldict 7 dict def
+mpldict begin
+/m { moveto } bind def
+/l { lineto } bind def
+/r { rlineto } bind def
+/box {
+m
+1 index 0 r
+0 exch r
+neg 0 r
+closepath
+} bind def
+/clipbox {
+box
+clip
+newpath
+} bind def
+/ellipse {
+newpath
+matrix currentmatrix 7 1 roll
+translate
+scale
+0 0 1 5 3 roll arc
+setmatrix
+closepath
+} bind def
+%%BeginFont: BitstreamVeraSans-Roman
+%!PS-TrueType-1.0-2.0
+8 dict begin
+/FontName /BitstreamVeraSans-Roman def
+/FontMatrix [1 0 0 1 0 0] def
+/FontType 42 def
+/Encoding StandardEncoding def
+/FontBBox [-375 -483 2636 1901] def
+/PaintType 0 def
+/FontInfo 7 dict dup begin
+/Notice (Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.) def
+/FamilyName (Bitstream Vera Sans) def
+/FullName (Bitstream Vera Sans) def
+/version (Release 1.10) def
+/isFixedPitch false def
+/UnderlinePosition -213 def
+/UnderlineThickness 143 def
+end readonly def
+/sfnts [
+<0001000000110100000400104F532F32B45FF4630000EB700000005650434C54D18A5E97
+0000EBC800000036636D6170A4C3E8A00000B16C0000035863767420FFD31D3900001EFC
+000001FC6670676DE7B4F1C4000026600000008B6761737000070007000101480000000C
+676C79660C7441CF000026EC00008A7E68646D7834F0210E0000EC000000154868656164
+DD84A2D00001015400000036686865611045086F0000EB4C00000024686D747809C68EB2
+0000B4C4000004306B65726EDC52D5990000BDA000002D8A6C6F6361F3CBD23D0000BB84
+0000021A6D6178700547063A0000EB2C000000206E616D65D9BCC8B50000011C00001DDF
+706F7374B45A2FBB0000B8F40000028E707265703B07F100000020F80000056800000016
+010E0001000000000000003A000000010000000000010013003A00010000000000020005
+005F00010000000000030013003A00010000000000040013003A0001000000000005000C
+006400010000000000060017004D0001000000000007003000AD0001000000000008000E
+086C000100000000000B00180983000100000000000D0913007000030001040900000074
+099B000300010409000100260A0F0003000104090002000A0A5900030001040900030026
+0A0F000300010409000400260A0F000300010409000500180A630003000104090006002E
+0A35000300010409000700600AF50003000104090008001C1A73000300010409000B0030
+1CA1000300010409000D12260A7B436F7079726967687420286329203230303320627920
+42697473747265616D2C20496E632E20416C6C205269676874732052657365727665642E
+42697473747265616D20566572612053616E7342697473747265616D5665726153616E73
+2D526F6D616E52656C6561736520312E3130436F70797269676874202863292032303033
+2062792042697473747265616D2C20496E632E0D0A416C6C205269676874732052657365
+727665642E0D0A42697473747265616D205665726120697320612074726164656D61726B
+206F662042697473747265616D2C20496E632E0D0A0D0A5065726D697373696F6E206973
+20686572656279206772616E7465642C2066726565206F66206368617267652C20746F20
+616E7920706572736F6E206F627461696E696E67206120636F7079206F66207468652066
+6F6E7473206163636F6D70616E79696E672074686973206C6963656E7365202822466F6E
+7473222920616E64206173736F63696174656420646F63756D656E746174696F6E206669
+6C657320287468652022466F6E7420536F66747761726522292C20746F20726570726F64
+75636520616E6420646973747269627574652074686520466F6E7420536F667477617265
+2C20696E636C7564696E6720776974686F7574206C696D69746174696F6E207468652072
+696768747320746F207573652C20636F70792C206D657267652C207075626C6973682C20
+646973747269627574652C20616E642F6F722073656C6C20636F70696573206F66207468
+6520466F6E7420536F6674776172652C20616E6420746F207065726D697420706572736F
+6E7320746F2077686F6D2074686520466F6E7420536F667477617265206973206675726E
+697368656420746F20646F20736F2C207375626A65637420746F2074686520666F6C6C6F
+77696E6720636F6E646974696F6E733A0D0A0D0A5468652061626F766520636F70797269
+67687420616E642074726164656D61726B206E6F746963657320616E6420746869732070
+65726D697373696F6E206E6F74696365207368616C6C20626520696E636C756465642069
+6E20616C6C20636F70696573206F66206F6E65206F72206D6F7265206F66207468652046
+6F6E7420536F667477617265207479706566616365732E0D0A0D0A54686520466F6E7420
+536F667477617265206D6179206265206D6F6469666965642C20616C74657265642C206F
+7220616464656420746F2C20616E6420696E20706172746963756C617220746865206465
+7369676E73206F6620676C79706873206F72206368617261637465727320696E20746865
+20466F6E7473206D6179206265206D6F64696669656420616E64206164646974696F6E61
+6C20676C79706873206F722063686172616374657273206D617920626520616464656420
+746F2074686520466F6E74732C206F6E6C792069662074686520666F6E74732061726520
+72656E616D656420746F206E616D6573206E6F7420636F6E7461696E696E672065697468
+65722074686520776F726473202242697473747265616D22206F722074686520776F7264
+202256657261222E0D0A0D0A54686973204C6963656E7365206265636F6D6573206E756C
+6C20616E6420766F696420746F2074686520657874656E74206170706C696361626C6520
+746F20466F6E7473206F7220466F6E7420536F6674776172652074686174206861732062
+65656E206D6F64696669656420616E6420697320646973747269627574656420756E6465
+7220746865202242697473747265616D205665726122206E616D65732E0D0A0D0A546865
+20466F6E7420536F667477617265206D617920626520736F6C642061732070617274206F
+662061206C617267657220736F667477617265207061636B61676520627574206E6F2063
+6F7079206F66206F6E65206F72206D6F7265206F662074686520466F6E7420536F667477
+61726520747970656661636573206D617920626520736F6C6420627920697473656C662E
+0D0A0D0A54484520464F4E5420534F4654574152452049532050524F5649444544202241
+53204953222C20574954484F55542057415252414E5459204F4620414E59204B494E442C
+2045585052455353204F5220494D504C4945442C20494E434C5544494E4720425554204E
+4F54204C494D4954454420544F20414E592057415252414E54494553204F46204D455243
+48414E544142494C4954592C204649544E45535320464F52204120504152544943554C41
+5220505552504F534520414E44204E4F4E494E4652494E47454D454E54204F4620434F50
+5952494748542C20504154454E542C2054524144454D41524B2C204F52204F5448455220
+52494748542E20494E204E4F204556454E54205348414C4C2042495453545245414D204F
+522054484520474E4F4D4520464F554E444154494F4E204245204C4941424C4520464F52
+20414E5920434C41494D2C2044414D41474553204F52204F54484552204C494142494C49
+54592C20494E434C5544494E4720414E592047454E4552414C2C205350454349414C2C20
+494E4449524543542C20494E434944454E54414C2C204F5220434F4E53455155454E5449
+414C2044414D414745532C205748455448455220494E20414E20414354494F4E204F4620
+434F4E54524143542C20544F5254204F52204F54484552574953452C2041524953494E47
+2046524F4D2C204F5554204F462054484520555345204F5220494E4142494C4954592054
+4F205553452054484520464F4E5420534F465457415245204F522046524F4D204F544845
+52204445414C494E475320494E2054484520464F4E5420534F4654574152452E0D0A0D0A
+45786365707420617320636F6E7461696E656420696E2074686973206E6F746963652C20
+746865206E616D6573206F6620476E6F6D652C2074686520476E6F6D6520466F756E6461
+74696F6E2C20616E642042697473747265616D20496E632E2C207368616C6C206E6F7420
+6265207573656420696E206164766572746973696E67206F72206F746865727769736520
+746F2070726F6D6F7465207468652073616C652C20757365206F72206F74686572206465
+616C696E677320696E207468697320466F6E7420536F66747761726520776974686F7574
+207072696F72207772697474656E20617574686F72697A6174696F6E2066726F6D207468
+6520476E6F6D6520466F756E646174696F6E206F722042697473747265616D20496E632E
+2C20726573706563746976656C792E20466F72206675727468657220696E666F726D6174
+696F6E2C20636F6E746163743A20666F6E747320617420676E6F6D6520646F74206F7267
+2E687474703A2F2F7777772E62697473747265616D2E636F6D0043006F00700079007200
+690067006800740020002800630029002000320030003000330020006200790020004200
+69007400730074007200650061006D002C00200049006E0063002E00200041006C006C00
+20005200690067006800740073002000520065007300650072007600650064002E004200
+69007400730074007200650061006D00200056006500720061002000530061006E007300
+420069007400730074007200650061006D005600650072006100530061006E0073002D00
+52006F006D0061006E00520065006C006500610073006500200031002E00310030004300
+6F0070007900720069006700680074002000280063002900200032003000300033002000
+620079002000420069007400730074007200650061006D002C00200049006E0063002E00
+0D000A0041006C006C002000520069006700680074007300200052006500730065007200
+7600650064002E000D000A00420069007400730074007200650061006D00200056006500
+72006100200069007300200061002000740072006100640065006D00610072006B002000
+6F0066002000420069007400730074007200650061006D002C00200049006E0063002E00
+0D000A000D000A005000650072006D0069007300730069006F006E002000690073002000
+68006500720065006200790020006700720061006E007400650064002C00200066007200
+6500650020006F00660020006300680061007200670065002C00200074006F0020006100
+6E007900200070006500720073006F006E0020006F0062007400610069006E0069006E00
+670020006100200063006F007000790020006F0066002000740068006500200066006F00
+6E007400730020006100630063006F006D00700061006E00790069006E00670020007400
+68006900730020006C006900630065006E007300650020002800220046006F006E007400
+730022002900200061006E00640020006100730073006F00630069006100740065006400
+200064006F00630075006D0065006E0074006100740069006F006E002000660069006C00
+65007300200028007400680065002000220046006F006E007400200053006F0066007400
+7700610072006500220029002C00200074006F00200072006500700072006F0064007500
+63006500200061006E006400200064006900730074007200690062007500740065002000
+740068006500200046006F006E007400200053006F006600740077006100720065002C00
+200069006E0063006C007500640069006E006700200077006900740068006F0075007400
+20006C0069006D00690074006100740069006F006E002000740068006500200072006900
+6700680074007300200074006F0020007500730065002C00200063006F00700079002C00
+20006D0065007200670065002C0020007000750062006C006900730068002C0020006400
+6900730074007200690062007500740065002C00200061006E0064002F006F0072002000
+730065006C006C00200063006F00700069006500730020006F0066002000740068006500
+200046006F006E007400200053006F006600740077006100720065002C00200061006E00
+6400200074006F0020007000650072006D0069007400200070006500720073006F006E00
+7300200074006F002000770068006F006D002000740068006500200046006F006E007400
+200053006F0066007400770061007200650020006900730020006600750072006E006900
+7300680065006400200074006F00200064006F00200073006F002C002000730075006200
+6A00650063007400200074006F002000740068006500200066006F006C006C006F007700
+69006E006700200063006F006E0064006900740069006F006E0073003A000D000A000D00
+0A005400680065002000610062006F0076006500200063006F0070007900720069006700
+68007400200061006E0064002000740072006100640065006D00610072006B0020006E00
+6F0074006900630065007300200061006E00640020007400680069007300200070006500
+72006D0069007300730069006F006E0020006E006F007400690063006500200073006800
+61006C006C00200062006500200069006E0063006C007500640065006400200069006E00
+200061006C006C00200063006F00700069006500730020006F00660020006F006E006500
+20006F00720020006D006F007200650020006F0066002000740068006500200046006F00
+6E007400200053006F006600740077006100720065002000740079007000650066006100
+6300650073002E000D000A000D000A00540068006500200046006F006E00740020005300
+6F0066007400770061007200650020006D006100790020006200650020006D006F006400
+690066006900650064002C00200061006C00740065007200650064002C0020006F007200
+200061006400640065006400200074006F002C00200061006E006400200069006E002000
+70006100720074006900630075006C006100720020007400680065002000640065007300
+690067006E00730020006F006600200067006C00790070006800730020006F0072002000
+6300680061007200610063007400650072007300200069006E0020007400680065002000
+46006F006E007400730020006D006100790020006200650020006D006F00640069006600
+690065006400200061006E00640020006100640064006900740069006F006E0061006C00
+200067006C00790070006800730020006F00720020006300680061007200610063007400
+65007200730020006D006100790020006200650020006100640064006500640020007400
+6F002000740068006500200046006F006E00740073002C0020006F006E006C0079002000
+690066002000740068006500200066006F006E0074007300200061007200650020007200
+65006E0061006D0065006400200074006F0020006E0061006D006500730020006E006F00
+7400200063006F006E007400610069006E0069006E006700200065006900740068006500
+72002000740068006500200077006F007200640073002000220042006900740073007400
+7200650061006D00220020006F0072002000740068006500200077006F00720064002000
+2200560065007200610022002E000D000A000D000A00540068006900730020004C006900
+630065006E007300650020006200650063006F006D006500730020006E0075006C006C00
+200061006E006400200076006F0069006400200074006F00200074006800650020006500
+7800740065006E00740020006100700070006C0069006300610062006C00650020007400
+6F00200046006F006E007400730020006F007200200046006F006E007400200053006F00
+660074007700610072006500200074006800610074002000680061007300200062006500
+65006E0020006D006F00640069006600690065006400200061006E006400200069007300
+200064006900730074007200690062007500740065006400200075006E00640065007200
+200074006800650020002200420069007400730074007200650061006D00200056006500
+72006100220020006E0061006D00650073002E000D000A000D000A005400680065002000
+46006F006E007400200053006F0066007400770061007200650020006D00610079002000
+62006500200073006F006C0064002000610073002000700061007200740020006F006600
+2000610020006C0061007200670065007200200073006F00660074007700610072006500
+20007000610063006B00610067006500200062007500740020006E006F00200063006F00
+7000790020006F00660020006F006E00650020006F00720020006D006F00720065002000
+6F0066002000740068006500200046006F006E007400200053006F006600740077006100
+72006500200074007900700065006600610063006500730020006D006100790020006200
+6500200073006F006C006400200062007900200069007400730065006C0066002E000D00
+0A000D000A00540048004500200046004F004E005400200053004F004600540057004100
+520045002000490053002000500052004F00560049004400450044002000220041005300
+20004900530022002C00200057004900540048004F005500540020005700410052005200
+41004E005400590020004F004600200041004E00590020004B0049004E0044002C002000
+450058005000520045005300530020004F005200200049004D0050004C00490045004400
+2C00200049004E0043004C005500440049004E004700200042005500540020004E004F00
+540020004C0049004D004900540045004400200054004F00200041004E00590020005700
+41005200520041004E00540049004500530020004F00460020004D004500520043004800
+41004E0054004100420049004C004900540059002C0020004600490054004E0045005300
+5300200046004F00520020004100200050004100520054004900430055004C0041005200
+200050005500520050004F0053004500200041004E00440020004E004F004E0049004E00
+4600520049004E00470045004D0045004E00540020004F004600200043004F0050005900
+520049004700480054002C00200050004100540045004E0054002C002000540052004100
+440045004D00410052004B002C0020004F00520020004F00540048004500520020005200
+49004700480054002E00200049004E0020004E004F0020004500560045004E0054002000
+5300480041004C004C002000420049005400530054005200450041004D0020004F005200
+2000540048004500200047004E004F004D004500200046004F0055004E00440041005400
+49004F004E0020004200450020004C004900410042004C004500200046004F0052002000
+41004E005900200043004C00410049004D002C002000440041004D004100470045005300
+20004F00520020004F00540048004500520020004C0049004100420049004C0049005400
+59002C00200049004E0043004C005500440049004E004700200041004E00590020004700
+45004E004500520041004C002C0020005300500045004300490041004C002C0020004900
+4E004400490052004500430054002C00200049004E0043004900440045004E0054004100
+4C002C0020004F005200200043004F004E00530045005100550045004E00540049004100
+4C002000440041004D0041004700450053002C0020005700480045005400480045005200
+200049004E00200041004E00200041004300540049004F004E0020004F00460020004300
+4F004E00540052004100430054002C00200054004F005200540020004F00520020004F00
+540048004500520057004900530045002C002000410052004900530049004E0047002000
+460052004F004D002C0020004F005500540020004F004600200054004800450020005500
+5300450020004F005200200049004E004100420049004C00490054005900200054004F00
+20005500530045002000540048004500200046004F004E005400200053004F0046005400
+570041005200450020004F0052002000460052004F004D0020004F005400480045005200
+20004400450041004C0049004E0047005300200049004E00200054004800450020004600
+4F004E005400200053004F004600540057004100520045002E000D000A000D000A004500
+78006300650070007400200061007300200063006F006E007400610069006E0065006400
+200069006E002000740068006900730020006E006F0074006900630065002C0020007400
+6800650020006E0061006D006500730020006F006600200047006E006F006D0065002C00
+2000740068006500200047006E006F006D006500200046006F0075006E00640061007400
+69006F006E002C00200061006E0064002000420069007400730074007200650061006D00
+200049006E0063002E002C0020007300680061006C006C0020006E006F00740020006200
+650020007500730065006400200069006E00200061006400760065007200740069007300
+69006E00670020006F00720020006F007400680065007200770069007300650020007400
+6F002000700072006F006D006F007400650020007400680065002000730061006C006500
+2C00200075007300650020006F00720020006F0074006800650072002000640065006100
+6C0069006E0067007300200069006E0020007400680069007300200046006F006E007400
+200053006F00660074007700610072006500200077006900740068006F00750074002000
+7000720069006F00720020007700720069007400740065006E0020006100750074006800
+6F00720069007A006100740069006F006E002000660072006F006D002000740068006500
+200047006E006F006D006500200046006F0075006E0064006100740069006F006E002000
+6F0072002000420069007400730074007200650061006D00200049006E0063002E002C00
+200072006500730070006500630074006900760065006C0079002E00200046006F007200
+20006600750072007400680065007200200069006E0066006F0072006D00610074006900
+6F006E002C00200063006F006E0074006100630074003A00200066006F006E0074007300
+200061007400200067006E006F006D006500200064006F00740020006F00720067002E00
+68007400740070003A002F002F007700770077002E006200690074007300740072006500
+61006D002E0063006F006D00013500B800CB00CB00C100AA009C01A600B8006600000071
+00CB00A002B20085007500B800C301CB0189022D00CB00A600F000D300AA008700CB03AA
+0400014A003300CB000000D9050200F4015400B4009C01390114013907060400044E04B4
+045204B804E704CD0037047304CD04600473013303A2055605A60556053903C5021200C9
+001F00B801DF007300BA03E9033303BC0444040E00DF03CD03AA00E503AA0404000000CB
+008F00A4007B00B80014016F007F027B0252008F00C705CD009A009A006F00CB00CD019E
+01D300F000BA018300D5009803040248009E01D500C100CB00F600830354027F00000333
+026600D300C700A400CD008F009A0073040005D5010A00FE022B00A400B4009C00000062
+009C0000001D032D05D505D505D505F0007F007B005400A406B80614072301D300B800CB
+00A601C301EC069300A000D3035C037103DB0185042304A80448008F0139011401390360
+008F05D5019A0614072306660179046004600460047B009C00000277046001AA00E90460
+0762007B00C5007F027B000000B4025205CD006600BC00660077061000CD013B01850389
+008F007B0000001D00CD074A042F009C009C0000077D006F0000006F0335006A006F007B
+00AE00B2002D0396008F027B00F600830354063705F6008F009C04E10266008F018D02F6
+00CD03440029006604EE007300001400B8028040FFFBFE03FA1403F92503F83203F79603
+F60E03F5FE03F4FE03F32503F20E03F19603F02503EF8A4105EFFE03EE9603ED9603ECFA
+03EBFA03EAFE03E93A03E84203E7FE03E63203E5E45305E59603E48A4105E45303E3E22F
+05E3FA03E22F03E1FE03E0FE03DF3203DE1403DD9603DCFE03DB1203DA7D03D9BB03D8FE
+03D68A4105D67D03D5D44705D57D03D44703D3D21B05D3FE03D21B03D1FE03D0FE03CFFE
+03CEFE03CD9603CCCB1E05CCFE03CB1E03CA3203C9FE03C6851105C61C03C51603C4FE03
+C3FE03C2FE03C1FE03C0FE03BFFE03BEFE03BDFE03BCFE03BBFE03BA1103B9862505B9FE
+03B8B7BB05B8FE03B7B65D05B7BB03B78004B6B52505B65D40FF03B64004B52503B4FE03
+B39603B2FE03B1FE03B0FE03AFFE03AE6403AD0E03ACAB2505AC6403ABAA1205AB2503AA
+1203A98A4105A9FA03A8FE03A7FE03A6FE03A51203A4FE03A3A20E05A33203A20E03A164
+03A08A4105A096039FFE039E9D0C059EFE039D0C039C9B19059C64039B9A10059B19039A
+1003990A0398FE0397960D0597FE03960D03958A410595960394930E05942803930E0392
+FA039190BB0591FE03908F5D0590BB039080048F8E25058F5D038F40048E25038DFE038C
+8B2E058CFE038B2E038A8625058A410389880B05891403880B0387862505876403868511
+0586250385110384FE038382110583FE0382110381FE0380FE037FFE0340FF7E7D7D057E
+FE037D7D037C64037B5415057B25037AFE0379FE03780E03770C03760A0375FE0374FA03
+73FA0372FA0371FA0370FE036FFE036EFE036C21036BFE036A1142056A530369FE03687D
+036711420566FE0365FE0364FE0363FE0362FE03613A0360FA035E0C035DFE035BFE035A
+FE0359580A0559FA03580A035716190557320356FE035554150555420354150353011005
+531803521403514A130551FE03500B034FFE034E4D10054EFE034D10034CFE034B4A1305
+4BFE034A4910054A1303491D0D05491003480D0347FE0346960345960344FE0343022D05
+43FA0342BB03414B0340FE033FFE033E3D12053E14033D3C0F053D12033C3B0D053C40FF
+0F033B0D033AFE0339FE033837140538FA033736100537140336350B05361003350B0334
+1E03330D0332310B0532FE03310B03302F0B05300D032F0B032E2D09052E10032D09032C
+32032B2A25052B64032A2912052A25032912032827250528410327250326250B05260F03
+250B0324FE0323FE03220F03210110052112032064031FFA031E1D0D051E64031D0D031C
+1142051CFE031BFA031A42031911420519FE031864031716190517FE0316011005161903
+15FE0314FE0313FE031211420512FE0311022D05114203107D030F64030EFE030D0C1605
+0DFE030C0110050C16030BFE030A100309FE0308022D0508FE0307140306640304011005
+04FE03401503022D0503FE0302011005022D0301100300FE0301B80164858D012B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B002B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B1DB6060504
+030201002C2010B002254964B040515820C859212D2CB002254964B040515820C859212D
+2C20100720B00050B00D7920B8FFFF5058041B0559B0051CB0032508B0042523E120B000
+50B00D7920B8FFFF5058041B0559B0051CB0032508E12D2C4B505820B0FD454459212D2C
+B002254560442D2C4B5358B00225B0022545445921212D2C45442D0000020066FE960466
+05A400030007001A400C04FB0006FB0108057F0204002FC4D4EC310010D4ECD4EC301311
+211125211121660400FC73031BFCE5FE96070EF8F2720629000201350000020005D50003
+00090040400F07008304810208070501030400000A10FC3CEC32393931002FE4FCCC3001
+4BB00B5458BD000A00400001000A000AFFC03811373859B6000B200B500B035D25331523
+1133110323030135CBCBCB14A215FEFE05D5FD71FE9B0165000200C503AA02E905D50003
+0007004D400F05018404008108040506000502040810FCFCDCEC310010F43CEC3230014B
+B012544BB013545B58BD00080040000100080008FFC03811373859400F30094009500960
+097009A009BF09075D0111231121112311016FAA0224AA05D5FDD5022BFDD5022B000002
+009E0000061705BE0003001F006040311B0B008707041D0905190D028717130F15111F1E
+1C1B1A17161514131211100E0D0C090807060504030201001A0A18062010FCCC17393100
+2F3CD43C3CFC3C3CD43C3CC432EC32323040110B010B020B0C0B0D14041A111A12141F08
+015D012103210B0121133303211521032115210323132103231321352113213521130417
+FEDD5401254468012469A0670138FEA152013EFE9B68A067FEDB67A168FEC5016054FEBE
+0169660385FEB20387FE61019FFE619AFEB299FE62019EFE62019E99014E9A019F000003
+00AAFED3046D061400210028002F00D5405522020A0B0A27012628020B0B0A1D011E1C02
+2F292F1B0229292F42131110220A1B29041706092A21050217861606860511231A8A1689
+10002A8A0589022D08160A1E07291A1203000922100903010726080D05063010FC3CECF4
+173CFC173CF4E4EC31002FE4ECC4D4E4EC32C410EE10EE11123911391112173911123930
+4B5358071004ED07100EED11173907100EED111739071004ED5922014BB0095458BD0030
+0040000100300030FFC03811373859014BB00C544BB010545B4BB00F545B58BD0030FFC0
+000100300030004038113738590123032E0127351E0117112E01353436373533151E0117
+152E0127111E011514060703110E0115141617113E0135342602B4640169D26A66D16FDD
+C9DACC645DAE5353AF5CE3D6E3D664747A71E17F817BFED3012D022D2DB440410101C824
+AC96A3BC0EEBE8041F1BAF2A2E04FE5523B49CA9C30F0300019A0D6A585660D5FE4F116E
+5A58680000050071FFE3072905F0000B001700230027003300954036240F252625260F27
+24274200920C1E922E8D18922406920C8D26128C2824913427211B2509030D150E090D0F
+210D2B0E1B0D0F310B3410FCC4ECF4EC10EEF6EE1139111239310010E432F43CE4EC10EE
+F6EE10EE304B5358071005ED071005ED5922014BB009544BB00B545B4BB00C545B4BB014
+545B4BB00E545B4BB00D545B58BD00340040000100340034FFC038113738590122061514
+163332363534262732161514062322263534360122061514163332363534262533012313
+321615140623222635343605D157636357556363559EBABB9DA0BABBFC97566362575763
+640331A0FC5AA01F9EBCBB9F9FB9BA029194848295958283957FDCBBBBDBDBBBBCDB0261
+95828494948481967FF9F3060DDBBBBDDADBBCBADC0000020081FFE305FE05F000090030
+01CD40960D010E0C861112110B860A0B1212110986000915161507010608861616150201
+0301861D1E1D008609001E1E1D201F02211E110A130A17161503181411130A0708020609
+1113130A0201020300110A130A171602181511130A141113130A42120B090306000A1E03
+28150E0628270695182B9527942491188C0E130A2E0B0E09002E1215270E1E032E122721
+0E110F132103121B103110FCECC4D4D4EC10C6EE1139111239391139391139113931002F
+C6E4F6E6EE10EE10C6111239111739111739304B5358071005ED0705ED111739071005ED
+111739071005ED1117390705ED111739071005ED111739071008ED07100EED1117390710
+0EED111739071008ED071008ED07100EED1117395922B20F3201015D40B2070B05220929
+1C001C011F02170B2A002A0126123A003412440B5E0059015A0A55125A1A5A1F5930671E
+7B009B009A0199029708950B931595169522992D1F090B090C08110C270C2818021B0919
+0B190C19111C141C15161D1F3227002701290923122A132A1428152F323B09341239133F
+324A094C144B1546194F3256015A09590C551259135C1F5F326A0C691160327501790C7A
+1193009301970295059C079C089F089A099B0B9A0C9032A032B032395D005D010E011514
+163332363709013E0137330602070123270E01232200353436372E013534363332161715
+2E0123220615141601F25B55D4A05FA649FE7B01FC3B4206BA0C685D0117FC8F68E483F1
+FECE86863032DEB853A555579E4469833B032351A15892C23F40028FFDF859CB7284FEFE
+7EFEE39359570113D780E1633F7D3CA2C52424B62F316F583367000100C503AA016F05D5
+00030042400A0184008104000502040410FCEC310010F4EC30014BB012544BB013545B58
+BD00040040000100040004FFC03811373859400D40055005600570059005A005065D0111
+2311016FAA05D5FDD5022B00000100B0FEF2027B0612000D004F400F069800970E0D0700
+03120600130A0E10DCE432EC113939310010FCEC30014BB0135458BD000E00400001000E
+000EFFC03811373859014BB00F5458BD000EFFC00001000E000E00403811373859010602
+1514121723260235341237027B86828385A0969594970612E6FE3EE7E7FE3BE5EB01C6E0
+DF01C4EC000100A4FEF2026F0612000D001F400F079800970E0701000B12041308000E10
+DC3CF4EC113939310010FCEC301333161215140207233612353402A4A096959596A08583
+830612ECFE3CDFE0FE3AEBE501C5E7E701C20001003D024A03C305F00011004E402C100D
+0B00040C090704020408039905110C990A010E9112080C0A030906110301030200140F04
+0B09140D061210D43CE432DC3CE432173911121739310010F4D43CEC32C4EC3217391217
+393001050507251123110527252537051133112503C3FE9901673AFEB072FEB03A0167FE
+993A015072015004DFC2C362CBFE870179CB62C3C263CB0179FE87CB000100D9000005DB
+0504000B002340110009019C07030502150400170A0615080C10DCFC3CFC3CEC31002FD4
+3CFC3CC43001112115211123112135211103AE022DFDD3A8FDD3022D0504FDD3AAFDD302
+2DAA022D0001009EFF1201C300FE00050019400C039E0083060304011900180610FCECD4
+CC310010FCEC30373315032313F0D3A48152FEACFEC001400001006401DF027F02830003
+0011B6009C020401000410DCCC310010D4EC301321152164021BFDE50283A400000100DB
+000001AE00FE00030011B7008302011900180410FCEC31002FEC3037331523DBD3D3FEFE
+00010000FF4202B205D50003002D4014001A010201021A03000342029F00810402000103
+2FC43939310010F4EC304B5358071005ED071005ED5922013301230208AAFDF8AA05D5F9
+6D0000020087FFE3048F05F0000B00170023401306A01200A00C91128C18091C0F1E031C
+151B1810FCECF4EC310010E4F4EC10EE3001220211101233321211100227320011100023
+2200111000028B9C9D9D9C9D9D9D9DFB0109FEF7FBFBFEF701090550FECDFECCFECDFECD
+0133013301340133A0FE73FE86FE87FE73018D0179017A018D00000100E10000045A05D5
+000A004B40154203A00402A005810700A009081F061C03001F010B10D4ECC4FCEC31002F
+EC32F4ECD4EC304B53585922014BB00F5458BD000BFFC00001000B000B00403811373859
+B40F030F04025D3721110535253311211521FE014AFE990165CA014AFCA4AA047348B848
+FAD5AA00000100960000044A05F0001C00A54027191A1B03181C11050400110505044210
+A111940DA014910400A00200100A02010A1C171003061D10FCC4D4ECC0C011123931002F
+EC32F4ECF4EC304B5358071005ED0705ED1117395922014BB015544BB016545B4BB01454
+5B58BD001D00400001001D001DFFC0381137385940325504560556077A047A05761B8719
+0704000419041A041B051C74007606751A731B741C82008619821A821B821CA800A81B11
+5D005D25211521353600373E0135342623220607353E01333204151406070600018902C1
+FC4C73018D33614DA7865FD3787AD458E80114455B19FEF4AAAAAA7701913A6D97497796
+4243CC3132E8C25CA5701DFEEB000001009CFFE3047305F00028007B402E0015130A8609
+1F862013A0150DA00993061CA020932391068C15A329161C13000314191C2620101C0314
+1F09062910FCC4C4D4ECF4EC11173939310010ECE4F4E4EC10E6EE10EE10EE10EE111239
+30014BB016544BB014545B58BD00290040000100290029FFC038113738594009641E611F
+6120642104005D011E0115140421222627351E013332363534262B013533323635342623
+220607353E01333204151406033F91A3FED0FEE85EC76A54C86DBEC7B9A5AEB6959EA398
+53BE7273C959E6010C8E03251FC490DDF22525C33132968F8495A67770737B2426B42020
+D1B27CAB00020064000004A405D50002000D008C401D010D030D0003030D4200030B07A0
+0501038109010C0A001C0608040C0E10DCD43CC4EC32113931002FE4D43CEC321239304B
+5358071004C9071005C95922014BB00B544BB00D545B58BD000E00400001000E000EFFC0
+3811373859402A0B002A0048005900690077008A000716012B0026012B0336014E014F0C
+4F0D5601660175017A0385010D5D005D09012103331133152311231121350306FE0201FE
+35FED5D5C9FD5E0525FCE303CDFC33A8FEA00160C3000001009EFFE3046405D5001D0075
+4023041A071186101D1AA00714A010890D02A000810D8C07A41E171C010A031C000A1006
+1E10FCC4D4EC10C4EE310010E4E4F4EC10E6EE10FEC410EE11123930014BB016544BB014
+545B58BD001E00400001001E001EFFC03811373859014BB00F5458BD001EFFC00001001E
+001E0040381137385913211521113E0133320015140021222627351E0133323635342623
+220607DD0319FDA02C582CFA0124FED4FEEF5EC3685AC06BADCACAAD51A15405D5AAFE92
+0F0FFEEEEAF1FEF52020CB3130B69C9CB62426000002008FFFE3049605F0000B00240058
+40241306000D860C00A01606A01C16A510A00C8922911C8C250C22091C191E131C03211F
+1B2510FCECECF4ECE4310010E4F4E4FCE410EE10EE10EE111239304014CB00CB01CD02CD
+03CD04CB05CB0607A41EB21E025D015D01220615141633323635342601152E0123220203
+3E0133320015140023200011100021321602A4889F9F88889F9F01094C9B4CC8D30F3BB2
+6BE10105FEF0E2FEFDFEEE0150011B4C9B033BBAA2A1BBBBA1A2BA0279B82426FEF2FEEF
+575DFEEFEBE6FEEA018D0179016201A51E00000100A80000046805D50006006340180511
+02030203110405044205A0008103050301040100060710FCCCC411393931002FF4EC304B
+5358071005ED071005ED5922014BB0165458BD00070040000100070007FFC03811373859
+401258020106031A05390548056703B000B006075D005D13211501230121A803C0FDE2D3
+01FEFD3305D556FA81052B000003008BFFE3048B05F0000B0023002F00434025180C00A0
+2706A01E2DA012911E8C27A330180C242A1C15241C0F091C151B1E031C0F211B3010FCC4
+ECF4C4EC10EE10EE113939310010ECE4F4EC10EE10EE3939300122061514163332363534
+262526263534363332161514060716161514042322243534361314163332363534262322
+06028B90A5A59090A6A5FEA58291FFDEDFFE918192A3FEF7F7F7FEF7A448918382939382
+839102C59A87879A9B86879A5620B280B3D0D0B380B22022C68FD9E8E8D98FC601617482
+82747482820000020081FFE3048705F00018002400584023071F1901860019A00AA504A0
+0089161FA01091168C25071C1C21131E0022221C0D1B2510FCECE4F4ECEC310010E4F4EC
+10E6FEF5EE10EE111239304016C419C21AC01BC01CC01DC21EC41F07AA12BC12E912035D
+015D37351E01333212130E01232200353400332000111000212226013236353426232206
+151416E14C9C4BC8D30F3AB26CE0FEFB0110E201030111FEB1FEE54C9C013E889F9F8888
+9F9F1FB82426010D0112565C010FEBE60116FE73FE86FE9FFE5B1E0297BAA2A1BBBBA1A2
+BA00000200F0000001C3042300030007001C400E068304A60083020501030400180810FC
+3CEC3231002FECF4EC303733152311331523F0D3D3D3D3FEFE0423FE0002009EFF1201C3
+04230003000900254013028300079E048300A60A07080501190400180A10FC3CEC32D4CC
+310010E4FCEC10EE3013331523113315032313F0D3D3D3A481520423FEFDD9ACFEC00140
+000100D9005E05DB04A60006004D402A029C030403019C0001040403019C020105060500
+9C06054205040201000503A806A7070102002404230710FCEC3239310010F4EC1739304B
+53580704ED071008ED071008ED071004ED592209021501350105DBFBF80408FAFE050203
+F0FE91FE93B601D1A601D100000200D9016005DB03A200030007001C400D009C02069C04
+0805010400230810FC3CC432310010D4ECD4EC301321152115211521D90502FAFE0502FA
+FE03A2A8F0AA000100D9005E05DB04A60006004F402B069C0006030403059C040403009C
+010201069C05060202014206050302000504A801A7070602240400230710FC3CEC393100
+10F4EC1739304B5358071008ED071004ED071004ED071008ED592213350115013501D905
+02FAFE040603F0B6FE2FA6FE2FB6016D00020093000003B005F0000300240070402B241E
+0906040A1D13040014861388109517910083021D1A0D0905040A1E010D1C1A041C050103
+00261A132510DCC4FCECD4EC10EE11393911123911123931002FEEF6FEF4EE10CD113939
+173930014BB00C5458BD00250040000100250025FFC03811373859B679097A0A7A20035D
+2533152313233534363F013E0135342623220607353E013332161514060F010E01070E01
+150187CBCBC5BF385A5A3933836C4FB3615EC167B8DF485A582F27080606FEFE01919A65
+825659355E31596E4643BC3938C29F4C8956562F3519153C340000020087FE9C077105A2
+000B004C00954032180C0309A919151B03A94C0F34330FAC30A93715AC24A937434D3334
+1E1A00281206180C281A2B1E2849122B2A28492C3D4D10DCECFCEC10FEFDFE3CC610EE11
+123939310010D4C4FCEC10FEEDD4C610C5EE3210C4EE11393930004BB009544BB00C545B
+4BB010545B4BB013545B4BB014545B58BD004DFFC00001004D004D004038113738594009
+0F4E1F4E2F4E3F4E04015D011416333236353426232206010E0123222635343633321617
+3533113E0135342627262423220607060215141217160433323637170604232224272602
+353412373624333204171E011510000502FA8E7C7B8D907A798F02213C9B67ACD7D8AB67
+9C3B8F92A53F4068FED5B07BE2609DB1736D6901149D81F9685A7DFED998B9FEB8808086
+887E810152BDD4016B7B4B4FFEC2FEE802198FA3A48E8CA5A4FE484D49F9C8C8FA4B4C83
+FD2016DFB16BBC50838B414066FEB5C19FFEEA6A686D57516F6167837D7D0149BDB6014A
+7D7F87AEA062E67BFEF9FED00600000200100000056805D50002000A00BA404100110100
+040504021105050401110A030A0011020003030A0711050406110505040911030A08110A
+030A4200030795010381090509080706040302010009050A0B10D4C4173931002F3CE4D4
+EC1239304B5358071005ED0705ED071005ED0705ED071008ED071005ED071005ED071008
+ED5922B2200C01015D403A0F005800760070008C00050701080206030904160119025601
+5802500C67016802780176027C0372047707780887018802800C980299039604175D005D
+090121013301230321032302BCFEEE0225FE7BE50239D288FD5F88D5050EFD1903AEFA2B
+017FFE81000300C9000004EC05D5000800110020004340231900950A0995128101950AAD
+1F110B080213191F05000E1C1605191C2E09001C12042110FCEC32FCECD4EC1117393939
+31002FECECF4EC10EE3930B20F2201015D01112132363534262301112132363534262325
+213216151406071E01151404232101930144A39D9DA3FEBC012B94919194FE0B0204E7FA
+807C95A5FEF0FBFDE802C9FDDD878B8C850266FE3E6F727170A6C0B189A21420CB98C8DA
+00010073FFE3052705F000190036401A0DA10EAE0A951101A100AE04951791118C1A0719
+0D003014101A10FCEC32EC310010E4F4ECF4EC10EEF6EE30B40F1B1F1B02015D01152E01
+23200011100021323637150E01232000111000213216052766E782FF00FEF00110010082
+E7666AED84FEADFE7A0186015386ED0562D55F5EFEC7FED8FED9FEC75E5FD34848019F01
+670168019F47000200C9000005B005D500080011002E4015009509810195100802100A00
+05190D32001C09041210FCECF4EC113939393931002FECF4EC30B2601301015D01113320
+00111000212521200011100029010193F40135011FFEE1FECBFE42019F01B20196FE68FE
+50FE61052FFB770118012E012C0117A6FE97FE80FE7EFE96000100C90000048B05D5000B
+002E401506950402950081089504AD0A05010907031C00040C10FCEC32D4C4C431002FEC
+ECF4EC10EE30B21F0D01015D132115211121152111211521C903B0FD1A02C7FD3902F8FC
+3E05D5AAFE46AAFDE3AA000100C90000042305D50009002940120695040295008104AD08
+050107031C00040A10FCEC32D4C431002FECF4EC10EE30B20F0B01015D13211521112115
+211123C9035AFD700250FDB0CA05D5AAFE48AAFD370000010073FFE3058B05F0001D0039
+402000051B0195031B950812A111AE15950E91088C1E02001C1134043318190B101E10FC
+ECFCE4FCC4310010E4F4ECF4EC10FED4EE11393930251121352111060423200011100021
+32041715262623200011100021323604C3FEB6021275FEE6A0FEA2FE75018B015E920107
+6F70FC8BFEEEFEED011301126BA8D50191A6FD7F53550199016D016E01994846D75F60FE
+CEFED1FED2FECE25000100C90000053B05D5000B002C4014089502AD0400810A0607031C
+053809011C00040C10FCEC32FCEC3231002F3CE432FCEC30B2500D01015D133311211133
+112311211123C9CA02DECACAFD22CA05D5FD9C0264FA2B02C7FD3900000100C900000193
+05D500030039B700AF02011C00040410FCEC31002FEC30014BB0105458BD0004FFC00001
+0004000400403811373859400D30054005500560058F059F05065D13331123C9CACA05D5
+FA2B0001FF96FE66019305D5000B004D40130B0200079505B000810C05080639011C0004
+0C10FCECE43939310010E4FCEC11393930014BB0105458BD000CFFC00001000C000C0040
+3811373859400D300D400D500D600D8F0D9F0D065D13331110062B013533323635C9CACD
+E34D3F866E05D5FA93FEF2F4AA96C200000100C90000056A05D5000A00EF402808110506
+0507110606050311040504021105050442080502030300AF09060501040608011C00040B
+10FCEC32D4C4113931002F3CEC321739304B5358071004ED071005ED071005ED071004ED
+5922B2080301015D40921402010402090816022805280837023605340847024605430855
+02670276027705830288058F0894029B08E702150603090509061B031907050A030A0718
+0328052B062A073604360536063507300C41034004450540064007400C62036004680567
+077705700C8B038B058E068F078F0C9A039D069D07B603B507C503C507D703D607E803E9
+04E805EA06F703F805F9062C5D71005D711333110121090121011123C9CA029E0104FD1B
+031AFEF6FD33CA05D5FD890277FD48FCE302CFFD3100000100C90000046A05D500050025
+400C0295008104011C033A00040610FCECEC31002FE4EC30400930075007800380040401
+5D133311211521C9CA02D7FC5F05D5FAD5AA000100C90000061F05D5000C00BF40340311
+0708070211010208080702110302090A0901110A0A09420A070203080300AF080B050908
+030201050A061C043E0A1C00040D10FCECFCEC11173931002F3CC4EC32111739304B5358
+071005ED071008ED071008ED071005ED5922B2700E01015D405603070F080F09020A1502
+1407130A260226072007260A200A3407350A69027C027B07790A80028207820A90021604
+010B0313011B0323012C032708280934013C035608590965086A097608790981018D0395
+019B03145D005D13210901211123110123011123C9012D017D017F012DC5FE7FCBFE7FC4
+05D5FC0803F8FA2B051FFC000400FAE1000100C90000053305D500090079401E07110102
+0102110607064207020300AF0805060107021C0436071C00040A10FCECFCEC1139393100
+2F3CEC323939304B5358071004ED071004ED5922B21F0B01015D40303602380748024707
+690266078002070601090615011A06460149065701580665016906790685018A0695019A
+069F0B105D005D13210111331121011123C901100296C4FEF0FD6AC405D5FB1F04E1FA2B
+04E1FB1F00020073FFE305D905F0000B00170023401306951200950C91128C1809190F33
+031915101810FCECFCEC310010E4F4EC10EE300122001110003332001110002720001110
+002120001110000327DCFEFD0103DCDC0101FEFFDC013A0178FE88FEC6FEC5FE87017905
+4CFEB8FEE5FEE6FEB80148011A011B0148A4FE5BFE9EFE9FFE5B01A40162016201A50002
+00C90000048D05D500080013003A40180195100095098112100A0802040005190D3F1100
+1C09041410FCEC32FCEC11173931002FF4ECD4EC30400B0F151F153F155F15AF1505015D
+011133323635342623252132041514042B0111230193FE8D9A9A8DFE3801C8FB0101FEFF
+FBFECA052FFDCF92878692A6E3DBDDE2FDA800020073FEF805D905F0000B001D0052402A
+1110020F010C0D0C0E010D0D0C420F1E0C06951200951891128C0D1E0D1B0F0C0309191B
+33031915101E10FCECFCEC1139391139310010C4E4F4EC10EE391239304B5358071005ED
+071005ED1739592201220011100033320011100013012327060623200011100021200011
+10020327DCFEFD0103DCDC0101FEFF3F010AF4DD212310FEC5FE870179013B013A0178D1
+054CFEB8FEE5FEE6FEB80148011A011B0148FACFFEDDEF020201A50161016201A5FE5BFE
+9EFEFCFE8E00000200C90000055405D50013001C00B14035090807030A06110304030511
+0404034206040015030415950914950D810B040506031109001C160E050A191904113F14
+0A1C0C041D10FCEC32FCC4EC1117391139393931002F3CF4ECD4EC123912391239304B53
+58071005ED071005ED1117395922B2401E01015D40427A13010500050105020603070415
+00150114021603170425002501250226032706260726082609201E360136024601460268
+0575047505771388068807980698071F5D005D011E01171323032E012B01112311212016
+151406011133323635342623038D417B3ECDD9BF4A8B78DCCA01C80100FC83FD89FE9295
+959202BC16907EFE68017F9662FD8905D5D6D88DBA024FFDEE878383850000010087FFE3
+04A205F00027007E403C0D0C020E0B021E1F1E080902070A021F1F1E420A0B1E1F041501
+0015A11494189511049500942591118C281E0A0B1F1B0700221B190E2D071914222810DC
+C4ECFCECE4111239393939310010E4F4E4EC10EEF6EE10C6111739304B535807100EED11
+173907100EED1117395922B20F2901015DB61F292F294F29035D01152E01232206151416
+1F011E0115140421222627351E013332363534262F012E01353424333216044873CC5FA5
+B377A67AE2D7FEDDFEE76AEF807BEC72ADBC879A7BE2CA0117F569DA05A4C53736807663
+651F192BD9B6D9E0302FD04546887E6E7C1F182DC0ABC6E426000001FFFA000004E905D5
+0007004A400E0602950081040140031C0040050810D4E4FCE431002FF4EC3230014BB00A
+5458BD00080040000100080008FFC03811373859401300091F00100110021F0710094009
+70099F09095D03211521112311210604EFFDEECBFDEE05D5AAFAD5052B00000100B2FFE3
+052905D50011004B40160802110B0005950E8C09008112081C0A38011C00411210FCECFC
+EC310010E432F4EC113939393930014BB0105458BD00120040000100120012FFC0381137
+3859B61F138F139F13035D133311141633323635113311100021200011B2CBAEC3C2AECB
+FEDFFEE6FEE5FEDF05D5FC75F0D3D3F0038BFC5CFEDCFED6012A01240001001000000568
+05D5000600B7402704110506050311020306060503110403000100021101010042030401
+AF0006040302000505010710D4C4173931002FEC3239304B5358071005ED071008ED0710
+08ED071005ED5922B2500801015D406200032A03470447055A037D038303070600070208
+040906150114021A041A052A002601260229042905250620083800330133023C043C0537
+06480045014502490449054706590056066602690469057A007601760279047905750680
+0898009706295D005D21013309013301024AFDC6D301D901DAD2FDC705D5FB1704E9FA2B
+00010044000007A605D5000C017B4049051A0605090A09041A0A09031A0A0B0A021A0102
+0B0B0A061107080705110405080807021103020C000C011100000C420A050203060300AF
+0B080C0B0A09080605040302010B07000D10D4CC173931002F3CEC32321739304B535807
+1005ED071008ED071008ED071005ED071008ED071005ED0705ED071008ED5922B2000E01
+015D40F206020605020A000A000A120A2805240A200A3E023E05340A300A4C024D05420A
+400A59026A026B05670A600A7B027F027C057F05800A960295051D070009020803000406
+050005000601070408000807090009040A0A0C000E1A0315041508190C100E2004210520
+06200720082309240A250B200E200E3C023A033504330530083609390B3F0C300E460046
+014A0240044505400542064207420840084009440A4D0C400E400E58025608590C500E66
+026703610462056006600760086409640A640B770076017B027803770474057906790777
+087008780C7F0C7F0E860287038804890585098A0B8F0E97049F0EAF0E5B5D005D133309
+0133090133012309012344CC013A0139E3013A0139CDFE89FEFEC5FEC2FE05D5FB1204EE
+FB1204EEFA2B0510FAF00001003D0000053B05D5000B015D404609110A0B0A081107080B
+0B0A081109080506050711060605031104050402110102050504021103020B000B011100
+000B420B080502040300AF09060B08050204000406000A0C10D4C4DCC411173931002F3C
+EC321739304B5358071005ED071008ED071008ED071005ED071005ED071008ED071008ED
+071005ED5922014BB00C544BB00D545B4BB00E545B58BD000CFFC00001000C000C004038
+1137385940B80702080816021908170B2708270B34023808360B4B0858055B0866026B08
+7702770B8602800287058B08850B9402900297059D08960B1B0601090308070709160119
+0319071709100D260128022903260528072709290B200D350034013C033B043A063B0734
+09340A380B3F0D48094F0D580B5F0D650065016A036A046805690669076C096C0A780379
+06790778087D097F0A780B800080018302880385058408830B8F0D900090019402970597
+069508930B9F0DAF0D405D005D13330901330901230901230181D901730175D9FE200200
+D9FE5CFE59DA021505D5FDD5022BFD33FCF8027BFD85031D0001FFFC000004E705D50008
+0094402803110405040211010205050402110302080008011100000842020300AF060207
+0440051C0040070910D4E4FCE4123931002FEC3239304B5358071005ED071008ED071008
+ED071005ED5922B2000A01015D403C050214023502300230053008460240024005400851
+02510551086502840293021016011A031F0A2601290337013803400A670168037803700A
+9F0A0D5D005D03330901330111231104D9019E019BD9FDF0CB05D5FD9A0266FCF2FD3902
+C7000001005C0000051F05D50009009B401B031107080708110203024208950081039505
+08030001420400060A10DCC4D4E411393931002FECF4EC304B5358071005ED071005ED59
+22014BB009544BB00A545B58BD000A00400001000A000AFFC03811373859404005020A07
+18072902260738074802470748080905030B08000B16031A08100B2F0B350339083F0B47
+034A084F0B55035908660369086F0B770378087F0B9F0B165D005D132115012115213501
+21730495FC5003C7FB3D03B0FC6705D59AFB6FAA9A049100000100B0FEF2025806140007
+0053400F04A906B202A900B10805010343000810DCFCCC32310010FCECF4EC30014BB00C
+5458BD0008FFC000010008000800403811373859014BB012544BB013545B58BD00080040
+000100080008FFC038113738591321152311331521B001A8F0F0FE5806148FF9FC8F0001
+0000FF4202B205D50003002D4014021A010100001A03030242019F008104020001032FC4
+3939310010F4EC304B5358071005ED071005ED592213012301AA0208AAFDF805D5F96D06
+9300000100C7FEF2026F06140007003C401003A901B205A900B1080043040602040810FC
+3CDCEC310010FCECF4EC30014BB00F544BB010545B58BD0008FFC0000100080008004038
+113738590111213533112335026FFE58EFEF0614F8DE8F06048F000100D903A805DB05D5
+00060018400A0304010081070301050710DCCC39310010F4CC3239300101230101230103
+BC021FC9FE48FE48C9021F05D5FDD3018BFE75022D000001FFECFE1D0414FEAC0003000F
+B500A90100020410C4C43100D4EC30011521350414FBD8FEAC8F8F00000100AA04F00289
+066600030031400901B400B3040344010410DCEC310010F4EC30004BB009544BB00E545B
+58BD0004FFC00001000400040040381137385909012301016F011A99FEBA0666FE8A0176
+0002007BFFE3042D047B000A002500BC4027191F0B17090E00A91706B90E1120861FBA1C
+B923B8118C170C001703180D09080B1F030814452610FCECCCD4EC323211393931002FC4
+E4F4FCF4EC10C6EE10EE11391139123930406E301D301E301F3020302130223F27401D40
+1E401F402040214022501D501E501F50205021502250277027851D871E871F8720872185
+229027A027F0271E301E301F30203021401E401F40204021501E501F50205021601E601F
+60206021701E701F70207021801E801F80208021185D015D0122061514163332363D0137
+1123350E01232226353436332135342623220607353E0133321602BEDFAC816F99B9B8B8
+3FBC88ACCBFDFB0102A79760B65465BE5AF3F00233667B6273D9B4294CFD81AA6661C1A2
+BDC0127F8B2E2EAA2727FC00000200BAFFE304A40614000B001C0038401903B90C0F09B9
+18158C0FB81B971900121247180C06081A461D10FCEC3232F4EC31002FECE4F4C4EC10C6
+EE30B6601E801EA01E03015D013426232206151416333236013E01333212111002232226
+271523113303E5A79292A7A79292A7FD8E3AB17BCCFFFFCC7BB13AB9B9022FCBE7E7CBCB
+E7E702526461FEBCFEF8FEF8FEBC6164A806140000010071FFE303E7047B0019003F401B
+00860188040E860D880AB91104B917B8118C1A07120D004814451A10FCE432EC310010E4
+F4EC10FEF4EE10F5EE30400B0F1B101B801B901BA01B05015D01152E0123220615141633
+323637150E0123220011100021321603E74E9D50B3C6C6B3509D4E4DA55DFDFED6012D01
+0655A20435AC2B2BE3CDCDE32B2BAA2424013E010E0112013A2300020071FFE3045A0614
+0010001C003840191AB9000E14B905088C0EB801970317040008024711120B451D10FCEC
+F4EC323231002FECE4F4C4EC10C4EE30B6601E801EA01E03015D0111331123350E012322
+0211101233321601141633323635342623220603A2B8B83AB17CCBFFFFCB7CB1FDC7A792
+92A8A89292A703B6025EF9ECA86461014401080108014461FE15CBE7E7CBCBE7E7000002
+0071FFE3047F047B0014001B00704024001501098608880515A90105B90C01BB18B912B8
+0C8C1C1B1502081508004B02120F451C10FCECF4ECC4111239310010E4F4ECE410EE10EE
+10F4EE1112393040293F1D701DA01DD01DF01D053F003F013F023F153F1B052C072F082F
+092C0A6F006F016F026F156F1B095D71015D0115211E0133323637150E01232000111000
+333200072E0123220607047FFCB20CCDB76AC76263D06BFEF4FEC70129FCE20107B802A5
+889AB90E025E5ABEC73434AE2A2C0138010A01130143FEDDC497B4AE9E000001002F0000
+02F8061400130070401C0510010C08A906018700970E06BC0A02130700070905080D0F0B
+4C1410FC3CC4FC3CC4C412393931002FE432FCEC10EE3212393930014BB00A5458BD0014
+FFC000010014001400403811373859014BB00E5458BD00140040000100140014FFC03811
+373859B640155015A015035D01152322061D012115211123112335333534363302F8B063
+4D012FFED1B9B0B0AEBD0614995068638FFC2F03D18F4EBBAB0000020071FE56045A047B
+000B0028004A4023190C1D0912861316B90F03B92623B827BC09B90FBD1A1D261900080C
+4706121220452910FCC4ECF4EC323231002FC4E4ECE4F4C4EC10FED5EE1112393930B660
+2A802AA02A03015D01342623220615141633323617100221222627351E013332363D010E
+0123220211101233321617353303A2A59594A5A59495A5B8FEFEFA61AC51519E52B5B439
+B27CCEFCFCCE7CB239B8023DC8DCDCC8C7DCDCEBFEE2FEE91D1EB32C2ABDBF5B6362013A
+01030104013A6263AA00000100BA000004640614001300344019030900030E0106870E11
+B80C970A010208004E0D09080B461410FCEC32F4EC31002F3CECF4C4EC1112173930B260
+1501015D0111231134262322061511231133113E013332160464B87C7C95ACB9B942B375
+C1C602A4FD5C029E9F9EBEA4FD870614FD9E6564EF00000200C100000179061400030007
+002B400E06BE04B100BC020501080400460810FC3CEC3231002FE4FCEC30400B10094009
+50096009700905015D1333112311331523C1B8B8B8B80460FBA00614E9000002FFDBFE56
+01790614000B000F0044401C0B0207000EBE0C078705BD00BC0CB110081005064F0D0108
+0C00461010FC3CEC32E4391239310010ECE4F4EC10EE1112393930400B10114011501160
+11701105015D13331114062B01353332363511331523C1B8A3B54631694CB8B80460FB8C
+D6C09C61990628E9000100BA0000049C0614000A00BC4029081105060507110606050311
+0405040211050504420805020303BC009709060501040608010800460B10FCEC32D4C411
+3931002F3CECE41739304B5358071004ED071005ED071005ED071004ED5922B2100C0101
+5D405F04020A081602270229052B0856026602670873027705820289058E089302960597
+08A3021209050906020B030A072803270428052B062B07400C6803600C8903850489058D
+068F079A039707AA03A705B607C507D607F703F003F704F0041A5D71005D133311013309
+0123011123BAB90225EBFDAE026BF0FDC7B90614FC6901E3FDF4FDAC0223FDDD000100C1
+00000179061400030022B7009702010800460410FCEC31002FEC30400D10054005500560
+057005F00506015D13331123C1B8B80614F9EC00000100BA0000071D047B0022005A4026
+061209180F00061D07150C871D2003B81BBC19100700110F0808065011080F501C18081A
+462310FCEC32FCFCFCEC11123931002F3C3CE4F43CC4EC32111217393040133024502470
+249024A024A024BF24DF24FF2409015D013E013332161511231134262322061511231134
+262322061511231133153E01333216042945C082AFBEB972758FA6B972778DA6B9B93FB0
+797AAB03897C76F5E2FD5C029EA19CBEA4FD87029EA29BBFA3FD870460AE67627C000001
+00BA00000464047B001300364019030900030E0106870E11B80CBC0A010208004E0D0908
+0B461410FCEC32F4EC31002F3CE4F4C4EC1112173930B46015CF1502015D011123113426
+2322061511231133153E013332160464B87C7C95ACB9B942B375C1C602A4FD5C029E9F9E
+BEA4FD870460AE6564EF00020071FFE30475047B000B0017004A401306B91200B90CB812
+8C1809120F51031215451810FCECF4EC310010E4F4EC10EE3040233F197B007B067F077F
+087F097F0A7F0B7B0C7F0D7F0E7F0F7F107F117B12A019F01911015D0122061514163332
+36353426273200111000232200111000027394ACAB9593ACAC93F00112FEEEF0F1FEEF01
+1103DFE7C9C9E7E8C8C7E99CFEC8FEECFEEDFEC70139011301140138000200BAFE5604A4
+047B0010001C003E401B1AB9000E14B90508B80E8C01BD03BC1D11120B47170400080246
+1D10FCEC3232F4EC310010E4E4E4F4C4EC10C4EE304009601E801EA01EE01E04015D2511
+231133153E013332121110022322260134262322061514163332360173B9B93AB17BCCFF
+FFCC7BB10238A79292A7A79292A7A8FDAE060AAA6461FEBCFEF8FEF8FEBC6101EBCBE7E7
+CBCBE7E700020071FE56045A047B000B001C003E401B03B90C0F09B91815B80F8C1BBD19
+BC1D180C06081A47001212451D10FCECF4EC3232310010E4E4E4F4C4EC10C6EE30400960
+1E801EA01EE01E04015D011416333236353426232206010E012322021110123332161735
+331123012FA79292A8A89292A702733AB17CCBFFFFCB7CB13AB8B8022FCBE7E7CBCBE7E7
+FDAE646101440108010801446164AAF9F600000100BA0000034A047B001100304014060B
+0700110B03870EB809BC070A06080008461210FCC4EC3231002FE4F4ECC4D4CC11123930
+B450139F1302015D012E012322061511231133153E0133321617034A1F492C9CA7B9B93A
+BA85132E1C03B41211CBBEFDB20460AE666305050001006FFFE303C7047B002700E7403C
+0D0C020E0B531F1E080902070A531E1F1E420A0B1E1F041500860189041486158918B911
+04B925B8118C281E0A0B1F1B0700521B080E07081422452810FCC4ECD4ECE41112393939
+39310010E4F4EC10FEF5EE10F5EE121739304B535807100EED111739070EED1117395922
+B2002701015D406D1C0A1C0B1C0C2E092C0A2C0B2C0C3B093B0A3B0B3B0C0B2000200124
+02280A280B2A132F142F152A16281E281F292029212427860A860B860C860D1200000001
+0202060A060B030C030D030E030F03100319031A031B031C041D09272F293F295F297F29
+80299029A029F029185D005D7101152E012322061514161F011E0115140623222627351E
+013332363534262F012E01353436333216038B4EA85A898962943FC4A5F7D85AC36C66C6
+61828C65AB40AB98E0CE66B4043FAE282854544049210E2A99899CB62323BE353559514B
+50250F2495829EAC1E0000010037000002F2059E0013003840190E05080F03A9001101BC
+08870A0B08090204000810120E461410FC3CC4FC3CC432393931002FECF43CC4EC321139
+3930B2AF1501015D01112115211114163B01152322263511233533110177017BFE854B73
+BDBDD5A28787059EFEC28FFDA0894E9A9FD202608F013E00000100AEFFE3045804600013
+00364019030900030E0106870E118C0A01BC0C0D09080B4E020800461410FCECF4EC3231
+002FE432F4C4EC1112173930B46015CF1502015D1311331114163332363511331123350E
+01232226AEB87C7C95ADB8B843B175C1C801BA02A6FD619F9FBEA4027BFBA0AC6663F000
+0001003D0000047F04600006011240270311040504021101020505040211030206000601
+1100000642020300BF0506050302010504000710D4C4173931002FEC3239304B53580710
+05ED071008ED071008ED071005ED5922014BB00A5458BD0007FFC0000100070007004038
+11373859014BB014544BB015545B58BD00070040000100070007FFC03811373859408E48
+026A027B027F02860280029102A402080600060109030904150015011A031A0426002601
+290329042008350035013A033A0430084600460149034904460548064008560056015903
+590450086600660169036904670568066008750074017B037B0475057A06850085018903
+8904890586069600960197029A03980498059706A805A706B008C008DF08FF083E5D005D
+133309013301233DC3015E015EC3FE5CFA0460FC5403ACFBA00000010056000006350460
+000C0201404905550605090A0904550A0903550A0B0A025501020B0B0A06110708070511
+0405080807021103020C000C011100000C420A050203060300BF0B080C0B0A0908060504
+0302010B07000D10D4CC173931002F3CEC32321739304B5358071005ED071008ED071008
+ED071005ED071008ED071005ED0705ED071008ED5922014BB00A544BB011545B4BB01254
+5B4BB013545B4BB00B545B58BD000DFFC00001000D000D00403811373859014BB00C544B
+B00D545B4BB010545B58BD000D00400001000D000DFFC0381137385940FF050216021605
+220A350A49024905460A400A5B025B05550A500A6E026E05660A79027F0279057F058702
+99029805940ABC02BC05CE02C703CF051D0502090306040B050A080B09040B050C150219
+0316041A051B081B09140B150C2500250123022703210425052206220725082709240A21
+0B230C390336043608390C300E460248034604400442054006400740084409440A440B40
+0E400E560056015602500451055206520750085309540A550B6300640165026A0365046A
+056A066A076E09610B670C6F0E7500750179027D0378047D057A067F067A077F07780879
+097F097B0A760B7D0C870288058F0E97009701940293039C049B05980698079908402F96
+0C9F0EA600A601A402A403AB04AB05A906A907AB08A40CAF0EB502B103BD04BB05B809BF
+0EC402C303CC04CA05795D005D13331B01331B013301230B012356B8E6E5D9E6E5B8FEDB
+D9F1F2D90460FC96036AFC96036AFBA00396FC6A0001003B000004790460000B015A4046
+0511060706041103040707060411050401020103110202010B110001000A11090A010100
+0A110B0A0708070911080807420A070401040800BF05020A0704010408000208060C10D4
+C4D4C411173931002F3CEC321739304B5358071005ED071008ED071008ED071005ED0710
+05ED071008ED071008ED071005ED5922014BB00A544BB00F545B4BB010545B4BB011545B
+58BD000CFFC00001000C000C00403811373859014BB0145458BD000C00400001000C000C
+FFC0381137385940980A04040A1A04150A260A3D04310A55045707580A660A76017A0476
+07740A8D04820A99049F049707920A900AA601A904AF04A507A30AA00A1C0A0304050509
+0A0B1A03150515091A0B2903260525092A0B200D3A013903370534073609390B300D4903
+460545094A0B400D590056015902590357055606590756085609590B500D6F0D78017F0D
+9B019407AB01A407B00DCF0DDF0DFF0D2F5D005D09022309012309013309010464FE6B01
+AAD9FEBAFEBAD901B3FE72D9012901290460FDDFFDC101B8FE48024A0216FE71018F0001
+003DFE56047F0460000F01A240430708020911000F0A110B0A00000F0E110F000F0D110C
+0D00000F0D110E0D0A0B0A0C110B0B0A420D0B0910000B058703BD0E0BBC100E0D0C0A09
+060300080F040F0B1010D4C4C4111739310010E432F4EC113911391239304B5358071005
+ED071008ED071008ED071005ED071008ED0705ED17325922014BB00A544BB008545B58BD
+0010FFC000010010001000403811373859014BB0145458BD00100040000100100010FFC0
+381137385940F0060005080609030D160A170D100D230D350D490A4F0A4E0D5A095A0A6A
+0A870D800D930D120A000A09060B050C0B0E0B0F1701150210041005170A140B140C1A0E
+1A0F2700240124022004200529082809250A240B240C270D2A0E2A0F2011370035013502
+30043005380A360B360C380D390E390F3011410040014002400340044005400640074008
+4209450A470D490E490F40115400510151025503500450055606550756085709570A550B
+550C590E590F501166016602680A690E690F60117B08780E780F89008A09850B850C890D
+890E890F9909950B950C9A0E9A0FA40BA40CAB0EAB0FB011CF11DF11FF11655D005D050E
+012B01353332363F01013309013302934E947C936C4C543321FE3BC3015E015EC368C87A
+9A488654044EFC94036C00010058000003DB0460000900B4401A08110203020311070807
+4208A900BC03A905080301000401060A10DCC432C411393931002FECF4EC304B53580710
+05ED071005ED5922014BB00B544BB00C545B58BD000A00400001000A000AFFC038113738
+59014BB0135458BD000AFFC00001000A000A004038113738594042050216022602470249
+07050B080F0B18031B082B08200B36033908300B40014002450340044005430857035908
+5F0B6001600266036004600562087F0B800BAF0B1B5D005D132115012115213501217103
+6AFD4C02B4FC7D02B4FD650460A8FCDB93A8032500010100FEB204170614002400824034
+190F150B0625091A10151D0B05202103000BA90900A901C00915A913B1250C090A052416
+19001D0A05130214002019430A0F052510D43CC4FC3CC432393911123911123939111239
+39310010FCECC4F4EC10EE12173912391139391112391112393930014BB00C5458BD0025
+FFC000010025002500403811373859B20026015D05152322263D0134262B01353332363D
+0134363B01152322061D011406071E011D0114163304173EF9A96C8E3D3D8F6BA9F93E44
+8D565B6E6F5A568DBE9094DDEF97748F7395F0DD938F588DF89D8E191B8E9CF88D580001
+0104FE1D01AE061D00030012B70100B1040005020410D4EC310010FCCC300111231101AE
+AA061DF80008000000010100FEB2041706140024009E40361F251B160C0F081B0B15190F
+040520030019A91B00A923C01B0FA911B1251C191A150F010400081A15231204001A1F15
+4310000B042510D43CC432FC3CC4111239391112391112393911123939310010FCECC4F4
+EC10EE12173911123939113911393911123930014BB00A5458BD00250040000100250025
+FFC03811373859014BB00E5458BD0025FFC000010025002500403811373859B20026015D
+053332363D013436372E013D0134262B01353332161D0114163B01152322061D0114062B
+010100468C555A6F6F5A558C463FF9A76C8E3E3E8E6CA7F93FBE568FF89C8E1B198E9DF8
+8E578F93DDF095738F7497EFDD94000100D901D305DB0331001D0023401001101B0C0013
+049C1B139C0C1E000F1E10D4C4310010D4FCD4EC10C01112393930011506062322272627
+26272623220607353636333217161716171633323605DB69B3616E920B05070F9B5E58AC
+6269B3616E930A05080E9B5E56A90331B24F443B040203053E4D53B24F453C040203053E
+4C00FFFF001000000568074E02270024000000000007010300BC01750003001000000568
+076D000B000E002100CB40540C110D0C1B1C1B0E111C1B1E111C1B1D111C1C1B0D11210F
+210C110E0C0F0F2120110F211F11210F21420C1B0F0D0903C115091E950D098E201C1E1D
+1C18201F210D12060E180C061B0056181C0F0656121C212210D4C4D4EC3210D4EE321139
+11391112391139391112393931002F3CE6D6EE10D4EE1112393939304B5358071005ED07
+05ED071008ED071005ED071005ED0705ED0705ED071008ED5922B2202301015D40201A0C
+730C9B0C03070F081B5023660D690E750D7B0E791C791D7620762180230C5D005D013426
+232206151416333236030121012E01353436333216151406070123032103230354593F40
+57583F3F5998FEF00221FE583D3E9F7372A13F3C0214D288FD5F88D5065A3F5957413F58
+58FEF3FD19034E29734973A0A172467629FA8B017FFE8100FFFF0073FE75052705F00227
+002600000000000700DD012D0000FFFF00C90000048B076B022700280000000000070104
+009E0175FFFF00C900000533075E02270031000000000007010500FE0175FFFF0073FFE3
+05D9074E02270032000000000007010301270175FFFF00B2FFE30529074E022700380000
+00000007010300EE0175FFFF007BFFE3042D066602270044000000000007008D00520000
+FFFF007BFFE3042D066602270044000000000007004300520000FFFF007BFFE3042D0666
+0227004400000000000700D700520000FFFF007BFFE3042D061002270044000000000007
+008E00520000FFFF007BFFE3042D06370227004400000000000700D800520000FFFF007B
+FFE3042D07060227004400000000000700DC00520000FFFF0071FE7503E7047B02270046
+00000000000700DD008F0000FFFF0071FFE3047F066602270048000000000007008D008B
+0000FFFF0071FFE3047F0666022700480000000000070043008B0000FFFF0071FFE3047F
+06660227004800000000000700D7008B0000FFFF0071FFE3047F06100227004800000000
+0007008E008B0000FFFF00900000026F0666022700D6000000000007008DFF1D0000FFFF
+FFC7000001A60666022700D60000000000070043FF1D0000FFFFFFDE0000025C06660227
+00D600000000000700D7FF1D0000FFFFFFF4000002460610022700D6000000000007008E
+FF1D0000FFFF00BA0000046406370227005100000000000700D800980000FFFF0071FFE3
+0475066602270052000000000007008D00730000FFFF0071FFE304750666022700520000
+00000007004300730000FFFF0071FFE3047506660227005200000000000700D700730000
+FFFF0071FFE30475061002270052000000000007008E00730000FFFF0071FFE304750637
+0227005200000000000700D800730000FFFF00AEFFE30458066602270058000000000007
+008D007B0000FFFF00AEFFE304580666022700580000000000070043007B0000FFFF00AE
+FFE3045806660227005800000000000700D7007B0000FFFF00AEFFE30458061002270058
+000000000007008E007B000000010039FF3B03C705D5000B002740140804B90A02008106
+C20C0359050157095907000C10D43CECFC3CEC310010E4F4D43CEC323001331121152111
+231121352101A8B0016FFE91B0FE91016F05D5FE5C99FBA3045D9900000200C30375033D
+05F0000B001A0020401106C315C400C30C911B095A125B035A181B10DCECFCEC310010F4
+ECFCEC300122061514163332363534262732161716161514062322263534360200506E6E
+50506E6F4F40762B2E2EB98687B4B8056F6F504F6D6D4F4F7081312E2D724284B7B48786
+BA00000200ACFEC704230598000600210051402B131614000F0C010B078608880B10860F
+880CB914160BB91D1F1CB8168C221C1500091E130B0F070412192210DCECD43CD43C3CEC
+3232310010E4F43CC4EC10C4FEF4EE10F5EE123911123911123930251106061514160115
+2626270336363715060607112311260011100037113313161602A693A4A402104A884401
+46894841894D66F1FEF70109F16601498983035812E2B8B9E203A1AC292A03FCA0052A27
+AA1E2307FEE4012014013301010102013216011FFEE10421000100810000046205F0001B
+00604021071608018600120AA914080C04A000941991100CA00E000D090B071C130F1511
+1C10DC3CCCCCFC3CC4D4C431002FEC32F4E4EC10D43CEE3210EE11393930014BB00C5458
+BD001CFFC00001001C001C00403811373859B43601360202005D01152E012322061D0121
+152111211521353311233533351036333216044E4C883D94740187FE79022DFC1FECC7C7
+D6E83D9705B4B629299BD4D78FFE2FAAAA01D18FEE0105F31F000002005CFF3D03A205F0
+000B003E0091403C2F302A0600171D3036040D278A260D8A0C2AC626C52310C60CC53C91
+233F2F0600173004131D2D0936031357392D572009570C221A3926220357333F10DCECE4
+C4D4E4ECD4EC10EE113911123911173939310010C4F4E4EC10E6EE10EE10EE1117393939
+11123930014BB00A544BB00B545B4BB00C545B4BB00E545B58BD003F00400001003F003F
+FFC03811373859010E01151416173E0135342613152E0123220615141716171E01151406
+071E0115140623222627351E0133323635342F012E01353436372E01353436333216017B
+3F3E8BFA3F3E8FCC538F38616CCE1A0ED3835C5D3E39CCAD499A5857943A6671DD19D680
+5D5B3B3BC8A6499903A82E5A2E4C85872D5B2E4B880293A4272750475A730F08779A655A
+8C35346D408EA81D1DA42727544C667B0E7899665B8F312C7045829F1D000001013301D1
+03850421000B0012B709C7030C065C000C10D4EC310010D4EC3001343633321615140623
+22260133AD7E7CABAC7D7DAC02FA7CABAB7C7DACAC000001009EFF3B043905D5000D0025
+4012080204C1008106020E00075D05035D010B0E10D4D4FCDCEC39310010C432F4EC1139
+300121112311231123112626353424027901C08DBE8ED7EB010405D5F966061FF9E1034E
+11DDB8BEE800000100BAFFE304AC0614002F009A40302D27210C04060D2000042A168617
+1AB9132AB90397138C2E0C090D1D2021270908242708061D082410162D081000463010FC
+C4FCCC10C6EED4EE10EE1139391239123931002FE4FEEE10FED5EE12173917393040400F
+050F060F070F270F288A0C8A0D070A060A070A0B0A0C0A0D0A1F0D200A210C220426190D
+191F19203A203A214D1F4D20492149226A1F6A20A506A507A620185D015D133436333216
+170E011514161F011E0115140623222627351E013332363534262F012E01353436372E01
+232206151123BAEFDAD0DB0397A83A4139A660E1D3408849508C4174783B655C6057A797
+0883718288BB0471C8DBE8E00873602F512A256A8E64ACB71918A41E1D5F5B3F543E373B
+875B7FAC1D67708B83FB93000004011B000006E505CD0017002F0038004C006040364542
+433F32C94830C9394A43CA0C39CA00C918C80CC924484533300431423C3F39364931604B
+3660433C5E12091E4B5E06091E5F2A4D10DCE4FCEC10FEFDC4EE10EE3211393912391217
+3931002FEEF6FEED10ED3210EED6EE391239393001220607060615141617161633323637
+363635342627262627320417161215140207060423222427260235341237362413231133
+32363534262732161514060716161717232726262323112311040083E25E5E60605E5EE2
+8384E35E5D5D5E5C5EE3849801076D6D6C6C6D6DFEF99898FEF96D6D6C6C6D6D01077D7B
+7B6E575866B0AE696018432E89AC813B4936429B05665E5E5EE58281E35E5E5F5F5E5DE2
+8385E35D5E5E676E6D6DFEFA9A98FEFB6D6D6E6E6D6D0105989A01066D6D6EFE62FEEC3E
+4B4C3F677779567011084D49DFD16033FE9C03440003011B000006E505CD0017002F0049
+004340263DCB3E3ACC41CA2431CB3034CC47CA18C900C824C90C3761443D305E2A090644
+5E1E0906124A10DCCCFCEC10FEED3210EE31002FEEF6FEFDEED6EE10FDEED6EE30013204
+171612151402070604232224272602353412373624172206070606151416171616333236
+373636353426272626171526262322061514163332363715060623222635343633321604
+009801076D6D6C6C6D6DFEF99898FEF96D6D6C6C6D6D01079883E25E5E60605E5EE28384
+E35E5D5D5E5C5EE3A742824295A7AB9B407A42438946D8FBFBD8498805CD6E6D6DFEFA9A
+98FEFB6D6D6E6E6D6D0105989A01066D6D6E675E5E5EE58281E35E5E5F5F5E5DE28385E3
+5D5E5EF5812120AF9D9FAE1F227F1D1CF4D0D1F21C00000201270393064605D5000C0014
+003E4021010607100A04120E090306C90D02008115010905620309620B0D630F62136311
+1510D4E4FCE4D4ECD4EC1139310010F43C3CEC1732D43C3CC41139300113133311231103
+23031123112315231123112335044AAEA4AA71C337CB7271CB72C905D5FF000100FDBE01
+E4FED1012FFE1C02425EFE1C01E45E000001017304EE0352066600030031400902B400B3
+040344010410D4EC310010F4EC30004BB009544BB00E545B58BD0004FFC0000100040004
+0040381137385901330123028BC7FEBA990666FE8800000200D705460329061000030007
+0092400E0602CE0400CD080164000564040810DCFCD4EC310010FC3CEC3230004BB00A54
+4BB00D545B58BD00080040000100080008FFC03811373859014BB00C544BB00D545B4BB0
+0E545B4BB017545B58BD0008FFC000010008000800403811373859014BB00F544BB01954
+5B58BD00080040000100080008FFC0381137385940116001600260056006700170027005
+7006085D0133152325331523025ECBCBFE79CBCB0610CACACA00000100D9002705DB04DD
+0013003E40220D0C0A0302CF04009C060CCF0E0A9C1206100814120E0D0C080403020809
+050F001410DC3CC4321739310010D43CCC32FC3CEC10FE3CEC3911123930132101170721
+1521072115210127372135213721D9030401007DAE012FFE48C3027BFCFAFEFE7DAEFED5
+01B6C3FD8703A2013B66D5A8F0AAFEC766D3AAF0000200080000074805D5000F00130087
+403911110E0F0E10110F0F0E0D110F0E0C110E0F0E420595030B95110195109500811107
+9503AD0D0911100F0D0C050E0A00040806021C120A0E1410D4D43CEC32D4C4C411121739
+31002F3CECECC4F4ECEC10EE10EE304B5358071005ED0705ED071005ED071005ED5922B2
+801501015D4013671177107711860C851096119015A015BF15095D011521112115211121
+15211121032301170121110735FD1B02C7FD3902F8FC3DFDF0A0CD02718BFEB601CB05D5
+AAFE46AAFDE3AA017FFE8105D59EFCF0031000030066FFBA05E5061700090013002B009E
+403C1D1F1A0D2B2C130A0100040D292620140D042A261E1A0495260D951A91268C2C2B2C
+2A141710201E23130A0100041D2910071F07192333101917102C10FCECFCECC011123939
+1739123939111239391139310010E4F4EC10EE10C010C011123939123912173912391112
+393930402A57005A15571955216A1565217B15761C7521094613590056136A006413641C
+6A287C007313761C7A280B5D015D09011E01333200113426272E01232200111416170726
+0235100021321617371707161215100021222627072704B6FD333EA15FDC010127793DA1
+5FDCFEFD2727864E4F0179013B82DD57A266AA4E50FE88FEC680DD5BA2670458FCB24043
+0148011A70B8B84043FEB8FEE570BC449E660108A0016201A54D4BBF59C667FEF69EFE9F
+FE5B4B4BBF58000300DD00DD05CF03EE000B0017002F00FF401D2D1B1509210300241804
+150F2721151B0F21300C00241812062A121E3010D4C4D4C41139393939310010D4C4D4C4
+10C01112173912391112393040BE05020503050400050006000705080509050A0A100F11
+0F120F130A1415021503150410051006100715081509150A1A0E1A0F1A101F111F121F13
+1A141A151A1624022403240420052006200724082409240A2A0E2A0F2A102F112F122F13
+2A142A152A1635023503350430053006300735083509350A3A0E3A0F3A103F113F123F13
+3A143A153A1645024503450440054006400745084509450A4A0E4A0F4A104F114F124F13
+4A144A154A1656B41FB020B021B022B026B027B028B429085D015D011E01333236353426
+232206072E01232206151416333236170E01232226353436333216173E01333216151406
+2322260393318654658076595285C4318555667F7659528690469D5E88BAA7865F994844
+9E6186BCA7865E95022F585A8769658687375858846A65868816877FDFA6AFD87E8A8A83
+E1A7AFD67700000200D9000005DB0504000B000F002E401805D007039C00D009010C9C0E
+0D02150400170C08150A061010D43CEC32FC3CEC3231002FECD43CECFC3CEC3001112115
+21112311213521110121152103AE022DFDD3A8FDD3022DFDD30502FAFE0504FE7DAAFE7D
+0183AA0183FBA6AA000200D9000005DB04A80006000A0054402E029C030403019C000104
+0403019C0201050605009C06054205040201000503D106A7079C0901080200240704230B
+10FC3CEC32323931002FECF4EC1739304B53580704ED071008ED071008ED071004ED5922
+0902150135010121152105DBFC4003C0FAFE0502FAFE0502FAFE03F8FEEBFEEEB20170AA
+016FFC02AA00000200D9000005DB04A80006000A0056402F069C0006030403059C040403
+009C010201069C05060202014206050302000504D101A7079C0806070224090400230B10
+FC3C3CEC323931002FECF4EC1739304B5358071008ED071004ED071004ED071008ED5922
+1335011501350101152135D90502FAFE03C10141FAFE03F8B0FE91AAFE90B20112FDC7AA
+AA0000010052000004C305D5001800C6404610021116110F020E0F1616110F02100F080D
+080E020D0D08420F0B090400D31706120BD31409100D81020C090E0305160F0315121003
+001166130065011C0D660A056507031910D43CEC32ECFCEC32EC12173912393911173931
+002FE432D43CEC32D43CEC32111239304B5358071005ED071008ED071008ED071005ED59
+22014BB00C5458BD0019FFC0000100190019004038113738594028860F900FA60FA00FB5
+0F05270C270D270E291028112812370E3910870C8812A60DA50EAA10A9110E5D005D0121
+1123112135213527213521013309013301211521071521048DFE63C9FE6001A054FEB401
+08FEC3BE017B0179BFFEC20108FEB554019F01C7FE3901C77B339B7B024AFD4402BCFDB6
+7B9B3300000100AEFE5604E504600020004D402513191F03160603090C0301120F06871C
+168C0A01BC00BD2119091209080B4E1F020800462110FCEC32F4ECC41239310010E4E432
+F43CECDCC41117391112173930B61F226022CF2203015D13113311141633323635113311
+141633323637150E01232226270E012322262711AEB88A879495B8232509201C29492345
+520F329162668F2AFE56060AFD489194A8A8028DFCA23C390B0C9417164E504F4F4E4EFD
+D70000020068FFE703C1052D001D002900624019002721091B062715060F211B0F15D52A
+0C2403001E1224182A10D4CCDCCC39391139310010E4CCDCCC10CE10CE11123911123930
+014BB00C544BB00B545B4BB00E545B4BB010545B4BB014545B58BD002A00400001002A00
+2AFFC03811373859013E0135342623220623222635343633321211100023222635341233
+321607342623220215141633321202F40F0F494837902424309065B4D6FEDFD598CBDDA2
+65820B574F6D8D56506D8D026D57A34B8183742C1F3E62FECAFEF9FEB1FE46D8A3C60101
+5BE0747DFEFECF747B01040000010019FE77053B05C1000B005D40140A040C0205070200
+070C0A05040301000606080C10D4C41739310010C4D4CC10CE1112393930403051035605
+50055A0A730370037604750570057A0A800380050C5A097F027F03700570067B09740B8F
+028F03800580060B5D015D1321152109012115213509013704EAFC4102A0FD4A03EFFADE
+02D5FD4905C1C1FD33FD04C095032102E3000001009CFE77057105C10007001E400F0602
+D704D600AF080367010567000810D4ECD4EC310010FCECEC323013211123112111239C04
+D5F0FD0AEF05C1F8B6067DF983000001FFE1FFF004AA042F002300CB40310B02151F1E03
+0008DA0F1A1600D922D80FD5180C1E1B1A19181706241201000B020423161505221F120C
+23126805231F2410D4D4D4EC12391112391239391117391112173931002F3CE4F4EC3232
+10EE111739393930014BB00A5458BD0024FFC0000100240024004038113738594056181E
+181F02090009010D020D030F040F050F060F070F080F090F0A0F0B0F0C0F0D0F0E0F0F0F
+100F110F120F130E140D1509160B1708180F180D19081A09231100110116021603171416
+15111617171C181C191123285D005D0123030E0115141633323637070E01232226353436
+37132103231323220607233E0133210487B6690F0F2F37112E251E1E371A7679152250FE
+BAC2B5C329363C09A01C8FA503790391FE194A5C163A3105058D080866642E90A10178FC
+6F03914045A67D000001002FFE8D03FA060E00250026401420DB001A0DDB131ADC07B126
+0A69176A1D69042610DCECFCEC310010FCECDCE410DEE430013213363712123332161514
+062322262726262322030607020223222635343633321617161601376A0E02010CBECA50
+6440372A380C0609106B0E040411BDC44F65443D21300F0A0AFEFA02B06C39020301BC54
+41363F26230F48FD95C16EFE21FE625341383F1D1C1253000003007301D5033B05F00003
+001E0029005F4033280725041F12181002E3001FDD1000E125DD050A19DF18DE15DD0AE0
+1C912A00180D1F10220602012811066B046C18226B0D2A10DCECCCFCEC3232C0C0111239
+39111239310010F4E4FCF4EC10C4EEEDD6EE10EE11123912391139393013211521011123
+35060623222635343633333534262322060735363633321605220615141633323635358B
+02B0FD5002AE952C905D8098BFBCB675753E8844499145B7B3FEECA17E6252688202507B
+02B8FE40703F448771878A045B5B22227F1C1CB0F0434F404D90721D0003006001D50364
+05F00003000F001B002E401902E300E116DD0AE010DD04911C00130D01196B076C136B0D
+1C10DCECFCEC39111239310010F4ECF4ECFCEC3013211521013216151406232226353436
+1722061514163332363534268B02B0FD500158B3CECEB3B3D0D0B3697E7F68697D7C0250
+7B041BDDBFBFDBDCBEBFDD73A18885A0A08589A00001004E000005CF05E7001F00404022
+09E51991120F030300E51001112016130F0C1F06020100026D061C1C0F6D0C1C162010D4
+ECECD4ECECC0C011123911123911123931002F3CEC1732F4EC3025152135361235340023
+2200151412171521352126023510002120001114020705CFFDA8B1C6FEF8D8D8FEF7C7B2
+FDA8013F9E91017F0131012F01818EA1B2B2B261014CCAF00122FEDDEFCAFEB461B2B28B
+012AB8013E018AFE77FECBC2FED88D000003007BFFE3076F047B00060033003E01034043
+272D253D0E0D0034A925168615881200A90E3A12B91C192E862DBA2A03B90EBB07310AB8
+1F198C253F343726060F0025371C07260F1500080D3D26080F2D370822453F10FCECCCD4
+FC3CD4ECC4111239391139111239111239310010C4E432F43CC4E4FC3CF4EC10C4EE3210
+EE10F4EE10EE11391139111239304081302B302C302D302E302F3030402B402C402D402E
+402F4030502B502C502D502E502F5030852B853080409040A040B040C040D040E040E040
+F0401D3F003F063F0D3F0E3F0F05302C302D302E302F402C402D402E402F502C502D502E
+502F6F006F066F0D6F0E6F0F602C602D602E602F702C702D702E702F802C802D802E802F
+1D5D71015D012E0123220607033E013332001D01211E0133323637150E01232226270E01
+232226353436332135342623220607353E013332160322061514163332363D0106B601A5
+8999B90E444AD484E20108FCB20CCCB768C86464D06AA7F84D49D88FBDD2FDFB0102A797
+60B65465BE5A8ED5EFDFAC816F99B9029497B4AE9E01305A5EFEDDFA5ABFC83535AE2A2C
+79777878BBA8BDC0127F8B2E2EAA272760FE18667B6273D9B42900030048FFA2049C04BC
+00090013002B00E4403C2B2C261F1D1A130A0100040D292620140D042A261E1A04B9260D
+B91AB8268C2C2B2C2A141710201E23130A01000410071F1D0712235129101217452C10FC
+EC32F4EC32C011121739123939111239391139310010E4F4EC10EE10C010C01112393912
+3912173911393911123930407028013F2D5914561C551D56206A1566217F007B047F057F
+067F077F087F097F0A7F0B7F0C7B0D7A157B1A7F1B7F1C7F1D7F1E7F1F7F207B217F227F
+237F247F257B269B199525A819A02DF02D2659005613551D5A2869006613651C6A287A00
+7413761C7A28891E95189A24A218AD24115D015D09011E01333236353426272E01232206
+15141617072E01351000333216173717071E011510002322262707270389FE1929674193
+AC145C2A673E97A913147D36360111F15D9F438B5F923536FEEEF060A13F8B600321FDB0
+2A28E8C84F759A2929EBD3486E2E974DC577011401383334A84FB34DC678FEEDFEC73433
+A84E0002008FFFE303AC05D5002000240086402F201A05020406190010860F880C002183
+230C95138C23812506221916090501001A2209001C01221C21260F091C162510DCECD4FC
+ECD4EC1112391112391112391239310010E4F4EC10FECD10F4EE123939173930014BB010
+544BB012545B4BB013545B58BD0025FFC000010025002500403811373859400B74047405
+74067407761C055D01331514060F010E0115141633323637150E012322263534363F013E
+01373E01351323353301F4BE375A5A3A33836D4EB4605EC067B8E04959583026080706C4
+CACA04449C65825758355E31596E4643BC3938C29F4C8956562F3519153C36010EFE0002
+01350000020005D5000300090062400F07008302810408070400030501000A10FC3CEC32
+393931002FF4FCCC30014BB00B5458BD000A00400001000A000AFFC03811373859014BB0
+0F544BB010545B4BB013545B58BD000AFFC00001000A000A00403811373859B6000B200B
+500B035D012335331123111333130200CBCBCB15A21404D7FEFA2B028F0165FE9B000001
+00D9011F05DB035E00050017400A049C020006031701000610DCD4EC310010D4C4EC3013
+2111231121D90502A8FBA6035EFDC10195000001003DFFD70519067D000A002A40180A09
+080706050B020402000B0A090706050403000801080B10D4CC1739310010D4CCC4111217
+39300133152301230107272501045CBD73FDAE42FEC17D19011B0100067D60F9BA03732D
+5062FD3B0001001FFE56050206140023008A40400E0D020F0C11191E190B0A0908040711
+1E1E1942190C130A071E011A0AA908138A12E616A90F018A00E604A921970F1C08241E1D
+1B1A190C0B0908070A00122410D4CC1739310010C432C4FCECF4EC10EEF6EE10EE321239
+3911123939304B5358071005ED1732071005ED1117395922014BB00C5458BD0024FFC000
+01002400240040381137385901152E01232206070321152103020623222627351E013332
+363713233521133E01333216050226502C6072193C011FFEC37F3ABCBA3A642F34612F61
+6D2289F801173F24C697356405F0A41D1C7A84FEC98FFD85FEE3D31516A6212189A602AD
+8F014AB7C312000200D9011005DB03F4001D003B003F401F2E1F392A002D221301101B0C
+1E2A9C31399C22049C1B0C9C133C1E002D0F3C10D43CC432310010D4ECD4ECDCFCD4ECC0
+111239391112393911123939300115060623222726272627262322060735363633321716
+171617163332361315060623222726272627262322060735363633321716171617163332
+3605DB69B3616E920A07060F9B5E58AC6269B3616E930B05060F9B5E56A96769B3616E92
+0A07060F9B5E58AC6269B3616E930A05070F9B5E56A9026FB34E453B040302063D4C54B3
+4E453B050202063D4B01DAB24F453B040302063D4C53B24E453B040203063D4B0002FFFA
+0000056005C1000200060038400F00030103050403020100050705060710D4CC11173931
+002FC4CC113930401463016D02700178027F0279057606076E007F00025D015D09012101
+33012102ACFE5E0344FDEFE00243FA9A04EEFBC4050FFA3F0002009E008D042504230006
+000D0086404903E804050402E8010205050402E8030206000601E80000060AE80B0C0B09
+E808090C0C0B09E80A090D070D08E807070D4209020B04E70700A60E090C05020703006F
+050A076F0C6E0E10FCFC3CD4EC321139111239310010F43CEC323939304B5358071004ED
+071008ED071008ED071004ED071004ED071008ED071008ED071004ED5922011501011501
+35131501011501350425FED3012DFE2B23FED3012DFE2B0423BFFEF4FEF4BF01A25201A2
+BFFEF4FEF4BF01A25200000200C1008D044804230006000D008640490CE80D0C090A090B
+E80A0A090DE80708070CE80B0C08080705E8060502030204E803030206E800010005E804
+05010100420C050A03E70700A60E0C08010500086F0A07016F0300700E10FC3CFCD43CEC
+1239111239310010F43CEC323939304B5358071008ED071004ED071004ED071008ED0710
+08ED071004ED071004ED071008ED59221301150135010125011501350101C101D5FE2B01
+2DFED301B201D5FE2B012DFED30423FE5E52FE5EBF010C010CBFFE5E52FE5EBF010C010C
+000300EC0000071400FE00030007000B00234011080400830A0602041905001901091908
+0C10D4FCD4ECD4EC31002F3C3CEC3232302533152325331523253315230396D4D402A9D5
+D5FAADD5D5FEFEFEFEFEFE00FFFF001000000568076B02270024000000000007010600BC
+0175FFFF001000000568075E02270024000000000007010500BC0175FFFF0073FFE305D9
+075E02270032000000000007010501270175000200730000080C05D500100019003B401F
+059503110195008118079503AD091812100A1506021C1100040815190D101A10FCECD4C4
+C4D4EC32123939393931002FECEC32F4EC3210EE30011521112115211121152120001110
+002117232000111000213307FAFD1A02C7FD3902F8FBD7FE4FFE4101BF01B16781FEBFFE
+C0014001418105D5AAFE46AAFDE3AA017C0170016D017CAAFEE1FEE0FEDFFEDF00030071
+FFE307C3047B0006002700330084403107080010860F880C00A9082E0CB916132803B908
+BB22251FB819138C340600162231090F0008074B311209512B121C453410FCECF4FCF4EC
+C4111239391239310010E432F43CC4E4EC3210C4EE3210EE10F4EE1112393040253F355F
+3570359F35CF35D035F035073F003F063F073F083F09056F006F066F076F086F09055D71
+015D012E01232206070515211E0133323637150E01232226270E01232200111000333216
+173E01333200252206151416333236353426070A02A48999B90E0348FCB20CCCB76AC862
+64D06AA0F25147D18CF1FEEF0111F18CD3424EE88FE20108FAB094ACAB9593ACAC029498
+B3AE9E355ABEC73434AE2A2C6E6D6E6D01390113011401386F6C6B70FEDD87E7C9C9E7E8
+C8C7E9000001000001E90400027900030010B602A900E90401002FC6310010FCEC301121
+15210400FC00027990000001000001E9080002790003000FB502A9000401002FCC310010
+D4EC30112115210800F800027990000200AE03E9036D05D50005000B0027401306009E09
+03810C090A0619070304070019010C10DCFCCCD4CC10FED4CE310010F43CEC3230012335
+1333030523351333030181D3A48152019AD3A4815203E9AD013FFEC1ADAD013FFEC10002
+00AE03E9036D05D50005000B0027401309039E0600810C090A0719060103040119000C10
+DCECD4CC10DCEED4CE310010F43CEC32300133150323132533150323130100D3A4815201
+9AD3A4815205D5ACFEC00140ACACFEC00140000100AE03E901D305D500050018400B009E
+03810603040019010610DCFCD4CC310010F4EC300123351333030181D3A4815203E9AD01
+3FFEC100000100B203FE01D705D500050018400B039E00810603040171000610DCECD4CC
+310010F4EC300133150323130104D3A4815205D598FEC1013F00000300D9009605DB046F
+00030007000B0029401400EA0206EA0402089C040A0C090501720400080C10DCD43CFC3C
+C4310010D4C4FCC410EE10EE3001331523113315230121152102DFF6F6F6F6FDFA0502FA
+FE046FF6FE12F50241AA00020006FE2303EE067500030007002240110206000804060806
+04030201000605070810D4CC1739310010D4CC1139123930090701FAFE7F01810181FE7F
+01F4FE0CFE0C0581FCCFFCC703390425FBDBFBD3042DFFFF003DFE56047F06100227005C
+000000000007008E005E0000FFFFFFFC000004E7074E0227003C00000000000701030073
+01750001FE89FFE302CD05F00003002B4013000F010201020F03000342028C0091040103
+0410D4CC310010E4E4304B5358071005ED071005ED592201330123022DA0FC5CA005F0F9
+F3000002005E005204BC04B20023002F0083404903091B15042D1E00271C02211D0C122D
+140B0A03130F011D2DB913EB0FEC27B91DEB21301E0C0012042A2414301C151B2A1D131C
+180903240B0A0103022428027306742A281C73183010DCE4ECF4E4EC1217391239391112
+393912393911123911121739310010D4E4ECF4E4EC10C011121739123939111239391139
+391217393001371707161615140607170727060623222627072737262635343637273717
+3636333216133426232206151416333236037BCF72CE25242628D172CF3B743D3A783DCF
+71CF25252626CF73CF3774403C755C9B72709E9D71719C03E1D173CE3B773E3F7339CF71
+CF28262525CF73CE3E763A407438CE73CF272524FE7C709A9A70729C9D000001009E008D
+0273042300060047402503E804050402E8010205050402E8030206000601E80006420204
+E700A6070203006F056E0710FCEC3239310010F4EC39304B53580704ED071008ED071008
+ED071004ED5922011501011501350273FED3012DFE2B0423BFFEF4FEF4BF01A252000001
+00C1008D0296042300060049402605E8060502030204E803030206E800010005E8040501
+0100420503E700A60705016F0300700710FC3CEC39310010F4EC39304B5358071008ED07
+1004ED071004ED071008ED592213011501350101C101D5FE2B012DFED30423FE5E52FE5E
+BF010C010C000002002F0000044A061400150019009B40280B14180703A90010870E18BE
+16B10E970900BC0501110E0F04160208000F1404080817000A064C1A10FC3CC432C4FC3C
+C410EE321112393931002F3CE632EEFEEE10EE10EE3212393930014BB00A5458BD001AFF
+C00001001A001A00403811373859014BB00E5458BD001A00400001001A001AFFC0381137
+3859401A101610171018101904301B501B800F8010801BA01BD01BEF1B085D005D011123
+11211123112335333534363B01152322061D0101331523044AB9FE07B9B0B0ADB3B9B063
+4D01F9B9B90460FBA003D1FC2F03D18F4EB7AF9950686301B2E90001002F0000044A0614
+0015008440210813040F0BA909048700971109BC0D0205000A080308010A0C0808100112
+0E4C1610FC3CC4C4FC3CC410EE1112393931002F3CE632FEEE10EE3212393930014BB00A
+5458BD0016FFC000010016001600403811373859014BB00E5458BD001600400001001600
+16FFC03811373859401130175017800A800B8017A017D017EF17085D0121112311212206
+1D01211521112311233533353436024A0200B9FEB7634D012FFED1B9B0B0AE0614F9EC05
+7B5068638FFC2F03D18F4EBBAB0000010039FF3B03C705D50013003E40201206B9001008
+B90A0400020E0A0C8102C2140F0059110D01570905590B07031410D43C3CEC32FC3C3CEC
+32310010E4F4C43210C43210EE3210EE3230252111231121352111213521113311211521
+112103C7FE91B0FE91016FFE91016FB0016FFE91016FDFFE5C01A49A021F9901A4FE5C99
+FDE1000100DB024801AE034600030012B7028300040119000410D4EC310010D4EC301333
+1523DBD3D30346FE000100AEFF1201D300FE00050018400B039E00830603040119000610
+D4ECD4CC310010FCEC302533150323130100D3A48152FEACFEC00140000200AEFF12036D
+00FE0005000B0027401309039E0600830C030401190007090A0719060C10DCECD4CC10DC
+EED4CE310010FC3CEC3230253315032313253315032313029AD3A48152FE66D3A48152FE
+ACFEC00140ACACFEC001400000070071FFE30A4C05F0000B0017002300270033003F004B
+00AE4044240F252625260F272427424000920C2E921E8D289218460692340C8D3A26128C
+2418914C25494327312B430D3D090D0F0E030D15310D1B3D0E490D15372B0D1B0E210B4C
+10FCE4ECD4C4ECE410EE10EEF6EE10EE111239111239310010E432F43C3CE432EC3210EE
+F6EE10EE32304B5358071005ED071005ED5922014BB014544BB009545B4BB00B545B4BB0
+0C545B4BB00D545B4BB00E545B58BD004C00400001004C004CFFC0381137385901220615
+141633323635342627321615140623222635343601321615140623222635343621330123
+132206151416333236353426013216151406232226353436172206151416333236353426
+08F457646457556363559EBABB9DA0BABBF9749EBCBB9F9FB9BA0425A0FC5AA01F566362
+5757636403B29EBABB9DA0BABB9F57636357556363029194848295958283957FDCBBBBDB
+DBBBBCDB02E0DBBBBDDADBBCBADCF9F3058E9582849494848196FD9FDCBBBBDBDBBBBCDB
+7F948482959582839500FFFF001000000568076D02270024000000000007010700BC0175
+FFFF00C90000048B076D022700280000000000070107009E0175FFFF001000000568076B
+02270024000000000007010400BC0175FFFF00C90000048B074E02270028000000000007
+0103009E0175FFFF00C90000048B076B022700280000000000070106009E0175FFFF00A2
+0000021F076B0227002C0000000000070104FF2F0175FFFFFFFE00000260076D0227002C
+0000000000070107FF2F0175FFFF000600000258074E0227002C0000000000070103FF2F
+0175FFFF003B000001BA076B0227002C0000000000070106FF2F0175FFFF0073FFE305D9
+076B02270032000000000007010401270175FFFF0073FFE305D9076D0227003200000000
+0007010701270175FFFF0073FFE305D9076B02270032000000000007010601270175FFFF
+00B2FFE30529076B02270038000000000007010400EE0175FFFF00B2FFE30529076D0227
+0038000000000007010700EE0175FFFF00B2FFE30529076B022700380000000000070106
+00EE0175000100C100000179046000030020B700BF02010800460410FCEC31002FEC3040
+0B1005400550056005700505015D13331123C1B8B80460FBA000000100C104EE033F0666
+00060037400C040502B400B307040275060710DCEC39310010F4EC323930004BB009544B
+B00E545B58BD0007FFC0000100070007004038113738590133132327072301B694F58BB4
+B48B0666FE88F5F5000100B6051D034A0637001B006340240012070E0B040112070F0B04
+12C3190704C3150BED1C0F010E000715561677075608761C10F4ECFCEC11393939393100
+10FC3CFCD43CEC11123911123911123911123930004BB009544BB00C545B58BD001CFFC0
+0001001C001C0040381137385901272E0123220607233E013332161F011E013332363733
+0E0123222601FC3916210D2624027D02665B2640253916210D2624027D02665B2640055A
+371413495287931C21371413495287931C00000100D50562032B05F60003002FB702EF00
+EE0401000410D4CC310010FCEC30004BB009544BB00E545B58BD0004FFC0000100040004
+0040381137385913211521D50256FDAA05F69400000100C7052903390648000D0057400E
+0BF0040700B30E0756080156000E10DCECD4EC310010F43CD4EC30004BB0095458BD000E
+FFC00001000E000E00403811373859004BB00F544BB010545B4BB011545B58BD000E0040
+0001000E000EFFC0381137385913331E0133323637330E01232226C7760B615756600D76
+0A9E91919E06484B4B4A4C8F90900001019A0544026606100003002C400902CE00CD0401
+64000410D4EC310010FCEC30004BB0095458BD0004FFC000010004000400403811373859
+01331523019ACCCC0610CC00000200EE04E103120706000B0017005F401103C115F209C1
+0FF11800560C780656121810D4ECF4EC310010F4ECF4EC30004BB009544BB00C545B58BD
+0018FFC000010018001800403811373859014BB00A544BB00B545B4BB00C545B58BD0018
+FFC000010018001800403811373859013426232206151416333236371406232226353436
+333216029858404157574140587A9F73739F9F73739F05F43F5857404157584073A0A073
+739F9F0000010123FE7502C100000013001F400E09060A0DF306001300102703091410DC
+D4ECD4CC31002FD4FCC41239302116161514062322262735161633323635342627025437
+3678762E572B224A2F3B3C2B2D3E6930595B0C0C83110F302E1E573D000200F004EE03AE
+066600030007004240110602B40400B3080407030005010305070810D4DCD4CC11391112
+39310010F43CEC3230004BB009544BB00E545B58BD0008FFC00001000800080040381137
+3859013303230333032302FCB2F88781AADF890666FE880178FE88000001014CFE7502C1
+000000130020400F0B0E0A07F30EF40001000A0427111410D4ECC4D4CC31002FFCFCC412
+3930213306061514163332363715060623222635343601B8772D2B3736203E1F26441E7A
+73353D581F2E2E0F0F850A0A575D3069000100C104EE033F066600060037400C0300B404
+01B307030575010710DCEC39310010F43CEC3930004BB009544BB00E545B58BD0007FFC0
+000100070007004038113738590103331737330301B6F58BB4B48BF504EE0178F5F5FE88
+0001FFF20000047505D5000D003F401E0C0B0A040302060006950081080304010B0E0004
+05011C0C073A0900790E10F43CECC4FC3CC411123911123931002FE4EC11173930B4300F
+500F02015D1333112517011121152111072737D3CB013950FE7702D7FC5E944DE105D5FD
+98DB6FFEEEFDE3AA023B6A6E9E0000010002000002480614000B005E401A0A0908040302
+06009706030401090A00047A0501080A7A07000C10D43CE4FC3CE411123911123931002F
+EC173930014BB0105458BD000C00400001000C000CFFC038113738594013100D400D500D
+600D73047A0A700DE00DF00D095D133311371707112311072737C7B87D4CC9B87B4AC506
+14FDA65A6A8DFCE3029A586A8D00FFFF0087FFE304A2076D022700360000000000070108
+008B0175FFFF006FFFE303C706660227005600000000000700E000170000FFFF005C0000
+051F076D0227003D000000000007010800BE0175FFFF0058000003DB06660227005D0000
+0000000700E0001B000000020104FEA201AE059800030007001C400D01F50004F5050804
+000506020810DC3CEC32310010D4ECD4EC30011123111311231101AEAAAAAA0198FD0A02
+F60400FD0A02F6000002000A000005BA05D5000C0019006740201009A90B0D9500811295
+0E0B0707011913040F0D161904320A110D1C0800791A10F43CEC32C4F4EC10C417393100
+2FC632EEF6EE10EE32304028201B7F1BB01B039F099F0A9F0B9F0C9F0E9F0F9F109F11BF
+09BF0ABF0BBF0CBF0EBF0FBF10BF11105D015D1321200011100029011123353313112115
+211133200011100021D301A001B10196FE69FE50FE60C9C9CB0150FEB0F30135011FFEE1
+FECB05D5FE97FE80FE7EFE9602BC9001E3FE1D90FDEA0118012E012C011700020071FFE3
+04750614000E00280127405E257B26251E231E247B23231E0F7B231E287B27281E231E26
+2728272524252828272223221F201F2120201F42282726252221201F08231E030F2303B9
+1B09B9158C1B23B1292627120C212018282523221F051E0F060C121251061218452910FC
+ECF4EC113939173912393911123939310010ECC4F4EC10EE12391239121739304B535807
+100EC9071008C9071008C907100EC9071008ED070EED071005ED071008ED5922B23F2A01
+015D407616252B1F28222F232F2429252D262D272A283625462558205821602060216622
+752075217522132523252426262627272836243625462445255A205A21622062217F007F
+017F027A037B097F0A7F0B7F0C7F0D7F0E7F0F7F107F117F127F137F147B157A1B7A1C7F
+1D7F1E762076217822A02AF02A275D005D012E0123220615141633323635342613161215
+140023220035340033321617270527252733172517050346325829A7B9AE9291AE36097E
+72FEE4E6E7FEE50114DD12342A9FFEC1210119B5E47F014D21FED903931110D8C3BCDEDE
+BC7ABC01268FFEE0ADFFFEC90137FFFA01370505B46B635CCC916F616200FFFFFFFC0000
+04E7076B0227003C000000000007010400730175FFFF003DFE56047F06660227005C0000
+00000007008D005E0000000200C90000048D05D5000C0015003D401B0E95090D9502F600
+810B150F090304011219063F0D0A011C00041610FCEC3232FCEC11173931002FF4FCECD4
+EC3040090F171F173F175F1704015D1333113332041514042B0111231311333236353426
+23C9CAFEFB0101FEFFFBFECACAFE8D9A998E05D5FEF8E1DCDCE2FEAE0427FDD192868691
+000200BAFE5604A406140010001C003E401B14B905081AB9000E8C08B801BD03971D1112
+0B471704000802461D10FCEC3232F4EC310010ECE4E4F4C4EC10C6EE304009601E801EA0
+1EE01E04015D2511231133113E0133321211100223222601342623220615141633323601
+73B9B93AB17BCCFFFFCC7BB10238A79292A7A79292A7A8FDAE07BEFDA26461FEBCFEF8FE
+F8FEBC6101EBCBE7E7CBCBE7E700000100D9022D05DB02D700030011B6009C0204010004
+10D4C4310010D4EC3013211521D90502FAFE02D7AA0000010119003F059C04C5000B0085
+404D0A9C0B0A070807099C080807049C0304070706059C060706049C0504010201039C02
+02010B9C0001000A9C090A010100420A080706040201000805030B090C0B0A0907050403
+0108020008060C10D43CCC321739310010D43CCC321739304B5358071008ED071005ED07
+1005ED071008ED071005ED071008ED071005ED071008ED59220902070101270101370101
+059CFE3701C977FE35FE357601C8FE387601CB01CB044CFE35FE377901CBFE357901C901
+CB79FE3501CB00010089029C02C505DF000A002C40180700DD0903DD0402DD09F705910B
+087C065D037C017C000B10DCF4E4FCE4310010F4ECECD4EC10EE32301333110735373311
+3315219CCCDFE689CDFDD7030A0263297427FD2B6E000001005E029C02B405F00018004A
+4024007D060400177D060604420402000EDD0F00DD02F70BDD0F129119000E087E01150E
+031910DCC4D4C4EC1139310010F4C4ECFCEC10EE111239304B5358071005ED17320705ED
+592201211521353637003534262322060735363633321615140106010C01A8FDAA223F01
+586855347A484D853991AEFEB538030E726E1F3801315E425123237B1C1C846C8BFEE430
+00010062028D02CD05F00028004840270015130ADD091FDD2013DD150DDD09F806F71CDD
+20F823912916130014197E26107E03141F092910DCC4C4D4ECD4EC11393939310010F4E4
+ECFCE4ECD4EC10EE10EE1112393001161615140623222627351616333236353426232335
+33323635342623220607353636333216151406020C5C65BEB1397D463477436D786F6C56
+5E5E61645F28665149803790A95A0460126D527C861514791B1A4F464A4C6C3F3C3A3D12
+1773111276634560FFFF0089FFE3077F05F0002700F000000000002700BC033500000007
+0109048BFD64FFFF0089FFE3073F05F0002700F000000000002700BC03350000000700F1
+048BFD64FFFF0062FFE3077F05F0002700F200000000002700BC0335000000070109048B
+FD64FFFF0073FFE3058B076D0227002A000000000007010A011B0175FFFF0071FE56045A
+06480227004A00000000000700DA008B0000FFFF00C90000019507500227002C00000000
+0007010BFF2F0175FFFF0087FE7504A205F00227003600000000000700DD008B0000FFFF
+006FFE7503C7047B0227005600000000000700DD00170000FFFF0073FFE30527076B0227
+00260000000000070104012D0175FFFF0071FFE303E7066602270046000000000007008D
+00890000FFFF0073FFE30527076D022700260000000000070108012D0175FFFF0071FFE3
+03E706660227004600000000000700E00089000000020071FFE304F4061400180024004A
+40240703D30901F922B900161CB90D108C16B805970B021F0C04030008080A0647191213
+452510FCECF43CC4FC173CC431002FECE4F4C4EC10C4EEFD3CEE3230B660268026A02603
+015D01112135213533153315231123350E01232202111012333216011416333236353426
+23220603A2FEBA0146B89A9AB83AB17CCBFFFFCB7CB1FDC7A79292A8A89292A703B6014E
+7D93937DFAFCA86461014401080108014461FE15CBE7E7CBCBE7E7000001006401DF027F
+028300030011B6009C020401000410DCCC310010D4EC301321152164021BFDE50283A400
+000100DB024801AE034600030012B7028300040119000410D4EC310010D4EC3013331523
+DBD3D30346FE00010000FFE3048F05F00031011C403A2012D322102B07D30919A11AAE16
+951D01A100AE04952F911D8C2909322B222129232612100A030D0911082C202613071108
+110D1C1900262A212F3CD4C432FCC4C41239391239391112391117391239391139393100
+10C432E4F4ECF4EC10EEF6EE10EE32DD3CEE3230014BB009544BB00C545B4BB00D545B4B
+B00F545B4BB017545B4BB018545B58BD0032FFC000010032003200403811373859407A0E
+000E010B020B315414690C6C0E6E0F6F106F116F126F1369146B1F6F206F216F226F236E
+246C256927692D9F079F089F099F0A9F0B9F0C9F0D9F0E9F0F9F109F119F129F13961F9F
+209F219F229F239F249F259F269F279F289F299F2A9F2B9F2C9D2D320008000910081009
+200820095515531E6A15671F0A5D005D01152E01232206072107210E0115141617210721
+1E0133323637150E01232200032337333426353436352337331200333216048F5BA9669D
+CA20024137FDE60201010201BE38FE8A20CA9D66A95B59B960EDFECB28D3378B0101C237
+9C280136EC62B90562D5695AC8BB7B182E23202E187BBBCA5A69D34848012201037B172F
+20232F177B0101012247000200D7050E032905D90003000700A5400D0400CE0602080164
+000564040810D4FCDCEC310010D43CEC3230004BB00E544BB011545B58BD000800400001
+00080008FFC03811373859014BB00E544BB00D545B4BB017545B58BD0008FFC000010008
+000800403811373859014BB011544BB019545B58BD00080040000100080008FFC0381137
+3859004BB0185458BD0008FFC00001000800080040381137385940116001600260056006
+700170027005700608015D0133152325331523025ECBCBFE79CBCB05D9CBCBCB00010173
+04EE02F005F60003007F40110203000301000003420002FA040103030410C410C0310010
+F4CC304B5358071005C9071005C95922004BB00C5458BD0004FFC0000100040004004038
+11373859004BB00E5458BD00040040000100040004FFC038113738594020060215022501
+25023602460256026A016702090F000F011F001F012F002F01065D015D013303230237B9
+E49905F6FEF8000100B6050E034A05E9001D0075402116100F03130C0701000308170CC3
+0413C31B08FA1E10010F00071656180756091E10D4ECD4EC1139393939310010F43CECD4
+EC321217391112173930004BB00C5458BD001EFFC00001001E001E00403811373859004B
+B00E5458BD001E00400001001E001EFFC03811373859B4100B1F1A025D01272E01232206
+1D012334363332161F011E013332363D01330E0123222601FC39191F0C24287D6756243D
+303917220F20287D026754223B0539210E0B322D066576101B1E0D0C3329066477100001
+010C04EE028B05F60003008940110102030200030302420001FA040103030410C410C031
+0010F4CC304B5358071005C9071005C95922004BB00C5458BD0004FFC000010004000400
+403811373859004BB00E5458BD00040040000100040004FFC03811373859402A06000601
+160012012400240135014301550055019F009F01AF00AF010E0F000F031F001F032F002F
+03065D015D0113230301C7C499E605F6FEF80108000100CF04EE033105F800060077400A
+04000502FA070402060710D4C439310010F43CC43930004BB00C5458BD0007FFC0000100
+07000700403811373859004BB00E5458BD00070040000100070007FFC03811373859014B
+B00E5458BD0007FFC00001000700070040381137385940130F000F010C041F001F011D04
+2F002F012D0409005D0133132327072301A2BCD38BA6A68B05F8FEF6B2B2000100CF04EE
+033105F800060086400A03040100FA070305010710D4C439310010F4C4323930004BB00C
+544BB009545B4BB00A545B4BB00B545B58BD0007FFC00001000700070040381137385900
+4BB00E5458BD00070040000100070007FFC03811373859014BB00E5458BD0007FFC00001
+0007000700403811373859401300000303000610001203100620002203200609005D0103
+331737330301A2D38BA6A68BD304EE010AB2B2FEF6000002003F029C02F405DF0002000D
+00D4401600030B07DD050109F703910E010C0A005D0608040C0E10DCD43CC4EC32113931
+0010F4FCD43CEC32123930014BB00E544BB00F545B4BB010545B4BB011545B4BB00B545B
+4BB00A545B58BD000E00400001000E000EFFC03811373859004BB011544BB00E545B58BD
+000EFFC00001000E000E0040381137385940540B011D012F01390149014603590369038B
+03AB03BB030B01000F010F020F050F060F070F080F0B0F0C0F0D13001F011F021F051F06
+1F071F081F0B1F0C1F0D2200350047004B0D53005B0D65008400A500B5001E5D015D0901
+21033311331523152335213501DDFECB013516A6878790FE620566FE5D021CFDE46DBABA
+7900000100C70506033905F8000D006A400E070004C30BFA0E0756080156000E10D4ECD4
+EC310010F4FCC43230004BB00C5458BD000EFFC00001000E000E00403811373859004BB0
+0E5458BD000E00400001000E000EFFC03811373859014BB00E544BB00F545B58BD000EFF
+C00001000E000E0040381137385913331E0133323637330E01232226C7760D6353526110
+760AA08F909F05F836393738777B7A000001019A050E026605DB00030011B60002FA0401
+000410D4CC310010F4CC3001331523019ACCCC05DBCD0000000000020001000000000014
+000300010000011A00000106000001000000000000000103000000020000000000000000
+00000000000000010000030405060708090A0B0C0D0E0F101112131415161718191A1B1C
+1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F40
+4142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F6061006263
+6465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F8081828384858687
+88898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAAB
+ACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF
+D0D100D2D3D4D5D6D7D8D9DADBDCDDDEDFE00004023E0000003A00200004001A007E00FF
+01070111011F01310142015301610178017E019202C702DD03A903C020262030203A20AC
+21222206221E222B2248226525CAFB02FFFF0000002000A00106010C011E013001410152
+015E0178017D019202C602D803A903C020132030203920AC21222202220F222B22482260
+25CAFB01FFFFFFE30000FFF50000FFD80000FFA0FF5E0000FF43FF68FF1400000000FCF6
+FCDB0000E096E085E056DF6A00000000DE71DE5F0000DAEF05BF000100000038000000F4
+000000FC0000000000FA00000000000000FA00FC00000000010200000000000000000120
+012800000000014200000000000000AC00A30084008500BD009600E70086008E008B009D
+00A900A40100008A00D90083009300F100F2008D0097008800C300DD00F0009E00AA00F3
+00F400F500A200AD00C900C700AE006200630090006400CB006500C800CA00CF00CC00CD
+00CE00E8006600D200D000D100AF006700EF009100D500D300D4006800EA00EC0089006A
+0069006B006D006C006E00A0006F0071007000720073007500740076007700E90078007A
+0079007B007D007C00B800A1007F007E0080008100EB00ED00BA00FD00FE000000000000
+00FF00F800D600F900FA00E300E400D700E000DA00DB00DC00DF00D800DE00B200B30000
+0000000000B600B700C4000000B400B500C50000008200C2008700000000000000AB0098
+00000000000000A8009A0000009900EE0000000000BC000000000000010100A500000000
+00000092008F0000000000000094009504CD006600000000028B0000028B000003350135
+03AE00C506B4009E051700AA079A0071063D0081023300C5031F00B0031F00A40400003D
+06B400D9028B009E02E30064028B00DB02B2000005170087051700E1051700960517009C
+051700640517009E0517008F051700A80517008B0517008102B200F002B2009E06B400D9
+06B400D906B400D9043F00930800008705790010057D00C905960073062900C9050E00C9
+049A00C906330073060400C9025C00C9025CFF96053F00C9047500C906E700C905FC00C9
+064C007304D300C9064C0073058F00C90514008704E3FFFA05DB00B20579001007E90044
+057B003D04E3FFFC057B005C031F00B002B20000031F00C706B400D90400FFEC040000AA
+04E7007B051400BA046600710514007104EC007102D1002F05140071051200BA023900C1
+0239FFDB04A200BA023900C107CB00BA051200BA04E50071051400BA05140071034A00BA
+042B006F03230037051200AE04BC003D068B005604BC003B04BC003D0433005805170100
+02B201040517010006B400D9057900100579001005960073050E00C905FC00C9064C0073
+05DB00B204E7007B04E7007B04E7007B04E7007B04E7007B04E7007B0466007104EC0071
+04EC007104EC007104EC0071023900900239FFC70239FFDE0239FFF4051200BA04E50071
+04E5007104E5007104E5007104E50071051200AE051200AE051200AE051200AE04000039
+040000C3051700AC051700810400005C04B801330517009E050A00BA0800011B0800011B
+0800012704000173040000D706B400D907CB0008064C006606AA00DD06B400D906B400D9
+06B400D905170052051700AE0423006805640019060E009C04B6FFE1042B002F03C50073
+03C50060061D004E07DB007B04E50048043F008F0335013506B400D90519003D0517001F
+06B400D9055AFFFA04E5009E04E500C1080000EC051700000579001005790010064C0073
+088F0073082F00710400000008000000042500AE042500AE028B00AE028B00B206B400D9
+03F4000604BC003D04E3FFFC0156FE890517005E0333009E033300C1050A002F050A002F
+04000039028B00DB028B00AE042500AE0ABC007105790010050E00C905790010050E00C9
+050E00C9025C00A2025CFFFE025C0006025C003B064C0073064C0073064C007305DB00B2
+05DB00B205DB00B2023900C1040000C1040000B6040000D5040000C70400019A040000EE
+04000123040000F00400014C040000C1047FFFF20246000205140087042B006F057B005C
+0433005802B201040633000A04E5007104E3FFFC04BC003D04D700C9051400BA06B400D9
+06B40119033500890335005E0335006207C1008907C1008907C100620633007305140071
+025C00C905140087042B006F059600730466007105960073046600710514007102E30064
+028B00DB05170000040000D704000173040000B60400010C040000CF040000CF0335003F
+040000C70400019A0002000000000000FF2B008F00000000000000000000000000000000
+00000000010C0000000100020003000400050006000700080009000A000B000C000D000E
+000F0010001100120013001400150016001700180019001A001B001C001D001E001F0020
+002100220023002400250026002700280029002A002B002C002D002E002F003000310032
+0033003400350036003700380039003A003B003C003D003E003F00400041004200430044
+00450046004700480049004A004B004C004D004E004F0050005100520053005400550056
+005700580059005A005B005C005D005E005F006000610062006300640065006600670068
+0069006A006B006C006D006E006F0070007100720073007400750076007700780079007A
+007B007C007D007E007F0080008100820083008400850086008700880089008A008B008C
+008D008E008F0090009100920093009400950096009700980099009A009B009C009D009E
+009F00A000A100A200A300A400A500A600A700A800A900AA00AB00AC00AD00AE00AF00B0
+00B100B200B300B400B500B600B700B800B900BA00BB00BC00BD00BE00BF00C000C100C2
+00C300C400C500C600C700C800C900CA00CB00CC00CD00CE00CF00D000D100D300D400D5
+00D600D700D800D900DA00DB00DC00DD00DE00DF00E000E100E200E300E400E500E600E7
+00E800E900EA00EB00EC00ED00EE00EF00F000F100F200F300F500F400F600F800F900FA
+00FB00FC00FD00FE00FF0100010101020103010401050106010701080109010A010B010C
+010D0973667468797068656E0E706572696F6463656E7465726564044575726F05633634
+353905633634363005633634363105633634363205633634363305633634363605633634
+36370563363436380563363436390000000000220022002200220058009300FF01B6024F
+038303B203F60421046E049804B404CA04DE0503054505820605067E06E1074C07B707FC
+086508CF08EE09160952097309AE0A1F0ADF0B580BB00BFB0C3A0C690C930CE60D140D3D
+0D7A0E0D0E2F0EAC0F000F450F850FEB107510F11129117011E012BD138A13EB1450148B
+14B114E115031518154015D61622166D16B91723177B17DF181B1843188018F819161977
+19B31A041A521AA11AD81B871BC41C001C9D1DBA1E871F771FE8205B207220F321352142
+21E221EF21FC2209221622232230223D224A225722642271227E228B229822A522B222BF
+22CC22D922E622F32300230D231A232723342341234E235B2368239423CF2434248F2533
+25532581261426BA274B279027B72813285828C3295F2A252A5C2AA32AE92B7A2BD32C44
+2C8F2CB12D502DA02E0E2E522EAA2F87304130BD31053121315031CF3248327A32DF3346
+33703370337D338A339733E6347A348F34A334D134FF351C353935673591359E35AB35CF
+365B369336CD374337A937EB3800381C384A390F391C3929393639433950395D396A3977
+39843991399E39AB39B839C539D239EF3A1C3A7B3AA03AE53B083B5E3B8E3BC43BF43C22
+3C5F3CA73CB43CC13CCE3CDB3CFE3D633E3B3E483E553E983EE73EFD3F613F8D3FDC403A
+404B405C406D407A4087409440A140AE40BB40C840D540E241404156416B424542AA42F7
+435F43B243FF445544DB452A453F00000000000100002D86000107941800000A15780010
+0024FFD300100025FFB70010002600000010002700000010002900000010002A004B0010
+002B00000010002D00720010002E00000010002F00000010003200390010003300000010
+0034004B00100035000000100037FF4400100039FF880010003AFFAD0010003BFF9A0010
+003CFF0D0010003D00000010004900000010005100000010005200260010005500000010
+0059FFC90010005A00000010005CFFDC00100062FFD30010006400000010006700390010
+007800000010007900260010007A00260010007B00260010007C00260010007D00260010
+00890000001000900000001000ADFFD3001000AEFFD3001000AF0039001000BAFFDC0010
+00BBFF0D001000C7FFD3001000C9FFD3001000D00039001000D10039001000D200390010
+00E50000001000E90000001000EAFF0D001000EBFFDC001000EC0000001000F6004B0010
+00FB0000001000FD000000240010FFD300240011FFDC0024001DFFDC0024002400390024
+0026FFDC0024002AFFDC00240032FFDC00240034FFDC00240036000000240037FF610024
+0038000000240039FF7D0024003AFF900024003B00000024003CFF6100240046FFDC0024
+0047FFDC00240048FFDC00240049FFB700240052FFDC00240054FFDC00240057FFDC0024
+0058000000240059FF880024005AFFAD0024005CFF7500240062003900240064FFDC0024
+0067FFDC0024006800000024006FFFDC00240070FFDC00240071FFDC00240072FFDC0024
+0073FFDC00240079FFDC0024007AFFDC0024007BFFDC0024007CFFDC0024007DFFDC0024
+007E00000024007F0000002400800000002400810000002400A9FFB7002400AA00000024
+00AD0039002400AE0039002400AFFFDC002400B4FEF8002400B5FF03002400BAFF750024
+00BBFF61002400C5002F002400C70039002400C90039002400D0FFDC002400D1FFDC0024
+00D2FFDC002400D30000002400D40000002400D50000002400E30000002400EAFF610024
+00EBFF75002400F6FFDC002400F90000002400FBFFDC002400FCFFDC002400FDFFDC0024
+00FEFFDC00250010000000250026FFDC0025002AFFDC00250032FFDC00250036FFDC0025
+0039FFC10025003AFFB70025003CFF9000250064FFDC00250067FFDC002500A9FFC10025
+00AAFFDC002500AFFFDC002500B4FF90002500B5FF90002500BBFF90002500C5FFAD0025
+00D0FFDC002500D1FFDC002500D2FFDC002500E3FFDC002500EAFF90002500F6FFDC0025
+00F9FFDC002500FBFFDC002500FDFFDC0026001000000026002400000026003600000026
+003CFFDC002600620000002600A9FFDC002600AAFFDC002600AD0000002600AE00000026
+00B40000002600B50026002600BBFFDC002600C50000002600C70000002600C900000026
+00E30000002600EAFFDC002600F9000000270010000000270024FFDC00270039FFDC0027
+003A00000027003CFF9000270062FFDC002700A9FFDC002700AAFFDC002700ADFFDC0027
+00AEFFDC002700B4FFD3002700B5FFC9002700BBFF90002700C5FF44002700C7FFDC0027
+00C9FFDC002700EAFF9000290010000000290011FEB70029001DFF6100290024FF440029
+0036FFDC00290037FFDC00290044FF4400290048FF900029004CFF6B00290052FFB70029
+0055FF6B00290058FF900029005CFF4400290062FF4400290069FF440029006AFF440029
+006BFF440029006CFF440029006DFF440029006EFF4400290070FF9000290071FF900029
+0072FF9000290073FF9000290079FFB70029007AFFB70029007BFFB70029007CFFB70029
+007DFFB70029007EFF900029007FFF9000290080FF9000290081FF90002900A900000029
+00AA0000002900ADFF44002900AEFF44002900B4FFD3002900B50000002900BAFF440029
+00C5FE88002900C7FF44002900C9FF44002900E3FFDC002900EBFF44002900F9FFDC002A
+00100000002A00240000002A0037FFB7002A003A0000002A003CFF9A002A00620000002A
+00A9FFDC002A00AAFFDC002A00AD0000002A00AE0000002A00B4FFD3002A00B5FFD3002A
+00BBFF9A002A00C5FFC9002A00C70000002A00C90000002A00EAFF9A002B00100000002B
+0011FFDC002B001D0000002B00A90000002B00AA0000002B00B4FFB7002B00B5FFC1002B
+00C5FFB7002D0010FFB7002D0024FFDC002D0062FFDC002D00A9FFDC002D00AAFFDC002D
+00ADFFDC002D00AEFFDC002D00B4FFB7002D00B5FFC1002D00C5FF90002D00C7FFDC002D
+00C9FFDC002E0010FF29002E0024FFDC002E0026FF90002E0032FF90002E0037FF61002E
+0038FFC9002E003AFFB7002E003CFFB7002E0044FFDC002E0048FF9A002E0052FF9A002E
+0058FF9A002E005CFF6B002E0062FFDC002E0064FF90002E0067FF90002E0068FFC9002E
+0069FFDC002E006AFFDC002E006BFFDC002E006CFFDC002E006DFFDC002E006EFFDC002E
+0070FF9A002E0071FF9A002E0072FF9A002E0073FF9A002E0079FF9A002E007AFF9A002E
+007BFF9A002E007CFF9A002E007DFF9A002E007EFF9A002E007FFF9A002E0080FF9A002E
+0081FF9A002E00A9FF7D002E00AA0000002E00ADFFDC002E00AEFFDC002E00AFFF90002E
+00B4FFC1002E00B5FFC1002E00BAFF6B002E00BBFFB7002E00C50000002E00C7FFDC002E
+00C9FFDC002E00D0FF90002E00D1FF90002E00D2FF90002E00D3FFC9002E00D4FFC9002E
+00D5FFC9002E00EAFFB7002E00EBFF6B002E00FBFF90002E00FDFF90002F0010FFDC002F
+0024002F002F0032FFB7002F0037FEE6002F0038FF9A002F0039FF1F002F003AFF44002F
+003CFEF0002F00440000002F0048FFDC002F0052FFDC002F0058FFDC002F005CFF44002F
+0062002F002F0067FFB7002F0068FF9A002F00690000002F006A0000002F006B0000002F
+006C0000002F006D0000002F006E0000002F0070FFDC002F0071FFDC002F0072FFDC002F
+0073FFDC002F0079FFDC002F007AFFDC002F007BFFDC002F007CFFDC002F007DFFDC002F
+007EFFDC002F007FFFDC002F0080FFDC002F0081FFDC002F00A90000002F00AA0000002F
+00AD002F002F00AE002F002F00AFFFB7002F00B4FE61002F00B5FDE6002F00BAFF44002F
+00BBFEF0002F00C50000002F00C7002F002F00C9002F002F00D0FFB7002F00D1FFB7002F
+00D2FFB7002F00D3FF9A002F00D4FF9A002F00D5FF9A002F00EAFEF0002F00EBFF440032
+0010003900320011FFAD0032001DFFDC00320024FFDC00320039FFDC0032003BFF7D0032
+003CFF9000320062FFDC003200A9FFDC003200AA0000003200ADFFDC003200AEFFDC0032
+00B4FFD3003200B5FFDC003200BBFF90003200C5FF44003200C7FFDC003200C9FFDC0032
+00EAFF9000330010FFD300330011FEC10033001D000000330024FF7D0033003800000033
+003A00000033003CFFD300330044FFA400330048FFB70033004CFFD300330051FFDC0033
+0052FFB700330055FFDC00330056FFDC00330058FFDC0033005C000000330062FF7D0033
+0068000000330069FFA40033006AFFA40033006BFFA40033006CFFA40033006DFFA40033
+006EFFA400330070FFB700330071FFB700330072FFB700330073FFB700330078FFDC0033
+0079FFB70033007AFFB70033007BFFB70033007CFFB70033007DFFB70033007EFFDC0033
+007FFFDC00330080FFDC00330081FFDC003300A9FFDC003300AA0000003300ADFF7D0033
+00AEFF7D003300B40026003300B50026003300BA0000003300BBFFD3003300C5FEB70033
+00C7FF7D003300C9FF7D003300D30000003300D40000003300D50000003300E4FFDC0033
+00EAFFD3003300EB0000003300FAFFDC003400100039003400A90000003400AA00000034
+00B4FFD3003400B5FFDC003400C5FF7D00350010FFAD00350011FFB70035001DFFC10035
+0024FFAD00350026FF9A00350037FF6B00350039FF900035003AFFAD0035003CFF7D0035
+0044FFD300350048FFA400350052FFA400350058FFA40035005CFF9000350062FFAD0035
+0064FF9A00350069FFD30035006AFFD30035006BFFD30035006CFFD30035006DFFD30035
+006EFFD300350070FFA400350071FFA400350072FFA400350073FFA400350079FFA40035
+007AFFA40035007BFFA40035007CFFA40035007DFFA40035007EFFA40035007FFFA40035
+0080FFA400350081FFA4003500A9FF90003500AAFFDC003500ADFFAD003500AEFFAD0035
+00B4FF6B003500B5FF7D003500BAFF90003500BBFF7D003500C5FFDC003500C7FFAD0035
+00C9FFAD003500EAFF7D003500EBFF90003500FBFF9A003500FDFF9A0036002400260036
+002600000036002A00000036003200000036003400000036003600000036006200260036
+00640000003600670000003600AD0026003600AE0026003600AF0000003600C700260036
+00C90026003600D00000003600D10000003600D20000003600E30000003600F600000036
+00F90000003600FB0000003600FD000000370010FF4400370011FF0D0037001DFF1F0037
+0024FF6100370026FF8800370037FFDC00370044FEAD00370046FEA400370048FEA40037
+004CFFC100370052FEA400370055FED300370056FEAD00370058FEC90037005AFEAD0037
+005CFEC100370062FF6100370064FF8800370069FEAD0037006AFEAD0037006BFEAD0037
+006CFEAD0037006DFEAD0037006EFEAD0037006FFEA400370070FEA400370071FEA40037
+0072FEA400370073FEA400370079FEA40037007AFEA40037007BFEA40037007CFEA40037
+007DFEA40037007EFEC90037007FFEC900370080FEC900370081FEC9003700A9FF440037
+00AAFF90003700ADFF61003700AEFF61003700B40000003700B5FFD3003700BAFEC10037
+00C5FEF8003700C7FF61003700C9FF61003700E4FEAD003700EBFEC1003700FAFEAD0037
+00FBFF88003700FCFEA4003700FDFF88003700FEFEA40038002400000038002D00000038
+003DFFDC003800620000003800AD0000003800AE0000003800C70000003800C900000038
+00E5FFDC00390010FF8800390011FEF80039001DFF5900390024FF7D00390032FFDC0039
+0044FF6100390048FF610039004CFFD300390052FF6100390058FF750039005CFFC90039
+0062FF7D00390067FFDC00390069FF610039006AFF610039006BFF610039006CFF610039
+006DFF610039006EFF6100390070FF6100390071FF6100390072FF6100390073FF610039
+0079FF610039007AFF610039007BFF610039007CFF610039007DFF610039007EFF750039
+007FFF7500390080FF7500390081FF75003900A9FF4E003900AAFF90003900ADFF7D0039
+00AEFF7D003900AFFFDC003900B40000003900B50000003900BAFFC9003900C5FEE60039
+00C7FF7D003900C9FF7D003900D0FFDC003900D1FFDC003900D2FFDC003900EBFFC9003A
+0010FFAD003A0011FF15003A001DFF88003A0024FF90003A0044FF7D003A0048FF88003A
+004CFFD3003A0052FF88003A0055FFA4003A0058FFB7003A005CFFDC003A0062FF90003A
+0069FF7D003A006AFF7D003A006BFF7D003A006CFF7D003A006DFF7D003A006EFF7D003A
+0070FF88003A0071FF88003A0072FF88003A0073FF88003A0079FF88003A007AFF88003A
+007BFF88003A007CFF88003A007DFF88003A007EFFB7003A007FFFB7003A0080FFB7003A
+0081FFB7003A00A9FF90003A00AAFFDC003A00ADFF90003A00AEFF90003A00B4FFDC003A
+00B50000003A00BAFFDC003A00C5FEF8003A00C7FF90003A00C9FF90003A00EBFFDC003B
+0010FF9A003B00240000003B0026FF6B003B0032FF7D003B0037FFDC003B0048FFA4003B
+00620000003B0064FF6B003B0067FF7D003B0070FFA4003B0071FFA4003B0072FFA4003B
+0073FFA4003B00A9FF90003B00AA0000003B00AD0000003B00AE0000003B00AFFF7D003B
+00B4FF61003B00B5FFAD003B00C5FFD3003B00C70000003B00C90000003B00D0FF7D003B
+00D1FF7D003B00D2FF7D003B00FBFF6B003B00FDFF6B003C0010FF0D003C0011FE61003C
+001DFEF0003C0024FF61003C0026FF90003C0032FF90003C0044FEE6003C0048FEF0003C
+004CFFB7003C0052FEF0003C0058FF15003C0062FF61003C0064FF90003C0067FF90003C
+0069FEE6003C006AFEE6003C006BFEE6003C006CFEE6003C006DFEE6003C006EFEE6003C
+0070FEF0003C0071FEF0003C0072FEF0003C0073FEF0003C0079FEF0003C007AFEF0003C
+007BFEF0003C007CFEF0003C007DFEF0003C007EFF15003C007FFF15003C0080FF15003C
+0081FF15003C00A9FF1F003C00AAFF6B003C00ADFF61003C00AEFF61003C00AFFF90003C
+00B4FF90003C00B5FFDC003C00C5FEF8003C00C7FF61003C00C9FF61003C00D0FF90003C
+00D1FF90003C00D2FF90003C00FBFF90003C00FDFF90003D0010FFDC003D00A90000003D
+00AA0000003D00B4FFDC003D00B5FFDC003D00C5FFDC0048005BFFDC00490010FF900049
+0011FF6B0049001DFFB700490057FFDC0049005AFFDC0049005CFFDC004900A9FFB70049
+00AAFFDC004900B40041004900B50000004900BAFFDC004900C5FF15004900EBFFDC004E
+0044FFDC004E0048FFB7004E0052FFB7004E0058FFC1004E005CFFB7004E0069FFDC004E
+006AFFDC004E006BFFDC004E006CFFDC004E006DFFDC004E006EFFDC004E0070FFB7004E
+0071FFB7004E0072FFB7004E0073FFB7004E0079FFB7004E007AFFB7004E007BFFB7004E
+007CFFB7004E007DFFB7004E007EFFC1004E007FFFC1004E0080FFC1004E0081FFC1004E
+00BAFFB7004E00EBFFB70051001000000051001100000051001D0000005100A900000051
+00AA0000005100B4FF6B005100B5FF90005100C5FFA400520010002600520011FFDC0052
+001D00000052005BFFC1005200A90000005200AA0000005200B4FF6B005200B5FFB70052
+00C5FF7D00550010FF7D00550011FF440055001DFFDC00550046FFD300550047FFDC0055
+0048FFD30055004900000055004AFFDC0055004BFFDC00550050FFDC00550051FFDC0055
+0052FFD300550054FFDC00550055FFDC0055005800000055005900000055005A00000055
+005BFFC90055005C00000055005D00000055006FFFD300550070FFD300550071FFD30055
+0072FFD300550073FFD300550078FFDC00550079FFD30055007AFFD30055007BFFD30055
+007CFFD30055007DFFD30055007E00000055007F00000055008000000055008100000055
+00A9FFB7005500AA0000005500B40000005500B50056005500BA0000005500C5FEC90055
+00E60000005500EB0000005500F7FFDC005500FCFFD3005500FEFFD300590010FFC90059
+0011FF610059001DFF90005900A9FFDC005900AAFFDC005900B40000005900B5FFDC0059
+00C5FEF0005A00100000005A0011FF44005A001DFF90005A00A9FFDC005A00AAFFDC005A
+00B40000005A00B50000005A00C5FF29005B0046FFDC005B0048FFC1005B0052FFC1005B
+006FFFDC005B0070FFC1005B0071FFC1005B0072FFC1005B0073FFC1005B0079FFC1005B
+007AFFC1005B007BFFC1005B007CFFC1005B007DFFC1005B00FCFFDC005B00FEFFDC005C
+0010FFDC005C0011FEDC005C001DFF6B005C00A9FFDC005C00AAFFDC005C00B40000005C
+00B50000005C00C5FED300620010FFD300620011FFDC0062001DFFDC0062002400390062
+0026FFDC0062002AFFDC00620032FFDC00620034FFDC00620036000000620037FF610062
+0038000000620039FF7D0062003AFF900062003B00000062003CFF6100620046FFDC0062
+0047FFDC00620048FFDC00620049FFB700620052FFDC00620054FFDC00620057FFDC0062
+0058000000620059FF880062005AFFAD0062005CFF7500620062003900620064FFDC0062
+0067FFDC0062006800000062006FFFDC00620070FFDC00620071FFDC00620072FFDC0062
+0073FFDC00620079FFDC0062007AFFDC0062007BFFDC0062007CFFDC0062007DFFDC0062
+007E00000062007F0000006200800000006200810000006200A9FFB7006200AA00000062
+00AD0039006200AE0039006200AFFFDC006200B4FEF8006200B5FF03006200BAFF750062
+00BBFF61006200C5002F006200C70039006200C90039006200D0FFDC006200D1FFDC0062
+00D2FFDC006200D30000006200D40000006200D50000006200E30000006200EAFF610062
+00EBFF75006200F6FFDC006200F90000006200FBFFDC006200FCFFDC006200FDFFDC0062
+00FEFFDC0064001000000064002400000064003600000064003CFFDC0064006200000064
+00A9FFDC006400AAFFDC006400AD0000006400AE0000006400B40000006400B500260064
+00BBFFDC006400C50000006400C70000006400C90000006400E30000006400EAFFDC0064
+00F9000000670010003900670011FFAD0067001DFFDC00670024FFDC00670039FFDC0067
+003BFF7D0067003CFF9000670062FFDC006700A9FFDC006700AA0000006700ADFFDC0067
+00AEFFDC006700B4FFD3006700B5FFDC006700BBFF90006700C5FF44006700C7FFDC0067
+00C9FFDC006700EAFF900068002400000068002D00000068003DFFDC0068006200000068
+00AD0000006800AE0000006800C70000006800C90000006800E5FFDC0070005BFFDC0071
+005BFFDC0072005BFFDC0073005BFFDC0078001000000078001100000078001D00000078
+00A90000007800AA0000007800B4FF6B007800B5FF90007800C5FFA40079001000260079
+0011FFDC0079001D00000079005BFFC1007900A90000007900AA0000007900B4FF6B0079
+00B5FFB7007900C5FF7D007A00100026007A0011FFDC007A001D0000007A005BFFC1007A
+00A90000007A00AA0000007A00B4FF6B007A00B5FFB7007A00C5FF7D007B00100026007B
+0011FFDC007B001D0000007B005BFFC1007B00A90000007B00AA0000007B00B4FF6B007B
+00B5FFB7007B00C5FF7D007C00100026007C0011FFDC007C001D0000007C005BFFC1007C
+00A90000007C00AA0000007C00B4FF6B007C00B5FFB7007C00C5FF7D007D00100026007D
+0011FFDC007D001D0000007D005BFFC1007D00A90000007D00AA0000007D00B4FF6B007D
+00B5FFB7007D00C5FF7D008900100026008900A90000008900AA0000008900B4FF900089
+00B5FF90008900C5FFAD009000100000009000A90000009000AA0000009000B4FFAD0090
+00B5FFA4009000C5FF9000A90024000000A90025FFDC00A90026FFDC00A90027FFDC00A9
+0029000000A9002AFFDC00A9002B000000A9002DFFDC00A9002E000000A9002F000000A9
+0032000000A90033000000A90034000000A90035000000A90037FF9000A90039FF9000A9
+003AFFDC00A9003B000000A9003CFF6B00A9003D000000A90049000000A90051000000A9
+0052000000A90055000000A90059FFDC00A9005AFFDC00A9005CFFDC00A90062000000A9
+0064FFDC00A90067000000A90078000000A90079000000A9007A000000A9007B000000A9
+007C000000A9007D000000A90089000000A90090009700A900AD000000A900AE000000A9
+00AF000000A900BAFFDC00A900BBFF6B00A900C7000000A900C9000000A900D0000000A9
+00D1000000A900D2000000A900E5000000A900E9000000A900EAFF6B00A900EBFFDC00A9
+00EC000000A900F6FFDC00A900FBFFDC00A900FDFFDC00AA0024FFB700AA0025FFB700AA
+0026FFDC00AA0027FFDC00AA0029000000AA002A000000AA002B000000AA002DFFDC00AA
+002E000000AA002F000000AA0032FFDC00AA0033000000AA0034000000AA0035000000AA
+0037FF4400AA0039FF4E00AA003AFF9000AA003BFF9000AA003CFF1F00AA003D000000AA
+0049000000AA0051000000AA0052000000AA0055000000AA0059FFDC00AA005AFFDC00AA
+005CFFDC00AA0062FFB700AA0064FFDC00AA0067FFDC00AA0078000000AA0079000000AA
+007A000000AA007B000000AA007C000000AA007D000000AA0089000000AA0090000000AA
+00ADFFB700AA00AEFFB700AA00AFFFDC00AA00BAFFDC00AA00BBFF1F00AA00C7FFB700AA
+00C9FFB700AA00D0FFDC00AA00D1FFDC00AA00D2FFDC00AA00E5000000AA00E9000000AA
+00EAFF1F00AA00EBFFDC00AA00EC000000AA00F6000000AA00FBFFDC00AA00FDFFDC00AD
+0010FFD300AD0011FFDC00AD001DFFDC00AD0024003900AD0026FFDC00AD002AFFDC00AD
+0032FFDC00AD0034FFDC00AD0036000000AD0037FF6100AD0038000000AD0039FF7D00AD
+003AFF9000AD003B000000AD003CFF6100AD0046FFDC00AD0047FFDC00AD0048FFDC00AD
+0049FFB700AD0052FFDC00AD0054FFDC00AD0057FFDC00AD0058000000AD0059FF8800AD
+005AFFAD00AD005CFF7500AD0062003900AD0064FFDC00AD0067FFDC00AD0068000000AD
+006FFFDC00AD0070FFDC00AD0071FFDC00AD0072FFDC00AD0073FFDC00AD0079FFDC00AD
+007AFFDC00AD007BFFDC00AD007CFFDC00AD007DFFDC00AD007E000000AD007F000000AD
+0080000000AD0081000000AD00A9FFB700AD00AA000000AD00AD003900AD00AE003900AD
+00AFFFDC00AD00B4FEF800AD00B5FF0300AD00BAFF7500AD00BBFF6100AD00C5002F00AD
+00C7003900AD00C9003900AD00D0FFDC00AD00D1FFDC00AD00D2FFDC00AD00D3000000AD
+00D4000000AD00D5000000AD00E3000000AD00EAFF6100AD00EBFF7500AD00F6FFDC00AD
+00F9000000AD00FBFFDC00AD00FCFFDC00AD00FDFFDC00AD00FEFFDC00AE0010FFD300AE
+0011FFDC00AE001DFFDC00AE0024003900AE0026FFDC00AE002AFFDC00AE0032FFDC00AE
+0034FFDC00AE0036000000AE0037FF6100AE0038000000AE0039FF7D00AE003AFF9000AE
+003B000000AE003CFF6100AE0046FFDC00AE0047FFDC00AE0048FFDC00AE0049FFB700AE
+0052FFDC00AE0054FFDC00AE0057FFDC00AE0058000000AE0059FF8800AE005AFFAD00AE
+005CFF7500AE0062003900AE0064FFDC00AE0067FFDC00AE0068000000AE006FFFDC00AE
+0070FFDC00AE0071FFDC00AE0072FFDC00AE0073FFDC00AE0079FFDC00AE007AFFDC00AE
+007BFFDC00AE007CFFDC00AE007DFFDC00AE007E000000AE007F000000AE0080000000AE
+0081000000AE00A9FFB700AE00AA000000AE00AD003900AE00AE003900AE00AFFFDC00AE
+00B4FEF800AE00B5FF0300AE00BAFF7500AE00BBFF6100AE00C5002F00AE00C7003900AE
+00C9003900AE00D0FFDC00AE00D1FFDC00AE00D2FFDC00AE00D3000000AE00D4000000AE
+00D5000000AE00E3000000AE00EAFF6100AE00EBFF7500AE00F6FFDC00AE00F9000000AE
+00FBFFDC00AE00FCFFDC00AE00FDFFDC00AE00FEFFDC00AF0010003900AF0011FFAD00AF
+001DFFDC00AF0024FFDC00AF0039FFDC00AF003BFF7D00AF003CFF9000AF0062FFDC00AF
+00A9FFDC00AF00AA000000AF00ADFFDC00AF00AEFFDC00AF00B4FFD300AF00B5FFDC00AF
+00BBFF9000AF00C5FF4400AF00C7FFDC00AF00C9FFDC00AF00EAFF9000B40024FEF800B4
+0025FFC100B40026FFB700B40027FFC100B40029FFC100B4002AFFB700B4002BFFC100B4
+002DFFC100B4002EFFC100B4002FFFC100B40032FFB700B40033FFC100B40034FFB700B4
+0035FFC100B40037000000B40039000000B4003A000000B4003BFF8800B4003C000000B4
+003DFFDC00B40049FFB700B40051FF9000B40052FF6B00B40055FF9000B40059FFB700B4
+005AFFB700B4005CFFB700B40062FEF800B40064FFB700B40067FFB700B40078FF9000B4
+0079FF6B00B4007AFF6B00B4007BFF6B00B4007CFF6B00B4007DFF6B00B40089FFC100B4
+0090FE7D00B400ADFEF800B400AEFEF800B400AFFFB700B400BAFFB700B400BB000000B4
+00C7FEF800B400C9FEF800B400D0FFB700B400D1FFB700B400D2FFB700B400E5FFDC00B4
+00E9FFB700B400EA000000B400EBFFB700B400ECFFC100B400F6FFB700B400FBFFB700B4
+00FDFFB700BA0010FFDC00BA0011FEDC00BA001DFF6B00BA00A9FFDC00BA00AAFFDC00BA
+00B4000000BA00B5000000BA00C5FED300BB0010FF0D00BB0011FE6100BB001DFEF000BB
+0024FF6100BB0026FF9000BB0032FF9000BB0044FEE600BB0048FEF000BB004CFFB700BB
+0052FEF000BB0058FF1500BB0062FF6100BB0064FF9000BB0067FF9000BB0069FEE600BB
+006AFEE600BB006BFEE600BB006CFEE600BB006DFEE600BB006EFEE600BB0070FEF000BB
+0071FEF000BB0072FEF000BB0073FEF000BB0079FEF000BB007AFEF000BB007BFEF000BB
+007CFEF000BB007DFEF000BB007EFF1500BB007FFF1500BB0080FF1500BB0081FF1500BB
+00A9FF1F00BB00AAFF6B00BB00ADFF6100BB00AEFF6100BB00AFFF9000BB00B4FF9000BB
+00B5FFDC00BB00C5FEF800BB00C7FF6100BB00C9FF6100BB00D0FF9000BB00D1FF9000BB
+00D2FF9000BB00FBFF9000BB00FDFF9000C50024002600C50025FFB700C50026FF9000C5
+0027FFB700C50029FFB700C5002AFFB700C5002BFFB700C5002D002F00C5002EFFB700C5
+002FFFB700C50032FF9000C50033FFB700C50034FF9000C50035FFB700C50037FEE600C5
+0039FE8800C5003AFF0300C5003BFFB700C5003CFE8800C5003D000000C50049FFDC00C5
+0051FFB700C50052FFB700C50055FFB700C50059FF1500C5005AFF3C00C5005CFF9000C5
+0062002600C50064FF9000C50067FF9000C50078FFB700C50079FFB700C5007AFFB700C5
+007BFFB700C5007CFFB700C5007DFFB700C50089FFB700C50090002600C500AD002600C5
+00AE002600C500AFFF9000C500BAFF9000C500BBFE8800C500C7002600C500C9002600C5
+00D0FF9000C500D1FF9000C500D2FF9000C500E5000000C500E9FFB700C500EAFE8800C5
+00EBFF9000C500ECFFB700C500F6FFB700C500FBFF9000C500FDFF9000C70010FFD300C7
+0011FFDC00C7001DFFDC00C70024003900C70026FFDC00C7002AFFDC00C70032FFDC00C7
+0034FFDC00C70036000000C70037FF6100C70038000000C70039FF7D00C7003AFF9000C7
+003B000000C7003CFF6100C70046FFDC00C70047FFDC00C70048FFDC00C70049FFB700C7
+0052FFDC00C70054FFDC00C70057FFDC00C70058000000C70059FF8800C7005AFFAD00C7
+005CFF7500C70062003900C70064FFDC00C70067FFDC00C70068000000C7006FFFDC00C7
+0070FFDC00C70071FFDC00C70072FFDC00C70073FFDC00C70079FFDC00C7007AFFDC00C7
+007BFFDC00C7007CFFDC00C7007DFFDC00C7007E000000C7007F000000C70080000000C7
+0081000000C700A9FFB700C700AA000000C700AD003900C700AE003900C700AFFFDC00C7
+00B4FEF800C700B5FF0300C700BAFF7500C700BBFF6100C700C5002F00C700C7003900C7
+00C9003900C700D0FFDC00C700D1FFDC00C700D2FFDC00C700D3000000C700D4000000C7
+00D5000000C700E3000000C700EAFF6100C700EBFF7500C700F6FFDC00C700F9000000C7
+00FBFFDC00C700FCFFDC00C700FDFFDC00C700FEFFDC00C90010FFD300C90011FFDC00C9
+001DFFDC00C90024003900C90026FFDC00C9002AFFDC00C90032FFDC00C90034FFDC00C9
+0036000000C90037FF6100C90038000000C90039FF7D00C9003AFF9000C9003B000000C9
+003CFF6100C90046FFDC00C90047FFDC00C90048FFDC00C90049FFB700C90052FFDC00C9
+0054FFDC00C90057FFDC00C90058000000C90059FF8800C9005AFFAD00C9005CFF7500C9
+0062003900C90064FFDC00C90067FFDC00C90068000000C9006FFFDC00C90070FFDC00C9
+0071FFDC00C90072FFDC00C90073FFDC00C90079FFDC00C9007AFFDC00C9007BFFDC00C9
+007CFFDC00C9007DFFDC00C9007E000000C9007F000000C90080000000C90081000000C9
+00A9FFB700C900AA000000C900AD003900C900AE003900C900AFFFDC00C900B4FEF800C9
+00B5FF0300C900BAFF7500C900BBFF6100C900C5002F00C900C7003900C900C9003900C9
+00D0FFDC00C900D1FFDC00C900D2FFDC00C900D3000000C900D4000000C900D5000000C9
+00E3000000C900EAFF6100C900EBFF7500C900F6FFDC00C900F9000000C900FBFFDC00C9
+00FCFFDC00C900FDFFDC00C900FEFFDC00D00010003900D00011FFAD00D0001DFFDC00D0
+0024FFDC00D00039FFDC00D0003BFF7D00D0003CFF9000D00062FFDC00D000A9FFDC00D0
+00AA000000D000ADFFDC00D000AEFFDC00D000B4FFD300D000B5FFDC00D000BBFF9000D0
+00C5FF4400D000C7FFDC00D000C9FFDC00D000EAFF9000D10010003900D10011FFAD00D1
+001DFFDC00D10024FFDC00D10039FFDC00D1003BFF7D00D1003CFF9000D10062FFDC00D1
+00A9FFDC00D100AA000000D100ADFFDC00D100AEFFDC00D100B4FFD300D100B5FFDC00D1
+00BBFF9000D100C5FF4400D100C7FFDC00D100C9FFDC00D100EAFF9000D20010003900D2
+0011FFAD00D2001DFFDC00D20024FFDC00D20039FFDC00D2003BFF7D00D2003CFF9000D2
+0062FFDC00D200A9FFDC00D200AA000000D200ADFFDC00D200AEFFDC00D200B4FFD300D2
+00B5FFDC00D200BBFF9000D200C5FF4400D200C7FFDC00D200C9FFDC00D200EAFF9000D3
+0024000000D3002D000000D3003DFFDC00D30062000000D300AD000000D300AE000000D3
+00C7000000D300C9000000D300E5FFDC00D40024000000D4002D000000D4003DFFDC00D4
+0062000000D400AD000000D400AE000000D400C7000000D400C9000000D400E5FFDC00D5
+0024000000D5002D000000D5003DFFDC00D50062000000D500AD000000D500AE000000D5
+00C7000000D500C9000000D500E5FFDC00E30024002600E30026000000E3002A000000E3
+0032000000E30034000000E30036000000E30062002600E30064000000E30067000000E3
+00AD002600E300AE002600E300AF000000E300C7002600E300C9002600E300D0000000E3
+00D1000000E300D2000000E300E3000000E300F6000000E300F9000000E300FB000000E3
+00FD000000E50010FFDC00E500A9000000E500AA000000E500B4FFDC00E500B5FFDC00E5
+00C5FFDC00E90010000000E900A9000000E900AA000000E900B4FFA400E900B5FF9000E9
+00C5FFB700EA0010FF0D00EA0011FE6100EA001DFEF000EA0024FF6100EA0026FF9000EA
+0032FF9000EA0044FEE600EA0048FEF000EA004CFFB700EA0052FEF000EA0058FF1500EA
+0062FF6100EA0064FF9000EA0067FF9000EA0069FEE600EA006AFEE600EA006BFEE600EA
+006CFEE600EA006DFEE600EA006EFEE600EA0070FEF000EA0071FEF000EA0072FEF000EA
+0073FEF000EA0079FEF000EA007AFEF000EA007BFEF000EA007CFEF000EA007DFEF000EA
+007EFF1500EA007FFF1500EA0080FF1500EA0081FF1500EA00A9FF1F00EA00AAFF6B00EA
+00ADFF6100EA00AEFF6100EA00AFFF9000EA00B4FF9000EA00B5FFDC00EA00C5FEF800EA
+00C7FF6100EA00C9FF6100EA00D0FF9000EA00D1FF9000EA00D2FF9000EA00FBFF9000EA
+00FDFF9000EB0010FFDC00EB0011FEDC00EB001DFF6B00EB00A9FFDC00EB00AAFFDC00EB
+00B4000000EB00B5000000EB00C5FED300EC0010000000EC0011FF6B00EC001DFFB700EC
+00A9000000EC00AA000000EC00B4FFDC00EC00B5000000EC00C5FF4400F60010000000F6
+0024000000F60037FFB700F6003A000000F6003CFF9A00F60062000000F600A9FFDC00F6
+00AAFFDC00F600AD000000F600AE000000F600B4FFD300F600B5FFD300F600BBFF9A00F6
+00C5FFC900F600C7000000F600C9000000F600EAFF9A00F90024002600F90026000000F9
+002A000000F90032000000F90034000000F90036000000F90062002600F90064000000F9
+0067000000F900AD002600F900AE002600F900AF000000F900C7002600F900C9002600F9
+00D0000000F900D1000000F900D2000000F900E3000000F900F6000000F900F9000000F9
+00FB000000F900FD000000FB0010000000FB0024000000FB0036000000FB003CFFDC00FB
+0062000000FB00A9FFDC00FB00AAFFDC00FB00AD000000FB00AE000000FB00B4000000FB
+00B5002600FB00BBFFDC00FB00C5000000FB00C7000000FB00C9000000FB00E3000000FB
+00EAFFDC00FB00F9000000FD0010000000FD0024000000FD0036000000FD003CFFDC00FD
+0062000000FD00A9FFDC00FD00AAFFDC00FD00AD000000FD00AE000000FD00B4000000FD
+00B5002600FD00BBFFDC00FD00C5000000FD00C7000000FD00C9000000FD00E3000000FD
+00EAFFDC00FD00F90000000000010000010C004D00070042000400020010004000070000
+041505680003000100010000076DFE1D00000ABCFE89FE890A4C00010000000000000000
+000000000000010C0001040E019000050004054704CC0000FE42054704CC00000253008F
+02660802020B0603030804020204800000AF1000204A0000000000000000426974730040
+0020FB020614FE14019A076D01E3000000010000000000000001000042001DB1028B0460
+0000236305D500005665726153616E730000000000000000FFFFFFFF36FFFFFE36323852
+30300000400000000000001400000110090C050003030304080609080204040508030303
+03060606060606060606060303080808050A060707070606070703030605080707060706
+070507060706050504030408050506060606060306060303050309060606060405040605
+070505060503050806060706070707060606060606060606060603030303060606060606
+060606060505060605050606090909050508090708080808060605060705050404070906
+05030806060806060609060606070A090509050503030804050502060404060605030305
+0C0606060606030303030707070707070305050505050505050505050307050506030706
+050506060808040404090909070603070507060706060303060505050505050405050000
+0A0D06000303040508060A09030404050803040303060606060606060606060303080808
+050B07070808070608080303070609080807080707050807090607060403040805050606
+050606040606020205020A06060606040504060608060605060306080707080708080806
+06060606060506060606020202020606060606060606060605050606050606060A0A0A05
+05080A0808080808060705070806050505080A060504080606080706060A060707080B0A
+050A0505030308050607020604040606050303050D070707070703030303080808080808
+02050505050505050505050602070506050308060706070608080404040A0A0A08060307
+05080508050604030605050505050504050500000B0F07000303030509070A0A03040406
+0904040404070707070707070707070404090909060C0708080807060908030307060908
+0907090708070807090707090404040906060707060707040707030306030B0707070705
+070407060906060507040709070708070809080707070707070607070707030303030707
+070707070707070706060707060607070B0B0B0606090B09090909090707060708060605
+05080B070603090707090707070B070707090C0B060B0606040409050607020704040707
+060404060F07070707070303030309090908080803060606060606060606060603080709
+050408070706070709090404040B0B0B0907030807080608060704040706060606060604
+060600000C100700040405050A080B0A030505060A040404040808080808080808080804
+040A0A0A060D0808080908070909030307060A0909080908080709080B0907090504050A
+06060808070808040808030307030B080808080507050806090606050804080A08080808
+090909080808080808070808080803030303080808080808080808080606080806070808
+0C0C0C06060A0C090A0A0A0A080806080907060606090C0806050A08080A0807070C0808
+08090D0D060C060604040A06060702080505070706040406100808080808030303030909
+090909090306060606060606060606060308070905040908070608080A0A0505050C0C0C
+0908030807080708070804040806060606060605060600000D110800040405050B080C0B
+030505070B040504040808080808080808080804040B0B0B070D0909090A08070A0A0303
+08070B0A0A080A0809070A090B0A070A0504050B07070808070808040808030307030D08
+0808080507050807090707070804080B090909080A0A0A08080808080807080808080303
+03030808080808080808080807070808070808080D0D0D07070B0D0A0B0B0B0B08080709
+0A080706060A0D0807050B08080B0908080D0809090A0E0D070D070704040B0607070208
+0505080807040407110908090808030303030A0A0A0A0A0A030707070707070707070707
+0309070A07040A08070708080B0B0505050D0D0D0A080309070907090708050408070707
+07070705070700000E130800040405050C090D0C030505070C0405040509090909090909
+09090905050C0C0C070E090A0A0B09080B0A030309070C0A0B090B0A09090A090D0B090A
+0505050C07070809080909040909030308030D0909090905080509070B0707080905090C
+09090A090A0B0A0808080808080809090909030303030909090909090909090907070909
+070809090E0E0E07070C0E0B0C0C0C0C090907090B080707070B0E0907050C09090C0909
+090E0909090B0F0F070E070704040C070709020906060808070404071309090909090303
+03030B0B0B0A0A0A0307070707070707070707070309080A08050B09090709090C0C0606
+060E0E0E0B090309080A080A080905040907070707070706070700000F14090005050606
+0D0A0E0B030606080D050505050A0A0A0A0A0A0A0A0A0A05050D0D0D080F0A0A0A0B0909
+0C0B03030A080D0B0C090C0A0A090B0A0F0A090B0605060D080809090809090509090303
+08030F0909090906080609080D0A08080A050A0D0A0A0A090B0C0B090909090909080909
+0909030303030909090909090909090908080A0A08090A090F0F0F08080D0F0C0D0D0D0D
+0A09080A0B090807070B0F0908060D0A0A0D0A09090F0A0A0A0C100F080F080805050D07
+0809030A0606090908050508140A090A0909030303030C0C0C0B0B0B0308080808080808
+08080808030A080B08050C09090809090D0D0606060F0F0F0C09030A080A080A08090505
+0A080808080808060808000010150A00050506060D0A0F0C030606080D050605050A0A0A
+0A0A0A0A0A0A0A05050D0D0D09100B0B0B0C0A090C0C05050A090D0C0D0A0D0B0A090C0B
+110B090C0605060D0808090A090A09060A0A030309030F0A0A0A0A0709060A090D0A0909
+0A050A0D0B0B0B0A0C0D0C0909090909090909090909030303030A0A0A0A0A0A0A0A0A0A
+08080A0A08090A0A10101008080D100D0D0D0D0D0A0A080B0C090808080C100A09060D0A
+0A0D0B0A0A100A0B0B0D110F0810080805050D080909030A06060A0A08050508150B0A0B
+0A0A050505050D0D0D0C0C0C030808080808080808080809040A090C09050D0A09090A0A
+0D0D0606061010100C0A050A090B090B090A06050A080808080808060808000011170A00
+050507080E0B100D050707090E050605060B0B0B0B0B0B0B0B0B0B06060E0E0E09110B0C
+0C0D0B0A0D0D06060C090F0D0D0A0D0C0B0A0D0B120D0A0C0706070E09090A0A080A0A06
+0A0B05050A05110B0A0A0A0708070B0A0F0A0A080B060B0E0B0B0C0B0D0D0D0A0A0A0A0A
+0A080A0A0A0A050505050B0A0A0A0A0A0B0B0B0B09090B0B090A0B0B11111109090E100D
+0E0E0E0E0B0B090B0D0A0908080D100A09070E0B0B0E0B0A0A110B0B0B0D121109110909
+05050E080A0A030B07070A0A09050509170B0B0B0B0B060606060D0D0D0D0D0D05090909
+090909090909090A050B080C08060D0A0A0A0A0A0E0E0707071010100D0A060B080C080C
+080A06050B090909090909070909000012180B00060607080F0B110D040707090F060706
+060B0B0B0B0B0B0B0B0B0B06060F0F0F0A120C0C0D0E0B0A0E0E06060C0A100E0E0B0E0D
+0B0C0E0C130D0C0D0706070F09090A0B090B0B060B0B05050A05110B0B0B0B0808070B0B
+100B0B090B060B0F0C0C0D0B0E0E0E0A0A0A0A0A0A090B0B0B0B050505050B0B0B0B0B0B
+0B0B0B0B09090B0B090B0B0B12121209090F110E0F0F0F0F0B0B090C0E0B0908080E110B
+0A070F0B0B0F0C0B0B120B0C0C0E13130912090906060F090B0C030B07070B0B09060609
+180C0B0C0B0B060606060E0E0E0E0E0E05090909090909090909090A050B080D09060E0B
+0C0B0B0B0F0F0707071111110E0B060B080D090D090B07060B0909090909090709090000
+131A0B0006060808100C120E0407070A10060706060C0C0C0C0C0C0C0C0C0C0606101010
+0A130D0D0D0F0C0B0F0E06060C0B100E0F0C0F0D0C0C0E0D140E0C0D070607100A0A0B0B
+090B0B060B0C05050B05110C0B0B0B0809080C0B110B0B0B0C060C100D0D0D0C0E0F0E0B
+0B0B0B0B0B090B0B0B0B050505050C0B0B0B0B0B0C0C0C0C0A0A0C0C0A0B0C0C1313130A
+0A10120F101010100C0C0A0D0E0B0A09090F120B0A08100C0C100D0C0C130C0D0D0F1413
+0A130A0A060610090B0C030C08080B0B0A06060A1A0D0C0D0C0C060606060F0F0F0E0E0E
+050A0A0A0A0A0A0A0A0A0A0B050C090D0B060F0B0C0B0C0B10100808081212120F0B060C
+090D090D090B07060C0A0A0A0A0A0A080A0A0000141B0C000606080A110D130F0608080A
+11060706070D0D0D0D0D0D0D0D0D0D07071111110B140E0E0E0F0D0C100F06060D0B110F
+100C100E0D0C0F0E140E0C0E080708110A0A0C0D0B0D0C070D0D06060C06140D0C0D0D08
+0A080D0B110B0B0B0D070D110E0E0E0D0F100F0C0C0C0C0C0C0B0C0C0C0C060606060D0C
+0C0C0C0C0D0D0D0D0A0A0D0D0A0C0D0D1414140A0A111410111111110D0D0A0D0F0C0A09
+090F130C0B08110D0D110D0C0C140D0E0E1015140A140A0A0606110A0B0C030D08080D0D
+0A06060A1B0E0D0E0D0D060606061010100F0F0F060A0A0A0A0A0A0A0A0A0A0B060D0A0E
+0B070F0C0C0B0C0D1111080808131313100D060D0A0E0B0E0B0D07060D0A0A0A0A0A0A08
+0A0A0000151C0D000707080A120D14100608080B12070807070D0D0D0D0D0D0D0D0D0D07
+071212120B150E0E0F100D0C101006060E0C1210110D110F0D0D0F0E150E0D0E08070812
+0B0B0D0D0C0D0D070D0D06060C06140E0D0D0D090B080E0B110D0D0B0D070D120E0E0F0D
+10110F0D0D0D0D0D0D0C0D0D0D0D060606060E0D0D0D0D0D0E0E0E0E0B0B0D0D0B0C0D0D
+1515150B0B121411121212120D0E0B0E100C0B0A0A10140D0B08120D0D120E0D0D150D0E
+0E1116160B150B0B0707120A0D0D040D08080D0D0B07070B1C0E0D0E0D0D060606061111
+110F0F0F060B0B0B0B0B0B0B0B0B0B0C060D0B0E0B07100D0D0D0D0D1212080808141414
+100D060D0B0F0C0F0C0D08070D0B0B0B0B0B0B080B0B0000161E0D000707090A120E1511
+0609090B12070807070E0E0E0E0E0E0E0E0E0E07071212120C160F0F0F110E0D11110606
+0E0C1310110D110F0E0D100F160F0D0F090709120B0B0D0E0C0E0D080E0E06060D06160E
+0D0E0E090B090E0E120E0E0C0E070E120F0F0F0E1011100D0D0D0D0D0D0C0D0D0D0D0606
+06060E0D0D0D0D0D0E0E0E0E0B0B0E0E0B0D0E0E1616160B0B121511121212120E0E0B0F
+110D0B0A0A11150D0C09120E0E120F0D0D160E0F0F1118160B160B0B0707120B0E0D040E
+09090D0D0B07070B1E0F0E0F0E0E06060606111111101010060B0B0B0B0B0B0B0B0B0B0C
+060E0B0F0C07110D0D0E0D0E1212090909151515110E060E0B0F0C0F0C0E08070E0B0B0B
+0B0B0B090B0B0000171F0E000707090B130F16120609090C13070807080F0F0F0F0F0F0F
+0F0F0F08081313130C17101010120F0D121107070F0D1411120E12100F0E111017100E10
+090809130C0C0E0F0D0F0E080F0F06060D06160F0E0E0E090C090F0E130E0E0C0F080F13
+1010100F1112110E0E0E0E0E0E0D0E0E0E0E060606060F0E0E0E0E0E0F0F0F0F0C0C0F0F
+0C0E0F0E1717170C0C131612131313130F0F0C10110E0C0B0B12150E0C09130F0F130F0E
+0E170F10101219180C170C0C0707130B0E0E040F09090F0F0C07070C1F100F100F0F0707
+0707121212111111060C0C0C0C0C0C0C0C0C0C0D060F0C100C08120E0E0E0E0E13130909
+09161616120F070F0C100D100D0F08070F0C0C0C0C0C0C090C0C000018200E0008080A0B
+140F17130709090C14080908080F0F0F0F0F0F0F0F0F0F08081414140D18101011120F0E
+13120707100D1512130E13110F0F121018100F10090809140C0C0E0F0D0F0E080F0F0707
+0E06180F0E0F0F0A0C090F0F140F0F0D0F080F141010110F1213120E0E0E0E0E0E0D0E0E
+0E0E070707070F0E0E0E0E0E0F0F0F0F0C0C0F0F0C0E0F0F1818180C0C14171314141414
+0F0F0C10120E0D0B0B12170E0D0A140F0F14100F0F180F1010131A180C180C0C0808140C
+0F0F040F0A0A0F0F0C08080C20100F100F0F07070707131313121212070C0C0C0C0C0C0C
+0C0C0C0D060F0C100D08130E0F0F0F0F14140A0A0A171717130F070F0C110D110D0F0908
+0F0C0C0C0C0C0C0A0C0C000019220F0008080A0C15101814070A0A0D1508090808101010
+1010101010101008081515150D1911111113100E13130707100E1613140F1411100F1211
+19110F110A080A150D0D0F100E100F09101007070E0718100F10100A0D0A100F140F0F0D
+10081015111111101314120F0F0F0F0F0F0E0F0F0F0F07070707100F0F0F0F0F10101010
+0D0D10100D0F10101919190D0D1518141515151510100D11130F0D0C0C13190F0D0A1510
+1015110F0F19101111141B1A0D190D0D0808150C0F0F04100A0A10100D08080D22111011
+101007070707141414121212070D0D0D0D0D0D0D0D0D0D0E07100D110D08130F0F0F0F10
+15150A0A0A181818131007100D110E110E100908100D0D0D0D0D0D0A0D0D00001A231000
+08080A0C16111914070A0A0D16080908091111111111111111111109091616160E1A1212
+1214100F14140808110E161314101412111013121A1210120A090A160D0D10110E111009
+111007070F0719101011110B0E0A100F150F0F0E11091116121212101314131010101010
+100E1010101007070707101010101010101010100D0D11110D0F11101A1A1A0D0D161914
+1616161611110D12140F0E0C0C141A100E0A161111161110101A111212141C1B0D1A0D0D
+0808160D0F1004110A0A10100D08080D23121012101008080808141414131313070D0D0D
+0D0D0D0D0D0D0D0F07110E120E091410100F101116160A0A0A191919141108110E120E12
+0E110908110D0D0D0D0D0D0A0D0D00001B24100009090B0C17111A15070B0B0E17090A09
+091111111111111111111109091717170E1B12131315111015140808120F171415101513
+111114121B1311130B090B170E0E11110F11110A1111080810081A111111110B0E0B1110
+1610100E11091117121213111415141111111111110F1111111108080808111111111111
+111111110E0E11110E1011111B1B1B0E0E171A151617171711110E1214100E0D0D151B11
+0E0B171111171211111B111212151D1C0E1B0E0E0909170D101105110B0B11110E09090E>
+<24121112111108080808151515141414080E0E0E0E0E0E0E0E0E0E0F08110E130E091511
+1110101117170B0B0B1A1A1A151108110E130F130F110A09110E0E0E0E0E0E0B0E0E0000
+1C26110009090B0D17121B16080B0B0E17090A0909121212121212121212120909171717
+0F1C131314161210161508081210181516111613121115131C1311130B090B170E0E1112
+0F12110A1212080810081B121112120C0F0B12111711110F120912171313141215161511
+11111111110F1111111108080808121111111111121212120E0E12120E1112121C1C1C0E
+0E171B161717171712120E1315100F0D0D151C110F0B171212171311111C121313161E1D
+0E1C0F0F0909170E111105120B0B12120E09090F26131213121208080808161616151515
+080E0E0E0E0E0E0E0E0E0E1008120F130F0916111111111217170B0B0B1B1B1B16120812
+0F140F140F120A09120E0E0E0E0E0E0B0E0E00000000000200080002FFFF000300010000
+000200000C500AEC5F0F3CF5001F080000000000BAB9F0B800000000BAC26791FE89FE1D
+0A4C076D00000008000100000000000000>
+] def
+/CharStrings 268 dict dup begin
+/.notdef 0 def /.null 1 def /nonmarkingreturn 2 def /space 3 def /exclam 4 def
+/quotedbl 5 def /numbersign 6 def /dollar 7 def /percent 8 def
+/ampersand 9 def /quotesingle 10 def /parenleft 11 def /parenright 12 def
+/asterisk 13 def /plus 14 def /comma 15 def /hyphen 16 def
+/period 17 def /slash 18 def /zero 19 def /one 20 def
+/two 21 def /three 22 def /four 23 def /five 24 def
+/six 25 def /seven 26 def /eight 27 def /nine 28 def
+/colon 29 def /semicolon 30 def /less 31 def /equal 32 def
+/greater 33 def /question 34 def /at 35 def /A 36 def
+/B 37 def /C 38 def /D 39 def /E 40 def
+/F 41 def /G 42 def /H 43 def /I 44 def
+/J 45 def /K 46 def /L 47 def /M 48 def
+/N 49 def /O 50 def /P 51 def /Q 52 def
+/R 53 def /S 54 def /T 55 def /U 56 def
+/V 57 def /W 58 def /X 59 def /Y 60 def
+/Z 61 def /bracketleft 62 def /backslash 63 def /bracketright 64 def
+/asciicircum 65 def /underscore 66 def /grave 67 def /a 68 def
+/b 69 def /c 70 def /d 71 def /e 72 def
+/f 73 def /g 74 def /h 75 def /i 76 def
+/j 77 def /k 78 def /l 79 def /m 80 def
+/n 81 def /o 82 def /p 83 def /q 84 def
+/r 85 def /s 86 def /t 87 def /u 88 def
+/v 89 def /w 90 def /x 91 def /y 92 def
+/z 93 def /braceleft 94 def /bar 95 def /braceright 96 def
+/asciitilde 97 def /Adieresis 98 def /Aring 99 def /Ccedilla 100 def
+/Eacute 101 def /Ntilde 102 def /Odieresis 103 def /Udieresis 104 def
+/aacute 105 def /agrave 106 def /acircumflex 107 def /adieresis 108 def
+/atilde 109 def /aring 110 def /ccedilla 111 def /eacute 112 def
+/egrave 113 def /ecircumflex 114 def /edieresis 115 def /iacute 116 def
+/igrave 117 def /icircumflex 118 def /idieresis 119 def /ntilde 120 def
+/oacute 121 def /ograve 122 def /ocircumflex 123 def /odieresis 124 def
+/otilde 125 def /uacute 126 def /ugrave 127 def /ucircumflex 128 def
+/udieresis 129 def /dagger 130 def /degree 131 def /cent 132 def
+/sterling 133 def /section 134 def /bullet 135 def /paragraph 136 def
+/germandbls 137 def /registered 138 def /copyright 139 def /trademark 140 def
+/acute 141 def /dieresis 142 def /notequal 143 def /AE 144 def
+/Oslash 145 def /infinity 146 def /plusminus 147 def /lessequal 148 def
+/greaterequal 149 def /yen 150 def /mu 151 def /partialdiff 152 def
+/summation 153 def /product 154 def /pi 155 def /integral 156 def
+/ordfeminine 157 def /ordmasculine 158 def /Omega 159 def /ae 160 def
+/oslash 161 def /questiondown 162 def /exclamdown 163 def /logicalnot 164 def
+/radical 165 def /florin 166 def /approxequal 167 def /Delta 168 def
+/guillemotleft 169 def /guillemotright 170 def /ellipsis 171 def /nonbreakingspace 172 def
+/Agrave 173 def /Atilde 174 def /Otilde 175 def /OE 176 def
+/oe 177 def /endash 178 def /emdash 179 def /quotedblleft 180 def
+/quotedblright 181 def /quoteleft 182 def /quoteright 183 def /divide 184 def
+/lozenge 185 def /ydieresis 186 def /Ydieresis 187 def /fraction 188 def
+/currency 189 def /guilsinglleft 190 def /guilsinglright 191 def /fi 192 def
+/fl 193 def /daggerdbl 194 def /periodcentered 195 def /quotesinglbase 196 def
+/quotedblbase 197 def /perthousand 198 def /Acircumflex 199 def /Ecircumflex 200 def
+/Aacute 201 def /Edieresis 202 def /Egrave 203 def /Iacute 204 def
+/Icircumflex 205 def /Idieresis 206 def /Igrave 207 def /Oacute 208 def
+/Ocircumflex 209 def /Ograve 210 def /Uacute 211 def /Ucircumflex 212 def
+/Ugrave 213 def /dotlessi 214 def /circumflex 215 def /tilde 216 def
+/macron 217 def /breve 218 def /dotaccent 219 def /ring 220 def
+/cedilla 221 def /hungarumlaut 222 def /ogonek 223 def /caron 224 def
+/Lslash 225 def /lslash 226 def /Scaron 227 def /scaron 228 def
+/Zcaron 229 def /zcaron 230 def /brokenbar 231 def /Eth 232 def
+/eth 233 def /Yacute 234 def /yacute 235 def /Thorn 236 def
+/thorn 237 def /minus 238 def /multiply 239 def /onesuperior 240 def
+/twosuperior 241 def /threesuperior 242 def /onequarter 243 def /onehalf 244 def
+/threequarters 245 def /Gbreve 246 def /gbreve 247 def /Idotaccent 248 def
+/Scedilla 249 def /scedilla 250 def /Cacute 251 def /cacute 252 def
+/Ccaron 253 def /ccaron 254 def /dcroat 255 def /sfthyphen 256 def
+/periodcentered 257 def /Euro 258 def /c6459 259 def /c6460 260 def
+/c6461 261 def /c6462 262 def /c6463 263 def /c6466 264 def
+/c6467 265 def /c6468 266 def /c6469 267 def 
+end readonly def
+FontName currentdict end definefont pop
+%%EndFont
+%%EndProlog
+mpldict begin
+18 180 translate
+576 432 0 0 clipbox
+1.000 setgray
+1.000 setlinewidth
+0 setlinejoin
+2 setlinecap
+[] 0 setdash
+0 0 m
+0 432 l
+576 432 l
+576 0 l
+closepath
+gsave
+fill
+grestore
+stroke
+0.000 setgray
+72 43.2 m
+72 388.8 l
+518.4 388.8 l
+518.4 43.2 l
+closepath
+gsave
+1.000 setgray
+fill
+grestore
+stroke
+0.000 0.000 1.000 setrgbcolor
+gsave
+446.400 345.600 72.000 43.200 clipbox
+518.400 319.680 m
+518.400 319.680 l
+518.400 319.680 l
+518.400 319.680 l
+518.400 319.680 l
+518.399 319.680 l
+518.399 319.680 l
+518.399 319.680 l
+518.400 319.680 l
+518.400 319.680 l
+518.400 319.680 l
+518.400 319.680 l
+518.400 319.680 l
+518.399 319.680 l
+518.400 319.680 l
+518.399 319.680 l
+495.606 316.888 l
+462.323 312.708 l
+433.708 308.983 l
+409.252 305.662 l
+388.482 302.703 l
+370.957 300.066 l
+356.268 297.715 l
+344.035 295.620 l
+333.911 293.753 l
+325.581 292.089 l
+318.765 290.606 l
+313.213 289.284 l
+308.710 288.105 l
+305.071 287.055 l
+293.311 283.282 l
+273.304 276.743 l
+255.866 270.916 l
+240.735 265.722 l
+227.671 261.093 l
+216.455 256.967 l
+206.882 253.290 l
+198.764 250.013 l
+191.925 247.092 l
+186.201 244.489 l
+181.441 242.169 l
+177.507 240.101 l
+174.275 238.258 l
+171.632 236.615 l
+169.482 235.152 l
+167.740 233.847 l
+166.333 232.684 l
+165.201 231.648 l
+164.291 230.724 l
+163.562 229.901 l
+159.821 225.115 l
+150.271 212.849 l
+141.759 201.916 l
+134.173 192.173 l
+127.411 183.489 l
+121.385 175.749 l
+116.015 168.852 l
+111.228 162.704 l
+106.962 157.225 l
+103.160 152.341 l
+99.771 147.989 l
+96.751 144.110 l
+94.060 140.653 l
+91.661 137.572 l
+89.523 134.826 l
+87.617 132.378 l
+85.919 130.197 l
+84.405 128.253 l
+83.056 126.520 l
+81.854 124.976 l
+80.782 123.600 l
+79.827 122.373 l
+78.976 121.280 l
+78.217 120.305 l
+77.541 119.437 l
+76.939 118.663 l
+76.402 117.973 l
+75.923 117.359 l
+75.496 116.810 l
+75.116 116.322 l
+74.777 115.887 l
+74.475 115.499 l
+74.206 115.153 l
+73.966 114.845 l
+73.752 114.571 l
+73.562 114.326 l
+73.392 114.108 l
+73.241 113.913 l
+73.106 113.740 l
+72.985 113.586 l
+72.878 113.448 l
+72.783 113.325 l
+72.698 113.216 l
+72.622 113.119 l
+72.554 113.032 l
+72.494 112.954 l
+72.440 112.885 l
+72.392 112.824 l
+72.350 112.769 l
+72.312 112.720 l
+stroke
+grestore
+0.000 setgray
+/BitstreamVeraSans-Roman findfont
+14.000 scalefont
+setfont
+173.2 395.712 m
+0 3 rmoveto
+(Risk-return trade-off curve \(fig 4.12\)) show
+/BitstreamVeraSans-Roman findfont
+12.000 scalefont
+setfont
+59 30.2 m
+(0.00) show
+0.500 setlinewidth
+0 setlinecap
+183.600 43.200 m 183.600 47.200 l
+stroke
+183.600 384.800 m 183.600 388.800 l
+stroke
+170.6 30.2 m
+(0.05) show
+295.200 43.200 m 295.200 47.200 l
+stroke
+295.200 384.800 m 295.200 388.800 l
+stroke
+282.2 30.2 m
+(0.10) show
+406.800 43.200 m 406.800 47.200 l
+stroke
+406.800 384.800 m 406.800 388.800 l
+stroke
+393.8 30.2 m
+(0.15) show
+505.4 30.2 m
+(0.20) show
+236.7 15.2 m
+(standard deviation) show
+42 38.7 m
+(0.00) show
+72.000 158.400 m 76.000 158.400 l
+stroke
+514.400 158.400 m 518.400 158.400 l
+stroke
+42 153.9 m
+(0.05) show
+72.000 273.600 m 76.000 273.600 l
+stroke
+514.400 273.600 m 518.400 273.600 l
+stroke
+42 269.1 m
+(0.10) show
+42 384.3 m
+(0.15) show
+37 166 m
+gsave
+90 rotate
+0 3 rmoveto
+(expected return) show
+grestore
+
+end
+showpage
diff --git a/doc/figures/portfolio2.eps b/doc/figures/portfolio2.eps
new file mode 100644
index 0000000..4aca7ec
--- /dev/null
+++ b/doc/figures/portfolio2.eps
@@ -0,0 +1,2805 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Title: portfolio2.eps
+%%Creator: matplotlib version 0.87.2, http://matplotlib.sourceforge.net/
+%%CreationDate: Wed Sep 13 10:10:08 2006
+%%Orientation: portrait
+%%BoundingBox: 18 180 594 612
+%%EndComments
+%%BeginProlog
+/mpldict 7 dict def
+mpldict begin
+/m { moveto } bind def
+/l { lineto } bind def
+/r { rlineto } bind def
+/box {
+m
+1 index 0 r
+0 exch r
+neg 0 r
+closepath
+} bind def
+/clipbox {
+box
+clip
+newpath
+} bind def
+/ellipse {
+newpath
+matrix currentmatrix 7 1 roll
+translate
+scale
+0 0 1 5 3 roll arc
+setmatrix
+closepath
+} bind def
+%%BeginFont: BitstreamVeraSans-Roman
+%!PS-TrueType-1.0-2.0
+8 dict begin
+/FontName /BitstreamVeraSans-Roman def
+/FontMatrix [1 0 0 1 0 0] def
+/FontType 42 def
+/Encoding StandardEncoding def
+/FontBBox [-375 -483 2636 1901] def
+/PaintType 0 def
+/FontInfo 7 dict dup begin
+/Notice (Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.) def
+/FamilyName (Bitstream Vera Sans) def
+/FullName (Bitstream Vera Sans) def
+/version (Release 1.10) def
+/isFixedPitch false def
+/UnderlinePosition -213 def
+/UnderlineThickness 143 def
+end readonly def
+/sfnts [
+<0001000000110100000400104F532F32B45FF4630000EB700000005650434C54D18A5E97
+0000EBC800000036636D6170A4C3E8A00000B16C0000035863767420FFD31D3900001EFC
+000001FC6670676DE7B4F1C4000026600000008B6761737000070007000101480000000C
+676C79660C7441CF000026EC00008A7E68646D7834F0210E0000EC000000154868656164
+DD84A2D00001015400000036686865611045086F0000EB4C00000024686D747809C68EB2
+0000B4C4000004306B65726EDC52D5990000BDA000002D8A6C6F6361F3CBD23D0000BB84
+0000021A6D6178700547063A0000EB2C000000206E616D65D9BCC8B50000011C00001DDF
+706F7374B45A2FBB0000B8F40000028E707265703B07F100000020F80000056800000016
+010E0001000000000000003A000000010000000000010013003A00010000000000020005
+005F00010000000000030013003A00010000000000040013003A0001000000000005000C
+006400010000000000060017004D0001000000000007003000AD0001000000000008000E
+086C000100000000000B00180983000100000000000D0913007000030001040900000074
+099B000300010409000100260A0F0003000104090002000A0A5900030001040900030026
+0A0F000300010409000400260A0F000300010409000500180A630003000104090006002E
+0A35000300010409000700600AF50003000104090008001C1A73000300010409000B0030
+1CA1000300010409000D12260A7B436F7079726967687420286329203230303320627920
+42697473747265616D2C20496E632E20416C6C205269676874732052657365727665642E
+42697473747265616D20566572612053616E7342697473747265616D5665726153616E73
+2D526F6D616E52656C6561736520312E3130436F70797269676874202863292032303033
+2062792042697473747265616D2C20496E632E0D0A416C6C205269676874732052657365
+727665642E0D0A42697473747265616D205665726120697320612074726164656D61726B
+206F662042697473747265616D2C20496E632E0D0A0D0A5065726D697373696F6E206973
+20686572656279206772616E7465642C2066726565206F66206368617267652C20746F20
+616E7920706572736F6E206F627461696E696E67206120636F7079206F66207468652066
+6F6E7473206163636F6D70616E79696E672074686973206C6963656E7365202822466F6E
+7473222920616E64206173736F63696174656420646F63756D656E746174696F6E206669
+6C657320287468652022466F6E7420536F66747761726522292C20746F20726570726F64
+75636520616E6420646973747269627574652074686520466F6E7420536F667477617265
+2C20696E636C7564696E6720776974686F7574206C696D69746174696F6E207468652072
+696768747320746F207573652C20636F70792C206D657267652C207075626C6973682C20
+646973747269627574652C20616E642F6F722073656C6C20636F70696573206F66207468
+6520466F6E7420536F6674776172652C20616E6420746F207065726D697420706572736F
+6E7320746F2077686F6D2074686520466F6E7420536F667477617265206973206675726E
+697368656420746F20646F20736F2C207375626A65637420746F2074686520666F6C6C6F
+77696E6720636F6E646974696F6E733A0D0A0D0A5468652061626F766520636F70797269
+67687420616E642074726164656D61726B206E6F746963657320616E6420746869732070
+65726D697373696F6E206E6F74696365207368616C6C20626520696E636C756465642069
+6E20616C6C20636F70696573206F66206F6E65206F72206D6F7265206F66207468652046
+6F6E7420536F667477617265207479706566616365732E0D0A0D0A54686520466F6E7420
+536F667477617265206D6179206265206D6F6469666965642C20616C74657265642C206F
+7220616464656420746F2C20616E6420696E20706172746963756C617220746865206465
+7369676E73206F6620676C79706873206F72206368617261637465727320696E20746865
+20466F6E7473206D6179206265206D6F64696669656420616E64206164646974696F6E61
+6C20676C79706873206F722063686172616374657273206D617920626520616464656420
+746F2074686520466F6E74732C206F6E6C792069662074686520666F6E74732061726520
+72656E616D656420746F206E616D6573206E6F7420636F6E7461696E696E672065697468
+65722074686520776F726473202242697473747265616D22206F722074686520776F7264
+202256657261222E0D0A0D0A54686973204C6963656E7365206265636F6D6573206E756C
+6C20616E6420766F696420746F2074686520657874656E74206170706C696361626C6520
+746F20466F6E7473206F7220466F6E7420536F6674776172652074686174206861732062
+65656E206D6F64696669656420616E6420697320646973747269627574656420756E6465
+7220746865202242697473747265616D205665726122206E616D65732E0D0A0D0A546865
+20466F6E7420536F667477617265206D617920626520736F6C642061732070617274206F
+662061206C617267657220736F667477617265207061636B61676520627574206E6F2063
+6F7079206F66206F6E65206F72206D6F7265206F662074686520466F6E7420536F667477
+61726520747970656661636573206D617920626520736F6C6420627920697473656C662E
+0D0A0D0A54484520464F4E5420534F4654574152452049532050524F5649444544202241
+53204953222C20574954484F55542057415252414E5459204F4620414E59204B494E442C
+2045585052455353204F5220494D504C4945442C20494E434C5544494E4720425554204E
+4F54204C494D4954454420544F20414E592057415252414E54494553204F46204D455243
+48414E544142494C4954592C204649544E45535320464F52204120504152544943554C41
+5220505552504F534520414E44204E4F4E494E4652494E47454D454E54204F4620434F50
+5952494748542C20504154454E542C2054524144454D41524B2C204F52204F5448455220
+52494748542E20494E204E4F204556454E54205348414C4C2042495453545245414D204F
+522054484520474E4F4D4520464F554E444154494F4E204245204C4941424C4520464F52
+20414E5920434C41494D2C2044414D41474553204F52204F54484552204C494142494C49
+54592C20494E434C5544494E4720414E592047454E4552414C2C205350454349414C2C20
+494E4449524543542C20494E434944454E54414C2C204F5220434F4E53455155454E5449
+414C2044414D414745532C205748455448455220494E20414E20414354494F4E204F4620
+434F4E54524143542C20544F5254204F52204F54484552574953452C2041524953494E47
+2046524F4D2C204F5554204F462054484520555345204F5220494E4142494C4954592054
+4F205553452054484520464F4E5420534F465457415245204F522046524F4D204F544845
+52204445414C494E475320494E2054484520464F4E5420534F4654574152452E0D0A0D0A
+45786365707420617320636F6E7461696E656420696E2074686973206E6F746963652C20
+746865206E616D6573206F6620476E6F6D652C2074686520476E6F6D6520466F756E6461
+74696F6E2C20616E642042697473747265616D20496E632E2C207368616C6C206E6F7420
+6265207573656420696E206164766572746973696E67206F72206F746865727769736520
+746F2070726F6D6F7465207468652073616C652C20757365206F72206F74686572206465
+616C696E677320696E207468697320466F6E7420536F66747761726520776974686F7574
+207072696F72207772697474656E20617574686F72697A6174696F6E2066726F6D207468
+6520476E6F6D6520466F756E646174696F6E206F722042697473747265616D20496E632E
+2C20726573706563746976656C792E20466F72206675727468657220696E666F726D6174
+696F6E2C20636F6E746163743A20666F6E747320617420676E6F6D6520646F74206F7267
+2E687474703A2F2F7777772E62697473747265616D2E636F6D0043006F00700079007200
+690067006800740020002800630029002000320030003000330020006200790020004200
+69007400730074007200650061006D002C00200049006E0063002E00200041006C006C00
+20005200690067006800740073002000520065007300650072007600650064002E004200
+69007400730074007200650061006D00200056006500720061002000530061006E007300
+420069007400730074007200650061006D005600650072006100530061006E0073002D00
+52006F006D0061006E00520065006C006500610073006500200031002E00310030004300
+6F0070007900720069006700680074002000280063002900200032003000300033002000
+620079002000420069007400730074007200650061006D002C00200049006E0063002E00
+0D000A0041006C006C002000520069006700680074007300200052006500730065007200
+7600650064002E000D000A00420069007400730074007200650061006D00200056006500
+72006100200069007300200061002000740072006100640065006D00610072006B002000
+6F0066002000420069007400730074007200650061006D002C00200049006E0063002E00
+0D000A000D000A005000650072006D0069007300730069006F006E002000690073002000
+68006500720065006200790020006700720061006E007400650064002C00200066007200
+6500650020006F00660020006300680061007200670065002C00200074006F0020006100
+6E007900200070006500720073006F006E0020006F0062007400610069006E0069006E00
+670020006100200063006F007000790020006F0066002000740068006500200066006F00
+6E007400730020006100630063006F006D00700061006E00790069006E00670020007400
+68006900730020006C006900630065006E007300650020002800220046006F006E007400
+730022002900200061006E00640020006100730073006F00630069006100740065006400
+200064006F00630075006D0065006E0074006100740069006F006E002000660069006C00
+65007300200028007400680065002000220046006F006E007400200053006F0066007400
+7700610072006500220029002C00200074006F00200072006500700072006F0064007500
+63006500200061006E006400200064006900730074007200690062007500740065002000
+740068006500200046006F006E007400200053006F006600740077006100720065002C00
+200069006E0063006C007500640069006E006700200077006900740068006F0075007400
+20006C0069006D00690074006100740069006F006E002000740068006500200072006900
+6700680074007300200074006F0020007500730065002C00200063006F00700079002C00
+20006D0065007200670065002C0020007000750062006C006900730068002C0020006400
+6900730074007200690062007500740065002C00200061006E0064002F006F0072002000
+730065006C006C00200063006F00700069006500730020006F0066002000740068006500
+200046006F006E007400200053006F006600740077006100720065002C00200061006E00
+6400200074006F0020007000650072006D0069007400200070006500720073006F006E00
+7300200074006F002000770068006F006D002000740068006500200046006F006E007400
+200053006F0066007400770061007200650020006900730020006600750072006E006900
+7300680065006400200074006F00200064006F00200073006F002C002000730075006200
+6A00650063007400200074006F002000740068006500200066006F006C006C006F007700
+69006E006700200063006F006E0064006900740069006F006E0073003A000D000A000D00
+0A005400680065002000610062006F0076006500200063006F0070007900720069006700
+68007400200061006E0064002000740072006100640065006D00610072006B0020006E00
+6F0074006900630065007300200061006E00640020007400680069007300200070006500
+72006D0069007300730069006F006E0020006E006F007400690063006500200073006800
+61006C006C00200062006500200069006E0063006C007500640065006400200069006E00
+200061006C006C00200063006F00700069006500730020006F00660020006F006E006500
+20006F00720020006D006F007200650020006F0066002000740068006500200046006F00
+6E007400200053006F006600740077006100720065002000740079007000650066006100
+6300650073002E000D000A000D000A00540068006500200046006F006E00740020005300
+6F0066007400770061007200650020006D006100790020006200650020006D006F006400
+690066006900650064002C00200061006C00740065007200650064002C0020006F007200
+200061006400640065006400200074006F002C00200061006E006400200069006E002000
+70006100720074006900630075006C006100720020007400680065002000640065007300
+690067006E00730020006F006600200067006C00790070006800730020006F0072002000
+6300680061007200610063007400650072007300200069006E0020007400680065002000
+46006F006E007400730020006D006100790020006200650020006D006F00640069006600
+690065006400200061006E00640020006100640064006900740069006F006E0061006C00
+200067006C00790070006800730020006F00720020006300680061007200610063007400
+65007200730020006D006100790020006200650020006100640064006500640020007400
+6F002000740068006500200046006F006E00740073002C0020006F006E006C0079002000
+690066002000740068006500200066006F006E0074007300200061007200650020007200
+65006E0061006D0065006400200074006F0020006E0061006D006500730020006E006F00
+7400200063006F006E007400610069006E0069006E006700200065006900740068006500
+72002000740068006500200077006F007200640073002000220042006900740073007400
+7200650061006D00220020006F0072002000740068006500200077006F00720064002000
+2200560065007200610022002E000D000A000D000A00540068006900730020004C006900
+630065006E007300650020006200650063006F006D006500730020006E0075006C006C00
+200061006E006400200076006F0069006400200074006F00200074006800650020006500
+7800740065006E00740020006100700070006C0069006300610062006C00650020007400
+6F00200046006F006E007400730020006F007200200046006F006E007400200053006F00
+660074007700610072006500200074006800610074002000680061007300200062006500
+65006E0020006D006F00640069006600690065006400200061006E006400200069007300
+200064006900730074007200690062007500740065006400200075006E00640065007200
+200074006800650020002200420069007400730074007200650061006D00200056006500
+72006100220020006E0061006D00650073002E000D000A000D000A005400680065002000
+46006F006E007400200053006F0066007400770061007200650020006D00610079002000
+62006500200073006F006C0064002000610073002000700061007200740020006F006600
+2000610020006C0061007200670065007200200073006F00660074007700610072006500
+20007000610063006B00610067006500200062007500740020006E006F00200063006F00
+7000790020006F00660020006F006E00650020006F00720020006D006F00720065002000
+6F0066002000740068006500200046006F006E007400200053006F006600740077006100
+72006500200074007900700065006600610063006500730020006D006100790020006200
+6500200073006F006C006400200062007900200069007400730065006C0066002E000D00
+0A000D000A00540048004500200046004F004E005400200053004F004600540057004100
+520045002000490053002000500052004F00560049004400450044002000220041005300
+20004900530022002C00200057004900540048004F005500540020005700410052005200
+41004E005400590020004F004600200041004E00590020004B0049004E0044002C002000
+450058005000520045005300530020004F005200200049004D0050004C00490045004400
+2C00200049004E0043004C005500440049004E004700200042005500540020004E004F00
+540020004C0049004D004900540045004400200054004F00200041004E00590020005700
+41005200520041004E00540049004500530020004F00460020004D004500520043004800
+41004E0054004100420049004C004900540059002C0020004600490054004E0045005300
+5300200046004F00520020004100200050004100520054004900430055004C0041005200
+200050005500520050004F0053004500200041004E00440020004E004F004E0049004E00
+4600520049004E00470045004D0045004E00540020004F004600200043004F0050005900
+520049004700480054002C00200050004100540045004E0054002C002000540052004100
+440045004D00410052004B002C0020004F00520020004F00540048004500520020005200
+49004700480054002E00200049004E0020004E004F0020004500560045004E0054002000
+5300480041004C004C002000420049005400530054005200450041004D0020004F005200
+2000540048004500200047004E004F004D004500200046004F0055004E00440041005400
+49004F004E0020004200450020004C004900410042004C004500200046004F0052002000
+41004E005900200043004C00410049004D002C002000440041004D004100470045005300
+20004F00520020004F00540048004500520020004C0049004100420049004C0049005400
+59002C00200049004E0043004C005500440049004E004700200041004E00590020004700
+45004E004500520041004C002C0020005300500045004300490041004C002C0020004900
+4E004400490052004500430054002C00200049004E0043004900440045004E0054004100
+4C002C0020004F005200200043004F004E00530045005100550045004E00540049004100
+4C002000440041004D0041004700450053002C0020005700480045005400480045005200
+200049004E00200041004E00200041004300540049004F004E0020004F00460020004300
+4F004E00540052004100430054002C00200054004F005200540020004F00520020004F00
+540048004500520057004900530045002C002000410052004900530049004E0047002000
+460052004F004D002C0020004F005500540020004F004600200054004800450020005500
+5300450020004F005200200049004E004100420049004C00490054005900200054004F00
+20005500530045002000540048004500200046004F004E005400200053004F0046005400
+570041005200450020004F0052002000460052004F004D0020004F005400480045005200
+20004400450041004C0049004E0047005300200049004E00200054004800450020004600
+4F004E005400200053004F004600540057004100520045002E000D000A000D000A004500
+78006300650070007400200061007300200063006F006E007400610069006E0065006400
+200069006E002000740068006900730020006E006F0074006900630065002C0020007400
+6800650020006E0061006D006500730020006F006600200047006E006F006D0065002C00
+2000740068006500200047006E006F006D006500200046006F0075006E00640061007400
+69006F006E002C00200061006E0064002000420069007400730074007200650061006D00
+200049006E0063002E002C0020007300680061006C006C0020006E006F00740020006200
+650020007500730065006400200069006E00200061006400760065007200740069007300
+69006E00670020006F00720020006F007400680065007200770069007300650020007400
+6F002000700072006F006D006F007400650020007400680065002000730061006C006500
+2C00200075007300650020006F00720020006F0074006800650072002000640065006100
+6C0069006E0067007300200069006E0020007400680069007300200046006F006E007400
+200053006F00660074007700610072006500200077006900740068006F00750074002000
+7000720069006F00720020007700720069007400740065006E0020006100750074006800
+6F00720069007A006100740069006F006E002000660072006F006D002000740068006500
+200047006E006F006D006500200046006F0075006E0064006100740069006F006E002000
+6F0072002000420069007400730074007200650061006D00200049006E0063002E002C00
+200072006500730070006500630074006900760065006C0079002E00200046006F007200
+20006600750072007400680065007200200069006E0066006F0072006D00610074006900
+6F006E002C00200063006F006E0074006100630074003A00200066006F006E0074007300
+200061007400200067006E006F006D006500200064006F00740020006F00720067002E00
+68007400740070003A002F002F007700770077002E006200690074007300740072006500
+61006D002E0063006F006D00013500B800CB00CB00C100AA009C01A600B8006600000071
+00CB00A002B20085007500B800C301CB0189022D00CB00A600F000D300AA008700CB03AA
+0400014A003300CB000000D9050200F4015400B4009C01390114013907060400044E04B4
+045204B804E704CD0037047304CD04600473013303A2055605A60556053903C5021200C9
+001F00B801DF007300BA03E9033303BC0444040E00DF03CD03AA00E503AA0404000000CB
+008F00A4007B00B80014016F007F027B0252008F00C705CD009A009A006F00CB00CD019E
+01D300F000BA018300D5009803040248009E01D500C100CB00F600830354027F00000333
+026600D300C700A400CD008F009A0073040005D5010A00FE022B00A400B4009C00000062
+009C0000001D032D05D505D505D505F0007F007B005400A406B80614072301D300B800CB
+00A601C301EC069300A000D3035C037103DB0185042304A80448008F0139011401390360
+008F05D5019A0614072306660179046004600460047B009C00000277046001AA00E90460
+0762007B00C5007F027B000000B4025205CD006600BC00660077061000CD013B01850389
+008F007B0000001D00CD074A042F009C009C0000077D006F0000006F0335006A006F007B
+00AE00B2002D0396008F027B00F600830354063705F6008F009C04E10266008F018D02F6
+00CD03440029006604EE007300001400B8028040FFFBFE03FA1403F92503F83203F79603
+F60E03F5FE03F4FE03F32503F20E03F19603F02503EF8A4105EFFE03EE9603ED9603ECFA
+03EBFA03EAFE03E93A03E84203E7FE03E63203E5E45305E59603E48A4105E45303E3E22F
+05E3FA03E22F03E1FE03E0FE03DF3203DE1403DD9603DCFE03DB1203DA7D03D9BB03D8FE
+03D68A4105D67D03D5D44705D57D03D44703D3D21B05D3FE03D21B03D1FE03D0FE03CFFE
+03CEFE03CD9603CCCB1E05CCFE03CB1E03CA3203C9FE03C6851105C61C03C51603C4FE03
+C3FE03C2FE03C1FE03C0FE03BFFE03BEFE03BDFE03BCFE03BBFE03BA1103B9862505B9FE
+03B8B7BB05B8FE03B7B65D05B7BB03B78004B6B52505B65D40FF03B64004B52503B4FE03
+B39603B2FE03B1FE03B0FE03AFFE03AE6403AD0E03ACAB2505AC6403ABAA1205AB2503AA
+1203A98A4105A9FA03A8FE03A7FE03A6FE03A51203A4FE03A3A20E05A33203A20E03A164
+03A08A4105A096039FFE039E9D0C059EFE039D0C039C9B19059C64039B9A10059B19039A
+1003990A0398FE0397960D0597FE03960D03958A410595960394930E05942803930E0392
+FA039190BB0591FE03908F5D0590BB039080048F8E25058F5D038F40048E25038DFE038C
+8B2E058CFE038B2E038A8625058A410389880B05891403880B0387862505876403868511
+0586250385110384FE038382110583FE0382110381FE0380FE037FFE0340FF7E7D7D057E
+FE037D7D037C64037B5415057B25037AFE0379FE03780E03770C03760A0375FE0374FA03
+73FA0372FA0371FA0370FE036FFE036EFE036C21036BFE036A1142056A530369FE03687D
+036711420566FE0365FE0364FE0363FE0362FE03613A0360FA035E0C035DFE035BFE035A
+FE0359580A0559FA03580A035716190557320356FE035554150555420354150353011005
+531803521403514A130551FE03500B034FFE034E4D10054EFE034D10034CFE034B4A1305
+4BFE034A4910054A1303491D0D05491003480D0347FE0346960345960344FE0343022D05
+43FA0342BB03414B0340FE033FFE033E3D12053E14033D3C0F053D12033C3B0D053C40FF
+0F033B0D033AFE0339FE033837140538FA033736100537140336350B05361003350B0334
+1E03330D0332310B0532FE03310B03302F0B05300D032F0B032E2D09052E10032D09032C
+32032B2A25052B64032A2912052A25032912032827250528410327250326250B05260F03
+250B0324FE0323FE03220F03210110052112032064031FFA031E1D0D051E64031D0D031C
+1142051CFE031BFA031A42031911420519FE031864031716190517FE0316011005161903
+15FE0314FE0313FE031211420512FE0311022D05114203107D030F64030EFE030D0C1605
+0DFE030C0110050C16030BFE030A100309FE0308022D0508FE0307140306640304011005
+04FE03401503022D0503FE0302011005022D0301100300FE0301B80164858D012B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B002B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B
+2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B1DB6060504
+030201002C2010B002254964B040515820C859212D2CB002254964B040515820C859212D
+2C20100720B00050B00D7920B8FFFF5058041B0559B0051CB0032508B0042523E120B000
+50B00D7920B8FFFF5058041B0559B0051CB0032508E12D2C4B505820B0FD454459212D2C
+B002254560442D2C4B5358B00225B0022545445921212D2C45442D0000020066FE960466
+05A400030007001A400C04FB0006FB0108057F0204002FC4D4EC310010D4ECD4EC301311
+211125211121660400FC73031BFCE5FE96070EF8F2720629000201350000020005D50003
+00090040400F07008304810208070501030400000A10FC3CEC32393931002FE4FCCC3001
+4BB00B5458BD000A00400001000A000AFFC03811373859B6000B200B500B035D25331523
+1133110323030135CBCBCB14A215FEFE05D5FD71FE9B0165000200C503AA02E905D50003
+0007004D400F05018404008108040506000502040810FCFCDCEC310010F43CEC3230014B
+B012544BB013545B58BD00080040000100080008FFC03811373859400F30094009500960
+097009A009BF09075D0111231121112311016FAA0224AA05D5FDD5022BFDD5022B000002
+009E0000061705BE0003001F006040311B0B008707041D0905190D028717130F15111F1E
+1C1B1A17161514131211100E0D0C090807060504030201001A0A18062010FCCC17393100
+2F3CD43C3CFC3C3CD43C3CC432EC32323040110B010B020B0C0B0D14041A111A12141F08
+015D012103210B0121133303211521032115210323132103231321352113213521130417
+FEDD5401254468012469A0670138FEA152013EFE9B68A067FEDB67A168FEC5016054FEBE
+0169660385FEB20387FE61019FFE619AFEB299FE62019EFE62019E99014E9A019F000003
+00AAFED3046D061400210028002F00D5405522020A0B0A27012628020B0B0A1D011E1C02
+2F292F1B0229292F42131110220A1B29041706092A21050217861606860511231A8A1689
+10002A8A0589022D08160A1E07291A1203000922100903010726080D05063010FC3CECF4
+173CFC173CF4E4EC31002FE4ECC4D4E4EC32C410EE10EE11123911391112173911123930
+4B5358071004ED07100EED11173907100EED111739071004ED5922014BB0095458BD0030
+0040000100300030FFC03811373859014BB00C544BB010545B4BB00F545B58BD0030FFC0
+000100300030004038113738590123032E0127351E0117112E01353436373533151E0117
+152E0127111E011514060703110E0115141617113E0135342602B4640169D26A66D16FDD
+C9DACC645DAE5353AF5CE3D6E3D664747A71E17F817BFED3012D022D2DB440410101C824
+AC96A3BC0EEBE8041F1BAF2A2E04FE5523B49CA9C30F0300019A0D6A585660D5FE4F116E
+5A58680000050071FFE3072905F0000B001700230027003300954036240F252625260F27
+24274200920C1E922E8D18922406920C8D26128C2824913427211B2509030D150E090D0F
+210D2B0E1B0D0F310B3410FCC4ECF4EC10EEF6EE1139111239310010E432F43CE4EC10EE
+F6EE10EE304B5358071005ED071005ED5922014BB009544BB00B545B4BB00C545B4BB014
+545B4BB00E545B4BB00D545B58BD00340040000100340034FFC038113738590122061514
+163332363534262732161514062322263534360122061514163332363534262533012313
+321615140623222635343605D157636357556363559EBABB9DA0BABBFC97566362575763
+640331A0FC5AA01F9EBCBB9F9FB9BA029194848295958283957FDCBBBBDBDBBBBCDB0261
+95828494948481967FF9F3060DDBBBBDDADBBCBADC0000020081FFE305FE05F000090030
+01CD40960D010E0C861112110B860A0B1212110986000915161507010608861616150201
+0301861D1E1D008609001E1E1D201F02211E110A130A17161503181411130A0708020609
+1113130A0201020300110A130A171602181511130A141113130A42120B090306000A1E03
+28150E0628270695182B9527942491188C0E130A2E0B0E09002E1215270E1E032E122721
+0E110F132103121B103110FCECC4D4D4EC10C6EE1139111239391139391139113931002F
+C6E4F6E6EE10EE10C6111239111739111739304B5358071005ED0705ED111739071005ED
+111739071005ED1117390705ED111739071005ED111739071008ED07100EED1117390710
+0EED111739071008ED071008ED07100EED1117395922B20F3201015D40B2070B05220929
+1C001C011F02170B2A002A0126123A003412440B5E0059015A0A55125A1A5A1F5930671E
+7B009B009A0199029708950B931595169522992D1F090B090C08110C270C2818021B0919
+0B190C19111C141C15161D1F3227002701290923122A132A1428152F323B09341239133F
+324A094C144B1546194F3256015A09590C551259135C1F5F326A0C691160327501790C7A
+1193009301970295059C079C089F089A099B0B9A0C9032A032B032395D005D010E011514
+163332363709013E0137330602070123270E01232200353436372E013534363332161715
+2E0123220615141601F25B55D4A05FA649FE7B01FC3B4206BA0C685D0117FC8F68E483F1
+FECE86863032DEB853A555579E4469833B032351A15892C23F40028FFDF859CB7284FEFE
+7EFEE39359570113D780E1633F7D3CA2C52424B62F316F583367000100C503AA016F05D5
+00030042400A0184008104000502040410FCEC310010F4EC30014BB012544BB013545B58
+BD00040040000100040004FFC03811373859400D40055005600570059005A005065D0111
+2311016FAA05D5FDD5022B00000100B0FEF2027B0612000D004F400F069800970E0D0700
+03120600130A0E10DCE432EC113939310010FCEC30014BB0135458BD000E00400001000E
+000EFFC03811373859014BB00F5458BD000EFFC00001000E000E00403811373859010602
+1514121723260235341237027B86828385A0969594970612E6FE3EE7E7FE3BE5EB01C6E0
+DF01C4EC000100A4FEF2026F0612000D001F400F079800970E0701000B12041308000E10
+DC3CF4EC113939310010FCEC301333161215140207233612353402A4A096959596A08583
+830612ECFE3CDFE0FE3AEBE501C5E7E701C20001003D024A03C305F00011004E402C100D
+0B00040C090704020408039905110C990A010E9112080C0A030906110301030200140F04
+0B09140D061210D43CE432DC3CE432173911121739310010F4D43CEC32C4EC3217391217
+393001050507251123110527252537051133112503C3FE9901673AFEB072FEB03A0167FE
+993A015072015004DFC2C362CBFE870179CB62C3C263CB0179FE87CB000100D9000005DB
+0504000B002340110009019C07030502150400170A0615080C10DCFC3CFC3CEC31002FD4
+3CFC3CC43001112115211123112135211103AE022DFDD3A8FDD3022D0504FDD3AAFDD302
+2DAA022D0001009EFF1201C300FE00050019400C039E0083060304011900180610FCECD4
+CC310010FCEC30373315032313F0D3A48152FEACFEC001400001006401DF027F02830003
+0011B6009C020401000410DCCC310010D4EC301321152164021BFDE50283A400000100DB
+000001AE00FE00030011B7008302011900180410FCEC31002FEC3037331523DBD3D3FEFE
+00010000FF4202B205D50003002D4014001A010201021A03000342029F00810402000103
+2FC43939310010F4EC304B5358071005ED071005ED5922013301230208AAFDF8AA05D5F9
+6D0000020087FFE3048F05F0000B00170023401306A01200A00C91128C18091C0F1E031C
+151B1810FCECF4EC310010E4F4EC10EE3001220211101233321211100227320011100023
+2200111000028B9C9D9D9C9D9D9D9DFB0109FEF7FBFBFEF701090550FECDFECCFECDFECD
+0133013301340133A0FE73FE86FE87FE73018D0179017A018D00000100E10000045A05D5
+000A004B40154203A00402A005810700A009081F061C03001F010B10D4ECC4FCEC31002F
+EC32F4ECD4EC304B53585922014BB00F5458BD000BFFC00001000B000B00403811373859
+B40F030F04025D3721110535253311211521FE014AFE990165CA014AFCA4AA047348B848
+FAD5AA00000100960000044A05F0001C00A54027191A1B03181C11050400110505044210
+A111940DA014910400A00200100A02010A1C171003061D10FCC4D4ECC0C011123931002F
+EC32F4ECF4EC304B5358071005ED0705ED1117395922014BB015544BB016545B4BB01454
+5B58BD001D00400001001D001DFFC0381137385940325504560556077A047A05761B8719
+0704000419041A041B051C74007606751A731B741C82008619821A821B821CA800A81B11
+5D005D25211521353600373E0135342623220607353E01333204151406070600018902C1
+FC4C73018D33614DA7865FD3787AD458E80114455B19FEF4AAAAAA7701913A6D97497796
+4243CC3132E8C25CA5701DFEEB000001009CFFE3047305F00028007B402E0015130A8609
+1F862013A0150DA00993061CA020932391068C15A329161C13000314191C2620101C0314
+1F09062910FCC4C4D4ECF4EC11173939310010ECE4F4E4EC10E6EE10EE10EE10EE111239
+30014BB016544BB014545B58BD00290040000100290029FFC038113738594009641E611F
+6120642104005D011E0115140421222627351E013332363534262B013533323635342623
+220607353E01333204151406033F91A3FED0FEE85EC76A54C86DBEC7B9A5AEB6959EA398
+53BE7273C959E6010C8E03251FC490DDF22525C33132968F8495A67770737B2426B42020
+D1B27CAB00020064000004A405D50002000D008C401D010D030D0003030D4200030B07A0
+0501038109010C0A001C0608040C0E10DCD43CC4EC32113931002FE4D43CEC321239304B
+5358071004C9071005C95922014BB00B544BB00D545B58BD000E00400001000E000EFFC0
+3811373859402A0B002A0048005900690077008A000716012B0026012B0336014E014F0C
+4F0D5601660175017A0385010D5D005D09012103331133152311231121350306FE0201FE
+35FED5D5C9FD5E0525FCE303CDFC33A8FEA00160C3000001009EFFE3046405D5001D0075
+4023041A071186101D1AA00714A010890D02A000810D8C07A41E171C010A031C000A1006
+1E10FCC4D4EC10C4EE310010E4E4F4EC10E6EE10FEC410EE11123930014BB016544BB014
+545B58BD001E00400001001E001EFFC03811373859014BB00F5458BD001EFFC00001001E
+001E0040381137385913211521113E0133320015140021222627351E0133323635342623
+220607DD0319FDA02C582CFA0124FED4FEEF5EC3685AC06BADCACAAD51A15405D5AAFE92
+0F0FFEEEEAF1FEF52020CB3130B69C9CB62426000002008FFFE3049605F0000B00240058
+40241306000D860C00A01606A01C16A510A00C8922911C8C250C22091C191E131C03211F
+1B2510FCECECF4ECE4310010E4F4E4FCE410EE10EE10EE111239304014CB00CB01CD02CD
+03CD04CB05CB0607A41EB21E025D015D01220615141633323635342601152E0123220203
+3E0133320015140023200011100021321602A4889F9F88889F9F01094C9B4CC8D30F3BB2
+6BE10105FEF0E2FEFDFEEE0150011B4C9B033BBAA2A1BBBBA1A2BA0279B82426FEF2FEEF
+575DFEEFEBE6FEEA018D0179016201A51E00000100A80000046805D50006006340180511
+02030203110405044205A0008103050301040100060710FCCCC411393931002FF4EC304B
+5358071005ED071005ED5922014BB0165458BD00070040000100070007FFC03811373859
+401258020106031A05390548056703B000B006075D005D13211501230121A803C0FDE2D3
+01FEFD3305D556FA81052B000003008BFFE3048B05F0000B0023002F00434025180C00A0
+2706A01E2DA012911E8C27A330180C242A1C15241C0F091C151B1E031C0F211B3010FCC4
+ECF4C4EC10EE10EE113939310010ECE4F4EC10EE10EE3939300122061514163332363534
+262526263534363332161514060716161514042322243534361314163332363534262322
+06028B90A5A59090A6A5FEA58291FFDEDFFE918192A3FEF7F7F7FEF7A448918382939382
+839102C59A87879A9B86879A5620B280B3D0D0B380B22022C68FD9E8E8D98FC601617482
+82747482820000020081FFE3048705F00018002400584023071F1901860019A00AA504A0
+0089161FA01091168C25071C1C21131E0022221C0D1B2510FCECE4F4ECEC310010E4F4EC
+10E6FEF5EE10EE111239304016C419C21AC01BC01CC01DC21EC41F07AA12BC12E912035D
+015D37351E01333212130E01232200353400332000111000212226013236353426232206
+151416E14C9C4BC8D30F3AB26CE0FEFB0110E201030111FEB1FEE54C9C013E889F9F8888
+9F9F1FB82426010D0112565C010FEBE60116FE73FE86FE9FFE5B1E0297BAA2A1BBBBA1A2
+BA00000200F0000001C3042300030007001C400E068304A60083020501030400180810FC
+3CEC3231002FECF4EC303733152311331523F0D3D3D3D3FEFE0423FE0002009EFF1201C3
+04230003000900254013028300079E048300A60A07080501190400180A10FC3CEC32D4CC
+310010E4FCEC10EE3013331523113315032313F0D3D3D3A481520423FEFDD9ACFEC00140
+000100D9005E05DB04A60006004D402A029C030403019C0001040403019C020105060500
+9C06054205040201000503A806A7070102002404230710FCEC3239310010F4EC1739304B
+53580704ED071008ED071008ED071004ED592209021501350105DBFBF80408FAFE050203
+F0FE91FE93B601D1A601D100000200D9016005DB03A200030007001C400D009C02069C04
+0805010400230810FC3CC432310010D4ECD4EC301321152115211521D90502FAFE0502FA
+FE03A2A8F0AA000100D9005E05DB04A60006004F402B069C0006030403059C040403009C
+010201069C05060202014206050302000504A801A7070602240400230710FC3CEC393100
+10F4EC1739304B5358071008ED071004ED071004ED071008ED592213350115013501D905
+02FAFE040603F0B6FE2FA6FE2FB6016D00020093000003B005F0000300240070402B241E
+0906040A1D13040014861388109517910083021D1A0D0905040A1E010D1C1A041C050103
+00261A132510DCC4FCECD4EC10EE11393911123911123931002FEEF6FEF4EE10CD113939
+173930014BB00C5458BD00250040000100250025FFC03811373859B679097A0A7A20035D
+2533152313233534363F013E0135342623220607353E013332161514060F010E01070E01
+150187CBCBC5BF385A5A3933836C4FB3615EC167B8DF485A582F27080606FEFE01919A65
+825659355E31596E4643BC3938C29F4C8956562F3519153C340000020087FE9C077105A2
+000B004C00954032180C0309A919151B03A94C0F34330FAC30A93715AC24A937434D3334
+1E1A00281206180C281A2B1E2849122B2A28492C3D4D10DCECFCEC10FEFDFE3CC610EE11
+123939310010D4C4FCEC10FEEDD4C610C5EE3210C4EE11393930004BB009544BB00C545B
+4BB010545B4BB013545B4BB014545B58BD004DFFC00001004D004D004038113738594009
+0F4E1F4E2F4E3F4E04015D011416333236353426232206010E0123222635343633321617
+3533113E0135342627262423220607060215141217160433323637170604232224272602
+353412373624333204171E011510000502FA8E7C7B8D907A798F02213C9B67ACD7D8AB67
+9C3B8F92A53F4068FED5B07BE2609DB1736D6901149D81F9685A7DFED998B9FEB8808086
+887E810152BDD4016B7B4B4FFEC2FEE802198FA3A48E8CA5A4FE484D49F9C8C8FA4B4C83
+FD2016DFB16BBC50838B414066FEB5C19FFEEA6A686D57516F6167837D7D0149BDB6014A
+7D7F87AEA062E67BFEF9FED00600000200100000056805D50002000A00BA404100110100
+040504021105050401110A030A0011020003030A0711050406110505040911030A08110A
+030A4200030795010381090509080706040302010009050A0B10D4C4173931002F3CE4D4
+EC1239304B5358071005ED0705ED071005ED0705ED071008ED071005ED071005ED071008
+ED5922B2200C01015D403A0F005800760070008C00050701080206030904160119025601
+5802500C67016802780176027C0372047707780887018802800C980299039604175D005D
+090121013301230321032302BCFEEE0225FE7BE50239D288FD5F88D5050EFD1903AEFA2B
+017FFE81000300C9000004EC05D5000800110020004340231900950A0995128101950AAD
+1F110B080213191F05000E1C1605191C2E09001C12042110FCEC32FCECD4EC1117393939
+31002FECECF4EC10EE3930B20F2201015D01112132363534262301112132363534262325
+213216151406071E01151404232101930144A39D9DA3FEBC012B94919194FE0B0204E7FA
+807C95A5FEF0FBFDE802C9FDDD878B8C850266FE3E6F727170A6C0B189A21420CB98C8DA
+00010073FFE3052705F000190036401A0DA10EAE0A951101A100AE04951791118C1A0719
+0D003014101A10FCEC32EC310010E4F4ECF4EC10EEF6EE30B40F1B1F1B02015D01152E01
+23200011100021323637150E01232000111000213216052766E782FF00FEF00110010082
+E7666AED84FEADFE7A0186015386ED0562D55F5EFEC7FED8FED9FEC75E5FD34848019F01
+670168019F47000200C9000005B005D500080011002E4015009509810195100802100A00
+05190D32001C09041210FCECF4EC113939393931002FECF4EC30B2601301015D01113320
+00111000212521200011100029010193F40135011FFEE1FECBFE42019F01B20196FE68FE
+50FE61052FFB770118012E012C0117A6FE97FE80FE7EFE96000100C90000048B05D5000B
+002E401506950402950081089504AD0A05010907031C00040C10FCEC32D4C4C431002FEC
+ECF4EC10EE30B21F0D01015D132115211121152111211521C903B0FD1A02C7FD3902F8FC
+3E05D5AAFE46AAFDE3AA000100C90000042305D50009002940120695040295008104AD08
+050107031C00040A10FCEC32D4C431002FECF4EC10EE30B20F0B01015D13211521112115
+211123C9035AFD700250FDB0CA05D5AAFE48AAFD370000010073FFE3058B05F0001D0039
+402000051B0195031B950812A111AE15950E91088C1E02001C1134043318190B101E10FC
+ECFCE4FCC4310010E4F4ECF4EC10FED4EE11393930251121352111060423200011100021
+32041715262623200011100021323604C3FEB6021275FEE6A0FEA2FE75018B015E920107
+6F70FC8BFEEEFEED011301126BA8D50191A6FD7F53550199016D016E01994846D75F60FE
+CEFED1FED2FECE25000100C90000053B05D5000B002C4014089502AD0400810A0607031C
+053809011C00040C10FCEC32FCEC3231002F3CE432FCEC30B2500D01015D133311211133
+112311211123C9CA02DECACAFD22CA05D5FD9C0264FA2B02C7FD3900000100C900000193
+05D500030039B700AF02011C00040410FCEC31002FEC30014BB0105458BD0004FFC00001
+0004000400403811373859400D30054005500560058F059F05065D13331123C9CACA05D5
+FA2B0001FF96FE66019305D5000B004D40130B0200079505B000810C05080639011C0004
+0C10FCECE43939310010E4FCEC11393930014BB0105458BD000CFFC00001000C000C0040
+3811373859400D300D400D500D600D8F0D9F0D065D13331110062B013533323635C9CACD
+E34D3F866E05D5FA93FEF2F4AA96C200000100C90000056A05D5000A00EF402808110506
+0507110606050311040504021105050442080502030300AF09060501040608011C00040B
+10FCEC32D4C4113931002F3CEC321739304B5358071004ED071005ED071005ED071004ED
+5922B2080301015D40921402010402090816022805280837023605340847024605430855
+02670276027705830288058F0894029B08E702150603090509061B031907050A030A0718
+0328052B062A073604360536063507300C41034004450540064007400C62036004680567
+077705700C8B038B058E068F078F0C9A039D069D07B603B507C503C507D703D607E803E9
+04E805EA06F703F805F9062C5D71005D711333110121090121011123C9CA029E0104FD1B
+031AFEF6FD33CA05D5FD890277FD48FCE302CFFD3100000100C90000046A05D500050025
+400C0295008104011C033A00040610FCECEC31002FE4EC30400930075007800380040401
+5D133311211521C9CA02D7FC5F05D5FAD5AA000100C90000061F05D5000C00BF40340311
+0708070211010208080702110302090A0901110A0A09420A070203080300AF080B050908
+030201050A061C043E0A1C00040D10FCECFCEC11173931002F3CC4EC32111739304B5358
+071005ED071008ED071008ED071005ED5922B2700E01015D405603070F080F09020A1502
+1407130A260226072007260A200A3407350A69027C027B07790A80028207820A90021604
+010B0313011B0323012C032708280934013C035608590965086A097608790981018D0395
+019B03145D005D13210901211123110123011123C9012D017D017F012DC5FE7FCBFE7FC4
+05D5FC0803F8FA2B051FFC000400FAE1000100C90000053305D500090079401E07110102
+0102110607064207020300AF0805060107021C0436071C00040A10FCECFCEC1139393100
+2F3CEC323939304B5358071004ED071004ED5922B21F0B01015D40303602380748024707
+690266078002070601090615011A06460149065701580665016906790685018A0695019A
+069F0B105D005D13210111331121011123C901100296C4FEF0FD6AC405D5FB1F04E1FA2B
+04E1FB1F00020073FFE305D905F0000B00170023401306951200950C91128C1809190F33
+031915101810FCECFCEC310010E4F4EC10EE300122001110003332001110002720001110
+002120001110000327DCFEFD0103DCDC0101FEFFDC013A0178FE88FEC6FEC5FE87017905
+4CFEB8FEE5FEE6FEB80148011A011B0148A4FE5BFE9EFE9FFE5B01A40162016201A50002
+00C90000048D05D500080013003A40180195100095098112100A0802040005190D3F1100
+1C09041410FCEC32FCEC11173931002FF4ECD4EC30400B0F151F153F155F15AF1505015D
+011133323635342623252132041514042B0111230193FE8D9A9A8DFE3801C8FB0101FEFF
+FBFECA052FFDCF92878692A6E3DBDDE2FDA800020073FEF805D905F0000B001D0052402A
+1110020F010C0D0C0E010D0D0C420F1E0C06951200951891128C0D1E0D1B0F0C0309191B
+33031915101E10FCECFCEC1139391139310010C4E4F4EC10EE391239304B5358071005ED
+071005ED1739592201220011100033320011100013012327060623200011100021200011
+10020327DCFEFD0103DCDC0101FEFF3F010AF4DD212310FEC5FE870179013B013A0178D1
+054CFEB8FEE5FEE6FEB80148011A011B0148FACFFEDDEF020201A50161016201A5FE5BFE
+9EFEFCFE8E00000200C90000055405D50013001C00B14035090807030A06110304030511
+0404034206040015030415950914950D810B040506031109001C160E050A191904113F14
+0A1C0C041D10FCEC32FCC4EC1117391139393931002F3CF4ECD4EC123912391239304B53
+58071005ED071005ED1117395922B2401E01015D40427A13010500050105020603070415
+00150114021603170425002501250226032706260726082609201E360136024601460268
+0575047505771388068807980698071F5D005D011E01171323032E012B01112311212016
+151406011133323635342623038D417B3ECDD9BF4A8B78DCCA01C80100FC83FD89FE9295
+959202BC16907EFE68017F9662FD8905D5D6D88DBA024FFDEE878383850000010087FFE3
+04A205F00027007E403C0D0C020E0B021E1F1E080902070A021F1F1E420A0B1E1F041501
+0015A11494189511049500942591118C281E0A0B1F1B0700221B190E2D071914222810DC
+C4ECFCECE4111239393939310010E4F4E4EC10EEF6EE10C6111739304B535807100EED11
+173907100EED1117395922B20F2901015DB61F292F294F29035D01152E01232206151416
+1F011E0115140421222627351E013332363534262F012E01353424333216044873CC5FA5
+B377A67AE2D7FEDDFEE76AEF807BEC72ADBC879A7BE2CA0117F569DA05A4C53736807663
+651F192BD9B6D9E0302FD04546887E6E7C1F182DC0ABC6E426000001FFFA000004E905D5
+0007004A400E0602950081040140031C0040050810D4E4FCE431002FF4EC3230014BB00A
+5458BD00080040000100080008FFC03811373859401300091F00100110021F0710094009
+70099F09095D03211521112311210604EFFDEECBFDEE05D5AAFAD5052B00000100B2FFE3
+052905D50011004B40160802110B0005950E8C09008112081C0A38011C00411210FCECFC
+EC310010E432F4EC113939393930014BB0105458BD00120040000100120012FFC0381137
+3859B61F138F139F13035D133311141633323635113311100021200011B2CBAEC3C2AECB
+FEDFFEE6FEE5FEDF05D5FC75F0D3D3F0038BFC5CFEDCFED6012A01240001001000000568
+05D5000600B7402704110506050311020306060503110403000100021101010042030401
+AF0006040302000505010710D4C4173931002FEC3239304B5358071005ED071008ED0710
+08ED071005ED5922B2500801015D406200032A03470447055A037D038303070600070208
+040906150114021A041A052A002601260229042905250620083800330133023C043C0537
+06480045014502490449054706590056066602690469057A007601760279047905750680
+0898009706295D005D21013309013301024AFDC6D301D901DAD2FDC705D5FB1704E9FA2B
+00010044000007A605D5000C017B4049051A0605090A09041A0A09031A0A0B0A021A0102
+0B0B0A061107080705110405080807021103020C000C011100000C420A050203060300AF
+0B080C0B0A09080605040302010B07000D10D4CC173931002F3CEC32321739304B535807
+1005ED071008ED071008ED071005ED071008ED071005ED0705ED071008ED5922B2000E01
+015D40F206020605020A000A000A120A2805240A200A3E023E05340A300A4C024D05420A
+400A59026A026B05670A600A7B027F027C057F05800A960295051D070009020803000406
+050005000601070408000807090009040A0A0C000E1A0315041508190C100E2004210520
+06200720082309240A250B200E200E3C023A033504330530083609390B3F0C300E460046
+014A0240044505400542064207420840084009440A4D0C400E400E58025608590C500E66
+026703610462056006600760086409640A640B770076017B027803770474057906790777
+087008780C7F0C7F0E860287038804890585098A0B8F0E97049F0EAF0E5B5D005D133309
+0133090133012309012344CC013A0139E3013A0139CDFE89FEFEC5FEC2FE05D5FB1204EE
+FB1204EEFA2B0510FAF00001003D0000053B05D5000B015D404609110A0B0A081107080B
+0B0A081109080506050711060605031104050402110102050504021103020B000B011100
+000B420B080502040300AF09060B08050204000406000A0C10D4C4DCC411173931002F3C
+EC321739304B5358071005ED071008ED071008ED071005ED071005ED071008ED071008ED
+071005ED5922014BB00C544BB00D545B4BB00E545B58BD000CFFC00001000C000C004038
+1137385940B80702080816021908170B2708270B34023808360B4B0858055B0866026B08
+7702770B8602800287058B08850B9402900297059D08960B1B0601090308070709160119
+0319071709100D260128022903260528072709290B200D350034013C033B043A063B0734
+09340A380B3F0D48094F0D580B5F0D650065016A036A046805690669076C096C0A780379
+06790778087D097F0A780B800080018302880385058408830B8F0D900090019402970597
+069508930B9F0DAF0D405D005D13330901330901230901230181D901730175D9FE200200
+D9FE5CFE59DA021505D5FDD5022BFD33FCF8027BFD85031D0001FFFC000004E705D50008
+0094402803110405040211010205050402110302080008011100000842020300AF060207
+0440051C0040070910D4E4FCE4123931002FEC3239304B5358071005ED071008ED071008
+ED071005ED5922B2000A01015D403C050214023502300230053008460240024005400851
+02510551086502840293021016011A031F0A2601290337013803400A670168037803700A
+9F0A0D5D005D03330901330111231104D9019E019BD9FDF0CB05D5FD9A0266FCF2FD3902
+C7000001005C0000051F05D50009009B401B031107080708110203024208950081039505
+08030001420400060A10DCC4D4E411393931002FECF4EC304B5358071005ED071005ED59
+22014BB009544BB00A545B58BD000A00400001000A000AFFC03811373859404005020A07
+18072902260738074802470748080905030B08000B16031A08100B2F0B350339083F0B47
+034A084F0B55035908660369086F0B770378087F0B9F0B165D005D132115012115213501
+21730495FC5003C7FB3D03B0FC6705D59AFB6FAA9A049100000100B0FEF2025806140007
+0053400F04A906B202A900B10805010343000810DCFCCC32310010FCECF4EC30014BB00C
+5458BD0008FFC000010008000800403811373859014BB012544BB013545B58BD00080040
+000100080008FFC038113738591321152311331521B001A8F0F0FE5806148FF9FC8F0001
+0000FF4202B205D50003002D4014021A010100001A03030242019F008104020001032FC4
+3939310010F4EC304B5358071005ED071005ED592213012301AA0208AAFDF805D5F96D06
+9300000100C7FEF2026F06140007003C401003A901B205A900B1080043040602040810FC
+3CDCEC310010FCECF4EC30014BB00F544BB010545B58BD0008FFC0000100080008004038
+113738590111213533112335026FFE58EFEF0614F8DE8F06048F000100D903A805DB05D5
+00060018400A0304010081070301050710DCCC39310010F4CC3239300101230101230103
+BC021FC9FE48FE48C9021F05D5FDD3018BFE75022D000001FFECFE1D0414FEAC0003000F
+B500A90100020410C4C43100D4EC30011521350414FBD8FEAC8F8F00000100AA04F00289
+066600030031400901B400B3040344010410DCEC310010F4EC30004BB009544BB00E545B
+58BD0004FFC00001000400040040381137385909012301016F011A99FEBA0666FE8A0176
+0002007BFFE3042D047B000A002500BC4027191F0B17090E00A91706B90E1120861FBA1C
+B923B8118C170C001703180D09080B1F030814452610FCECCCD4EC323211393931002FC4
+E4F4FCF4EC10C6EE10EE11391139123930406E301D301E301F3020302130223F27401D40
+1E401F402040214022501D501E501F50205021502250277027851D871E871F8720872185
+229027A027F0271E301E301F30203021401E401F40204021501E501F50205021601E601F
+60206021701E701F70207021801E801F80208021185D015D0122061514163332363D0137
+1123350E01232226353436332135342623220607353E0133321602BEDFAC816F99B9B8B8
+3FBC88ACCBFDFB0102A79760B65465BE5AF3F00233667B6273D9B4294CFD81AA6661C1A2
+BDC0127F8B2E2EAA2727FC00000200BAFFE304A40614000B001C0038401903B90C0F09B9
+18158C0FB81B971900121247180C06081A461D10FCEC3232F4EC31002FECE4F4C4EC10C6
+EE30B6601E801EA01E03015D013426232206151416333236013E01333212111002232226
+271523113303E5A79292A7A79292A7FD8E3AB17BCCFFFFCC7BB13AB9B9022FCBE7E7CBCB
+E7E702526461FEBCFEF8FEF8FEBC6164A806140000010071FFE303E7047B0019003F401B
+00860188040E860D880AB91104B917B8118C1A07120D004814451A10FCE432EC310010E4
+F4EC10FEF4EE10F5EE30400B0F1B101B801B901BA01B05015D01152E0123220615141633
+323637150E0123220011100021321603E74E9D50B3C6C6B3509D4E4DA55DFDFED6012D01
+0655A20435AC2B2BE3CDCDE32B2BAA2424013E010E0112013A2300020071FFE3045A0614
+0010001C003840191AB9000E14B905088C0EB801970317040008024711120B451D10FCEC
+F4EC323231002FECE4F4C4EC10C4EE30B6601E801EA01E03015D0111331123350E012322
+0211101233321601141633323635342623220603A2B8B83AB17CCBFFFFCB7CB1FDC7A792
+92A8A89292A703B6025EF9ECA86461014401080108014461FE15CBE7E7CBCBE7E7000002
+0071FFE3047F047B0014001B00704024001501098608880515A90105B90C01BB18B912B8
+0C8C1C1B1502081508004B02120F451C10FCECF4ECC4111239310010E4F4ECE410EE10EE
+10F4EE1112393040293F1D701DA01DD01DF01D053F003F013F023F153F1B052C072F082F
+092C0A6F006F016F026F156F1B095D71015D0115211E0133323637150E01232000111000
+333200072E0123220607047FFCB20CCDB76AC76263D06BFEF4FEC70129FCE20107B802A5
+889AB90E025E5ABEC73434AE2A2C0138010A01130143FEDDC497B4AE9E000001002F0000
+02F8061400130070401C0510010C08A906018700970E06BC0A02130700070905080D0F0B
+4C1410FC3CC4FC3CC4C412393931002FE432FCEC10EE3212393930014BB00A5458BD0014
+FFC000010014001400403811373859014BB00E5458BD00140040000100140014FFC03811
+373859B640155015A015035D01152322061D012115211123112335333534363302F8B063
+4D012FFED1B9B0B0AEBD0614995068638FFC2F03D18F4EBBAB0000020071FE56045A047B
+000B0028004A4023190C1D0912861316B90F03B92623B827BC09B90FBD1A1D261900080C
+4706121220452910FCC4ECF4EC323231002FC4E4ECE4F4C4EC10FED5EE1112393930B660
+2A802AA02A03015D01342623220615141633323617100221222627351E013332363D010E
+0123220211101233321617353303A2A59594A5A59495A5B8FEFEFA61AC51519E52B5B439
+B27CCEFCFCCE7CB239B8023DC8DCDCC8C7DCDCEBFEE2FEE91D1EB32C2ABDBF5B6362013A
+01030104013A6263AA00000100BA000004640614001300344019030900030E0106870E11
+B80C970A010208004E0D09080B461410FCEC32F4EC31002F3CECF4C4EC1112173930B260
+1501015D0111231134262322061511231133113E013332160464B87C7C95ACB9B942B375
+C1C602A4FD5C029E9F9EBEA4FD870614FD9E6564EF00000200C100000179061400030007
+002B400E06BE04B100BC020501080400460810FC3CEC3231002FE4FCEC30400B10094009
+50096009700905015D1333112311331523C1B8B8B8B80460FBA00614E9000002FFDBFE56
+01790614000B000F0044401C0B0207000EBE0C078705BD00BC0CB110081005064F0D0108
+0C00461010FC3CEC32E4391239310010ECE4F4EC10EE1112393930400B10114011501160
+11701105015D13331114062B01353332363511331523C1B8A3B54631694CB8B80460FB8C
+D6C09C61990628E9000100BA0000049C0614000A00BC4029081105060507110606050311
+0405040211050504420805020303BC009709060501040608010800460B10FCEC32D4C411
+3931002F3CECE41739304B5358071004ED071005ED071005ED071004ED5922B2100C0101
+5D405F04020A081602270229052B0856026602670873027705820289058E089302960597
+08A3021209050906020B030A072803270428052B062B07400C6803600C8903850489058D
+068F079A039707AA03A705B607C507D607F703F003F704F0041A5D71005D133311013309
+0123011123BAB90225EBFDAE026BF0FDC7B90614FC6901E3FDF4FDAC0223FDDD000100C1
+00000179061400030022B7009702010800460410FCEC31002FEC30400D10054005500560
+057005F00506015D13331123C1B8B80614F9EC00000100BA0000071D047B0022005A4026
+061209180F00061D07150C871D2003B81BBC19100700110F0808065011080F501C18081A
+462310FCEC32FCFCFCEC11123931002F3C3CE4F43CC4EC32111217393040133024502470
+249024A024A024BF24DF24FF2409015D013E013332161511231134262322061511231134
+262322061511231133153E01333216042945C082AFBEB972758FA6B972778DA6B9B93FB0
+797AAB03897C76F5E2FD5C029EA19CBEA4FD87029EA29BBFA3FD870460AE67627C000001
+00BA00000464047B001300364019030900030E0106870E11B80CBC0A010208004E0D0908
+0B461410FCEC32F4EC31002F3CE4F4C4EC1112173930B46015CF1502015D011123113426
+2322061511231133153E013332160464B87C7C95ACB9B942B375C1C602A4FD5C029E9F9E
+BEA4FD870460AE6564EF00020071FFE30475047B000B0017004A401306B91200B90CB812
+8C1809120F51031215451810FCECF4EC310010E4F4EC10EE3040233F197B007B067F077F
+087F097F0A7F0B7B0C7F0D7F0E7F0F7F107F117B12A019F01911015D0122061514163332
+36353426273200111000232200111000027394ACAB9593ACAC93F00112FEEEF0F1FEEF01
+1103DFE7C9C9E7E8C8C7E99CFEC8FEECFEEDFEC70139011301140138000200BAFE5604A4
+047B0010001C003E401B1AB9000E14B90508B80E8C01BD03BC1D11120B47170400080246
+1D10FCEC3232F4EC310010E4E4E4F4C4EC10C4EE304009601E801EA01EE01E04015D2511
+231133153E013332121110022322260134262322061514163332360173B9B93AB17BCCFF
+FFCC7BB10238A79292A7A79292A7A8FDAE060AAA6461FEBCFEF8FEF8FEBC6101EBCBE7E7
+CBCBE7E700020071FE56045A047B000B001C003E401B03B90C0F09B91815B80F8C1BBD19
+BC1D180C06081A47001212451D10FCECF4EC3232310010E4E4E4F4C4EC10C6EE30400960
+1E801EA01EE01E04015D011416333236353426232206010E012322021110123332161735
+331123012FA79292A8A89292A702733AB17CCBFFFFCB7CB13AB8B8022FCBE7E7CBCBE7E7
+FDAE646101440108010801446164AAF9F600000100BA0000034A047B001100304014060B
+0700110B03870EB809BC070A06080008461210FCC4EC3231002FE4F4ECC4D4CC11123930
+B450139F1302015D012E012322061511231133153E0133321617034A1F492C9CA7B9B93A
+BA85132E1C03B41211CBBEFDB20460AE666305050001006FFFE303C7047B002700E7403C
+0D0C020E0B531F1E080902070A531E1F1E420A0B1E1F041500860189041486158918B911
+04B925B8118C281E0A0B1F1B0700521B080E07081422452810FCC4ECD4ECE41112393939
+39310010E4F4EC10FEF5EE10F5EE121739304B535807100EED111739070EED1117395922
+B2002701015D406D1C0A1C0B1C0C2E092C0A2C0B2C0C3B093B0A3B0B3B0C0B2000200124
+02280A280B2A132F142F152A16281E281F292029212427860A860B860C860D1200000001
+0202060A060B030C030D030E030F03100319031A031B031C041D09272F293F295F297F29
+80299029A029F029185D005D7101152E012322061514161F011E0115140623222627351E
+013332363534262F012E01353436333216038B4EA85A898962943FC4A5F7D85AC36C66C6
+61828C65AB40AB98E0CE66B4043FAE282854544049210E2A99899CB62323BE353559514B
+50250F2495829EAC1E0000010037000002F2059E0013003840190E05080F03A9001101BC
+08870A0B08090204000810120E461410FC3CC4FC3CC432393931002FECF43CC4EC321139
+3930B2AF1501015D01112115211114163B01152322263511233533110177017BFE854B73
+BDBDD5A28787059EFEC28FFDA0894E9A9FD202608F013E00000100AEFFE3045804600013
+00364019030900030E0106870E118C0A01BC0C0D09080B4E020800461410FCECF4EC3231
+002FE432F4C4EC1112173930B46015CF1502015D1311331114163332363511331123350E
+01232226AEB87C7C95ADB8B843B175C1C801BA02A6FD619F9FBEA4027BFBA0AC6663F000
+0001003D0000047F04600006011240270311040504021101020505040211030206000601
+1100000642020300BF0506050302010504000710D4C4173931002FEC3239304B53580710
+05ED071008ED071008ED071005ED5922014BB00A5458BD0007FFC0000100070007004038
+11373859014BB014544BB015545B58BD00070040000100070007FFC03811373859408E48
+026A027B027F02860280029102A402080600060109030904150015011A031A0426002601
+290329042008350035013A033A0430084600460149034904460548064008560056015903
+590450086600660169036904670568066008750074017B037B0475057A06850085018903
+8904890586069600960197029A03980498059706A805A706B008C008DF08FF083E5D005D
+133309013301233DC3015E015EC3FE5CFA0460FC5403ACFBA00000010056000006350460
+000C0201404905550605090A0904550A0903550A0B0A025501020B0B0A06110708070511
+0405080807021103020C000C011100000C420A050203060300BF0B080C0B0A0908060504
+0302010B07000D10D4CC173931002F3CEC32321739304B5358071005ED071008ED071008
+ED071005ED071008ED071005ED0705ED071008ED5922014BB00A544BB011545B4BB01254
+5B4BB013545B4BB00B545B58BD000DFFC00001000D000D00403811373859014BB00C544B
+B00D545B4BB010545B58BD000D00400001000D000DFFC0381137385940FF050216021605
+220A350A49024905460A400A5B025B05550A500A6E026E05660A79027F0279057F058702
+99029805940ABC02BC05CE02C703CF051D0502090306040B050A080B09040B050C150219
+0316041A051B081B09140B150C2500250123022703210425052206220725082709240A21
+0B230C390336043608390C300E460248034604400442054006400740084409440A440B40
+0E400E560056015602500451055206520750085309540A550B6300640165026A0365046A
+056A066A076E09610B670C6F0E7500750179027D0378047D057A067F067A077F07780879
+097F097B0A760B7D0C870288058F0E97009701940293039C049B05980698079908402F96
+0C9F0EA600A601A402A403AB04AB05A906A907AB08A40CAF0EB502B103BD04BB05B809BF
+0EC402C303CC04CA05795D005D13331B01331B013301230B012356B8E6E5D9E6E5B8FEDB
+D9F1F2D90460FC96036AFC96036AFBA00396FC6A0001003B000004790460000B015A4046
+0511060706041103040707060411050401020103110202010B110001000A11090A010100
+0A110B0A0708070911080807420A070401040800BF05020A0704010408000208060C10D4
+C4D4C411173931002F3CEC321739304B5358071005ED071008ED071008ED071005ED0710
+05ED071008ED071008ED071005ED5922014BB00A544BB00F545B4BB010545B4BB011545B
+58BD000CFFC00001000C000C00403811373859014BB0145458BD000C00400001000C000C
+FFC0381137385940980A04040A1A04150A260A3D04310A55045707580A660A76017A0476
+07740A8D04820A99049F049707920A900AA601A904AF04A507A30AA00A1C0A0304050509
+0A0B1A03150515091A0B2903260525092A0B200D3A013903370534073609390B300D4903
+460545094A0B400D590056015902590357055606590756085609590B500D6F0D78017F0D
+9B019407AB01A407B00DCF0DDF0DFF0D2F5D005D09022309012309013309010464FE6B01
+AAD9FEBAFEBAD901B3FE72D9012901290460FDDFFDC101B8FE48024A0216FE71018F0001
+003DFE56047F0460000F01A240430708020911000F0A110B0A00000F0E110F000F0D110C
+0D00000F0D110E0D0A0B0A0C110B0B0A420D0B0910000B058703BD0E0BBC100E0D0C0A09
+060300080F040F0B1010D4C4C4111739310010E432F4EC113911391239304B5358071005
+ED071008ED071008ED071005ED071008ED0705ED17325922014BB00A544BB008545B58BD
+0010FFC000010010001000403811373859014BB0145458BD00100040000100100010FFC0
+381137385940F0060005080609030D160A170D100D230D350D490A4F0A4E0D5A095A0A6A
+0A870D800D930D120A000A09060B050C0B0E0B0F1701150210041005170A140B140C1A0E
+1A0F2700240124022004200529082809250A240B240C270D2A0E2A0F2011370035013502
+30043005380A360B360C380D390E390F3011410040014002400340044005400640074008
+4209450A470D490E490F40115400510151025503500450055606550756085709570A550B
+550C590E590F501166016602680A690E690F60117B08780E780F89008A09850B850C890D
+890E890F9909950B950C9A0E9A0FA40BA40CAB0EAB0FB011CF11DF11FF11655D005D050E
+012B01353332363F01013309013302934E947C936C4C543321FE3BC3015E015EC368C87A
+9A488654044EFC94036C00010058000003DB0460000900B4401A08110203020311070807
+4208A900BC03A905080301000401060A10DCC432C411393931002FECF4EC304B53580710
+05ED071005ED5922014BB00B544BB00C545B58BD000A00400001000A000AFFC038113738
+59014BB0135458BD000AFFC00001000A000A004038113738594042050216022602470249
+07050B080F0B18031B082B08200B36033908300B40014002450340044005430857035908
+5F0B6001600266036004600562087F0B800BAF0B1B5D005D132115012115213501217103
+6AFD4C02B4FC7D02B4FD650460A8FCDB93A8032500010100FEB204170614002400824034
+190F150B0625091A10151D0B05202103000BA90900A901C00915A913B1250C090A052416
+19001D0A05130214002019430A0F052510D43CC4FC3CC432393911123911123939111239
+39310010FCECC4F4EC10EE12173912391139391112391112393930014BB00C5458BD0025
+FFC000010025002500403811373859B20026015D05152322263D0134262B01353332363D
+0134363B01152322061D011406071E011D0114163304173EF9A96C8E3D3D8F6BA9F93E44
+8D565B6E6F5A568DBE9094DDEF97748F7395F0DD938F588DF89D8E191B8E9CF88D580001
+0104FE1D01AE061D00030012B70100B1040005020410D4EC310010FCCC300111231101AE
+AA061DF80008000000010100FEB2041706140024009E40361F251B160C0F081B0B15190F
+040520030019A91B00A923C01B0FA911B1251C191A150F010400081A15231204001A1F15
+4310000B042510D43CC432FC3CC4111239391112391112393911123939310010FCECC4F4
+EC10EE12173911123939113911393911123930014BB00A5458BD00250040000100250025
+FFC03811373859014BB00E5458BD0025FFC000010025002500403811373859B20026015D
+053332363D013436372E013D0134262B01353332161D0114163B01152322061D0114062B
+010100468C555A6F6F5A558C463FF9A76C8E3E3E8E6CA7F93FBE568FF89C8E1B198E9DF8
+8E578F93DDF095738F7497EFDD94000100D901D305DB0331001D0023401001101B0C0013
+049C1B139C0C1E000F1E10D4C4310010D4FCD4EC10C01112393930011506062322272627
+26272623220607353636333217161716171633323605DB69B3616E920B05070F9B5E58AC
+6269B3616E930A05080E9B5E56A90331B24F443B040203053E4D53B24F453C040203053E
+4C00FFFF001000000568074E02270024000000000007010300BC01750003001000000568
+076D000B000E002100CB40540C110D0C1B1C1B0E111C1B1E111C1B1D111C1C1B0D11210F
+210C110E0C0F0F2120110F211F11210F21420C1B0F0D0903C115091E950D098E201C1E1D
+1C18201F210D12060E180C061B0056181C0F0656121C212210D4C4D4EC3210D4EE321139
+11391112391139391112393931002F3CE6D6EE10D4EE1112393939304B5358071005ED07
+05ED071008ED071005ED071005ED0705ED0705ED071008ED5922B2202301015D40201A0C
+730C9B0C03070F081B5023660D690E750D7B0E791C791D7620762180230C5D005D013426
+232206151416333236030121012E01353436333216151406070123032103230354593F40
+57583F3F5998FEF00221FE583D3E9F7372A13F3C0214D288FD5F88D5065A3F5957413F58
+58FEF3FD19034E29734973A0A172467629FA8B017FFE8100FFFF0073FE75052705F00227
+002600000000000700DD012D0000FFFF00C90000048B076B022700280000000000070104
+009E0175FFFF00C900000533075E02270031000000000007010500FE0175FFFF0073FFE3
+05D9074E02270032000000000007010301270175FFFF00B2FFE30529074E022700380000
+00000007010300EE0175FFFF007BFFE3042D066602270044000000000007008D00520000
+FFFF007BFFE3042D066602270044000000000007004300520000FFFF007BFFE3042D0666
+0227004400000000000700D700520000FFFF007BFFE3042D061002270044000000000007
+008E00520000FFFF007BFFE3042D06370227004400000000000700D800520000FFFF007B
+FFE3042D07060227004400000000000700DC00520000FFFF0071FE7503E7047B02270046
+00000000000700DD008F0000FFFF0071FFE3047F066602270048000000000007008D008B
+0000FFFF0071FFE3047F0666022700480000000000070043008B0000FFFF0071FFE3047F
+06660227004800000000000700D7008B0000FFFF0071FFE3047F06100227004800000000
+0007008E008B0000FFFF00900000026F0666022700D6000000000007008DFF1D0000FFFF
+FFC7000001A60666022700D60000000000070043FF1D0000FFFFFFDE0000025C06660227
+00D600000000000700D7FF1D0000FFFFFFF4000002460610022700D6000000000007008E
+FF1D0000FFFF00BA0000046406370227005100000000000700D800980000FFFF0071FFE3
+0475066602270052000000000007008D00730000FFFF0071FFE304750666022700520000
+00000007004300730000FFFF0071FFE3047506660227005200000000000700D700730000
+FFFF0071FFE30475061002270052000000000007008E00730000FFFF0071FFE304750637
+0227005200000000000700D800730000FFFF00AEFFE30458066602270058000000000007
+008D007B0000FFFF00AEFFE304580666022700580000000000070043007B0000FFFF00AE
+FFE3045806660227005800000000000700D7007B0000FFFF00AEFFE30458061002270058
+000000000007008E007B000000010039FF3B03C705D5000B002740140804B90A02008106
+C20C0359050157095907000C10D43CECFC3CEC310010E4F4D43CEC323001331121152111
+231121352101A8B0016FFE91B0FE91016F05D5FE5C99FBA3045D9900000200C30375033D
+05F0000B001A0020401106C315C400C30C911B095A125B035A181B10DCECFCEC310010F4
+ECFCEC300122061514163332363534262732161716161514062322263534360200506E6E
+50506E6F4F40762B2E2EB98687B4B8056F6F504F6D6D4F4F7081312E2D724284B7B48786
+BA00000200ACFEC704230598000600210051402B131614000F0C010B078608880B10860F
+880CB914160BB91D1F1CB8168C221C1500091E130B0F070412192210DCECD43CD43C3CEC
+3232310010E4F43CC4EC10C4FEF4EE10F5EE123911123911123930251106061514160115
+2626270336363715060607112311260011100037113313161602A693A4A402104A884401
+46894841894D66F1FEF70109F16601498983035812E2B8B9E203A1AC292A03FCA0052A27
+AA1E2307FEE4012014013301010102013216011FFEE10421000100810000046205F0001B
+00604021071608018600120AA914080C04A000941991100CA00E000D090B071C130F1511
+1C10DC3CCCCCFC3CC4D4C431002FEC32F4E4EC10D43CEE3210EE11393930014BB00C5458
+BD001CFFC00001001C001C00403811373859B43601360202005D01152E012322061D0121
+152111211521353311233533351036333216044E4C883D94740187FE79022DFC1FECC7C7
+D6E83D9705B4B629299BD4D78FFE2FAAAA01D18FEE0105F31F000002005CFF3D03A205F0
+000B003E0091403C2F302A0600171D3036040D278A260D8A0C2AC626C52310C60CC53C91
+233F2F0600173004131D2D0936031357392D572009570C221A3926220357333F10DCECE4
+C4D4E4ECD4EC10EE113911123911173939310010C4F4E4EC10E6EE10EE10EE1117393939
+11123930014BB00A544BB00B545B4BB00C545B4BB00E545B58BD003F00400001003F003F
+FFC03811373859010E01151416173E0135342613152E0123220615141716171E01151406
+071E0115140623222627351E0133323635342F012E01353436372E01353436333216017B
+3F3E8BFA3F3E8FCC538F38616CCE1A0ED3835C5D3E39CCAD499A5857943A6671DD19D680
+5D5B3B3BC8A6499903A82E5A2E4C85872D5B2E4B880293A4272750475A730F08779A655A
+8C35346D408EA81D1DA42727544C667B0E7899665B8F312C7045829F1D000001013301D1
+03850421000B0012B709C7030C065C000C10D4EC310010D4EC3001343633321615140623
+22260133AD7E7CABAC7D7DAC02FA7CABAB7C7DACAC000001009EFF3B043905D5000D0025
+4012080204C1008106020E00075D05035D010B0E10D4D4FCDCEC39310010C432F4EC1139
+300121112311231123112626353424027901C08DBE8ED7EB010405D5F966061FF9E1034E
+11DDB8BEE800000100BAFFE304AC0614002F009A40302D27210C04060D2000042A168617
+1AB9132AB90397138C2E0C090D1D2021270908242708061D082410162D081000463010FC
+C4FCCC10C6EED4EE10EE1139391239123931002FE4FEEE10FED5EE12173917393040400F
+050F060F070F270F288A0C8A0D070A060A070A0B0A0C0A0D0A1F0D200A210C220426190D
+191F19203A203A214D1F4D20492149226A1F6A20A506A507A620185D015D133436333216
+170E011514161F011E0115140623222627351E013332363534262F012E01353436372E01
+232206151123BAEFDAD0DB0397A83A4139A660E1D3408849508C4174783B655C6057A797
+0883718288BB0471C8DBE8E00873602F512A256A8E64ACB71918A41E1D5F5B3F543E373B
+875B7FAC1D67708B83FB93000004011B000006E505CD0017002F0038004C006040364542
+433F32C94830C9394A43CA0C39CA00C918C80CC924484533300431423C3F39364931604B
+3660433C5E12091E4B5E06091E5F2A4D10DCE4FCEC10FEFDC4EE10EE3211393912391217
+3931002FEEF6FEED10ED3210EED6EE391239393001220607060615141617161633323637
+363635342627262627320417161215140207060423222427260235341237362413231133
+32363534262732161514060716161717232726262323112311040083E25E5E60605E5EE2
+8384E35E5D5D5E5C5EE3849801076D6D6C6C6D6DFEF99898FEF96D6D6C6C6D6D01077D7B
+7B6E575866B0AE696018432E89AC813B4936429B05665E5E5EE58281E35E5E5F5F5E5DE2
+8385E35D5E5E676E6D6DFEFA9A98FEFB6D6D6E6E6D6D0105989A01066D6D6EFE62FEEC3E
+4B4C3F677779567011084D49DFD16033FE9C03440003011B000006E505CD0017002F0049
+004340263DCB3E3ACC41CA2431CB3034CC47CA18C900C824C90C3761443D305E2A090644
+5E1E0906124A10DCCCFCEC10FEED3210EE31002FEEF6FEFDEED6EE10FDEED6EE30013204
+171612151402070604232224272602353412373624172206070606151416171616333236
+373636353426272626171526262322061514163332363715060623222635343633321604
+009801076D6D6C6C6D6DFEF99898FEF96D6D6C6C6D6D01079883E25E5E60605E5EE28384
+E35E5D5D5E5C5EE3A742824295A7AB9B407A42438946D8FBFBD8498805CD6E6D6DFEFA9A
+98FEFB6D6D6E6E6D6D0105989A01066D6D6E675E5E5EE58281E35E5E5F5F5E5DE28385E3
+5D5E5EF5812120AF9D9FAE1F227F1D1CF4D0D1F21C00000201270393064605D5000C0014
+003E4021010607100A04120E090306C90D02008115010905620309620B0D630F62136311
+1510D4E4FCE4D4ECD4EC1139310010F43C3CEC1732D43C3CC41139300113133311231103
+23031123112315231123112335044AAEA4AA71C337CB7271CB72C905D5FF000100FDBE01
+E4FED1012FFE1C02425EFE1C01E45E000001017304EE0352066600030031400902B400B3
+040344010410D4EC310010F4EC30004BB009544BB00E545B58BD0004FFC0000100040004
+0040381137385901330123028BC7FEBA990666FE8800000200D705460329061000030007
+0092400E0602CE0400CD080164000564040810DCFCD4EC310010FC3CEC3230004BB00A54
+4BB00D545B58BD00080040000100080008FFC03811373859014BB00C544BB00D545B4BB0
+0E545B4BB017545B58BD0008FFC000010008000800403811373859014BB00F544BB01954
+5B58BD00080040000100080008FFC0381137385940116001600260056006700170027005
+7006085D0133152325331523025ECBCBFE79CBCB0610CACACA00000100D9002705DB04DD
+0013003E40220D0C0A0302CF04009C060CCF0E0A9C1206100814120E0D0C080403020809
+050F001410DC3CC4321739310010D43CCC32FC3CEC10FE3CEC3911123930132101170721
+1521072115210127372135213721D9030401007DAE012FFE48C3027BFCFAFEFE7DAEFED5
+01B6C3FD8703A2013B66D5A8F0AAFEC766D3AAF0000200080000074805D5000F00130087
+403911110E0F0E10110F0F0E0D110F0E0C110E0F0E420595030B95110195109500811107
+9503AD0D0911100F0D0C050E0A00040806021C120A0E1410D4D43CEC32D4C4C411121739
+31002F3CECECC4F4ECEC10EE10EE304B5358071005ED0705ED071005ED071005ED5922B2
+801501015D4013671177107711860C851096119015A015BF15095D011521112115211121
+15211121032301170121110735FD1B02C7FD3902F8FC3DFDF0A0CD02718BFEB601CB05D5
+AAFE46AAFDE3AA017FFE8105D59EFCF0031000030066FFBA05E5061700090013002B009E
+403C1D1F1A0D2B2C130A0100040D292620140D042A261E1A0495260D951A91268C2C2B2C
+2A141710201E23130A0100041D2910071F07192333101917102C10FCECFCECC011123939
+1739123939111239391139310010E4F4EC10EE10C010C011123939123912173912391112
+393930402A57005A15571955216A1565217B15761C7521094613590056136A006413641C
+6A287C007313761C7A280B5D015D09011E01333200113426272E01232200111416170726
+0235100021321617371707161215100021222627072704B6FD333EA15FDC010127793DA1
+5FDCFEFD2727864E4F0179013B82DD57A266AA4E50FE88FEC680DD5BA2670458FCB24043
+0148011A70B8B84043FEB8FEE570BC449E660108A0016201A54D4BBF59C667FEF69EFE9F
+FE5B4B4BBF58000300DD00DD05CF03EE000B0017002F00FF401D2D1B1509210300241804
+150F2721151B0F21300C00241812062A121E3010D4C4D4C41139393939310010D4C4D4C4
+10C01112173912391112393040BE05020503050400050006000705080509050A0A100F11
+0F120F130A1415021503150410051006100715081509150A1A0E1A0F1A101F111F121F13
+1A141A151A1624022403240420052006200724082409240A2A0E2A0F2A102F112F122F13
+2A142A152A1635023503350430053006300735083509350A3A0E3A0F3A103F113F123F13
+3A143A153A1645024503450440054006400745084509450A4A0E4A0F4A104F114F124F13
+4A144A154A1656B41FB020B021B022B026B027B028B429085D015D011E01333236353426
+232206072E01232206151416333236170E01232226353436333216173E01333216151406
+2322260393318654658076595285C4318555667F7659528690469D5E88BAA7865F994844
+9E6186BCA7865E95022F585A8769658687375858846A65868816877FDFA6AFD87E8A8A83
+E1A7AFD67700000200D9000005DB0504000B000F002E401805D007039C00D009010C9C0E
+0D02150400170C08150A061010D43CEC32FC3CEC3231002FECD43CECFC3CEC3001112115
+21112311213521110121152103AE022DFDD3A8FDD3022DFDD30502FAFE0504FE7DAAFE7D
+0183AA0183FBA6AA000200D9000005DB04A80006000A0054402E029C030403019C000104
+0403019C0201050605009C06054205040201000503D106A7079C0901080200240704230B
+10FC3CEC32323931002FECF4EC1739304B53580704ED071008ED071008ED071004ED5922
+0902150135010121152105DBFC4003C0FAFE0502FAFE0502FAFE03F8FEEBFEEEB20170AA
+016FFC02AA00000200D9000005DB04A80006000A0056402F069C0006030403059C040403
+009C010201069C05060202014206050302000504D101A7079C0806070224090400230B10
+FC3C3CEC323931002FECF4EC1739304B5358071008ED071004ED071004ED071008ED5922
+1335011501350101152135D90502FAFE03C10141FAFE03F8B0FE91AAFE90B20112FDC7AA
+AA0000010052000004C305D5001800C6404610021116110F020E0F1616110F02100F080D
+080E020D0D08420F0B090400D31706120BD31409100D81020C090E0305160F0315121003
+001166130065011C0D660A056507031910D43CEC32ECFCEC32EC12173912393911173931
+002FE432D43CEC32D43CEC32111239304B5358071005ED071008ED071008ED071005ED59
+22014BB00C5458BD0019FFC0000100190019004038113738594028860F900FA60FA00FB5
+0F05270C270D270E291028112812370E3910870C8812A60DA50EAA10A9110E5D005D0121
+1123112135213527213521013309013301211521071521048DFE63C9FE6001A054FEB401
+08FEC3BE017B0179BFFEC20108FEB554019F01C7FE3901C77B339B7B024AFD4402BCFDB6
+7B9B3300000100AEFE5604E504600020004D402513191F03160603090C0301120F06871C
+168C0A01BC00BD2119091209080B4E1F020800462110FCEC32F4ECC41239310010E4E432
+F43CECDCC41117391112173930B61F226022CF2203015D13113311141633323635113311
+141633323637150E01232226270E012322262711AEB88A879495B8232509201C29492345
+520F329162668F2AFE56060AFD489194A8A8028DFCA23C390B0C9417164E504F4F4E4EFD
+D70000020068FFE703C1052D001D002900624019002721091B062715060F211B0F15D52A
+0C2403001E1224182A10D4CCDCCC39391139310010E4CCDCCC10CE10CE11123911123930
+014BB00C544BB00B545B4BB00E545B4BB010545B4BB014545B58BD002A00400001002A00
+2AFFC03811373859013E0135342623220623222635343633321211100023222635341233
+321607342623220215141633321202F40F0F494837902424309065B4D6FEDFD598CBDDA2
+65820B574F6D8D56506D8D026D57A34B8183742C1F3E62FECAFEF9FEB1FE46D8A3C60101
+5BE0747DFEFECF747B01040000010019FE77053B05C1000B005D40140A040C0205070200
+070C0A05040301000606080C10D4C41739310010C4D4CC10CE1112393930403051035605
+50055A0A730370037604750570057A0A800380050C5A097F027F03700570067B09740B8F
+028F03800580060B5D015D1321152109012115213509013704EAFC4102A0FD4A03EFFADE
+02D5FD4905C1C1FD33FD04C095032102E3000001009CFE77057105C10007001E400F0602
+D704D600AF080367010567000810D4ECD4EC310010FCECEC323013211123112111239C04
+D5F0FD0AEF05C1F8B6067DF983000001FFE1FFF004AA042F002300CB40310B02151F1E03
+0008DA0F1A1600D922D80FD5180C1E1B1A19181706241201000B020423161505221F120C
+23126805231F2410D4D4D4EC12391112391239391117391112173931002F3CE4F4EC3232
+10EE111739393930014BB00A5458BD0024FFC0000100240024004038113738594056181E
+181F02090009010D020D030F040F050F060F070F080F090F0A0F0B0F0C0F0D0F0E0F0F0F
+100F110F120F130E140D1509160B1708180F180D19081A09231100110116021603171416
+15111617171C181C191123285D005D0123030E0115141633323637070E01232226353436
+37132103231323220607233E0133210487B6690F0F2F37112E251E1E371A7679152250FE
+BAC2B5C329363C09A01C8FA503790391FE194A5C163A3105058D080866642E90A10178FC
+6F03914045A67D000001002FFE8D03FA060E00250026401420DB001A0DDB131ADC07B126
+0A69176A1D69042610DCECFCEC310010FCECDCE410DEE430013213363712123332161514
+062322262726262322030607020223222635343633321617161601376A0E02010CBECA50
+6440372A380C0609106B0E040411BDC44F65443D21300F0A0AFEFA02B06C39020301BC54
+41363F26230F48FD95C16EFE21FE625341383F1D1C1253000003007301D5033B05F00003
+001E0029005F4033280725041F12181002E3001FDD1000E125DD050A19DF18DE15DD0AE0
+1C912A00180D1F10220602012811066B046C18226B0D2A10DCECCCFCEC3232C0C0111239
+39111239310010F4E4FCF4EC10C4EEEDD6EE10EE11123912391139393013211521011123
+35060623222635343633333534262322060735363633321605220615141633323635358B
+02B0FD5002AE952C905D8098BFBCB675753E8844499145B7B3FEECA17E6252688202507B
+02B8FE40703F448771878A045B5B22227F1C1CB0F0434F404D90721D0003006001D50364
+05F00003000F001B002E401902E300E116DD0AE010DD04911C00130D01196B076C136B0D
+1C10DCECFCEC39111239310010F4ECF4ECFCEC3013211521013216151406232226353436
+1722061514163332363534268B02B0FD500158B3CECEB3B3D0D0B3697E7F68697D7C0250
+7B041BDDBFBFDBDCBEBFDD73A18885A0A08589A00001004E000005CF05E7001F00404022
+09E51991120F030300E51001112016130F0C1F06020100026D061C1C0F6D0C1C162010D4
+ECECD4ECECC0C011123911123911123931002F3CEC1732F4EC3025152135361235340023
+2200151412171521352126023510002120001114020705CFFDA8B1C6FEF8D8D8FEF7C7B2
+FDA8013F9E91017F0131012F01818EA1B2B2B261014CCAF00122FEDDEFCAFEB461B2B28B
+012AB8013E018AFE77FECBC2FED88D000003007BFFE3076F047B00060033003E01034043
+272D253D0E0D0034A925168615881200A90E3A12B91C192E862DBA2A03B90EBB07310AB8
+1F198C253F343726060F0025371C07260F1500080D3D26080F2D370822453F10FCECCCD4
+FC3CD4ECC4111239391139111239111239310010C4E432F43CC4E4FC3CF4EC10C4EE3210
+EE10F4EE10EE11391139111239304081302B302C302D302E302F3030402B402C402D402E
+402F4030502B502C502D502E502F5030852B853080409040A040B040C040D040E040E040
+F0401D3F003F063F0D3F0E3F0F05302C302D302E302F402C402D402E402F502C502D502E
+502F6F006F066F0D6F0E6F0F602C602D602E602F702C702D702E702F802C802D802E802F
+1D5D71015D012E0123220607033E013332001D01211E0133323637150E01232226270E01
+232226353436332135342623220607353E013332160322061514163332363D0106B601A5
+8999B90E444AD484E20108FCB20CCCB768C86464D06AA7F84D49D88FBDD2FDFB0102A797
+60B65465BE5A8ED5EFDFAC816F99B9029497B4AE9E01305A5EFEDDFA5ABFC83535AE2A2C
+79777878BBA8BDC0127F8B2E2EAA272760FE18667B6273D9B42900030048FFA2049C04BC
+00090013002B00E4403C2B2C261F1D1A130A0100040D292620140D042A261E1A04B9260D
+B91AB8268C2C2B2C2A141710201E23130A01000410071F1D0712235129101217452C10FC
+EC32F4EC32C011121739123939111239391139310010E4F4EC10EE10C010C01112393912
+3912173911393911123930407028013F2D5914561C551D56206A1566217F007B047F057F
+067F077F087F097F0A7F0B7F0C7B0D7A157B1A7F1B7F1C7F1D7F1E7F1F7F207B217F227F
+237F247F257B269B199525A819A02DF02D2659005613551D5A2869006613651C6A287A00
+7413761C7A28891E95189A24A218AD24115D015D09011E01333236353426272E01232206
+15141617072E01351000333216173717071E011510002322262707270389FE1929674193
+AC145C2A673E97A913147D36360111F15D9F438B5F923536FEEEF060A13F8B600321FDB0
+2A28E8C84F759A2929EBD3486E2E974DC577011401383334A84FB34DC678FEEDFEC73433
+A84E0002008FFFE303AC05D5002000240086402F201A05020406190010860F880C002183
+230C95138C23812506221916090501001A2209001C01221C21260F091C162510DCECD4FC
+ECD4EC1112391112391112391239310010E4F4EC10FECD10F4EE123939173930014BB010
+544BB012545B4BB013545B58BD0025FFC000010025002500403811373859400B74047405
+74067407761C055D01331514060F010E0115141633323637150E012322263534363F013E
+01373E01351323353301F4BE375A5A3A33836D4EB4605EC067B8E04959583026080706C4
+CACA04449C65825758355E31596E4643BC3938C29F4C8956562F3519153C36010EFE0002
+01350000020005D5000300090062400F07008302810408070400030501000A10FC3CEC32
+393931002FF4FCCC30014BB00B5458BD000A00400001000A000AFFC03811373859014BB0
+0F544BB010545B4BB013545B58BD000AFFC00001000A000A00403811373859B6000B200B
+500B035D012335331123111333130200CBCBCB15A21404D7FEFA2B028F0165FE9B000001
+00D9011F05DB035E00050017400A049C020006031701000610DCD4EC310010D4C4EC3013
+2111231121D90502A8FBA6035EFDC10195000001003DFFD70519067D000A002A40180A09
+080706050B020402000B0A090706050403000801080B10D4CC1739310010D4CCC4111217
+39300133152301230107272501045CBD73FDAE42FEC17D19011B0100067D60F9BA03732D
+5062FD3B0001001FFE56050206140023008A40400E0D020F0C11191E190B0A0908040711
+1E1E1942190C130A071E011A0AA908138A12E616A90F018A00E604A921970F1C08241E1D
+1B1A190C0B0908070A00122410D4CC1739310010C432C4FCECF4EC10EEF6EE10EE321239
+3911123939304B5358071005ED1732071005ED1117395922014BB00C5458BD0024FFC000
+01002400240040381137385901152E01232206070321152103020623222627351E013332
+363713233521133E01333216050226502C6072193C011FFEC37F3ABCBA3A642F34612F61
+6D2289F801173F24C697356405F0A41D1C7A84FEC98FFD85FEE3D31516A6212189A602AD
+8F014AB7C312000200D9011005DB03F4001D003B003F401F2E1F392A002D221301101B0C
+1E2A9C31399C22049C1B0C9C133C1E002D0F3C10D43CC432310010D4ECD4ECDCFCD4ECC0
+111239391112393911123939300115060623222726272627262322060735363633321716
+171617163332361315060623222726272627262322060735363633321716171617163332
+3605DB69B3616E920A07060F9B5E58AC6269B3616E930B05060F9B5E56A96769B3616E92
+0A07060F9B5E58AC6269B3616E930A05070F9B5E56A9026FB34E453B040302063D4C54B3
+4E453B050202063D4B01DAB24F453B040302063D4C53B24E453B040203063D4B0002FFFA
+0000056005C1000200060038400F00030103050403020100050705060710D4CC11173931
+002FC4CC113930401463016D02700178027F0279057606076E007F00025D015D09012101
+33012102ACFE5E0344FDEFE00243FA9A04EEFBC4050FFA3F0002009E008D042504230006
+000D0086404903E804050402E8010205050402E8030206000601E80000060AE80B0C0B09
+E808090C0C0B09E80A090D070D08E807070D4209020B04E70700A60E090C05020703006F
+050A076F0C6E0E10FCFC3CD4EC321139111239310010F43CEC323939304B5358071004ED
+071008ED071008ED071004ED071004ED071008ED071008ED071004ED5922011501011501
+35131501011501350425FED3012DFE2B23FED3012DFE2B0423BFFEF4FEF4BF01A25201A2
+BFFEF4FEF4BF01A25200000200C1008D044804230006000D008640490CE80D0C090A090B
+E80A0A090DE80708070CE80B0C08080705E8060502030204E803030206E800010005E804
+05010100420C050A03E70700A60E0C08010500086F0A07016F0300700E10FC3CFCD43CEC
+1239111239310010F43CEC323939304B5358071008ED071004ED071004ED071008ED0710
+08ED071004ED071004ED071008ED59221301150135010125011501350101C101D5FE2B01
+2DFED301B201D5FE2B012DFED30423FE5E52FE5EBF010C010CBFFE5E52FE5EBF010C010C
+000300EC0000071400FE00030007000B00234011080400830A0602041905001901091908
+0C10D4FCD4ECD4EC31002F3C3CEC3232302533152325331523253315230396D4D402A9D5
+D5FAADD5D5FEFEFEFEFEFE00FFFF001000000568076B02270024000000000007010600BC
+0175FFFF001000000568075E02270024000000000007010500BC0175FFFF0073FFE305D9
+075E02270032000000000007010501270175000200730000080C05D500100019003B401F
+059503110195008118079503AD091812100A1506021C1100040815190D101A10FCECD4C4
+C4D4EC32123939393931002FECEC32F4EC3210EE30011521112115211121152120001110
+002117232000111000213307FAFD1A02C7FD3902F8FBD7FE4FFE4101BF01B16781FEBFFE
+C0014001418105D5AAFE46AAFDE3AA017C0170016D017CAAFEE1FEE0FEDFFEDF00030071
+FFE307C3047B0006002700330084403107080010860F880C00A9082E0CB916132803B908
+BB22251FB819138C340600162231090F0008074B311209512B121C453410FCECF4FCF4EC
+C4111239391239310010E432F43CC4E4EC3210C4EE3210EE10F4EE1112393040253F355F
+3570359F35CF35D035F035073F003F063F073F083F09056F006F066F076F086F09055D71
+015D012E01232206070515211E0133323637150E01232226270E01232200111000333216
+173E01333200252206151416333236353426070A02A48999B90E0348FCB20CCCB76AC862
+64D06AA0F25147D18CF1FEEF0111F18CD3424EE88FE20108FAB094ACAB9593ACAC029498
+B3AE9E355ABEC73434AE2A2C6E6D6E6D01390113011401386F6C6B70FEDD87E7C9C9E7E8
+C8C7E9000001000001E90400027900030010B602A900E90401002FC6310010FCEC301121
+15210400FC00027990000001000001E9080002790003000FB502A9000401002FCC310010
+D4EC30112115210800F800027990000200AE03E9036D05D50005000B0027401306009E09
+03810C090A0619070304070019010C10DCFCCCD4CC10FED4CE310010F43CEC3230012335
+1333030523351333030181D3A48152019AD3A4815203E9AD013FFEC1ADAD013FFEC10002
+00AE03E9036D05D50005000B0027401309039E0600810C090A0719060103040119000C10
+DCECD4CC10DCEED4CE310010F43CEC32300133150323132533150323130100D3A4815201
+9AD3A4815205D5ACFEC00140ACACFEC00140000100AE03E901D305D500050018400B009E
+03810603040019010610DCFCD4CC310010F4EC300123351333030181D3A4815203E9AD01
+3FFEC100000100B203FE01D705D500050018400B039E00810603040171000610DCECD4CC
+310010F4EC300133150323130104D3A4815205D598FEC1013F00000300D9009605DB046F
+00030007000B0029401400EA0206EA0402089C040A0C090501720400080C10DCD43CFC3C
+C4310010D4C4FCC410EE10EE3001331523113315230121152102DFF6F6F6F6FDFA0502FA
+FE046FF6FE12F50241AA00020006FE2303EE067500030007002240110206000804060806
+04030201000605070810D4CC1739310010D4CC1139123930090701FAFE7F01810181FE7F
+01F4FE0CFE0C0581FCCFFCC703390425FBDBFBD3042DFFFF003DFE56047F06100227005C
+000000000007008E005E0000FFFFFFFC000004E7074E0227003C00000000000701030073
+01750001FE89FFE302CD05F00003002B4013000F010201020F03000342028C0091040103
+0410D4CC310010E4E4304B5358071005ED071005ED592201330123022DA0FC5CA005F0F9
+F3000002005E005204BC04B20023002F0083404903091B15042D1E00271C02211D0C122D
+140B0A03130F011D2DB913EB0FEC27B91DEB21301E0C0012042A2414301C151B2A1D131C
+180903240B0A0103022428027306742A281C73183010DCE4ECF4E4EC1217391239391112
+393912393911123911121739310010D4E4ECF4E4EC10C011121739123939111239391139
+391217393001371707161615140607170727060623222627072737262635343637273717
+3636333216133426232206151416333236037BCF72CE25242628D172CF3B743D3A783DCF
+71CF25252626CF73CF3774403C755C9B72709E9D71719C03E1D173CE3B773E3F7339CF71
+CF28262525CF73CE3E763A407438CE73CF272524FE7C709A9A70729C9D000001009E008D
+0273042300060047402503E804050402E8010205050402E8030206000601E80006420204
+E700A6070203006F056E0710FCEC3239310010F4EC39304B53580704ED071008ED071008
+ED071004ED5922011501011501350273FED3012DFE2B0423BFFEF4FEF4BF01A252000001
+00C1008D0296042300060049402605E8060502030204E803030206E800010005E8040501
+0100420503E700A60705016F0300700710FC3CEC39310010F4EC39304B5358071008ED07
+1004ED071004ED071008ED592213011501350101C101D5FE2B012DFED30423FE5E52FE5E
+BF010C010C000002002F0000044A061400150019009B40280B14180703A90010870E18BE
+16B10E970900BC0501110E0F04160208000F1404080817000A064C1A10FC3CC432C4FC3C
+C410EE321112393931002F3CE632EEFEEE10EE10EE3212393930014BB00A5458BD001AFF
+C00001001A001A00403811373859014BB00E5458BD001A00400001001A001AFFC0381137
+3859401A101610171018101904301B501B800F8010801BA01BD01BEF1B085D005D011123
+11211123112335333534363B01152322061D0101331523044AB9FE07B9B0B0ADB3B9B063
+4D01F9B9B90460FBA003D1FC2F03D18F4EB7AF9950686301B2E90001002F0000044A0614
+0015008440210813040F0BA909048700971109BC0D0205000A080308010A0C0808100112
+0E4C1610FC3CC4C4FC3CC410EE1112393931002F3CE632FEEE10EE3212393930014BB00A
+5458BD0016FFC000010016001600403811373859014BB00E5458BD001600400001001600
+16FFC03811373859401130175017800A800B8017A017D017EF17085D0121112311212206
+1D01211521112311233533353436024A0200B9FEB7634D012FFED1B9B0B0AE0614F9EC05
+7B5068638FFC2F03D18F4EBBAB0000010039FF3B03C705D50013003E40201206B9001008
+B90A0400020E0A0C8102C2140F0059110D01570905590B07031410D43C3CEC32FC3C3CEC
+32310010E4F4C43210C43210EE3210EE3230252111231121352111213521113311211521
+112103C7FE91B0FE91016FFE91016FB0016FFE91016FDFFE5C01A49A021F9901A4FE5C99
+FDE1000100DB024801AE034600030012B7028300040119000410D4EC310010D4EC301333
+1523DBD3D30346FE000100AEFF1201D300FE00050018400B039E00830603040119000610
+D4ECD4CC310010FCEC302533150323130100D3A48152FEACFEC00140000200AEFF12036D
+00FE0005000B0027401309039E0600830C030401190007090A0719060C10DCECD4CC10DC
+EED4CE310010FC3CEC3230253315032313253315032313029AD3A48152FE66D3A48152FE
+ACFEC00140ACACFEC001400000070071FFE30A4C05F0000B0017002300270033003F004B
+00AE4044240F252625260F272427424000920C2E921E8D289218460692340C8D3A26128C
+2418914C25494327312B430D3D090D0F0E030D15310D1B3D0E490D15372B0D1B0E210B4C
+10FCE4ECD4C4ECE410EE10EEF6EE10EE111239111239310010E432F43C3CE432EC3210EE
+F6EE10EE32304B5358071005ED071005ED5922014BB014544BB009545B4BB00B545B4BB0
+0C545B4BB00D545B4BB00E545B58BD004C00400001004C004CFFC0381137385901220615
+141633323635342627321615140623222635343601321615140623222635343621330123
+132206151416333236353426013216151406232226353436172206151416333236353426
+08F457646457556363559EBABB9DA0BABBF9749EBCBB9F9FB9BA0425A0FC5AA01F566362
+5757636403B29EBABB9DA0BABB9F57636357556363029194848295958283957FDCBBBBDB
+DBBBBCDB02E0DBBBBDDADBBCBADCF9F3058E9582849494848196FD9FDCBBBBDBDBBBBCDB
+7F948482959582839500FFFF001000000568076D02270024000000000007010700BC0175
+FFFF00C90000048B076D022700280000000000070107009E0175FFFF001000000568076B
+02270024000000000007010400BC0175FFFF00C90000048B074E02270028000000000007
+0103009E0175FFFF00C90000048B076B022700280000000000070106009E0175FFFF00A2
+0000021F076B0227002C0000000000070104FF2F0175FFFFFFFE00000260076D0227002C
+0000000000070107FF2F0175FFFF000600000258074E0227002C0000000000070103FF2F
+0175FFFF003B000001BA076B0227002C0000000000070106FF2F0175FFFF0073FFE305D9
+076B02270032000000000007010401270175FFFF0073FFE305D9076D0227003200000000
+0007010701270175FFFF0073FFE305D9076B02270032000000000007010601270175FFFF
+00B2FFE30529076B02270038000000000007010400EE0175FFFF00B2FFE30529076D0227
+0038000000000007010700EE0175FFFF00B2FFE30529076B022700380000000000070106
+00EE0175000100C100000179046000030020B700BF02010800460410FCEC31002FEC3040
+0B1005400550056005700505015D13331123C1B8B80460FBA000000100C104EE033F0666
+00060037400C040502B400B307040275060710DCEC39310010F4EC323930004BB009544B
+B00E545B58BD0007FFC0000100070007004038113738590133132327072301B694F58BB4
+B48B0666FE88F5F5000100B6051D034A0637001B006340240012070E0B040112070F0B04
+12C3190704C3150BED1C0F010E000715561677075608761C10F4ECFCEC11393939393100
+10FC3CFCD43CEC11123911123911123911123930004BB009544BB00C545B58BD001CFFC0
+0001001C001C0040381137385901272E0123220607233E013332161F011E013332363733
+0E0123222601FC3916210D2624027D02665B2640253916210D2624027D02665B2640055A
+371413495287931C21371413495287931C00000100D50562032B05F60003002FB702EF00
+EE0401000410D4CC310010FCEC30004BB009544BB00E545B58BD0004FFC0000100040004
+0040381137385913211521D50256FDAA05F69400000100C7052903390648000D0057400E
+0BF0040700B30E0756080156000E10DCECD4EC310010F43CD4EC30004BB0095458BD000E
+FFC00001000E000E00403811373859004BB00F544BB010545B4BB011545B58BD000E0040
+0001000E000EFFC0381137385913331E0133323637330E01232226C7760B615756600D76
+0A9E91919E06484B4B4A4C8F90900001019A0544026606100003002C400902CE00CD0401
+64000410D4EC310010FCEC30004BB0095458BD0004FFC000010004000400403811373859
+01331523019ACCCC0610CC00000200EE04E103120706000B0017005F401103C115F209C1
+0FF11800560C780656121810D4ECF4EC310010F4ECF4EC30004BB009544BB00C545B58BD
+0018FFC000010018001800403811373859014BB00A544BB00B545B4BB00C545B58BD0018
+FFC000010018001800403811373859013426232206151416333236371406232226353436
+333216029858404157574140587A9F73739F9F73739F05F43F5857404157584073A0A073
+739F9F0000010123FE7502C100000013001F400E09060A0DF306001300102703091410DC
+D4ECD4CC31002FD4FCC41239302116161514062322262735161633323635342627025437
+3678762E572B224A2F3B3C2B2D3E6930595B0C0C83110F302E1E573D000200F004EE03AE
+066600030007004240110602B40400B3080407030005010305070810D4DCD4CC11391112
+39310010F43CEC3230004BB009544BB00E545B58BD0008FFC00001000800080040381137
+3859013303230333032302FCB2F88781AADF890666FE880178FE88000001014CFE7502C1
+000000130020400F0B0E0A07F30EF40001000A0427111410D4ECC4D4CC31002FFCFCC412
+3930213306061514163332363715060623222635343601B8772D2B3736203E1F26441E7A
+73353D581F2E2E0F0F850A0A575D3069000100C104EE033F066600060037400C0300B404
+01B307030575010710DCEC39310010F43CEC3930004BB009544BB00E545B58BD0007FFC0
+000100070007004038113738590103331737330301B6F58BB4B48BF504EE0178F5F5FE88
+0001FFF20000047505D5000D003F401E0C0B0A040302060006950081080304010B0E0004
+05011C0C073A0900790E10F43CECC4FC3CC411123911123931002FE4EC11173930B4300F
+500F02015D1333112517011121152111072737D3CB013950FE7702D7FC5E944DE105D5FD
+98DB6FFEEEFDE3AA023B6A6E9E0000010002000002480614000B005E401A0A0908040302
+06009706030401090A00047A0501080A7A07000C10D43CE4FC3CE411123911123931002F
+EC173930014BB0105458BD000C00400001000C000CFFC038113738594013100D400D500D
+600D73047A0A700DE00DF00D095D133311371707112311072737C7B87D4CC9B87B4AC506
+14FDA65A6A8DFCE3029A586A8D00FFFF0087FFE304A2076D022700360000000000070108
+008B0175FFFF006FFFE303C706660227005600000000000700E000170000FFFF005C0000
+051F076D0227003D000000000007010800BE0175FFFF0058000003DB06660227005D0000
+0000000700E0001B000000020104FEA201AE059800030007001C400D01F50004F5050804
+000506020810DC3CEC32310010D4ECD4EC30011123111311231101AEAAAAAA0198FD0A02
+F60400FD0A02F6000002000A000005BA05D5000C0019006740201009A90B0D9500811295
+0E0B0707011913040F0D161904320A110D1C0800791A10F43CEC32C4F4EC10C417393100
+2FC632EEF6EE10EE32304028201B7F1BB01B039F099F0A9F0B9F0C9F0E9F0F9F109F11BF
+09BF0ABF0BBF0CBF0EBF0FBF10BF11105D015D1321200011100029011123353313112115
+211133200011100021D301A001B10196FE69FE50FE60C9C9CB0150FEB0F30135011FFEE1
+FECB05D5FE97FE80FE7EFE9602BC9001E3FE1D90FDEA0118012E012C011700020071FFE3
+04750614000E00280127405E257B26251E231E247B23231E0F7B231E287B27281E231E26
+2728272524252828272223221F201F2120201F42282726252221201F08231E030F2303B9
+1B09B9158C1B23B1292627120C212018282523221F051E0F060C121251061218452910FC
+ECF4EC113939173912393911123939310010ECC4F4EC10EE12391239121739304B535807
+100EC9071008C9071008C907100EC9071008ED070EED071005ED071008ED5922B23F2A01
+015D407616252B1F28222F232F2429252D262D272A283625462558205821602060216622
+752075217522132523252426262627272836243625462445255A205A21622062217F007F
+017F027A037B097F0A7F0B7F0C7F0D7F0E7F0F7F107F117F127F137F147B157A1B7A1C7F
+1D7F1E762076217822A02AF02A275D005D012E0123220615141633323635342613161215
+140023220035340033321617270527252733172517050346325829A7B9AE9291AE36097E
+72FEE4E6E7FEE50114DD12342A9FFEC1210119B5E47F014D21FED903931110D8C3BCDEDE
+BC7ABC01268FFEE0ADFFFEC90137FFFA01370505B46B635CCC916F616200FFFFFFFC0000
+04E7076B0227003C000000000007010400730175FFFF003DFE56047F06660227005C0000
+00000007008D005E0000000200C90000048D05D5000C0015003D401B0E95090D9502F600
+810B150F090304011219063F0D0A011C00041610FCEC3232FCEC11173931002FF4FCECD4
+EC3040090F171F173F175F1704015D1333113332041514042B0111231311333236353426
+23C9CAFEFB0101FEFFFBFECACAFE8D9A998E05D5FEF8E1DCDCE2FEAE0427FDD192868691
+000200BAFE5604A406140010001C003E401B14B905081AB9000E8C08B801BD03971D1112
+0B471704000802461D10FCEC3232F4EC310010ECE4E4F4C4EC10C6EE304009601E801EA0
+1EE01E04015D2511231133113E0133321211100223222601342623220615141633323601
+73B9B93AB17BCCFFFFCC7BB10238A79292A7A79292A7A8FDAE07BEFDA26461FEBCFEF8FE
+F8FEBC6101EBCBE7E7CBCBE7E700000100D9022D05DB02D700030011B6009C0204010004
+10D4C4310010D4EC3013211521D90502FAFE02D7AA0000010119003F059C04C5000B0085
+404D0A9C0B0A070807099C080807049C0304070706059C060706049C0504010201039C02
+02010B9C0001000A9C090A010100420A080706040201000805030B090C0B0A0907050403
+0108020008060C10D43CCC321739310010D43CCC321739304B5358071008ED071005ED07
+1005ED071008ED071005ED071008ED071005ED071008ED59220902070101270101370101
+059CFE3701C977FE35FE357601C8FE387601CB01CB044CFE35FE377901CBFE357901C901
+CB79FE3501CB00010089029C02C505DF000A002C40180700DD0903DD0402DD09F705910B
+087C065D037C017C000B10DCF4E4FCE4310010F4ECECD4EC10EE32301333110735373311
+3315219CCCDFE689CDFDD7030A0263297427FD2B6E000001005E029C02B405F00018004A
+4024007D060400177D060604420402000EDD0F00DD02F70BDD0F129119000E087E01150E
+031910DCC4D4C4EC1139310010F4C4ECFCEC10EE111239304B5358071005ED17320705ED
+592201211521353637003534262322060735363633321615140106010C01A8FDAA223F01
+586855347A484D853991AEFEB538030E726E1F3801315E425123237B1C1C846C8BFEE430
+00010062028D02CD05F00028004840270015130ADD091FDD2013DD150DDD09F806F71CDD
+20F823912916130014197E26107E03141F092910DCC4C4D4ECD4EC11393939310010F4E4
+ECFCE4ECD4EC10EE10EE1112393001161615140623222627351616333236353426232335
+33323635342623220607353636333216151406020C5C65BEB1397D463477436D786F6C56
+5E5E61645F28665149803790A95A0460126D527C861514791B1A4F464A4C6C3F3C3A3D12
+1773111276634560FFFF0089FFE3077F05F0002700F000000000002700BC033500000007
+0109048BFD64FFFF0089FFE3073F05F0002700F000000000002700BC03350000000700F1
+048BFD64FFFF0062FFE3077F05F0002700F200000000002700BC0335000000070109048B
+FD64FFFF0073FFE3058B076D0227002A000000000007010A011B0175FFFF0071FE56045A
+06480227004A00000000000700DA008B0000FFFF00C90000019507500227002C00000000
+0007010BFF2F0175FFFF0087FE7504A205F00227003600000000000700DD008B0000FFFF
+006FFE7503C7047B0227005600000000000700DD00170000FFFF0073FFE30527076B0227
+00260000000000070104012D0175FFFF0071FFE303E7066602270046000000000007008D
+00890000FFFF0073FFE30527076D022700260000000000070108012D0175FFFF0071FFE3
+03E706660227004600000000000700E00089000000020071FFE304F4061400180024004A
+40240703D30901F922B900161CB90D108C16B805970B021F0C04030008080A0647191213
+452510FCECF43CC4FC173CC431002FECE4F4C4EC10C4EEFD3CEE3230B660268026A02603
+015D01112135213533153315231123350E01232202111012333216011416333236353426
+23220603A2FEBA0146B89A9AB83AB17CCBFFFFCB7CB1FDC7A79292A8A89292A703B6014E
+7D93937DFAFCA86461014401080108014461FE15CBE7E7CBCBE7E7000001006401DF027F
+028300030011B6009C020401000410DCCC310010D4EC301321152164021BFDE50283A400
+000100DB024801AE034600030012B7028300040119000410D4EC310010D4EC3013331523
+DBD3D30346FE00010000FFE3048F05F00031011C403A2012D322102B07D30919A11AAE16
+951D01A100AE04952F911D8C2909322B222129232612100A030D0911082C202613071108
+110D1C1900262A212F3CD4C432FCC4C41239391239391112391117391239391139393100
+10C432E4F4ECF4EC10EEF6EE10EE32DD3CEE3230014BB009544BB00C545B4BB00D545B4B
+B00F545B4BB017545B4BB018545B58BD0032FFC000010032003200403811373859407A0E
+000E010B020B315414690C6C0E6E0F6F106F116F126F1369146B1F6F206F216F226F236E
+246C256927692D9F079F089F099F0A9F0B9F0C9F0D9F0E9F0F9F109F119F129F13961F9F
+209F219F229F239F249F259F269F279F289F299F2A9F2B9F2C9D2D320008000910081009
+200820095515531E6A15671F0A5D005D01152E01232206072107210E0115141617210721
+1E0133323637150E01232200032337333426353436352337331200333216048F5BA9669D
+CA20024137FDE60201010201BE38FE8A20CA9D66A95B59B960EDFECB28D3378B0101C237
+9C280136EC62B90562D5695AC8BB7B182E23202E187BBBCA5A69D34848012201037B172F
+20232F177B0101012247000200D7050E032905D90003000700A5400D0400CE0602080164
+000564040810D4FCDCEC310010D43CEC3230004BB00E544BB011545B58BD000800400001
+00080008FFC03811373859014BB00E544BB00D545B4BB017545B58BD0008FFC000010008
+000800403811373859014BB011544BB019545B58BD00080040000100080008FFC0381137
+3859004BB0185458BD0008FFC00001000800080040381137385940116001600260056006
+700170027005700608015D0133152325331523025ECBCBFE79CBCB05D9CBCBCB00010173
+04EE02F005F60003007F40110203000301000003420002FA040103030410C410C0310010
+F4CC304B5358071005C9071005C95922004BB00C5458BD0004FFC0000100040004004038
+11373859004BB00E5458BD00040040000100040004FFC038113738594020060215022501
+25023602460256026A016702090F000F011F001F012F002F01065D015D013303230237B9
+E49905F6FEF8000100B6050E034A05E9001D0075402116100F03130C0701000308170CC3
+0413C31B08FA1E10010F00071656180756091E10D4ECD4EC1139393939310010F43CECD4
+EC321217391112173930004BB00C5458BD001EFFC00001001E001E00403811373859004B
+B00E5458BD001E00400001001E001EFFC03811373859B4100B1F1A025D01272E01232206
+1D012334363332161F011E013332363D01330E0123222601FC39191F0C24287D6756243D
+303917220F20287D026754223B0539210E0B322D066576101B1E0D0C3329066477100001
+010C04EE028B05F60003008940110102030200030302420001FA040103030410C410C031
+0010F4CC304B5358071005C9071005C95922004BB00C5458BD0004FFC000010004000400
+403811373859004BB00E5458BD00040040000100040004FFC03811373859402A06000601
+160012012400240135014301550055019F009F01AF00AF010E0F000F031F001F032F002F
+03065D015D0113230301C7C499E605F6FEF80108000100CF04EE033105F800060077400A
+04000502FA070402060710D4C439310010F43CC43930004BB00C5458BD0007FFC0000100
+07000700403811373859004BB00E5458BD00070040000100070007FFC03811373859014B
+B00E5458BD0007FFC00001000700070040381137385940130F000F010C041F001F011D04
+2F002F012D0409005D0133132327072301A2BCD38BA6A68B05F8FEF6B2B2000100CF04EE
+033105F800060086400A03040100FA070305010710D4C439310010F4C4323930004BB00C
+544BB009545B4BB00A545B4BB00B545B58BD0007FFC00001000700070040381137385900
+4BB00E5458BD00070040000100070007FFC03811373859014BB00E5458BD0007FFC00001
+0007000700403811373859401300000303000610001203100620002203200609005D0103
+331737330301A2D38BA6A68BD304EE010AB2B2FEF6000002003F029C02F405DF0002000D
+00D4401600030B07DD050109F703910E010C0A005D0608040C0E10DCD43CC4EC32113931
+0010F4FCD43CEC32123930014BB00E544BB00F545B4BB010545B4BB011545B4BB00B545B
+4BB00A545B58BD000E00400001000E000EFFC03811373859004BB011544BB00E545B58BD
+000EFFC00001000E000E0040381137385940540B011D012F01390149014603590369038B
+03AB03BB030B01000F010F020F050F060F070F080F0B0F0C0F0D13001F011F021F051F06
+1F071F081F0B1F0C1F0D2200350047004B0D53005B0D65008400A500B5001E5D015D0901
+21033311331523152335213501DDFECB013516A6878790FE620566FE5D021CFDE46DBABA
+7900000100C70506033905F8000D006A400E070004C30BFA0E0756080156000E10D4ECD4
+EC310010F4FCC43230004BB00C5458BD000EFFC00001000E000E00403811373859004BB0
+0E5458BD000E00400001000E000EFFC03811373859014BB00E544BB00F545B58BD000EFF
+C00001000E000E0040381137385913331E0133323637330E01232226C7760D6353526110
+760AA08F909F05F836393738777B7A000001019A050E026605DB00030011B60002FA0401
+000410D4CC310010F4CC3001331523019ACCCC05DBCD0000000000020001000000000014
+000300010000011A00000106000001000000000000000103000000020000000000000000
+00000000000000010000030405060708090A0B0C0D0E0F101112131415161718191A1B1C
+1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F40
+4142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F6061006263
+6465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F8081828384858687
+88898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAAB
+ACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF
+D0D100D2D3D4D5D6D7D8D9DADBDCDDDEDFE00004023E0000003A00200004001A007E00FF
+01070111011F01310142015301610178017E019202C702DD03A903C020262030203A20AC
+21222206221E222B2248226525CAFB02FFFF0000002000A00106010C011E013001410152
+015E0178017D019202C602D803A903C020132030203920AC21222202220F222B22482260
+25CAFB01FFFFFFE30000FFF50000FFD80000FFA0FF5E0000FF43FF68FF1400000000FCF6
+FCDB0000E096E085E056DF6A00000000DE71DE5F0000DAEF05BF000100000038000000F4
+000000FC0000000000FA00000000000000FA00FC00000000010200000000000000000120
+012800000000014200000000000000AC00A30084008500BD009600E70086008E008B009D
+00A900A40100008A00D90083009300F100F2008D0097008800C300DD00F0009E00AA00F3
+00F400F500A200AD00C900C700AE006200630090006400CB006500C800CA00CF00CC00CD
+00CE00E8006600D200D000D100AF006700EF009100D500D300D4006800EA00EC0089006A
+0069006B006D006C006E00A0006F0071007000720073007500740076007700E90078007A
+0079007B007D007C00B800A1007F007E0080008100EB00ED00BA00FD00FE000000000000
+00FF00F800D600F900FA00E300E400D700E000DA00DB00DC00DF00D800DE00B200B30000
+0000000000B600B700C4000000B400B500C50000008200C2008700000000000000AB0098
+00000000000000A8009A0000009900EE0000000000BC000000000000010100A500000000
+00000092008F0000000000000094009504CD006600000000028B0000028B000003350135
+03AE00C506B4009E051700AA079A0071063D0081023300C5031F00B0031F00A40400003D
+06B400D9028B009E02E30064028B00DB02B2000005170087051700E1051700960517009C
+051700640517009E0517008F051700A80517008B0517008102B200F002B2009E06B400D9
+06B400D906B400D9043F00930800008705790010057D00C905960073062900C9050E00C9
+049A00C906330073060400C9025C00C9025CFF96053F00C9047500C906E700C905FC00C9
+064C007304D300C9064C0073058F00C90514008704E3FFFA05DB00B20579001007E90044
+057B003D04E3FFFC057B005C031F00B002B20000031F00C706B400D90400FFEC040000AA
+04E7007B051400BA046600710514007104EC007102D1002F05140071051200BA023900C1
+0239FFDB04A200BA023900C107CB00BA051200BA04E50071051400BA05140071034A00BA
+042B006F03230037051200AE04BC003D068B005604BC003B04BC003D0433005805170100
+02B201040517010006B400D9057900100579001005960073050E00C905FC00C9064C0073
+05DB00B204E7007B04E7007B04E7007B04E7007B04E7007B04E7007B0466007104EC0071
+04EC007104EC007104EC0071023900900239FFC70239FFDE0239FFF4051200BA04E50071
+04E5007104E5007104E5007104E50071051200AE051200AE051200AE051200AE04000039
+040000C3051700AC051700810400005C04B801330517009E050A00BA0800011B0800011B
+0800012704000173040000D706B400D907CB0008064C006606AA00DD06B400D906B400D9
+06B400D905170052051700AE0423006805640019060E009C04B6FFE1042B002F03C50073
+03C50060061D004E07DB007B04E50048043F008F0335013506B400D90519003D0517001F
+06B400D9055AFFFA04E5009E04E500C1080000EC051700000579001005790010064C0073
+088F0073082F00710400000008000000042500AE042500AE028B00AE028B00B206B400D9
+03F4000604BC003D04E3FFFC0156FE890517005E0333009E033300C1050A002F050A002F
+04000039028B00DB028B00AE042500AE0ABC007105790010050E00C905790010050E00C9
+050E00C9025C00A2025CFFFE025C0006025C003B064C0073064C0073064C007305DB00B2
+05DB00B205DB00B2023900C1040000C1040000B6040000D5040000C70400019A040000EE
+04000123040000F00400014C040000C1047FFFF20246000205140087042B006F057B005C
+0433005802B201040633000A04E5007104E3FFFC04BC003D04D700C9051400BA06B400D9
+06B40119033500890335005E0335006207C1008907C1008907C100620633007305140071
+025C00C905140087042B006F059600730466007105960073046600710514007102E30064
+028B00DB05170000040000D704000173040000B60400010C040000CF040000CF0335003F
+040000C70400019A0002000000000000FF2B008F00000000000000000000000000000000
+00000000010C0000000100020003000400050006000700080009000A000B000C000D000E
+000F0010001100120013001400150016001700180019001A001B001C001D001E001F0020
+002100220023002400250026002700280029002A002B002C002D002E002F003000310032
+0033003400350036003700380039003A003B003C003D003E003F00400041004200430044
+00450046004700480049004A004B004C004D004E004F0050005100520053005400550056
+005700580059005A005B005C005D005E005F006000610062006300640065006600670068
+0069006A006B006C006D006E006F0070007100720073007400750076007700780079007A
+007B007C007D007E007F0080008100820083008400850086008700880089008A008B008C
+008D008E008F0090009100920093009400950096009700980099009A009B009C009D009E
+009F00A000A100A200A300A400A500A600A700A800A900AA00AB00AC00AD00AE00AF00B0
+00B100B200B300B400B500B600B700B800B900BA00BB00BC00BD00BE00BF00C000C100C2
+00C300C400C500C600C700C800C900CA00CB00CC00CD00CE00CF00D000D100D300D400D5
+00D600D700D800D900DA00DB00DC00DD00DE00DF00E000E100E200E300E400E500E600E7
+00E800E900EA00EB00EC00ED00EE00EF00F000F100F200F300F500F400F600F800F900FA
+00FB00FC00FD00FE00FF0100010101020103010401050106010701080109010A010B010C
+010D0973667468797068656E0E706572696F6463656E7465726564044575726F05633634
+353905633634363005633634363105633634363205633634363305633634363605633634
+36370563363436380563363436390000000000220022002200220058009300FF01B6024F
+038303B203F60421046E049804B404CA04DE0503054505820605067E06E1074C07B707FC
+086508CF08EE09160952097309AE0A1F0ADF0B580BB00BFB0C3A0C690C930CE60D140D3D
+0D7A0E0D0E2F0EAC0F000F450F850FEB107510F11129117011E012BD138A13EB1450148B
+14B114E115031518154015D61622166D16B91723177B17DF181B1843188018F819161977
+19B31A041A521AA11AD81B871BC41C001C9D1DBA1E871F771FE8205B207220F321352142
+21E221EF21FC2209221622232230223D224A225722642271227E228B229822A522B222BF
+22CC22D922E622F32300230D231A232723342341234E235B2368239423CF2434248F2533
+25532581261426BA274B279027B72813285828C3295F2A252A5C2AA32AE92B7A2BD32C44
+2C8F2CB12D502DA02E0E2E522EAA2F87304130BD31053121315031CF3248327A32DF3346
+33703370337D338A339733E6347A348F34A334D134FF351C353935673591359E35AB35CF
+365B369336CD374337A937EB3800381C384A390F391C3929393639433950395D396A3977
+39843991399E39AB39B839C539D239EF3A1C3A7B3AA03AE53B083B5E3B8E3BC43BF43C22
+3C5F3CA73CB43CC13CCE3CDB3CFE3D633E3B3E483E553E983EE73EFD3F613F8D3FDC403A
+404B405C406D407A4087409440A140AE40BB40C840D540E241404156416B424542AA42F7
+435F43B243FF445544DB452A453F00000000000100002D86000107941800000A15780010
+0024FFD300100025FFB70010002600000010002700000010002900000010002A004B0010
+002B00000010002D00720010002E00000010002F00000010003200390010003300000010
+0034004B00100035000000100037FF4400100039FF880010003AFFAD0010003BFF9A0010
+003CFF0D0010003D00000010004900000010005100000010005200260010005500000010
+0059FFC90010005A00000010005CFFDC00100062FFD30010006400000010006700390010
+007800000010007900260010007A00260010007B00260010007C00260010007D00260010
+00890000001000900000001000ADFFD3001000AEFFD3001000AF0039001000BAFFDC0010
+00BBFF0D001000C7FFD3001000C9FFD3001000D00039001000D10039001000D200390010
+00E50000001000E90000001000EAFF0D001000EBFFDC001000EC0000001000F6004B0010
+00FB0000001000FD000000240010FFD300240011FFDC0024001DFFDC0024002400390024
+0026FFDC0024002AFFDC00240032FFDC00240034FFDC00240036000000240037FF610024
+0038000000240039FF7D0024003AFF900024003B00000024003CFF6100240046FFDC0024
+0047FFDC00240048FFDC00240049FFB700240052FFDC00240054FFDC00240057FFDC0024
+0058000000240059FF880024005AFFAD0024005CFF7500240062003900240064FFDC0024
+0067FFDC0024006800000024006FFFDC00240070FFDC00240071FFDC00240072FFDC0024
+0073FFDC00240079FFDC0024007AFFDC0024007BFFDC0024007CFFDC0024007DFFDC0024
+007E00000024007F0000002400800000002400810000002400A9FFB7002400AA00000024
+00AD0039002400AE0039002400AFFFDC002400B4FEF8002400B5FF03002400BAFF750024
+00BBFF61002400C5002F002400C70039002400C90039002400D0FFDC002400D1FFDC0024
+00D2FFDC002400D30000002400D40000002400D50000002400E30000002400EAFF610024
+00EBFF75002400F6FFDC002400F90000002400FBFFDC002400FCFFDC002400FDFFDC0024
+00FEFFDC00250010000000250026FFDC0025002AFFDC00250032FFDC00250036FFDC0025
+0039FFC10025003AFFB70025003CFF9000250064FFDC00250067FFDC002500A9FFC10025
+00AAFFDC002500AFFFDC002500B4FF90002500B5FF90002500BBFF90002500C5FFAD0025
+00D0FFDC002500D1FFDC002500D2FFDC002500E3FFDC002500EAFF90002500F6FFDC0025
+00F9FFDC002500FBFFDC002500FDFFDC0026001000000026002400000026003600000026
+003CFFDC002600620000002600A9FFDC002600AAFFDC002600AD0000002600AE00000026
+00B40000002600B50026002600BBFFDC002600C50000002600C70000002600C900000026
+00E30000002600EAFFDC002600F9000000270010000000270024FFDC00270039FFDC0027
+003A00000027003CFF9000270062FFDC002700A9FFDC002700AAFFDC002700ADFFDC0027
+00AEFFDC002700B4FFD3002700B5FFC9002700BBFF90002700C5FF44002700C7FFDC0027
+00C9FFDC002700EAFF9000290010000000290011FEB70029001DFF6100290024FF440029
+0036FFDC00290037FFDC00290044FF4400290048FF900029004CFF6B00290052FFB70029
+0055FF6B00290058FF900029005CFF4400290062FF4400290069FF440029006AFF440029
+006BFF440029006CFF440029006DFF440029006EFF4400290070FF9000290071FF900029
+0072FF9000290073FF9000290079FFB70029007AFFB70029007BFFB70029007CFFB70029
+007DFFB70029007EFF900029007FFF9000290080FF9000290081FF90002900A900000029
+00AA0000002900ADFF44002900AEFF44002900B4FFD3002900B50000002900BAFF440029
+00C5FE88002900C7FF44002900C9FF44002900E3FFDC002900EBFF44002900F9FFDC002A
+00100000002A00240000002A0037FFB7002A003A0000002A003CFF9A002A00620000002A
+00A9FFDC002A00AAFFDC002A00AD0000002A00AE0000002A00B4FFD3002A00B5FFD3002A
+00BBFF9A002A00C5FFC9002A00C70000002A00C90000002A00EAFF9A002B00100000002B
+0011FFDC002B001D0000002B00A90000002B00AA0000002B00B4FFB7002B00B5FFC1002B
+00C5FFB7002D0010FFB7002D0024FFDC002D0062FFDC002D00A9FFDC002D00AAFFDC002D
+00ADFFDC002D00AEFFDC002D00B4FFB7002D00B5FFC1002D00C5FF90002D00C7FFDC002D
+00C9FFDC002E0010FF29002E0024FFDC002E0026FF90002E0032FF90002E0037FF61002E
+0038FFC9002E003AFFB7002E003CFFB7002E0044FFDC002E0048FF9A002E0052FF9A002E
+0058FF9A002E005CFF6B002E0062FFDC002E0064FF90002E0067FF90002E0068FFC9002E
+0069FFDC002E006AFFDC002E006BFFDC002E006CFFDC002E006DFFDC002E006EFFDC002E
+0070FF9A002E0071FF9A002E0072FF9A002E0073FF9A002E0079FF9A002E007AFF9A002E
+007BFF9A002E007CFF9A002E007DFF9A002E007EFF9A002E007FFF9A002E0080FF9A002E
+0081FF9A002E00A9FF7D002E00AA0000002E00ADFFDC002E00AEFFDC002E00AFFF90002E
+00B4FFC1002E00B5FFC1002E00BAFF6B002E00BBFFB7002E00C50000002E00C7FFDC002E
+00C9FFDC002E00D0FF90002E00D1FF90002E00D2FF90002E00D3FFC9002E00D4FFC9002E
+00D5FFC9002E00EAFFB7002E00EBFF6B002E00FBFF90002E00FDFF90002F0010FFDC002F
+0024002F002F0032FFB7002F0037FEE6002F0038FF9A002F0039FF1F002F003AFF44002F
+003CFEF0002F00440000002F0048FFDC002F0052FFDC002F0058FFDC002F005CFF44002F
+0062002F002F0067FFB7002F0068FF9A002F00690000002F006A0000002F006B0000002F
+006C0000002F006D0000002F006E0000002F0070FFDC002F0071FFDC002F0072FFDC002F
+0073FFDC002F0079FFDC002F007AFFDC002F007BFFDC002F007CFFDC002F007DFFDC002F
+007EFFDC002F007FFFDC002F0080FFDC002F0081FFDC002F00A90000002F00AA0000002F
+00AD002F002F00AE002F002F00AFFFB7002F00B4FE61002F00B5FDE6002F00BAFF44002F
+00BBFEF0002F00C50000002F00C7002F002F00C9002F002F00D0FFB7002F00D1FFB7002F
+00D2FFB7002F00D3FF9A002F00D4FF9A002F00D5FF9A002F00EAFEF0002F00EBFF440032
+0010003900320011FFAD0032001DFFDC00320024FFDC00320039FFDC0032003BFF7D0032
+003CFF9000320062FFDC003200A9FFDC003200AA0000003200ADFFDC003200AEFFDC0032
+00B4FFD3003200B5FFDC003200BBFF90003200C5FF44003200C7FFDC003200C9FFDC0032
+00EAFF9000330010FFD300330011FEC10033001D000000330024FF7D0033003800000033
+003A00000033003CFFD300330044FFA400330048FFB70033004CFFD300330051FFDC0033
+0052FFB700330055FFDC00330056FFDC00330058FFDC0033005C000000330062FF7D0033
+0068000000330069FFA40033006AFFA40033006BFFA40033006CFFA40033006DFFA40033
+006EFFA400330070FFB700330071FFB700330072FFB700330073FFB700330078FFDC0033
+0079FFB70033007AFFB70033007BFFB70033007CFFB70033007DFFB70033007EFFDC0033
+007FFFDC00330080FFDC00330081FFDC003300A9FFDC003300AA0000003300ADFF7D0033
+00AEFF7D003300B40026003300B50026003300BA0000003300BBFFD3003300C5FEB70033
+00C7FF7D003300C9FF7D003300D30000003300D40000003300D50000003300E4FFDC0033
+00EAFFD3003300EB0000003300FAFFDC003400100039003400A90000003400AA00000034
+00B4FFD3003400B5FFDC003400C5FF7D00350010FFAD00350011FFB70035001DFFC10035
+0024FFAD00350026FF9A00350037FF6B00350039FF900035003AFFAD0035003CFF7D0035
+0044FFD300350048FFA400350052FFA400350058FFA40035005CFF9000350062FFAD0035
+0064FF9A00350069FFD30035006AFFD30035006BFFD30035006CFFD30035006DFFD30035
+006EFFD300350070FFA400350071FFA400350072FFA400350073FFA400350079FFA40035
+007AFFA40035007BFFA40035007CFFA40035007DFFA40035007EFFA40035007FFFA40035
+0080FFA400350081FFA4003500A9FF90003500AAFFDC003500ADFFAD003500AEFFAD0035
+00B4FF6B003500B5FF7D003500BAFF90003500BBFF7D003500C5FFDC003500C7FFAD0035
+00C9FFAD003500EAFF7D003500EBFF90003500FBFF9A003500FDFF9A0036002400260036
+002600000036002A00000036003200000036003400000036003600000036006200260036
+00640000003600670000003600AD0026003600AE0026003600AF0000003600C700260036
+00C90026003600D00000003600D10000003600D20000003600E30000003600F600000036
+00F90000003600FB0000003600FD000000370010FF4400370011FF0D0037001DFF1F0037
+0024FF6100370026FF8800370037FFDC00370044FEAD00370046FEA400370048FEA40037
+004CFFC100370052FEA400370055FED300370056FEAD00370058FEC90037005AFEAD0037
+005CFEC100370062FF6100370064FF8800370069FEAD0037006AFEAD0037006BFEAD0037
+006CFEAD0037006DFEAD0037006EFEAD0037006FFEA400370070FEA400370071FEA40037
+0072FEA400370073FEA400370079FEA40037007AFEA40037007BFEA40037007CFEA40037
+007DFEA40037007EFEC90037007FFEC900370080FEC900370081FEC9003700A9FF440037
+00AAFF90003700ADFF61003700AEFF61003700B40000003700B5FFD3003700BAFEC10037
+00C5FEF8003700C7FF61003700C9FF61003700E4FEAD003700EBFEC1003700FAFEAD0037
+00FBFF88003700FCFEA4003700FDFF88003700FEFEA40038002400000038002D00000038
+003DFFDC003800620000003800AD0000003800AE0000003800C70000003800C900000038
+00E5FFDC00390010FF8800390011FEF80039001DFF5900390024FF7D00390032FFDC0039
+0044FF6100390048FF610039004CFFD300390052FF6100390058FF750039005CFFC90039
+0062FF7D00390067FFDC00390069FF610039006AFF610039006BFF610039006CFF610039
+006DFF610039006EFF6100390070FF6100390071FF6100390072FF6100390073FF610039
+0079FF610039007AFF610039007BFF610039007CFF610039007DFF610039007EFF750039
+007FFF7500390080FF7500390081FF75003900A9FF4E003900AAFF90003900ADFF7D0039
+00AEFF7D003900AFFFDC003900B40000003900B50000003900BAFFC9003900C5FEE60039
+00C7FF7D003900C9FF7D003900D0FFDC003900D1FFDC003900D2FFDC003900EBFFC9003A
+0010FFAD003A0011FF15003A001DFF88003A0024FF90003A0044FF7D003A0048FF88003A
+004CFFD3003A0052FF88003A0055FFA4003A0058FFB7003A005CFFDC003A0062FF90003A
+0069FF7D003A006AFF7D003A006BFF7D003A006CFF7D003A006DFF7D003A006EFF7D003A
+0070FF88003A0071FF88003A0072FF88003A0073FF88003A0079FF88003A007AFF88003A
+007BFF88003A007CFF88003A007DFF88003A007EFFB7003A007FFFB7003A0080FFB7003A
+0081FFB7003A00A9FF90003A00AAFFDC003A00ADFF90003A00AEFF90003A00B4FFDC003A
+00B50000003A00BAFFDC003A00C5FEF8003A00C7FF90003A00C9FF90003A00EBFFDC003B
+0010FF9A003B00240000003B0026FF6B003B0032FF7D003B0037FFDC003B0048FFA4003B
+00620000003B0064FF6B003B0067FF7D003B0070FFA4003B0071FFA4003B0072FFA4003B
+0073FFA4003B00A9FF90003B00AA0000003B00AD0000003B00AE0000003B00AFFF7D003B
+00B4FF61003B00B5FFAD003B00C5FFD3003B00C70000003B00C90000003B00D0FF7D003B
+00D1FF7D003B00D2FF7D003B00FBFF6B003B00FDFF6B003C0010FF0D003C0011FE61003C
+001DFEF0003C0024FF61003C0026FF90003C0032FF90003C0044FEE6003C0048FEF0003C
+004CFFB7003C0052FEF0003C0058FF15003C0062FF61003C0064FF90003C0067FF90003C
+0069FEE6003C006AFEE6003C006BFEE6003C006CFEE6003C006DFEE6003C006EFEE6003C
+0070FEF0003C0071FEF0003C0072FEF0003C0073FEF0003C0079FEF0003C007AFEF0003C
+007BFEF0003C007CFEF0003C007DFEF0003C007EFF15003C007FFF15003C0080FF15003C
+0081FF15003C00A9FF1F003C00AAFF6B003C00ADFF61003C00AEFF61003C00AFFF90003C
+00B4FF90003C00B5FFDC003C00C5FEF8003C00C7FF61003C00C9FF61003C00D0FF90003C
+00D1FF90003C00D2FF90003C00FBFF90003C00FDFF90003D0010FFDC003D00A90000003D
+00AA0000003D00B4FFDC003D00B5FFDC003D00C5FFDC0048005BFFDC00490010FF900049
+0011FF6B0049001DFFB700490057FFDC0049005AFFDC0049005CFFDC004900A9FFB70049
+00AAFFDC004900B40041004900B50000004900BAFFDC004900C5FF15004900EBFFDC004E
+0044FFDC004E0048FFB7004E0052FFB7004E0058FFC1004E005CFFB7004E0069FFDC004E
+006AFFDC004E006BFFDC004E006CFFDC004E006DFFDC004E006EFFDC004E0070FFB7004E
+0071FFB7004E0072FFB7004E0073FFB7004E0079FFB7004E007AFFB7004E007BFFB7004E
+007CFFB7004E007DFFB7004E007EFFC1004E007FFFC1004E0080FFC1004E0081FFC1004E
+00BAFFB7004E00EBFFB70051001000000051001100000051001D0000005100A900000051
+00AA0000005100B4FF6B005100B5FF90005100C5FFA400520010002600520011FFDC0052
+001D00000052005BFFC1005200A90000005200AA0000005200B4FF6B005200B5FFB70052
+00C5FF7D00550010FF7D00550011FF440055001DFFDC00550046FFD300550047FFDC0055
+0048FFD30055004900000055004AFFDC0055004BFFDC00550050FFDC00550051FFDC0055
+0052FFD300550054FFDC00550055FFDC0055005800000055005900000055005A00000055
+005BFFC90055005C00000055005D00000055006FFFD300550070FFD300550071FFD30055
+0072FFD300550073FFD300550078FFDC00550079FFD30055007AFFD30055007BFFD30055
+007CFFD30055007DFFD30055007E00000055007F00000055008000000055008100000055
+00A9FFB7005500AA0000005500B40000005500B50056005500BA0000005500C5FEC90055
+00E60000005500EB0000005500F7FFDC005500FCFFD3005500FEFFD300590010FFC90059
+0011FF610059001DFF90005900A9FFDC005900AAFFDC005900B40000005900B5FFDC0059
+00C5FEF0005A00100000005A0011FF44005A001DFF90005A00A9FFDC005A00AAFFDC005A
+00B40000005A00B50000005A00C5FF29005B0046FFDC005B0048FFC1005B0052FFC1005B
+006FFFDC005B0070FFC1005B0071FFC1005B0072FFC1005B0073FFC1005B0079FFC1005B
+007AFFC1005B007BFFC1005B007CFFC1005B007DFFC1005B00FCFFDC005B00FEFFDC005C
+0010FFDC005C0011FEDC005C001DFF6B005C00A9FFDC005C00AAFFDC005C00B40000005C
+00B50000005C00C5FED300620010FFD300620011FFDC0062001DFFDC0062002400390062
+0026FFDC0062002AFFDC00620032FFDC00620034FFDC00620036000000620037FF610062
+0038000000620039FF7D0062003AFF900062003B00000062003CFF6100620046FFDC0062
+0047FFDC00620048FFDC00620049FFB700620052FFDC00620054FFDC00620057FFDC0062
+0058000000620059FF880062005AFFAD0062005CFF7500620062003900620064FFDC0062
+0067FFDC0062006800000062006FFFDC00620070FFDC00620071FFDC00620072FFDC0062
+0073FFDC00620079FFDC0062007AFFDC0062007BFFDC0062007CFFDC0062007DFFDC0062
+007E00000062007F0000006200800000006200810000006200A9FFB7006200AA00000062
+00AD0039006200AE0039006200AFFFDC006200B4FEF8006200B5FF03006200BAFF750062
+00BBFF61006200C5002F006200C70039006200C90039006200D0FFDC006200D1FFDC0062
+00D2FFDC006200D30000006200D40000006200D50000006200E30000006200EAFF610062
+00EBFF75006200F6FFDC006200F90000006200FBFFDC006200FCFFDC006200FDFFDC0062
+00FEFFDC0064001000000064002400000064003600000064003CFFDC0064006200000064
+00A9FFDC006400AAFFDC006400AD0000006400AE0000006400B40000006400B500260064
+00BBFFDC006400C50000006400C70000006400C90000006400E30000006400EAFFDC0064
+00F9000000670010003900670011FFAD0067001DFFDC00670024FFDC00670039FFDC0067
+003BFF7D0067003CFF9000670062FFDC006700A9FFDC006700AA0000006700ADFFDC0067
+00AEFFDC006700B4FFD3006700B5FFDC006700BBFF90006700C5FF44006700C7FFDC0067
+00C9FFDC006700EAFF900068002400000068002D00000068003DFFDC0068006200000068
+00AD0000006800AE0000006800C70000006800C90000006800E5FFDC0070005BFFDC0071
+005BFFDC0072005BFFDC0073005BFFDC0078001000000078001100000078001D00000078
+00A90000007800AA0000007800B4FF6B007800B5FF90007800C5FFA40079001000260079
+0011FFDC0079001D00000079005BFFC1007900A90000007900AA0000007900B4FF6B0079
+00B5FFB7007900C5FF7D007A00100026007A0011FFDC007A001D0000007A005BFFC1007A
+00A90000007A00AA0000007A00B4FF6B007A00B5FFB7007A00C5FF7D007B00100026007B
+0011FFDC007B001D0000007B005BFFC1007B00A90000007B00AA0000007B00B4FF6B007B
+00B5FFB7007B00C5FF7D007C00100026007C0011FFDC007C001D0000007C005BFFC1007C
+00A90000007C00AA0000007C00B4FF6B007C00B5FFB7007C00C5FF7D007D00100026007D
+0011FFDC007D001D0000007D005BFFC1007D00A90000007D00AA0000007D00B4FF6B007D
+00B5FFB7007D00C5FF7D008900100026008900A90000008900AA0000008900B4FF900089
+00B5FF90008900C5FFAD009000100000009000A90000009000AA0000009000B4FFAD0090
+00B5FFA4009000C5FF9000A90024000000A90025FFDC00A90026FFDC00A90027FFDC00A9
+0029000000A9002AFFDC00A9002B000000A9002DFFDC00A9002E000000A9002F000000A9
+0032000000A90033000000A90034000000A90035000000A90037FF9000A90039FF9000A9
+003AFFDC00A9003B000000A9003CFF6B00A9003D000000A90049000000A90051000000A9
+0052000000A90055000000A90059FFDC00A9005AFFDC00A9005CFFDC00A90062000000A9
+0064FFDC00A90067000000A90078000000A90079000000A9007A000000A9007B000000A9
+007C000000A9007D000000A90089000000A90090009700A900AD000000A900AE000000A9
+00AF000000A900BAFFDC00A900BBFF6B00A900C7000000A900C9000000A900D0000000A9
+00D1000000A900D2000000A900E5000000A900E9000000A900EAFF6B00A900EBFFDC00A9
+00EC000000A900F6FFDC00A900FBFFDC00A900FDFFDC00AA0024FFB700AA0025FFB700AA
+0026FFDC00AA0027FFDC00AA0029000000AA002A000000AA002B000000AA002DFFDC00AA
+002E000000AA002F000000AA0032FFDC00AA0033000000AA0034000000AA0035000000AA
+0037FF4400AA0039FF4E00AA003AFF9000AA003BFF9000AA003CFF1F00AA003D000000AA
+0049000000AA0051000000AA0052000000AA0055000000AA0059FFDC00AA005AFFDC00AA
+005CFFDC00AA0062FFB700AA0064FFDC00AA0067FFDC00AA0078000000AA0079000000AA
+007A000000AA007B000000AA007C000000AA007D000000AA0089000000AA0090000000AA
+00ADFFB700AA00AEFFB700AA00AFFFDC00AA00BAFFDC00AA00BBFF1F00AA00C7FFB700AA
+00C9FFB700AA00D0FFDC00AA00D1FFDC00AA00D2FFDC00AA00E5000000AA00E9000000AA
+00EAFF1F00AA00EBFFDC00AA00EC000000AA00F6000000AA00FBFFDC00AA00FDFFDC00AD
+0010FFD300AD0011FFDC00AD001DFFDC00AD0024003900AD0026FFDC00AD002AFFDC00AD
+0032FFDC00AD0034FFDC00AD0036000000AD0037FF6100AD0038000000AD0039FF7D00AD
+003AFF9000AD003B000000AD003CFF6100AD0046FFDC00AD0047FFDC00AD0048FFDC00AD
+0049FFB700AD0052FFDC00AD0054FFDC00AD0057FFDC00AD0058000000AD0059FF8800AD
+005AFFAD00AD005CFF7500AD0062003900AD0064FFDC00AD0067FFDC00AD0068000000AD
+006FFFDC00AD0070FFDC00AD0071FFDC00AD0072FFDC00AD0073FFDC00AD0079FFDC00AD
+007AFFDC00AD007BFFDC00AD007CFFDC00AD007DFFDC00AD007E000000AD007F000000AD
+0080000000AD0081000000AD00A9FFB700AD00AA000000AD00AD003900AD00AE003900AD
+00AFFFDC00AD00B4FEF800AD00B5FF0300AD00BAFF7500AD00BBFF6100AD00C5002F00AD
+00C7003900AD00C9003900AD00D0FFDC00AD00D1FFDC00AD00D2FFDC00AD00D3000000AD
+00D4000000AD00D5000000AD00E3000000AD00EAFF6100AD00EBFF7500AD00F6FFDC00AD
+00F9000000AD00FBFFDC00AD00FCFFDC00AD00FDFFDC00AD00FEFFDC00AE0010FFD300AE
+0011FFDC00AE001DFFDC00AE0024003900AE0026FFDC00AE002AFFDC00AE0032FFDC00AE
+0034FFDC00AE0036000000AE0037FF6100AE0038000000AE0039FF7D00AE003AFF9000AE
+003B000000AE003CFF6100AE0046FFDC00AE0047FFDC00AE0048FFDC00AE0049FFB700AE
+0052FFDC00AE0054FFDC00AE0057FFDC00AE0058000000AE0059FF8800AE005AFFAD00AE
+005CFF7500AE0062003900AE0064FFDC00AE0067FFDC00AE0068000000AE006FFFDC00AE
+0070FFDC00AE0071FFDC00AE0072FFDC00AE0073FFDC00AE0079FFDC00AE007AFFDC00AE
+007BFFDC00AE007CFFDC00AE007DFFDC00AE007E000000AE007F000000AE0080000000AE
+0081000000AE00A9FFB700AE00AA000000AE00AD003900AE00AE003900AE00AFFFDC00AE
+00B4FEF800AE00B5FF0300AE00BAFF7500AE00BBFF6100AE00C5002F00AE00C7003900AE
+00C9003900AE00D0FFDC00AE00D1FFDC00AE00D2FFDC00AE00D3000000AE00D4000000AE
+00D5000000AE00E3000000AE00EAFF6100AE00EBFF7500AE00F6FFDC00AE00F9000000AE
+00FBFFDC00AE00FCFFDC00AE00FDFFDC00AE00FEFFDC00AF0010003900AF0011FFAD00AF
+001DFFDC00AF0024FFDC00AF0039FFDC00AF003BFF7D00AF003CFF9000AF0062FFDC00AF
+00A9FFDC00AF00AA000000AF00ADFFDC00AF00AEFFDC00AF00B4FFD300AF00B5FFDC00AF
+00BBFF9000AF00C5FF4400AF00C7FFDC00AF00C9FFDC00AF00EAFF9000B40024FEF800B4
+0025FFC100B40026FFB700B40027FFC100B40029FFC100B4002AFFB700B4002BFFC100B4
+002DFFC100B4002EFFC100B4002FFFC100B40032FFB700B40033FFC100B40034FFB700B4
+0035FFC100B40037000000B40039000000B4003A000000B4003BFF8800B4003C000000B4
+003DFFDC00B40049FFB700B40051FF9000B40052FF6B00B40055FF9000B40059FFB700B4
+005AFFB700B4005CFFB700B40062FEF800B40064FFB700B40067FFB700B40078FF9000B4
+0079FF6B00B4007AFF6B00B4007BFF6B00B4007CFF6B00B4007DFF6B00B40089FFC100B4
+0090FE7D00B400ADFEF800B400AEFEF800B400AFFFB700B400BAFFB700B400BB000000B4
+00C7FEF800B400C9FEF800B400D0FFB700B400D1FFB700B400D2FFB700B400E5FFDC00B4
+00E9FFB700B400EA000000B400EBFFB700B400ECFFC100B400F6FFB700B400FBFFB700B4
+00FDFFB700BA0010FFDC00BA0011FEDC00BA001DFF6B00BA00A9FFDC00BA00AAFFDC00BA
+00B4000000BA00B5000000BA00C5FED300BB0010FF0D00BB0011FE6100BB001DFEF000BB
+0024FF6100BB0026FF9000BB0032FF9000BB0044FEE600BB0048FEF000BB004CFFB700BB
+0052FEF000BB0058FF1500BB0062FF6100BB0064FF9000BB0067FF9000BB0069FEE600BB
+006AFEE600BB006BFEE600BB006CFEE600BB006DFEE600BB006EFEE600BB0070FEF000BB
+0071FEF000BB0072FEF000BB0073FEF000BB0079FEF000BB007AFEF000BB007BFEF000BB
+007CFEF000BB007DFEF000BB007EFF1500BB007FFF1500BB0080FF1500BB0081FF1500BB
+00A9FF1F00BB00AAFF6B00BB00ADFF6100BB00AEFF6100BB00AFFF9000BB00B4FF9000BB
+00B5FFDC00BB00C5FEF800BB00C7FF6100BB00C9FF6100BB00D0FF9000BB00D1FF9000BB
+00D2FF9000BB00FBFF9000BB00FDFF9000C50024002600C50025FFB700C50026FF9000C5
+0027FFB700C50029FFB700C5002AFFB700C5002BFFB700C5002D002F00C5002EFFB700C5
+002FFFB700C50032FF9000C50033FFB700C50034FF9000C50035FFB700C50037FEE600C5
+0039FE8800C5003AFF0300C5003BFFB700C5003CFE8800C5003D000000C50049FFDC00C5
+0051FFB700C50052FFB700C50055FFB700C50059FF1500C5005AFF3C00C5005CFF9000C5
+0062002600C50064FF9000C50067FF9000C50078FFB700C50079FFB700C5007AFFB700C5
+007BFFB700C5007CFFB700C5007DFFB700C50089FFB700C50090002600C500AD002600C5
+00AE002600C500AFFF9000C500BAFF9000C500BBFE8800C500C7002600C500C9002600C5
+00D0FF9000C500D1FF9000C500D2FF9000C500E5000000C500E9FFB700C500EAFE8800C5
+00EBFF9000C500ECFFB700C500F6FFB700C500FBFF9000C500FDFF9000C70010FFD300C7
+0011FFDC00C7001DFFDC00C70024003900C70026FFDC00C7002AFFDC00C70032FFDC00C7
+0034FFDC00C70036000000C70037FF6100C70038000000C70039FF7D00C7003AFF9000C7
+003B000000C7003CFF6100C70046FFDC00C70047FFDC00C70048FFDC00C70049FFB700C7
+0052FFDC00C70054FFDC00C70057FFDC00C70058000000C70059FF8800C7005AFFAD00C7
+005CFF7500C70062003900C70064FFDC00C70067FFDC00C70068000000C7006FFFDC00C7
+0070FFDC00C70071FFDC00C70072FFDC00C70073FFDC00C70079FFDC00C7007AFFDC00C7
+007BFFDC00C7007CFFDC00C7007DFFDC00C7007E000000C7007F000000C70080000000C7
+0081000000C700A9FFB700C700AA000000C700AD003900C700AE003900C700AFFFDC00C7
+00B4FEF800C700B5FF0300C700BAFF7500C700BBFF6100C700C5002F00C700C7003900C7
+00C9003900C700D0FFDC00C700D1FFDC00C700D2FFDC00C700D3000000C700D4000000C7
+00D5000000C700E3000000C700EAFF6100C700EBFF7500C700F6FFDC00C700F9000000C7
+00FBFFDC00C700FCFFDC00C700FDFFDC00C700FEFFDC00C90010FFD300C90011FFDC00C9
+001DFFDC00C90024003900C90026FFDC00C9002AFFDC00C90032FFDC00C90034FFDC00C9
+0036000000C90037FF6100C90038000000C90039FF7D00C9003AFF9000C9003B000000C9
+003CFF6100C90046FFDC00C90047FFDC00C90048FFDC00C90049FFB700C90052FFDC00C9
+0054FFDC00C90057FFDC00C90058000000C90059FF8800C9005AFFAD00C9005CFF7500C9
+0062003900C90064FFDC00C90067FFDC00C90068000000C9006FFFDC00C90070FFDC00C9
+0071FFDC00C90072FFDC00C90073FFDC00C90079FFDC00C9007AFFDC00C9007BFFDC00C9
+007CFFDC00C9007DFFDC00C9007E000000C9007F000000C90080000000C90081000000C9
+00A9FFB700C900AA000000C900AD003900C900AE003900C900AFFFDC00C900B4FEF800C9
+00B5FF0300C900BAFF7500C900BBFF6100C900C5002F00C900C7003900C900C9003900C9
+00D0FFDC00C900D1FFDC00C900D2FFDC00C900D3000000C900D4000000C900D5000000C9
+00E3000000C900EAFF6100C900EBFF7500C900F6FFDC00C900F9000000C900FBFFDC00C9
+00FCFFDC00C900FDFFDC00C900FEFFDC00D00010003900D00011FFAD00D0001DFFDC00D0
+0024FFDC00D00039FFDC00D0003BFF7D00D0003CFF9000D00062FFDC00D000A9FFDC00D0
+00AA000000D000ADFFDC00D000AEFFDC00D000B4FFD300D000B5FFDC00D000BBFF9000D0
+00C5FF4400D000C7FFDC00D000C9FFDC00D000EAFF9000D10010003900D10011FFAD00D1
+001DFFDC00D10024FFDC00D10039FFDC00D1003BFF7D00D1003CFF9000D10062FFDC00D1
+00A9FFDC00D100AA000000D100ADFFDC00D100AEFFDC00D100B4FFD300D100B5FFDC00D1
+00BBFF9000D100C5FF4400D100C7FFDC00D100C9FFDC00D100EAFF9000D20010003900D2
+0011FFAD00D2001DFFDC00D20024FFDC00D20039FFDC00D2003BFF7D00D2003CFF9000D2
+0062FFDC00D200A9FFDC00D200AA000000D200ADFFDC00D200AEFFDC00D200B4FFD300D2
+00B5FFDC00D200BBFF9000D200C5FF4400D200C7FFDC00D200C9FFDC00D200EAFF9000D3
+0024000000D3002D000000D3003DFFDC00D30062000000D300AD000000D300AE000000D3
+00C7000000D300C9000000D300E5FFDC00D40024000000D4002D000000D4003DFFDC00D4
+0062000000D400AD000000D400AE000000D400C7000000D400C9000000D400E5FFDC00D5
+0024000000D5002D000000D5003DFFDC00D50062000000D500AD000000D500AE000000D5
+00C7000000D500C9000000D500E5FFDC00E30024002600E30026000000E3002A000000E3
+0032000000E30034000000E30036000000E30062002600E30064000000E30067000000E3
+00AD002600E300AE002600E300AF000000E300C7002600E300C9002600E300D0000000E3
+00D1000000E300D2000000E300E3000000E300F6000000E300F9000000E300FB000000E3
+00FD000000E50010FFDC00E500A9000000E500AA000000E500B4FFDC00E500B5FFDC00E5
+00C5FFDC00E90010000000E900A9000000E900AA000000E900B4FFA400E900B5FF9000E9
+00C5FFB700EA0010FF0D00EA0011FE6100EA001DFEF000EA0024FF6100EA0026FF9000EA
+0032FF9000EA0044FEE600EA0048FEF000EA004CFFB700EA0052FEF000EA0058FF1500EA
+0062FF6100EA0064FF9000EA0067FF9000EA0069FEE600EA006AFEE600EA006BFEE600EA
+006CFEE600EA006DFEE600EA006EFEE600EA0070FEF000EA0071FEF000EA0072FEF000EA
+0073FEF000EA0079FEF000EA007AFEF000EA007BFEF000EA007CFEF000EA007DFEF000EA
+007EFF1500EA007FFF1500EA0080FF1500EA0081FF1500EA00A9FF1F00EA00AAFF6B00EA
+00ADFF6100EA00AEFF6100EA00AFFF9000EA00B4FF9000EA00B5FFDC00EA00C5FEF800EA
+00C7FF6100EA00C9FF6100EA00D0FF9000EA00D1FF9000EA00D2FF9000EA00FBFF9000EA
+00FDFF9000EB0010FFDC00EB0011FEDC00EB001DFF6B00EB00A9FFDC00EB00AAFFDC00EB
+00B4000000EB00B5000000EB00C5FED300EC0010000000EC0011FF6B00EC001DFFB700EC
+00A9000000EC00AA000000EC00B4FFDC00EC00B5000000EC00C5FF4400F60010000000F6
+0024000000F60037FFB700F6003A000000F6003CFF9A00F60062000000F600A9FFDC00F6
+00AAFFDC00F600AD000000F600AE000000F600B4FFD300F600B5FFD300F600BBFF9A00F6
+00C5FFC900F600C7000000F600C9000000F600EAFF9A00F90024002600F90026000000F9
+002A000000F90032000000F90034000000F90036000000F90062002600F90064000000F9
+0067000000F900AD002600F900AE002600F900AF000000F900C7002600F900C9002600F9
+00D0000000F900D1000000F900D2000000F900E3000000F900F6000000F900F9000000F9
+00FB000000F900FD000000FB0010000000FB0024000000FB0036000000FB003CFFDC00FB
+0062000000FB00A9FFDC00FB00AAFFDC00FB00AD000000FB00AE000000FB00B4000000FB
+00B5002600FB00BBFFDC00FB00C5000000FB00C7000000FB00C9000000FB00E3000000FB
+00EAFFDC00FB00F9000000FD0010000000FD0024000000FD0036000000FD003CFFDC00FD
+0062000000FD00A9FFDC00FD00AAFFDC00FD00AD000000FD00AE000000FD00B4000000FD
+00B5002600FD00BBFFDC00FD00C5000000FD00C7000000FD00C9000000FD00E3000000FD
+00EAFFDC00FD00F90000000000010000010C004D00070042000400020010004000070000
+041505680003000100010000076DFE1D00000ABCFE89FE890A4C00010000000000000000
+000000000000010C0001040E019000050004054704CC0000FE42054704CC00000253008F
+02660802020B0603030804020204800000AF1000204A0000000000000000426974730040
+0020FB020614FE14019A076D01E3000000010000000000000001000042001DB1028B0460
+0000236305D500005665726153616E730000000000000000FFFFFFFF36FFFFFE36323852
+30300000400000000000001400000110090C050003030304080609080204040508030303
+03060606060606060606060303080808050A060707070606070703030605080707060706
+070507060706050504030408050506060606060306060303050309060606060405040605
+070505060503050806060706070707060606060606060606060603030303060606060606
+060606060505060605050606090909050508090708080808060605060705050404070906
+05030806060806060609060606070A090509050503030804050502060404060605030305
+0C0606060606030303030707070707070305050505050505050505050307050506030706
+050506060808040404090909070603070507060706060303060505050505050405050000
+0A0D06000303040508060A09030404050803040303060606060606060606060303080808
+050B07070808070608080303070609080807080707050807090607060403040805050606
+050606040606020205020A06060606040504060608060605060306080707080708080806
+06060606060506060606020202020606060606060606060605050606050606060A0A0A05
+05080A0808080808060705070806050505080A060504080606080706060A060707080B0A
+050A0505030308050607020604040606050303050D070707070703030303080808080808
+02050505050505050505050602070506050308060706070608080404040A0A0A08060307
+05080508050604030605050505050504050500000B0F07000303030509070A0A03040406
+0904040404070707070707070707070404090909060C0708080807060908030307060908
+0907090708070807090707090404040906060707060707040707030306030B0707070705
+070407060906060507040709070708070809080707070707070607070707030303030707
+070707070707070706060707060607070B0B0B0606090B09090909090707060708060605
+05080B070603090707090707070B070707090C0B060B0606040409050607020704040707
+060404060F07070707070303030309090908080803060606060606060606060603080709
+050408070706070709090404040B0B0B0907030807080608060704040706060606060604
+060600000C100700040405050A080B0A030505060A040404040808080808080808080804
+040A0A0A060D0808080908070909030307060A0909080908080709080B0907090504050A
+06060808070808040808030307030B080808080507050806090606050804080A08080808
+090909080808080808070808080803030303080808080808080808080606080806070808
+0C0C0C06060A0C090A0A0A0A080806080907060606090C0806050A08080A0807070C0808
+08090D0D060C060604040A06060702080505070706040406100808080808030303030909
+090909090306060606060606060606060308070905040908070608080A0A0505050C0C0C
+0908030807080708070804040806060606060605060600000D110800040405050B080C0B
+030505070B040504040808080808080808080804040B0B0B070D0909090A08070A0A0303
+08070B0A0A080A0809070A090B0A070A0504050B07070808070808040808030307030D08
+0808080507050807090707070804080B090909080A0A0A08080808080807080808080303
+03030808080808080808080807070808070808080D0D0D07070B0D0A0B0B0B0B08080709
+0A080706060A0D0807050B08080B0908080D0809090A0E0D070D070704040B0607070208
+0505080807040407110908090808030303030A0A0A0A0A0A030707070707070707070707
+0309070A07040A08070708080B0B0505050D0D0D0A080309070907090708050408070707
+07070705070700000E130800040405050C090D0C030505070C0405040509090909090909
+09090905050C0C0C070E090A0A0B09080B0A030309070C0A0B090B0A09090A090D0B090A
+0505050C07070809080909040909030308030D0909090905080509070B0707080905090C
+09090A090A0B0A0808080808080809090909030303030909090909090909090907070909
+070809090E0E0E07070C0E0B0C0C0C0C090907090B080707070B0E0907050C09090C0909
+090E0909090B0F0F070E070704040C070709020906060808070404071309090909090303
+03030B0B0B0A0A0A0307070707070707070707070309080A08050B09090709090C0C0606
+060E0E0E0B090309080A080A080905040907070707070706070700000F14090005050606
+0D0A0E0B030606080D050505050A0A0A0A0A0A0A0A0A0A05050D0D0D080F0A0A0A0B0909
+0C0B03030A080D0B0C090C0A0A090B0A0F0A090B0605060D080809090809090509090303
+08030F0909090906080609080D0A08080A050A0D0A0A0A090B0C0B090909090909080909
+0909030303030909090909090909090908080A0A08090A090F0F0F08080D0F0C0D0D0D0D
+0A09080A0B090807070B0F0908060D0A0A0D0A09090F0A0A0A0C100F080F080805050D07
+0809030A0606090908050508140A090A0909030303030C0C0C0B0B0B0308080808080808
+08080808030A080B08050C09090809090D0D0606060F0F0F0C09030A080A080A08090505
+0A080808080808060808000010150A00050506060D0A0F0C030606080D050605050A0A0A
+0A0A0A0A0A0A0A05050D0D0D09100B0B0B0C0A090C0C05050A090D0C0D0A0D0B0A090C0B
+110B090C0605060D0808090A090A09060A0A030309030F0A0A0A0A0709060A090D0A0909
+0A050A0D0B0B0B0A0C0D0C0909090909090909090909030303030A0A0A0A0A0A0A0A0A0A
+08080A0A08090A0A10101008080D100D0D0D0D0D0A0A080B0C090808080C100A09060D0A
+0A0D0B0A0A100A0B0B0D110F0810080805050D080909030A06060A0A08050508150B0A0B
+0A0A050505050D0D0D0C0C0C030808080808080808080809040A090C09050D0A09090A0A
+0D0D0606061010100C0A050A090B090B090A06050A080808080808060808000011170A00
+050507080E0B100D050707090E050605060B0B0B0B0B0B0B0B0B0B06060E0E0E09110B0C
+0C0D0B0A0D0D06060C090F0D0D0A0D0C0B0A0D0B120D0A0C0706070E09090A0A080A0A06
+0A0B05050A05110B0A0A0A0708070B0A0F0A0A080B060B0E0B0B0C0B0D0D0D0A0A0A0A0A
+0A080A0A0A0A050505050B0A0A0A0A0A0B0B0B0B09090B0B090A0B0B11111109090E100D
+0E0E0E0E0B0B090B0D0A0908080D100A09070E0B0B0E0B0A0A110B0B0B0D121109110909
+05050E080A0A030B07070A0A09050509170B0B0B0B0B060606060D0D0D0D0D0D05090909
+090909090909090A050B080C08060D0A0A0A0A0A0E0E0707071010100D0A060B080C080C
+080A06050B090909090909070909000012180B00060607080F0B110D040707090F060706
+060B0B0B0B0B0B0B0B0B0B06060F0F0F0A120C0C0D0E0B0A0E0E06060C0A100E0E0B0E0D
+0B0C0E0C130D0C0D0706070F09090A0B090B0B060B0B05050A05110B0B0B0B0808070B0B
+100B0B090B060B0F0C0C0D0B0E0E0E0A0A0A0A0A0A090B0B0B0B050505050B0B0B0B0B0B
+0B0B0B0B09090B0B090B0B0B12121209090F110E0F0F0F0F0B0B090C0E0B0908080E110B
+0A070F0B0B0F0C0B0B120B0C0C0E13130912090906060F090B0C030B07070B0B09060609
+180C0B0C0B0B060606060E0E0E0E0E0E05090909090909090909090A050B080D09060E0B
+0C0B0B0B0F0F0707071111110E0B060B080D090D090B07060B0909090909090709090000
+131A0B0006060808100C120E0407070A10060706060C0C0C0C0C0C0C0C0C0C0606101010
+0A130D0D0D0F0C0B0F0E06060C0B100E0F0C0F0D0C0C0E0D140E0C0D070607100A0A0B0B
+090B0B060B0C05050B05110C0B0B0B0809080C0B110B0B0B0C060C100D0D0D0C0E0F0E0B
+0B0B0B0B0B090B0B0B0B050505050C0B0B0B0B0B0C0C0C0C0A0A0C0C0A0B0C0C1313130A
+0A10120F101010100C0C0A0D0E0B0A09090F120B0A08100C0C100D0C0C130C0D0D0F1413
+0A130A0A060610090B0C030C08080B0B0A06060A1A0D0C0D0C0C060606060F0F0F0E0E0E
+050A0A0A0A0A0A0A0A0A0A0B050C090D0B060F0B0C0B0C0B10100808081212120F0B060C
+090D090D090B07060C0A0A0A0A0A0A080A0A0000141B0C000606080A110D130F0608080A
+11060706070D0D0D0D0D0D0D0D0D0D07071111110B140E0E0E0F0D0C100F06060D0B110F
+100C100E0D0C0F0E140E0C0E080708110A0A0C0D0B0D0C070D0D06060C06140D0C0D0D08
+0A080D0B110B0B0B0D070D110E0E0E0D0F100F0C0C0C0C0C0C0B0C0C0C0C060606060D0C
+0C0C0C0C0D0D0D0D0A0A0D0D0A0C0D0D1414140A0A111410111111110D0D0A0D0F0C0A09
+090F130C0B08110D0D110D0C0C140D0E0E1015140A140A0A0606110A0B0C030D08080D0D
+0A06060A1B0E0D0E0D0D060606061010100F0F0F060A0A0A0A0A0A0A0A0A0A0B060D0A0E
+0B070F0C0C0B0C0D1111080808131313100D060D0A0E0B0E0B0D07060D0A0A0A0A0A0A08
+0A0A0000151C0D000707080A120D14100608080B12070807070D0D0D0D0D0D0D0D0D0D07
+071212120B150E0E0F100D0C101006060E0C1210110D110F0D0D0F0E150E0D0E08070812
+0B0B0D0D0C0D0D070D0D06060C06140E0D0D0D090B080E0B110D0D0B0D070D120E0E0F0D
+10110F0D0D0D0D0D0D0C0D0D0D0D060606060E0D0D0D0D0D0E0E0E0E0B0B0D0D0B0C0D0D
+1515150B0B121411121212120D0E0B0E100C0B0A0A10140D0B08120D0D120E0D0D150D0E
+0E1116160B150B0B0707120A0D0D040D08080D0D0B07070B1C0E0D0E0D0D060606061111
+110F0F0F060B0B0B0B0B0B0B0B0B0B0C060D0B0E0B07100D0D0D0D0D1212080808141414
+100D060D0B0F0C0F0C0D08070D0B0B0B0B0B0B080B0B0000161E0D000707090A120E1511
+0609090B12070807070E0E0E0E0E0E0E0E0E0E07071212120C160F0F0F110E0D11110606
+0E0C1310110D110F0E0D100F160F0D0F090709120B0B0D0E0C0E0D080E0E06060D06160E
+0D0E0E090B090E0E120E0E0C0E070E120F0F0F0E1011100D0D0D0D0D0D0C0D0D0D0D0606
+06060E0D0D0D0D0D0E0E0E0E0B0B0E0E0B0D0E0E1616160B0B121511121212120E0E0B0F
+110D0B0A0A11150D0C09120E0E120F0D0D160E0F0F1118160B160B0B0707120B0E0D040E
+09090D0D0B07070B1E0F0E0F0E0E06060606111111101010060B0B0B0B0B0B0B0B0B0B0C
+060E0B0F0C07110D0D0E0D0E1212090909151515110E060E0B0F0C0F0C0E08070E0B0B0B
+0B0B0B090B0B0000171F0E000707090B130F16120609090C13070807080F0F0F0F0F0F0F
+0F0F0F08081313130C17101010120F0D121107070F0D1411120E12100F0E111017100E10
+090809130C0C0E0F0D0F0E080F0F06060D06160F0E0E0E090C090F0E130E0E0C0F080F13
+1010100F1112110E0E0E0E0E0E0D0E0E0E0E060606060F0E0E0E0E0E0F0F0F0F0C0C0F0F
+0C0E0F0E1717170C0C131612131313130F0F0C10110E0C0B0B12150E0C09130F0F130F0E
+0E170F10101219180C170C0C0707130B0E0E040F09090F0F0C07070C1F100F100F0F0707
+0707121212111111060C0C0C0C0C0C0C0C0C0C0D060F0C100C08120E0E0E0E0E13130909
+09161616120F070F0C100D100D0F08070F0C0C0C0C0C0C090C0C000018200E0008080A0B
+140F17130709090C14080908080F0F0F0F0F0F0F0F0F0F08081414140D18101011120F0E
+13120707100D1512130E13110F0F121018100F10090809140C0C0E0F0D0F0E080F0F0707
+0E06180F0E0F0F0A0C090F0F140F0F0D0F080F141010110F1213120E0E0E0E0E0E0D0E0E
+0E0E070707070F0E0E0E0E0E0F0F0F0F0C0C0F0F0C0E0F0F1818180C0C14171314141414
+0F0F0C10120E0D0B0B12170E0D0A140F0F14100F0F180F1010131A180C180C0C0808140C
+0F0F040F0A0A0F0F0C08080C20100F100F0F07070707131313121212070C0C0C0C0C0C0C
+0C0C0C0D060F0C100D08130E0F0F0F0F14140A0A0A171717130F070F0C110D110D0F0908
+0F0C0C0C0C0C0C0A0C0C000019220F0008080A0C15101814070A0A0D1508090808101010
+1010101010101008081515150D1911111113100E13130707100E1613140F1411100F1211
+19110F110A080A150D0D0F100E100F09101007070E0718100F10100A0D0A100F140F0F0D
+10081015111111101314120F0F0F0F0F0F0E0F0F0F0F07070707100F0F0F0F0F10101010
+0D0D10100D0F10101919190D0D1518141515151510100D11130F0D0C0C13190F0D0A1510
+1015110F0F19101111141B1A0D190D0D0808150C0F0F04100A0A10100D08080D22111011
+101007070707141414121212070D0D0D0D0D0D0D0D0D0D0E07100D110D08130F0F0F0F10
+15150A0A0A181818131007100D110E110E100908100D0D0D0D0D0D0A0D0D00001A231000
+08080A0C16111914070A0A0D16080908091111111111111111111109091616160E1A1212
+1214100F14140808110E161314101412111013121A1210120A090A160D0D10110E111009
+111007070F0719101011110B0E0A100F150F0F0E11091116121212101314131010101010
+100E1010101007070707101010101010101010100D0D11110D0F11101A1A1A0D0D161914
+1616161611110D12140F0E0C0C141A100E0A161111161110101A111212141C1B0D1A0D0D
+0808160D0F1004110A0A10100D08080D23121012101008080808141414131313070D0D0D
+0D0D0D0D0D0D0D0F07110E120E091410100F101116160A0A0A191919141108110E120E12
+0E110908110D0D0D0D0D0D0A0D0D00001B24100009090B0C17111A15070B0B0E17090A09
+091111111111111111111109091717170E1B12131315111015140808120F171415101513
+111114121B1311130B090B170E0E11110F11110A1111080810081A111111110B0E0B1110
+1610100E11091117121213111415141111111111110F1111111108080808111111111111
+111111110E0E11110E1011111B1B1B0E0E171A151617171711110E1214100E0D0D151B11
+0E0B171111171211111B111212151D1C0E1B0E0E0909170D101105110B0B11110E09090E>
+<24121112111108080808151515141414080E0E0E0E0E0E0E0E0E0E0F08110E130E091511
+1110101117170B0B0B1A1A1A151108110E130F130F110A09110E0E0E0E0E0E0B0E0E0000
+1C26110009090B0D17121B16080B0B0E17090A0909121212121212121212120909171717
+0F1C131314161210161508081210181516111613121115131C1311130B090B170E0E1112
+0F12110A1212080810081B121112120C0F0B12111711110F120912171313141215161511
+11111111110F1111111108080808121111111111121212120E0E12120E1112121C1C1C0E
+0E171B161717171712120E1315100F0D0D151C110F0B171212171311111C121313161E1D
+0E1C0F0F0909170E111105120B0B12120E09090F26131213121208080808161616151515
+080E0E0E0E0E0E0E0E0E0E1008120F130F0916111111111217170B0B0B1B1B1B16120812
+0F140F140F120A09120E0E0E0E0E0E0B0E0E00000000000200080002FFFF000300010000
+000200000C500AEC5F0F3CF5001F080000000000BAB9F0B800000000BAC26791FE89FE1D
+0A4C076D00000008000100000000000000>
+] def
+/CharStrings 268 dict dup begin
+/.notdef 0 def /.null 1 def /nonmarkingreturn 2 def /space 3 def /exclam 4 def
+/quotedbl 5 def /numbersign 6 def /dollar 7 def /percent 8 def
+/ampersand 9 def /quotesingle 10 def /parenleft 11 def /parenright 12 def
+/asterisk 13 def /plus 14 def /comma 15 def /hyphen 16 def
+/period 17 def /slash 18 def /zero 19 def /one 20 def
+/two 21 def /three 22 def /four 23 def /five 24 def
+/six 25 def /seven 26 def /eight 27 def /nine 28 def
+/colon 29 def /semicolon 30 def /less 31 def /equal 32 def
+/greater 33 def /question 34 def /at 35 def /A 36 def
+/B 37 def /C 38 def /D 39 def /E 40 def
+/F 41 def /G 42 def /H 43 def /I 44 def
+/J 45 def /K 46 def /L 47 def /M 48 def
+/N 49 def /O 50 def /P 51 def /Q 52 def
+/R 53 def /S 54 def /T 55 def /U 56 def
+/V 57 def /W 58 def /X 59 def /Y 60 def
+/Z 61 def /bracketleft 62 def /backslash 63 def /bracketright 64 def
+/asciicircum 65 def /underscore 66 def /grave 67 def /a 68 def
+/b 69 def /c 70 def /d 71 def /e 72 def
+/f 73 def /g 74 def /h 75 def /i 76 def
+/j 77 def /k 78 def /l 79 def /m 80 def
+/n 81 def /o 82 def /p 83 def /q 84 def
+/r 85 def /s 86 def /t 87 def /u 88 def
+/v 89 def /w 90 def /x 91 def /y 92 def
+/z 93 def /braceleft 94 def /bar 95 def /braceright 96 def
+/asciitilde 97 def /Adieresis 98 def /Aring 99 def /Ccedilla 100 def
+/Eacute 101 def /Ntilde 102 def /Odieresis 103 def /Udieresis 104 def
+/aacute 105 def /agrave 106 def /acircumflex 107 def /adieresis 108 def
+/atilde 109 def /aring 110 def /ccedilla 111 def /eacute 112 def
+/egrave 113 def /ecircumflex 114 def /edieresis 115 def /iacute 116 def
+/igrave 117 def /icircumflex 118 def /idieresis 119 def /ntilde 120 def
+/oacute 121 def /ograve 122 def /ocircumflex 123 def /odieresis 124 def
+/otilde 125 def /uacute 126 def /ugrave 127 def /ucircumflex 128 def
+/udieresis 129 def /dagger 130 def /degree 131 def /cent 132 def
+/sterling 133 def /section 134 def /bullet 135 def /paragraph 136 def
+/germandbls 137 def /registered 138 def /copyright 139 def /trademark 140 def
+/acute 141 def /dieresis 142 def /notequal 143 def /AE 144 def
+/Oslash 145 def /infinity 146 def /plusminus 147 def /lessequal 148 def
+/greaterequal 149 def /yen 150 def /mu 151 def /partialdiff 152 def
+/summation 153 def /product 154 def /pi 155 def /integral 156 def
+/ordfeminine 157 def /ordmasculine 158 def /Omega 159 def /ae 160 def
+/oslash 161 def /questiondown 162 def /exclamdown 163 def /logicalnot 164 def
+/radical 165 def /florin 166 def /approxequal 167 def /Delta 168 def
+/guillemotleft 169 def /guillemotright 170 def /ellipsis 171 def /nonbreakingspace 172 def
+/Agrave 173 def /Atilde 174 def /Otilde 175 def /OE 176 def
+/oe 177 def /endash 178 def /emdash 179 def /quotedblleft 180 def
+/quotedblright 181 def /quoteleft 182 def /quoteright 183 def /divide 184 def
+/lozenge 185 def /ydieresis 186 def /Ydieresis 187 def /fraction 188 def
+/currency 189 def /guilsinglleft 190 def /guilsinglright 191 def /fi 192 def
+/fl 193 def /daggerdbl 194 def /periodcentered 195 def /quotesinglbase 196 def
+/quotedblbase 197 def /perthousand 198 def /Acircumflex 199 def /Ecircumflex 200 def
+/Aacute 201 def /Edieresis 202 def /Egrave 203 def /Iacute 204 def
+/Icircumflex 205 def /Idieresis 206 def /Igrave 207 def /Oacute 208 def
+/Ocircumflex 209 def /Ograve 210 def /Uacute 211 def /Ucircumflex 212 def
+/Ugrave 213 def /dotlessi 214 def /circumflex 215 def /tilde 216 def
+/macron 217 def /breve 218 def /dotaccent 219 def /ring 220 def
+/cedilla 221 def /hungarumlaut 222 def /ogonek 223 def /caron 224 def
+/Lslash 225 def /lslash 226 def /Scaron 227 def /scaron 228 def
+/Zcaron 229 def /zcaron 230 def /brokenbar 231 def /Eth 232 def
+/eth 233 def /Yacute 234 def /yacute 235 def /Thorn 236 def
+/thorn 237 def /minus 238 def /multiply 239 def /onesuperior 240 def
+/twosuperior 241 def /threesuperior 242 def /onequarter 243 def /onehalf 244 def
+/threequarters 245 def /Gbreve 246 def /gbreve 247 def /Idotaccent 248 def
+/Scedilla 249 def /scedilla 250 def /Cacute 251 def /cacute 252 def
+/Ccaron 253 def /ccaron 254 def /dcroat 255 def /sfthyphen 256 def
+/periodcentered 257 def /Euro 258 def /c6459 259 def /c6460 260 def
+/c6461 261 def /c6462 262 def /c6463 263 def /c6466 264 def
+/c6467 265 def /c6468 266 def /c6469 267 def 
+end readonly def
+FontName currentdict end definefont pop
+%%EndFont
+%%EndProlog
+mpldict begin
+18 180 translate
+576 432 0 0 clipbox
+1.000 setgray
+1.000 setlinewidth
+0 setlinejoin
+2 setlinecap
+[] 0 setdash
+0 0 m
+0 432 l
+576 432 l
+576 0 l
+closepath
+gsave
+fill
+grestore
+stroke
+0.000 setgray
+72 43.2 m
+72 388.8 l
+518.4 388.8 l
+518.4 43.2 l
+closepath
+gsave
+1.000 setgray
+fill
+grestore
+stroke
+gsave
+446.400 345.600 72.000 43.200 clipbox
+518.4 388.8 m
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.399 388.8 l
+518.399 388.799 l
+518.399 388.799 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.399 388.799 l
+518.4 388.8 l
+518.399 388.799 l
+495.606 367.86 l
+462.323 336.512 l
+433.708 308.57 l
+409.252 283.668 l
+388.482 261.474 l
+370.957 241.693 l
+356.268 224.063 l
+344.035 208.351 l
+333.911 194.347 l
+325.581 181.866 l
+318.765 170.742 l
+313.213 160.828 l
+308.71 151.993 l
+305.071 144.118 l
+293.311 137.099 l
+273.304 130.844 l
+255.866 125.269 l
+240.735 120.3 l
+227.671 115.872 l
+216.455 111.925 l
+206.882 108.407 l
+198.764 105.272 l
+191.925 102.478 l
+186.201 99.988 l
+181.441 97.768 l
+177.507 95.79 l
+174.275 94.027 l
+171.632 92.456 l
+169.482 91.056 l
+167.74 89.808 l
+166.333 88.695 l
+165.201 87.704 l
+164.291 86.82 l
+163.562 86.033 l
+159.821 84.001 l
+150.271 79.564 l
+141.759 75.609 l
+134.173 72.085 l
+127.411 68.944 l
+121.385 66.144 l
+116.015 63.649 l
+111.228 61.425 l
+106.962 59.443 l
+103.16 57.677 l
+99.771 56.102 l
+96.751 54.699 l
+94.06 53.449 l
+91.661 52.334 l
+89.523 51.341 l
+87.617 50.456 l
+85.919 49.667 l
+84.405 48.963 l
+83.056 48.337 l
+81.854 47.778 l
+80.782 47.28 l
+79.827 46.836 l
+78.976 46.441 l
+78.217 46.088 l
+77.541 45.774 l
+76.939 45.494 l
+76.402 45.245 l
+75.923 45.023 l
+75.496 44.824 l
+75.116 44.648 l
+74.777 44.49 l
+74.475 44.35 l
+74.206 44.225 l
+73.966 44.113 l
+73.752 44.014 l
+73.562 43.926 l
+73.392 43.847 l
+73.241 43.776 l
+73.106 43.714 l
+72.985 43.658 l
+72.878 43.608 l
+72.783 43.564 l
+72.698 43.524 l
+72.622 43.489 l
+72.554 43.457 l
+72.494 43.429 l
+72.44 43.404 l
+72.392 43.382 l
+72.35 43.362 l
+72.312 43.345 l
+518.4 43.2 l
+closepath
+gsave
+0.941 setgray
+fill
+grestore
+stroke
+grestore
+gsave
+446.400 345.600 72.000 43.200 clipbox
+72.312 43.529 m
+72.35 43.57 l
+72.392 43.615 l
+72.44 43.665 l
+72.494 43.722 l
+72.554 43.786 l
+72.622 43.857 l
+72.698 43.937 l
+72.783 44.027 l
+72.878 44.128 l
+72.985 44.241 l
+73.106 44.369 l
+73.241 44.511 l
+73.392 44.671 l
+73.562 44.851 l
+73.752 45.052 l
+73.966 45.278 l
+74.206 45.532 l
+74.475 45.816 l
+74.777 46.135 l
+75.116 46.493 l
+75.496 46.895 l
+75.923 47.346 l
+76.402 47.852 l
+76.939 48.42 l
+77.541 49.057 l
+78.217 49.771 l
+78.976 50.573 l
+79.827 51.473 l
+80.782 52.482 l
+81.854 53.615 l
+83.056 54.886 l
+84.405 56.312 l
+85.919 57.911 l
+87.617 59.706 l
+89.523 61.72 l
+91.661 63.98 l
+94.06 66.516 l
+96.751 69.361 l
+99.771 72.553 l
+103.16 76.135 l
+106.962 80.153 l
+111.228 84.662 l
+116.015 89.721 l
+121.385 95.398 l
+127.411 101.767 l
+134.173 108.913 l
+141.759 116.931 l
+150.271 125.928 l
+159.821 136.022 l
+163.562 141.75 l
+164.291 145.341 l
+165.201 149.37 l
+166.333 153.89 l
+167.74 158.963 l
+169.482 164.654 l
+171.632 171.04 l
+174.275 178.205 l
+177.507 186.244 l
+181.441 195.264 l
+186.201 205.385 l
+191.925 216.74 l
+198.764 229.482 l
+206.882 243.777 l
+216.455 259.818 l
+227.671 277.815 l
+240.735 298.008 l
+255.866 320.666 l
+273.304 346.088 l
+293.311 374.61 l
+305.071 388.799 l
+308.71 388.799 l
+313.213 388.8 l
+318.765 388.8 l
+325.581 388.799 l
+333.911 388.8 l
+344.035 388.8 l
+356.268 388.8 l
+370.957 388.8 l
+388.482 388.8 l
+409.252 388.8 l
+433.708 388.8 l
+462.323 388.8 l
+495.606 388.8 l
+518.399 388.8 l
+518.4 388.8 l
+518.399 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.399 388.8 l
+518.399 388.8 l
+518.399 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.399 388.8 l
+518.399 388.799 l
+518.399 388.799 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.399 388.799 l
+518.4 388.8 l
+518.399 388.799 l
+495.606 367.86 l
+462.323 336.512 l
+433.708 308.57 l
+409.252 283.668 l
+388.482 261.474 l
+370.957 241.693 l
+356.268 224.063 l
+344.035 208.351 l
+333.911 194.347 l
+325.581 181.866 l
+318.765 170.742 l
+313.213 160.828 l
+308.71 151.993 l
+305.071 144.118 l
+293.311 137.099 l
+273.304 130.844 l
+255.866 125.269 l
+240.735 120.3 l
+227.671 115.872 l
+216.455 111.925 l
+206.882 108.407 l
+198.764 105.272 l
+191.925 102.478 l
+186.201 99.988 l
+181.441 97.768 l
+177.507 95.79 l
+174.275 94.027 l
+171.632 92.456 l
+169.482 91.056 l
+167.74 89.808 l
+166.333 88.695 l
+165.201 87.704 l
+164.291 86.82 l
+163.562 86.033 l
+159.821 84.001 l
+150.271 79.564 l
+141.759 75.609 l
+134.173 72.085 l
+127.411 68.944 l
+121.385 66.144 l
+116.015 63.649 l
+111.228 61.425 l
+106.962 59.443 l
+103.16 57.677 l
+99.771 56.102 l
+96.751 54.699 l
+94.06 53.449 l
+91.661 52.334 l
+89.523 51.341 l
+87.617 50.456 l
+85.919 49.667 l
+84.405 48.963 l
+83.056 48.337 l
+81.854 47.778 l
+80.782 47.28 l
+79.827 46.836 l
+78.976 46.441 l
+78.217 46.088 l
+77.541 45.774 l
+76.939 45.494 l
+76.402 45.245 l
+75.923 45.023 l
+75.496 44.824 l
+75.116 44.648 l
+74.777 44.49 l
+74.475 44.35 l
+74.206 44.225 l
+73.966 44.113 l
+73.752 44.014 l
+73.562 43.926 l
+73.392 43.847 l
+73.241 43.776 l
+73.106 43.714 l
+72.985 43.658 l
+72.878 43.608 l
+72.783 43.564 l
+72.698 43.524 l
+72.622 43.489 l
+72.554 43.457 l
+72.494 43.429 l
+72.44 43.404 l
+72.392 43.382 l
+72.35 43.362 l
+72.312 43.345 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+gsave
+446.400 345.600 72.000 43.200 clipbox
+72.312 44.381 m
+72.35 44.526 l
+72.392 44.687 l
+72.44 44.869 l
+72.494 45.072 l
+72.554 45.301 l
+72.622 45.557 l
+72.698 45.845 l
+72.783 46.168 l
+72.878 46.53 l
+72.985 46.936 l
+73.106 47.392 l
+73.241 47.903 l
+73.392 48.477 l
+73.562 49.121 l
+73.752 49.844 l
+73.966 50.654 l
+74.206 51.564 l
+74.475 52.584 l
+74.777 53.729 l
+75.116 55.014 l
+75.496 56.456 l
+75.923 58.073 l
+76.402 59.888 l
+76.939 61.924 l
+77.541 64.209 l
+78.217 66.772 l
+78.976 69.648 l
+79.827 72.876 l
+80.782 76.497 l
+81.854 80.559 l
+83.056 85.118 l
+84.405 90.233 l
+85.919 95.971 l
+87.617 102.411 l
+89.523 109.635 l
+91.661 117.742 l
+94.06 126.837 l
+96.751 137.042 l
+99.771 148.493 l
+103.16 161.341 l
+106.962 175.756 l
+111.228 191.93 l
+116.015 210.078 l
+121.385 230.44 l
+127.411 253.287 l
+134.173 278.921 l
+141.759 307.684 l
+150.271 339.955 l
+159.821 376.165 l
+163.562 388.8 l
+164.291 388.8 l
+165.201 388.8 l
+166.333 388.8 l
+167.74 388.8 l
+169.482 388.8 l
+171.632 388.8 l
+174.275 388.8 l
+177.507 388.8 l
+181.441 388.8 l
+186.201 388.8 l
+191.925 388.8 l
+198.764 388.8 l
+206.882 388.8 l
+216.455 388.8 l
+227.671 388.8 l
+240.735 388.8 l
+255.866 388.8 l
+273.304 388.8 l
+293.311 388.8 l
+305.071 388.8 l
+308.71 388.8 l
+313.213 388.8 l
+318.765 388.8 l
+325.581 388.8 l
+333.911 388.8 l
+344.035 388.8 l
+356.268 388.8 l
+370.957 388.8 l
+388.482 388.8 l
+409.252 388.8 l
+433.708 388.8 l
+462.323 388.8 l
+495.606 388.8 l
+518.399 388.8 l
+518.4 388.8 l
+518.399 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.399 388.8 l
+518.399 388.8 l
+518.399 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.399 388.8 l
+518.399 388.8 l
+518.399 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.399 388.8 l
+518.4 388.8 l
+518.399 388.8 l
+495.606 388.8 l
+462.323 388.8 l
+433.708 388.8 l
+409.252 388.8 l
+388.482 388.8 l
+370.957 388.8 l
+356.268 388.8 l
+344.035 388.8 l
+333.911 388.8 l
+325.581 388.799 l
+318.765 388.8 l
+313.213 388.8 l
+308.71 388.799 l
+305.071 388.799 l
+293.311 374.61 l
+273.304 346.088 l
+255.866 320.666 l
+240.735 298.008 l
+227.671 277.815 l
+216.455 259.818 l
+206.882 243.777 l
+198.764 229.482 l
+191.925 216.74 l
+186.201 205.385 l
+181.441 195.264 l
+177.507 186.244 l
+174.275 178.205 l
+171.632 171.04 l
+169.482 164.654 l
+167.74 158.963 l
+166.333 153.89 l
+165.201 149.37 l
+164.291 145.341 l
+163.562 141.75 l
+159.821 136.022 l
+150.271 125.928 l
+141.759 116.931 l
+134.173 108.913 l
+127.411 101.767 l
+121.385 95.398 l
+116.015 89.721 l
+111.228 84.662 l
+106.962 80.153 l
+103.16 76.135 l
+99.771 72.553 l
+96.751 69.361 l
+94.06 66.516 l
+91.661 63.98 l
+89.523 61.72 l
+87.617 59.706 l
+85.919 57.911 l
+84.405 56.312 l
+83.056 54.886 l
+81.854 53.615 l
+80.782 52.482 l
+79.827 51.473 l
+78.976 50.573 l
+78.217 49.771 l
+77.541 49.057 l
+76.939 48.42 l
+76.402 47.852 l
+75.923 47.346 l
+75.496 46.895 l
+75.116 46.493 l
+74.777 46.135 l
+74.475 45.816 l
+74.206 45.532 l
+73.966 45.278 l
+73.752 45.052 l
+73.562 44.851 l
+73.392 44.671 l
+73.241 44.511 l
+73.106 44.369 l
+72.985 44.241 l
+72.878 44.128 l
+72.783 44.027 l
+72.698 43.937 l
+72.622 43.857 l
+72.554 43.786 l
+72.494 43.722 l
+72.44 43.665 l
+72.392 43.615 l
+72.35 43.57 l
+72.312 43.529 l
+closepath
+gsave
+0.941 setgray
+fill
+grestore
+stroke
+grestore
+gsave
+446.400 345.600 72.000 43.200 clipbox
+72.312 388.8 m
+72.35 388.8 l
+72.392 388.8 l
+72.44 388.8 l
+72.494 388.8 l
+72.554 388.8 l
+72.622 388.8 l
+72.698 388.8 l
+72.783 388.8 l
+72.878 388.8 l
+72.985 388.8 l
+73.106 388.8 l
+73.241 388.8 l
+73.392 388.8 l
+73.562 388.8 l
+73.752 388.8 l
+73.966 388.8 l
+74.206 388.8 l
+74.475 388.8 l
+74.777 388.8 l
+75.116 388.8 l
+75.496 388.8 l
+75.923 388.8 l
+76.402 388.8 l
+76.939 388.8 l
+77.541 388.8 l
+78.217 388.8 l
+78.976 388.8 l
+79.827 388.8 l
+80.782 388.8 l
+81.854 388.8 l
+83.056 388.8 l
+84.405 388.8 l
+85.919 388.8 l
+87.617 388.8 l
+89.523 388.8 l
+91.661 388.8 l
+94.06 388.8 l
+96.751 388.8 l
+99.771 388.8 l
+103.16 388.8 l
+106.962 388.8 l
+111.228 388.8 l
+116.015 388.8 l
+121.385 388.8 l
+127.411 388.8 l
+134.173 388.8 l
+141.759 388.8 l
+150.271 388.8 l
+159.821 388.8 l
+163.562 388.8 l
+164.291 388.8 l
+165.201 388.8 l
+166.333 388.8 l
+167.74 388.8 l
+169.482 388.8 l
+171.632 388.8 l
+174.275 388.8 l
+177.507 388.8 l
+181.441 388.8 l
+186.201 388.8 l
+191.925 388.8 l
+198.764 388.8 l
+206.882 388.8 l
+216.455 388.8 l
+227.671 388.8 l
+240.735 388.8 l
+255.866 388.8 l
+273.304 388.8 l
+293.311 388.8 l
+305.071 388.8 l
+308.71 388.8 l
+313.213 388.8 l
+318.765 388.8 l
+325.581 388.8 l
+333.911 388.8 l
+344.035 388.8 l
+356.268 388.8 l
+370.957 388.8 l
+388.482 388.8 l
+409.252 388.8 l
+433.708 388.8 l
+462.323 388.8 l
+495.606 388.8 l
+518.399 388.8 l
+518.4 388.8 l
+518.399 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.399 388.8 l
+518.399 388.8 l
+518.399 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.399 388.8 l
+518.399 388.8 l
+518.399 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.4 388.8 l
+518.399 388.8 l
+518.4 388.8 l
+518.399 388.8 l
+495.606 388.8 l
+462.323 388.8 l
+433.708 388.8 l
+409.252 388.8 l
+388.482 388.8 l
+370.957 388.8 l
+356.268 388.8 l
+344.035 388.8 l
+333.911 388.8 l
+325.581 388.8 l
+318.765 388.8 l
+313.213 388.8 l
+308.71 388.8 l
+305.071 388.8 l
+293.311 388.8 l
+273.304 388.8 l
+255.866 388.8 l
+240.735 388.8 l
+227.671 388.8 l
+216.455 388.8 l
+206.882 388.8 l
+198.764 388.8 l
+191.925 388.8 l
+186.201 388.8 l
+181.441 388.8 l
+177.507 388.8 l
+174.275 388.8 l
+171.632 388.8 l
+169.482 388.8 l
+167.74 388.8 l
+166.333 388.8 l
+165.201 388.8 l
+164.291 388.8 l
+163.562 388.8 l
+159.821 376.165 l
+150.271 339.955 l
+141.759 307.684 l
+134.173 278.921 l
+127.411 253.287 l
+121.385 230.44 l
+116.015 210.078 l
+111.228 191.93 l
+106.962 175.756 l
+103.16 161.341 l
+99.771 148.493 l
+96.751 137.042 l
+94.06 126.837 l
+91.661 117.742 l
+89.523 109.635 l
+87.617 102.411 l
+85.919 95.971 l
+84.405 90.233 l
+83.056 85.118 l
+81.854 80.559 l
+80.782 76.497 l
+79.827 72.876 l
+78.976 69.648 l
+78.217 66.772 l
+77.541 64.209 l
+76.939 61.924 l
+76.402 59.888 l
+75.923 58.073 l
+75.496 56.456 l
+75.116 55.014 l
+74.777 53.729 l
+74.475 52.584 l
+74.206 51.564 l
+73.966 50.654 l
+73.752 49.844 l
+73.562 49.121 l
+73.392 48.477 l
+73.241 47.903 l
+73.106 47.392 l
+72.985 46.936 l
+72.878 46.53 l
+72.783 46.168 l
+72.698 45.845 l
+72.622 45.557 l
+72.554 45.301 l
+72.494 45.072 l
+72.44 44.869 l
+72.392 44.687 l
+72.35 44.526 l
+72.312 44.381 l
+closepath
+gsave
+0.816 setgray
+fill
+grestore
+stroke
+grestore
+/BitstreamVeraSans-Roman findfont
+12.000 scalefont
+setfont
+406.8 216 m
+(x1) show
+295.2 285.12 m
+(x2) show
+183.6 285.12 m
+(x3) show
+94.32 285.12 m
+(x4) show
+/BitstreamVeraSans-Roman findfont
+14.000 scalefont
+setfont
+198.7 395.712 m
+0 3 rmoveto
+(Optimal allocations \(fig 4.12\)) show
+/BitstreamVeraSans-Roman findfont
+12.000 scalefont
+setfont
+59 30.2 m
+(0.00) show
+0.500 setlinewidth
+0 setlinecap
+183.600 43.200 m 183.600 47.200 l
+stroke
+183.600 384.800 m 183.600 388.800 l
+stroke
+170.6 30.2 m
+(0.05) show
+295.200 43.200 m 295.200 47.200 l
+stroke
+295.200 384.800 m 295.200 388.800 l
+stroke
+282.2 30.2 m
+(0.10) show
+406.800 43.200 m 406.800 47.200 l
+stroke
+406.800 384.800 m 406.800 388.800 l
+stroke
+393.8 30.2 m
+(0.15) show
+505.4 30.2 m
+(0.20) show
+236.7 15.2 m
+(standard deviation) show
+50 38.7 m
+(0.0) show
+72.000 112.320 m 76.000 112.320 l
+stroke
+514.400 112.320 m 518.400 112.320 l
+stroke
+49.953 107.82 m
+(0.2) show
+72.000 181.440 m 76.000 181.440 l
+stroke
+514.400 181.440 m 518.400 181.440 l
+stroke
+50 176.94 m
+(0.4) show
+72.000 250.560 m 76.000 250.560 l
+stroke
+514.400 250.560 m 518.400 250.560 l
+stroke
+50 246.06 m
+(0.6) show
+72.000 319.680 m 76.000 319.680 l
+stroke
+514.400 319.680 m 518.400 319.680 l
+stroke
+50 315.18 m
+(0.8) show
+50 384.3 m
+(1.0) show
+44.953 186.5 m
+gsave
+90 rotate
+(allocation) show
+grestore
+
+end
+showpage
diff --git a/doc/intro.tex b/doc/intro.tex
new file mode 100644
index 0000000..f9f510c
--- /dev/null
+++ b/doc/intro.tex
@@ -0,0 +1,56 @@
+\chapter{Introduction}\label{chap:intro}
+
+CVXOPT is a free software package for convex optimization based on
+the Python programming language.
+It can be used with the interactive Python interpreter, 
+on the command line by executing Python scripts, or integrated in 
+other software via Python extension modules.
+Its main purpose is to make the development of software for convex 
+optimization applications straightforward by building on Python's 
+extensive standard library and on the strengths of Python as a 
+high-level programming language.  
+
+Release 0.8.2 of CVXOPT includes routines for basic linear algebra 
+calculations, 
+interfaces to efficient libraries for solving dense and sparse linear 
+equations, 
+convex optimization solvers written in Python,
+interfaces to a few other optimization libraries, 
+and a modeling tool for piecewise-linear convex optimization problems.
+These components are organized in different modules.  
+\begin{description}
+\item[\module{cvxopt.base}] This module defines a Python type
+ \mtrx\ for storing and manipulating dense matrices, 
+ a Python type \spmtrx\ for storing and manipulating sparse 
+ matrices, and routines for sparse matrix-vector and matrix-matrix 
+ multiplication (see chapters~\ref{chap:matrix} 
+ and~\ref{chap:spmatrix}).
+\item[\module{cvxopt.random}] Routines for generating random matrices 
+ with uniformly or normally distributed entries 
+ (see section~\ref{s-random}).
+\item[\module{cvxopt.blas}] Interface to most of the double-precision 
+ real and complex BLAS (chapter~\ref{chap:blas}).
+\item[\module{cvxopt.lapack}] Interface to the dense double-precision 
+ real and complex linear equation solvers and eigenvalue routines 
+ from LAPACK (chapter~\ref{chap:lapack}).
+\item[\module{cvxopt.fftw}] An optional interface to the 
+ discrete transform routines from FFTW (section~\ref{c-fftw}). 
+\item[\module{cvxopt.amd}]  Interface to the approximate minimum degree
+ ordering routine from AMD (chapter~\ref{s-orderings}).
+\item[\module{cvxopt.umfpack}] Interface to the sparse LU solver 
+ from UMFPACK (section~\ref{s-umfpack}).
+\item[\module{cvxopt.cholmod}] Interface to the sparse Cholesky 
+ solver from CHOLMOD (section~\ref{s-cholmod}).
+\item[\module{cvxopt.solvers}] Convex optimization routines
+ and optional interfaces to solvers from GLPK, MOSEK and DSDP5
+ (chapter~\ref{chap:solvers}).
+\item[\module{cvxopt.modeling}]  Routines for specifying and solving 
+ linear programs and convex optimization problems with piecewise-linear 
+ cost and constraint functions (chapter~\ref{chap:modeling}).
+\item[\module{cvxopt.info}] Defines a string \code{version} with
+ the version number of the CVXOPT installation and a function 
+ \function{license()} that prints the CVXOPT license.  
+\end{description}
+The modules are described in detail in this manual and in the 
+on-line Python help facility \program{pydoc}.  Several example scripts 
+are included in the distribution. 
diff --git a/doc/lapack.tex b/doc/lapack.tex
new file mode 100644
index 0000000..15f4433
--- /dev/null
+++ b/doc/lapack.tex
@@ -0,0 +1,1041 @@
+\chapter{The LAPACK Interface (\module{cvxopt.lapack})}
+\label{chap:lapack}
+
+The module \module{cvxopt.lapack} includes functions for 
+solving dense sets of linear equations, for the corresponding matrix 
+factorizations (LU, Cholesky, LDL$\mathrm{{}^T}$),
+for solving least-squares and least-norm problems, for QR 
+factorization, for symmetric eigenvalue problems and for singular 
+value decomposition.  
+
+In this chapter we briefly describe the Python calling sequences.
+For further details on the underlying LAPACK functions we refer to the 
+LAPACK Users' Guide and manual pages.  
+
+The BLAS conventional storage scheme of section~\ref{s-conventions} is 
+used. As in the previous chapter, we omit from the function definitions
+less important arguments that are useful for selecting submatrices. 
+The complete definitions are documented in the docstrings in the 
+source code.
+
+\begin{seealso}
+\seelink{http://www.netlib.org/lapack/lug/lapack_lug.html}{LAPACK 
+Users' Guide, Third Edition, SIAM, 1999.}{} 
+\end{seealso}
+
+
+\section{General Linear Equations}
+\begin{funcdesc}{gesv}{A, B\optional{, ipiv=None}}
+Solves
+\[ 
+   A X = B,
+\]
+where {\it A} and {\it B} are real or complex matrices, with {\it A}
+square and nonsingular.  On exit, \var{B} is replaced by the solution.  
+The arguments \var{A} and \var{B} must have the same type (\dtc\ or
+\ztc).  
+The optional argument \var{ipiv} is an integer matrix of length at 
+least \var{n}.  
+If \var{ipiv} is provided, then \function{gesv()} solves the system, 
+replaces \var{A} with its triangular factors, and returns the 
+permutation matrix in \var{ipiv}.
+If \var{ipiv} is not specified, then \function{gesv()} solves the
+system but does not return the LU factorization and does not 
+modify \var{A}.  
+For example,
+\begin{verbatim}
+>>> gesv(A, B)
+\end{verbatim}
+solves the system without modifying \var{A} and returns the solution 
+in \var{B}.
+\begin{verbatim}
+>>> gesv(A, B, ipiv)
+\end{verbatim}
+returns the solution in \var{B} and also returns the details of the 
+LU factorization in \var{A} and \var{ipiv}.
+
+Raises an \code{ArithmeticError} if the matrix is singular.
+\end{funcdesc}
+
+\begin{funcdesc}{getrf}{A, ipiv}
+LU factorization of a general, possibly rectangular, real or
+complex matrix,  
+\[
+  A = PLU 
+\]
+where {\it A} is \var{m} by \var{n}.
+The argument \var{ipiv} is an integer matrix of length at least
+min\{\var{m}, \var{n}\}.
+On exit, the lower triangular part of \var{A} is replaced by {\it L},
+the upper triangular part by {\it U}, and the permutation matrix is 
+returned in \var{ipiv}.
+Raises an \code{ArithmeticError} if the matrix is not full rank.
+\end{funcdesc}
+
+\begin{funcdesc}{getrs}{A, ipiv, B\optional{, trans='N'}}
+Solves a general set of linear equations
+\[
+ AX=B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+ A^TX=B \quad (\mathrm{trans} = \mathrm{'T'}), \qquad 
+ A^HX=B \quad (\mathrm{trans} = \mathrm{'C'}), 
+\]
+given the LU factorization computed by \function{gesv()} or 
+\function{getrf()}.
+On entry, \var{A} and \var{ipiv} must contain the factorization
+as computed by \function{gesv()} or \function{getrf()}.  
+On exit, \var{B} is overwritten with the solution. 
+\var{B} must have the same type as \var{A}.
+\end{funcdesc}
+
+\begin{funcdesc}{getri}{A, ipiv}
+Computes the inverse of a matrix.
+On entry, \var{A} and \var{ipiv} must contain the factorization
+as computed by \function{gesv()} or \function{getrf()}.  On exit, 
+\var{A} contains the inverse.
+\end{funcdesc}
+
+In the following example we compute
+\[
+ x = (A^{-1} + A^{-T})b
+\]
+for randomly generated problem data, factoring the coefficient matrix 
+once.
+\begin{verbatim}
+>>> from cvxopt.base import matrix
+>>> from cvxopt.random import normal
+>>> from cvxopt.lapack import gesv, getrs
+>>> n = 10
+>>> A = normal(n,n)
+>>> b = normal(n)
+>>> ipiv = matrix(0, (n,1))
+>>> x = +b
+>>> gesv(A, x, ipiv)               # x = A^{-1}*b 
+>>> x2 = +b
+>>> getrs(A, ipiv, x2, trans='T')  # x2 = A^{-T}*b
+>>> x += x2
+\end{verbatim}
+
+Separate functions are provided for equations with band matrices.
+\begin{funcdesc}{gbsv}{A, kl, B\optional{, ipiv=None}}
+Solves
+\[ 
+   A X = B,
+\]
+where {\it A} and {\it B} are real or complex matrices, with {\it A}
+{\it n} by {\it n} and banded with \var{kl} subdiagonals.  
+The arguments \var{A} and \var{B} must have the same type (\dtc\ or
+\ztc).  
+
+The optional argument \var{ipiv} is an integer matrix of length at least
+{\it n}.
+If \var{ipiv} is provided, then \var{A} must have 
+2\var{kl} + \var{ku} + 1 rows.  On entry the diagonals of {\it A} are
+stored in rows \var{kl} + 1 to 2\var{kl} + \var{ku} +1 of the \var{A}, using
+the BLAS format for general band matrices (see section~\ref{s-conventions}).
+On exit, the factorization is returned in {\var A} and \var{ipiv}.
+
+If \var{ipiv} is not provided, then \var{A} must have \var{kl} + \var{ku} + 
+1 rows.  On entry the diagonals of {\it A} are stored in the rows of 
+\var{A}, following the standard format for general band matrices. 
+In this case, \function{gbsv()} does not modify \var{A} on exit and does
+not return the factorization.
+
+On exit, \var{B} is replaced by the solution {\it X}.  
+Raises an \code{ArithmeticError} if the matrix is singular.
+\end{funcdesc}
+
+\begin{funcdesc}{gbtrf}{A, m, kl, ipiv}
+LU factorization of a general {\it m} by {\it n} real or complex band 
+matrix with \var{kl} subdiagonals.
+The matrix is stored using the BLAS format for general band matrices
+(see section~\ref{s-conventions}), by providing the 
+diagonals (stored as rows of a \var{ku} + \var{kl} + 1 by {\it n} matrix),
+the number of rows \var{m}, and the number of subdiagonals \var{kl}.
+The argument \var{ipiv} is an integer matrix of length at least
+min\{{\it m}, {\it n}\}.
+On exit, \var{A} and \var{ipiv} contain the details of the factorization.
+Raises an \code{ArithmeticError} if the matrix is not full rank.
+\end{funcdesc}
+
+\begin{funcdesc}{gbtrs}{A, kl, ipiv, B\optional{, trans='N'}}
+Solves a set of linear equations 
+\[
+ AX=B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+ A^TX=B \quad (\mathrm{trans} = \mathrm{'T'}), \qquad 
+ A^HX=B \quad (\mathrm{trans} = \mathrm{'C'}), 
+\]
+with {\it A} a general band matrix with \var{kl} subdiagonals, given the 
+LU factorization computed by \function{gbsv()} or \function{gbtrf()}.
+On entry, \var{A} and \var{ipiv} must contain the factorization
+as computed by \function{gbsv()} or \function{gbtrf()}.  
+On exit, \var{B} is overwritten with the solution. 
+\var{B} must have the same type as \var{A}.
+\end{funcdesc}
+
+As an example, we solve a linear equation with
+\[
+ A = \left[ \begin{array}{cccc}
+ 1 & 2 & 0 & 0 \\
+ 3 & 4 & 5 & 0 \\
+ 6 & 7 & 8 & 9 \\
+ 0 & 10 & 11 & 12 
+ \end{array}\right], \qquad  x = \left[\begin{array}{c} 1 \\ 1 \\ 1 \\ 1
+ \end{array}\right].
+\]
+\begin{verbatim}
+>>> from cvxopt.base import matrix
+>>> from cvxopt.lapack import gbsv, gbtrf, gbtrs
+>>> n, kl, ku = 4, 2, 1
+>>> A = matrix([[0., 1., 3., 6.], [2., 4., 7., 10.], [5., 8., 11., 0.], [9., 12., 0., 0.]])
+>>> x = matrix(1.0, (4,1))
+>>> gbsv(A, kl, x)
+>>> print x
+   7.1429e-02
+   4.6429e-01
+  -2.1429e-01
+  -1.0714e-01
+\end{verbatim}
+The code below illustrates how one can reuse the factorization returned
+by \function{gbsv()}. 
+\begin{verbatim}
+>>> Ac = matrix(0.0, (2*kl+ku+1,n))
+>>> Ac[kl:,:] = A
+>>> ipiv = matrix(0, (n,1))
+>>> x = matrix(1.0, (4,1))
+>>> gbsv(Ac, kl, x, ipiv)                 # solves A*x = 1
+>>> print x                 
+   7.1429e-02
+   4.6429e-01
+  -2.1429e-01
+  -1.0714e-01
+>>> x = matrix(1.0, (4,1))
+>>> gbtrs(Ac, kl, ipiv, x, trans='T')     # solve A^T*x = 1
+>>> print x
+   7.1429e-02
+   2.3810e-02
+   1.4286e-01
+  -2.3810e-02
+\end{verbatim}
+An alternative method uses \function{getrf()} for the factorization.
+\begin{verbatim}
+>>> Ac[kl:,:] = A
+>>> gbtrf(Ac, n, kl, ipiv)                 
+>>> x = matrix(1.0, (4,1))
+>>> gbtrs(Ac, kl, ipiv, x)                # solve A^T*x = 1
+>>> print x                 
+   7.1429e-02
+   4.6429e-01
+  -2.1429e-01
+  -1.0714e-01
+>>> x = matrix(1.0, (4,1))
+>>> gbtrs(Ac, kl, ipiv, x, trans='T')     # solve A^T*x = 1
+>>> print x
+   7.1429e-02
+   2.3810e-02
+   1.4286e-01
+  -2.3810e-02
+\end{verbatim}
+
+The following functions can be used for tridiagonal matrices They use a 
+simpler matrix format, that stores the diagonals in three separate 
+vectors.
+
+\begin{funcdesc}{gtsv}{dl, d, du, B)}
+Solves
+\[ 
+   A X = B,
+\]
+where {\it A} is an {\it n} by {\it n} tridiagonal matrix, 
+with subdiagonal \var{dl} (a matrix of length {\it n}-1), 
+diagonal \var{d} (a matrix of length {\it n}), and superdiagonal 
+\var{du} (a matrix of length {\it n}-1).  
+The four arguments must have the same type (\dtc\ or \ztc).
+On exit \var{dl}, \var{d}, \var{du} are overwritten with the details of 
+the LU factorization of {\it A}, and \var{B} is overwritten with the 
+solution {\it X}.  
+Raises an \code{ArithmeticError} if the matrix is singular.
+\end{funcdesc}
+
+\begin{funcdesc}{gttrf}{dl, d, du, du2, ipiv}
+LU factorization of an {\it n} by {\it n} tridiagonal matrix with
+subdiagonal \var{dl}, diagonal \var{d} and superdiagonal \var{du}.
+\var{dl}, \var{d} and \var{du} must have the same type.
+\var{du2} is a matrix of length {\it n}-2, and of the same type as 
+\var{dl}.
+\var{ipiv} is an \itc\ matrix of length {\it n}.
+On exit, the five arguments contain the details of the factorization.
+Raises an \code{ArithmeticError} if the matrix is singular.
+\end{funcdesc}
+
+\begin{funcdesc}{pttrs}{dl, d, du, du2, ipiv, B\optional{, trans='N'}}
+Solves a set of linear equations 
+\[
+ AX=B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+ A^TX=B \quad (\mathrm{trans} = \mathrm{'T'}), \qquad 
+ A^HX=B \quad (\mathrm{trans} = \mathrm{'C'}), 
+\]
+where {\it A} is an {\it n} by {\it n} tridiagonal matrix.
+The arguments \var{dl}, \var{d}, \var{du}, \var{du2} and \var{ipiv}
+contain the details of the LU factorization as returned by 
+\function{gttrf()}.
+On exit, \var{B} is overwritten with the solution {\it X}. 
+\var{B} must have the same type as \var{dl}.
+\end{funcdesc}
+
+
+\section{Positive Definite Linear Equations}
+\begin{funcdesc}{posv}{A, B\optional{, uplo='L'}}
+Solves
+\[ 
+   A X = B,
+\]
+where {\it A} is a real symmetric or complex Hermitian positive 
+definite matrix.
+On exit, \var{B} is replaced by the solution, and \var{A} is 
+overwritten with the Cholesky factor.
+The matrices \var{A} and \var{B} must have the same type (\dtc\ or 
+\ztc).
+Raises an \code{ArithmeticError} if the matrix is not positive definite.
+\end{funcdesc}
+
+\begin{funcdesc}{potrf}{A\optional{, uplo='L'}}
+Cholesky factorization 
+\[
+ A = LL^T \qquad \mbox{or} \qquad A = LL^H
+\]
+of a positive definite real symmetric or complex Hermitian matrix
+{\it A}.  On exit, the lower triangular part of \var{A} 
+(if \var{uplo} is \code{'L'}) or the upper triangular part 
+(if \var{uplo} is \code{'U'}) is overwritten with the Cholesky factor 
+or its (conjugate) transpose.
+Raises an \code{ArithmeticError} if the matrix is not positive definite.
+\end{funcdesc}
+
+\begin{funcdesc}{potrs}{A, B\optional{, uplo='L'}}
+Solves a set of linear equations
+\[
+ AX=B
+\]
+with a positive 
+definite real symmetric or complex Hermitian matrix,
+given the Cholesky factorization computed by 
+\function{posv()} or \function{potrf()}.
+On entry, \var{A} contains the triangular factor, as computed by
+\function{posv()} or \function{potrf()}.  On exit, \var{B} is replaced 
+by the solution.
+\var{B} must have the same type as \var{A}.
+\end{funcdesc}
+
+\begin{funcdesc}{potri}{A\optional{, uplo='L'}} 
+Computes the inverse of a positive definite matrix.
+On entry, \var{A} contains the Cholesky factorization computed 
+by \function{potrf()} or \function{posv()}. On exit, it contains
+the inverse.
+\end{funcdesc}
+
+As an example, we use \function{posv()} to solve the linear system
+\BEQ \label{e-kkt-example}
+ \left[ \begin{array}{cc}
+ -\diag(d)^2  & A \\
+ A^T  & 0 \end{array} \right]
+ \left[ \begin{array}{c} x_1 \\ x_2 \end{array} \right]
+ = \left[ \begin{array}{c} b_1 \\ b_2 \end{array} \right]
+\EEQ
+by block-elimination. 
+We first pick a random problem.
+\begin{verbatim}
+>>> from cvxopt.base import matrix, div
+>>> from cvxopt.random import normal, uniform
+>>> from cvxopt.blas import syrk, gemv
+>>> from cvxopt.lapack import posv
+>>> m, n = 100, 50  
+>>> A = normal(m,n)
+>>> b1, b2 = normal(m), normal(n)
+>>> d = uniform(m)
+\end{verbatim}
+We then solve the equations 
+\[
+ A^T \diag(d)^{-2}A x_2 = b_2 + A^T \diag(d)^{-2} b_1, \qquad
+ \diag(d)^2 x_1 = Ax_2 - b_1.
+\]
+\begin{verbatim}
+>>> Asc = div(A, d[:, n*[0]])                # Asc := diag(d)^{-1}*A
+>>> B = matrix(0.0, (n,n))
+>>> syrk(Asc, B, trans='T')                  # B := Asc^T * Asc = A^T * diag(d)^{-2} * A
+>>> x1 = div(b1, d)                          # x1 := diag(d)^{-1}*b1
+>>> x2 = +b2
+>>> gemv(Asc, x1, x2, trans='T', beta=1.0)   # x2 := x2 + Asc^T*x1 = b2 + A^T*diag(d)^{-2}*b1 
+>>> posv(B, x2)                              # x2 := B^{-1}*x2 = B^{-1}*(b2 + A^T*diag(d)^{-2}*b1)
+>>> gemv(Asc, x2, x1, beta=-1.0)             # x1 := Asc*x2 - x1 = diag(d)^{-1} * (A*x2 - b1)
+>>> x1 = div(x1, d)                          # x1 := diag(d)^{-1}*x1 = diag(d)^{-2} * (A*x2 - b1)
+\end{verbatim}
+
+
+There are separate routines for equations with positive definite band 
+matrices.
+\begin{funcdesc}{pbsv}{A, B\optional{, uplo='L'}}
+Solves
+\[
+ AX=B
+\]
+where {\it A} is a real symmetric or complex Hermitian positive definite
+band matrix.  On entry, the diagonals of {\it A} are stored in \var{A}, 
+using the BLAS format for symmetric or Hermitian band matrices
+(see section~\ref{s-conventions}).  On exit, \var{B} is replaced by the
+solution, and \var{A} is overwritten with the Cholesky factor (in the
+BLAS format for triangular band matrices).  The matrices \var{A} and 
+\var{B} must have the same type (\dtc\ or \ztc).
+Raises an \code{ArithmeticError} if the matrix is not positive definite.
+\end{funcdesc}
+
+\begin{funcdesc}{pbtrf}{A\optional{, uplo='L'}}
+Cholesky factorization 
+\[
+ A = LL^T \qquad \mbox{or} \qquad A = LL^H
+\]
+of a positive definite real symmetric or complex Hermitian band matrix
+{\it A}.  On entry, the diagonals of {\it A} are stored in \var{A}, 
+using the BLAS format for symmetric or Hermitian band matrices.
+On exit, \var{A} contains the Cholesky factor, in the BLAS format
+for triangular band matrices.
+Raises an \code{ArithmeticError} if the matrix is not positive definite.
+\end{funcdesc}
+
+\begin{funcdesc}{pbtrs}{A, B\optional{, uplo='L'}}
+Solves a set of linear equations
+\[
+ AX=B
+\]
+with a positive definite real symmetric or complex Hermitian band matrix,
+given the Cholesky factorization computed by \function{pbsv()} or 
+\function{pbtrf()}.
+On entry, \var{A} contains the triangular factor, as computed by
+\function{pbsv()} or \function{pbtrf()}.  On exit, \var{B} is replaced 
+by the solution.  \var{B} must have the same type as \var{A}.
+\end{funcdesc}
+
+The following functions are useful for tridiagonal systems.
+
+\begin{funcdesc}{ptsv}{d, e, B}
+Solves
+\[ 
+   A X = B,
+\]
+where {\it A} is an {\it n} by {\it n} real symmetric or complex 
+Hermitian tridiagonal matrix, with diagonal \var{d} (a \dtc\ matrix of 
+length {\it n}) and subdiagonal \var{e} (a \dtc\ or \ztc\ matrix of length 
+{\it n}-1).
+The arguments \var{e} and \var{B} must have the same type.  
+On exit \var{d} contains the diagonal elements of {\it D} in 
+the LDL${}\mathrm{^T}$ or LDL${}\mathrm{^H}$ factorization 
+of {\it A}, and \var{e} contains the subdiagonal elements of the unit 
+lower bidiagonal matrix {\it L}.  
+\var{B} is overwritten with the solution {\it X}.  
+Raises an \code{ArithmeticError} if the matrix is singular.
+\end{funcdesc}
+
+\begin{funcdesc}{pttrf}{d, e}
+LDL${}\mathrm{^T}$ or LDL${}\mathrm{^H}$ factorization of an {\it n} by 
+{\it n} real symmetric or complex Hermitian tridiagonal matrix {\it A}.
+On entry, the argument \var{d} is a \dtc\ matrix with the diagonal elements
+of {\it A}.  The argument \var{e} is \dtc\ or \ztc\ matrix with
+the subdiagonal elements of {\it A}.
+On exit \var{d} contains the diagonal elements of {\it D}, and \var{e} 
+contains the subdiagonal elements of the unit lower bidiagonal matrix 
+{\it L}.  Raises an \code{ArithmeticError} if the matrix is singular.
+\end{funcdesc}
+
+\begin{funcdesc}{gttrs}{d, e, B\optional{, uplo='L'}}
+Solves a set of linear equations 
+\[
+ AX=B 
+\]
+where {\it A} is an {\it n} by {\it n} real symmetric or complex
+Hermitian tridiagonal matrix, given its LDL${}\mathrm{^T}$ or 
+LDL${}\mathrm{^H}$ factorization.
+The argument \var{d} is the diagonal of the diagonal matrix {\it D}.
+The argument \var{uplo} only matters for complex matrices.
+If \var{uplo} is \code{'L'}, then \var{e} contains the subdiagonal 
+elements of the unit bidiagonal matrix {\it L}.
+If \var{uplo} is \code{'U'}, then \var{e} contains the complex
+conjugates of the elements of the unit bidiagonal matrix {\it L}.
+On exit, \var{B} is overwritten with the solution {\it X}. 
+\var{B} must have the same type as \var{e}.
+\end{funcdesc}
+
+
+\section{Symmetric and Hermitian Linear Equations}
+\begin{funcdesc}{sysv}{A, B\optional{, ipiv=None\optional{, uplo='L'}}}
+Solves
+\[
+ AX=B
+\] 
+where {\it A} is a real or complex symmetric matrix  of order {\it n}.
+On exit, \var{B} is replaced by the solution.  
+The matrices \var{A} and \var{B} must have the same type (\dtc\ or 
+\ztc).
+The optional argument \var{ipiv} is an integer matrix of length at 
+least equal to {\it n}.
+If \var{ipiv} is provided, \function{sysv()} solves the system and 
+returns the factorization in \var{A} and \var{ipiv}.
+If \var{ipiv} is not specified, \function{sysv()} solves the
+system but does not return the factorization and does not modify 
+\var{A}.
+Raises an \code{ArithmeticError} if the matrix is singular.
+\end{funcdesc}
+
+\begin{funcdesc}{sytrf}{A, ipiv\optional{, uplo='L'}}
+LDL${}\mathrm{^T}$ factorization 
+\[
+ PAP^T = LDL^T
+\]
+of a real or complex symmetric matrix $A$ of order {\it n}.
+\var{ipiv} is an \itc\ matrix of length at least {\it n}.
+On exit, \var{A} and \var{ipiv} contain the factorization.
+Raises an \code{ArithmeticError} if the matrix is singular.
+\end{funcdesc}
+
+\begin{funcdesc}{sytrs}{A, ipiv, B\optional{, uplo='L'}}
+Solves 
+\[
+  A X = B
+\]
+given the LDL${}\mathrm{^T}$ factorization computed by 
+\function{sytrf()} or \function{sysv()}. \var{B} must have the same
+type as \var{A}.
+\end{funcdesc}
+
+\begin{funcdesc}{sytri}{A, ipiv\optional{, uplo='L'}}
+Computes the inverse of a real or complex symmetric matrix.
+On entry, \var{A} and \var{ipiv} contain the LDL${}\mathrm{^T}$ 
+factorization computed by \function{sytrf()} or \function{sysv()}. 
+On exit, \var{A} contains the inverse.
+\end{funcdesc}
+
+\begin{funcdesc}{hesv}{A, B\optional{, ipiv=\None\optional{, uplo='L'}}}
+Solves
+\[
+ A X = B
+\]
+where {\it A} is a real symmetric or complex Hermitian of order {\it n}.
+On exit, \var{B} is replaced by the solution.
+The matrices \var{A} and \var{B} must have the same type (\dtc\ or 
+\ztc).
+The optional argument \var{ipiv} is an integer matrix of length at 
+least \var{n}.  
+If \var{ipiv} is provided, then \function{hesv()} solves the system and 
+returns the factorization in \var{A} and \var{ipiv}.
+If \var{ipiv} is not specified, then \function{hesv()} solves the
+system but does not return the factorization and does not modify 
+\var{A}.
+Raises an \code{ArithmeticError} if the matrix is singular.
+\end{funcdesc}
+
+\begin{funcdesc}{hetrf}{A, ipiv\optional{, uplo='L'}}
+LDL${}\mathrm{^H}$ factorization 
+\[
+ PAP^T = LDL^H
+\]
+of a real symmetric or complex Hermitian matrix of order {\it  n}.
+\var{ipiv} is an \itc\ matrix of length at least \var{n}.
+On exit, \var{A} and \var{ipiv} contain the factorization.
+Raises an \code{ArithmeticError} if the matrix is singular.
+\end{funcdesc}
+
+\begin{funcdesc}{hetrs}{A, ipiv, B\optional{, uplo='L'}}
+Solves 
+\[
+ A X = B
+\]
+given the LDL${}\mathrm{^H}$ factorization computed by 
+\function{hetrf()} or \function{hesv()}.
+\end{funcdesc}
+
+\begin{funcdesc}{hetri}{A, ipiv\optional{, uplo='L'}}
+Computes the inverse of a real symmetric or complex Hermitian  matrix.
+On entry, \var{A} and \var{ipiv} contain the LDL${}\mathrm{^H}$ 
+factorization computed by \function{hetrf()} or \function{hesv()}. 
+On exit, \var{A} contains the inverse.
+\end{funcdesc}
+
+As an example we solve the KKT system~(\ref{e-kkt-example}).
+\begin{verbatim}
+>>> from cvxopt.lapack import sysv
+>>> K = matrix(0.0, (m+n,m+n))
+>>> K[: (m+n)*m : m+n+1] = -d**2
+>>> K[:m, m:] = A
+>>> x = matrix(0.0, (m+n,1))
+>>> x[:m], x[m:] = b1, b2
+>>> sysv(K, x, uplo='U')   
+\end{verbatim}
+
+\section{Triangular Linear Equations}
+
+\begin{funcdesc}{trtrs}{A, B\optional{, uplo='L'\optional{, 
+trans='N'\optional{, diag='N'}}}}
+Solves a triangular set of equations
+\[
+ AX=B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+ A^TX=B \quad (\mathrm{trans} = \mathrm{'T'}), \qquad 
+ A^HX=B \quad (\mathrm{trans} = \mathrm{'C'}), 
+\]
+where {\it A} is real or complex and triangular of order {\it n}, 
+and \var{B} is a matrix with {\it n} rows.
+\var{A} and \var{B} are matrices with the same type (\dtc\ or \ztc).
+\function{trtrs()} is similar to \function{blas.trsm()}, except
+that it raises an \code{ArithmeticError} if a diagonal element of 
+\var{A} is zero (whereas \function{blas.trsm()} returns \code{inf}
+values).
+\end{funcdesc}
+
+\begin{funcdesc}{trtri}{A\optional{, uplo='L'\optional{, diag='N'}}}
+Computes the inverse of a real or complex triangular matrix {\it A}.  
+On exit, \var{A} contains the inverse.
+\end{funcdesc}
+
+\begin{funcdesc}{tbtrs}{A, B\optional{, uplo='L'\optional{, 
+trans='T'\optional{,diag='N'}}}}
+Solves a triangular set of equations
+\[
+ AX=B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+ A^TX=B \quad (\mathrm{trans} = \mathrm{'T'}), \qquad 
+ A^HX=B \quad (\mathrm{trans} = \mathrm{'C'}), 
+\]
+where {\it A} is real or complex triangular band matrix of order {\it n}, 
+and \var{B} is a matrix with {\it n} rows.
+The diagonals of {\it A} are stored in \var{A} using the BLAS conventions 
+for triangular band matrices. 
+\var{A} and \var{B} are matrices with the same type (\dtc\ or \ztc).
+On exit, \var{B} is replaced by the solution {\it X}.
+\end{funcdesc}
+
+\section{Least-Squares and Least-Norm Problems}
+\begin{funcdesc}{gels}{A, B\optional{, trans='N'}}
+Solves least-squares and least-norm problems with a full rank 
+{\it m} by {\it n} matrix {\it A}.
+
+\begin{enumerate}
+\item \var{trans} is \code{'N'}.  If {\it m} is greater than or equal
+to {\it n}, \function{gels()} solves the least-squares problem
+\[
+ \begin{array}{ll} 
+ \mbox{minimize} & \|AX-B\|_F.
+ \end{array} 
+\]
+If {\it m} is less than or equal to {\it n}, \function{gels()} solves 
+the least-norm problem
+\[
+ \begin{array}{ll} 
+ \mbox{minimize} & \|X\|_F \\
+ \mbox{subject to} & AX = B.
+ \end{array}
+\]
+
+\item \var{trans} is \code{'T'} or \code{'C'} and \var{A} and \var{B}
+are real.  If {\it m} is greater than or equal to {\it n},
+\function{gels()} solves the least-norm problem
+\[
+ \begin{array}{ll} 
+ \mbox{minimize} & \|X\|_F \\
+ \mbox{subject to} & A^TX=B.
+ \end{array}
+\]
+If {\it m} is less than or equal to {\it n}, \function{gels()} solves 
+the least-squares problem
+\[
+ \begin{array}{ll} 
+ \mbox{minimize} & \|A^TX-B\|_F.
+ \end{array}
+\]
+
+\item \var{trans} is \code{'C'} and \var{A} and \var{B}
+are complex. If {\it m} is greater than or equal to {\it n}, 
+\function{gels()} solves the least-norm problem
+\[
+ \begin{array}{ll} 
+ \mbox{minimize} & \|X\|_F \\
+ \mbox{subject to} & A^HX=B.
+ \end{array}
+\]
+If {\it m} is less than or equal to {\it n}, \function{gels()} solves 
+the least-squares problem
+\[
+ \begin{array}{ll} 
+ \mbox{minimize} & \|A^HX-B\|_F.
+ \end{array}
+\]
+\end{enumerate}
+\var{A} and \var{B} must have the same typecode (\dtc\ or \ztc).
+\var{trans} = \code{'T'} is not allowed if \var{A} is complex.
+On exit, the solution {\it X} is stored as the leading submatrix 
+of \var{B}.
+The array \var{A} is overwritten with details of the QR or the LQ 
+factorization of {\it A}.
+Note that \function{gels()} does not check whether $A$ is full rank.
+\end{funcdesc}
+
+\begin{funcdesc}{geqrf}{A, tau}
+QR factorization of a real or complex matrix \var{A}:
+\[
+  A = Q R.
+\]
+If \var{A} is {\it m} by {\it n}, then {\it Q} is {\it m} by {\it m} 
+and orthogonal/unitary, and \var{R} is {\it m} by {\it n}
+and upper triangular (if \var{m} is greater than or equal to \var{n}), 
+or upper trapezoidal (if \var{m} is less than or equal to \var{n}).  
+\var{tau}  is a matrix of the same type as {\var A} and of length at 
+least min\{\var{m}, \var{n}\}.
+On exit, {\it R} is stored in the upper triangular part of \var{A}.
+The matrix {\it Q} is stored as a product of min\{\var{m}, \var{n}\}
+elementary reflectors in the first min\{\var{m}, \var{n}\} columns 
+of \var{A} and in \var{tau}.
+\end{funcdesc}
+
+\begin{funcdesc}{ormqr}{A, tau, C\optional{, side='L'\optional{, 
+trans='N'}}}
+Product with a real orthogonal matrix:
+\[
+ C := \op(Q)C \quad (\mathrm{side} = \mathrm{'L'}), \qquad 
+ C := C\op(Q) \quad (\mathrm{side} = \mathrm{'R'}), \qquad 
+ \op(Q) =  \left\{ \begin{array}{ll}
+ Q & \mathrm{trans} = \mathrm{'N'} \\
+ Q^T & \mathrm{trans} = \mathrm{'T'},
+\end{array}\right.
+\]
+where {\it Q} is square and orthogonal.  
+{\it Q} is stored in \var{A} and \var{tau} as a product 
+of min\{\var{A}.\member{size}[0], \var{A}.\member{size}[1]\} 
+elementary reflectors, as computed by \function{geqrf()}.
+\end{funcdesc}
+
+\begin{funcdesc}{unmqr}{A, tau, C\optional{, side='L'\optional{, 
+trans='N'}}}
+Product with a real orthogonal or complex unitary matrix:
+\[
+ C := \op(Q)C \quad (\mathrm{side} = \mathrm{'L'}), \qquad 
+ C := C\op(Q) \quad (\mathrm{side} = \mathrm{'R'}), \qquad 
+ \op(Q) =  \left\{ \begin{array}{ll}
+ Q & \mathrm{trans} = \mathrm{'N'} \\
+ Q^T & \mathrm{trans} = \mathrm{'T'} \\
+ Q^H & \mathrm{trans} = \mathrm{'C'},
+\end{array}\right.
+\]
+{\it Q} is square and orthogonal or unitary.  
+{\it Q} is stored in \var{A} and \var{tau} as a product of 
+min\{\var{A}.\member{size}[0], \var{A}.\member{size}[1]\} 
+elementary reflectors, as computed by \function{geqrf()}.
+The arrays \var{A}, \var{tau} and \var{C} must have the same type.
+\code{\var{trans} = 'T'} is only allowed if the typecode is \dtc.
+\end{funcdesc}
+
+
+In the following example, we solve a least-squares problem 
+by a direct call to \function{gels()}, and by separate calls to 
+\function{geqrf()}, \function{ormqr()}, and \function{trtrs()}.
+\begin{verbatim}
+>>> from cvxopt import random, blas, lapack
+>>> from cvxopt.base import matrix
+>>> m, n = 10, 5
+>>> A, b = random.normal(m,n), random.normal(m,1)
+>>> x1 = +b
+>>> lapack.gels(+A, x1)                  # x1[:n] minimizes ||A*x1[:n] - b||_2
+>>> tau = matrix(0.0, (n,1)) 
+>>> lapack.geqrf(A, tau)                 # A = [Q1, Q2] * [R1; 0]
+>>> x2 = +b
+>>> lapack.ormqr(A, tau, x2, trans='T')  # x2 := [Q1, Q2]' * b
+>>> lapack.trtrs(A[:n,:], x2, uplo='U')  # x2[:n] := R1^{-1}*x2[:n]
+>>> blas.nrm2(x1[:n] - x2[:n])
+3.0050798580569307e-16
+\end{verbatim}
+
+
+\section{Symmetric and Hermitian Eigenvalue Decomposition}
+The first four routines compute all or selected  eigenvalues and 
+eigenvectors of a real symmetric matrix $A$:
+\[
+ A = V\diag(\lambda)V^T,\qquad  V^TV = I.
+\]
+
+\begin{funcdesc}{syev}{A, W\optional{, jobz='N'\optional{, uplo='L'}}}
+Eigenvalue decomposition of a real symmetric matrix of order {\it n}.
+\var{W} is a real matrix of length at least {\it n}.
+On exit, \var{W} contains the eigenvalues in ascending order.
+If \var{jobz} is \code{'V'}, the eigenvectors are also computed
+and returned in \var{A}.
+If \var{jobz} is \code{'N'}, the eigenvectors are not returned and the 
+contents of \var{A} are destroyed.
+Raises an \code{ArithmeticError} if the eigenvalue decomposition fails.
+\end{funcdesc}
+
+\begin{funcdesc}{syevd}{A, W\optional{, jobz='N'\optional{, uplo='L'}}}
+This is an alternative to \function{syev()}, based on a different
+algorithm.  It is faster on large problems, but also uses more memory.
+\end{funcdesc}
+
+\begin{funcdesc}{syevx}{A, W\optional{, jobz='N'\optional{, 
+range='A'\optional{, uplo='L'\optional{, vl=0.0, vu=0.0\optional{, 
+il=1, iu=1\optional{, Z=\None}}}}}}}
+Computes selected eigenvalues and eigenvectors of a real symmetric 
+matrix \var{A} of order {\it n}.
+
+\var{W} is a real matrix of length at least \var{n}.
+On exit, \var{W} contains the eigenvalues in ascending order.
+If \var{range} is \code{'A'}, all the eigenvalues are computed.
+If \var{range} is \code{'I'}, eigenvalues \var{il} through \var{iu}
+are computed, where \var{1} \code{<=} \var{il} \code{<=} \var{iu} 
+\code{<=} \var{n}. 
+If \var{range} is \code{'V'}, the eigenvalues in the interval 
+\code{(\var{vl},\var{vu}]} are computed. 
+
+If \var{jobz} is \code{'V'}, the (normalized) eigenvectors are 
+computed, and returned in \var{Z}.  If \var{jobz} is \code{'N'}, the 
+eigenvectors are not computed.  In both cases, the contents of \var{A} 
+are destroyed on exit.
+\var{Z} is optional (and not referenced) if \var{jobz} is \code{'N'}.
+It is required if \var{jobz} is \code{'V'} and must have at least
+\var{n} columns if \var{range} is \code{'A'} or \code{'V'} and  at
+least \code{\var{iu}-\var{il}+1} columns if \var{range} is \code{'I'}.
+
+\function{syevx()} returns the number of computed eigenvalues.
+\end{funcdesc}
+
+\begin{funcdesc}{syevr}{A, W\optional{, jobz='N'\optional{, 
+range='A'\optional{, uplo='L'\optional{, vl=0.0, vu=0.0\optional{, 
+il=1, iu=n\optional{, Z=\None}}}}}}}
+This is an alternative to \function{syevx()}. 
+\function{syevr()} is the most recent LAPACK routine for symmetric 
+eigenvalue problems, and expected to supersede the three other 
+routines in future releases.
+\end{funcdesc}
+
+The next four routines can be used to compute eigenvalues and 
+eigenvectors for complex Hermitian matrices:
+\[
+ A = V\diag(\lambda)V^H,\qquad  V^HV = I.
+\]
+For real symmetric matrices they are identical to the corresponding
+\function{syev\_()} routines.
+
+\begin{funcdesc}{heev}{A, W\optional{, jobz='N'\optional{, uplo='L'}}}
+Eigenvalue decomposition of a real symmetric or complex Hermitian
+matrix of order {\it n}.
+The calling sequence is identical to \function{syev()}, except that 
+\var{A} can be real or complex.
+\end{funcdesc}
+
+\begin{funcdesc}{heevd}{A, W\optional{, jobz='N'\optional{, uplo='L'}}}
+This is an alternative to \function{heev()}. 
+\end{funcdesc}
+
+\begin{funcdesc}{heevx}{A, W\optional{, jobz='N'\optional{, 
+range='A'\optional{, uplo='L'\optional{, vl=0.0, vu=0.0 \optional{, 
+il=1, iu=n\optional{, Z=\None}}}}}}}
+Computes selected eigenvalues and eigenvectors of a real symmetric 
+or complex Hermitian matrix of order {\it n}.
+The calling sequence is identical to \function{syevx()},
+except that \var{A} can be real or complex.
+\var{Z} must have the same type as \var{A}.
+\end{funcdesc}
+
+\begin{funcdesc}{heevr}{A, W\optional{, jobz='N'\optional{, 
+range='A'\optional{, uplo='L'\optional{, vl=0.0, vu=0.0\optional{, 
+il=1, iu=n\optional{, Z=\None}}}}}}}
+This is an alternative to \function{heevx()}. 
+\end{funcdesc}
+
+\section{Generalized Symmetric Definite Eigenproblems}
+Three types of generalized eigenvalue problems can be solved:
+\BEQ \label{e-gevd}
+ AZ = BZ\diag(\lambda)\quad \mbox{(type 1)}, \qquad 
+ ABZ = Z\diag(\lambda) \quad \mbox{(type 2)}, \qquad 
+ BAZ = Z\diag(\lambda) \quad \mbox{(type 3)}, 
+\EEQ
+with $A$ and $B$ real symmetric or complex Hermitian, and $B$ positive 
+definite.
+The matrix of eigenvectors is normalized as follows:
+\[
+ Z^H BZ = I \quad \mbox{(types 1 and 2)}, \qquad 
+ Z^H B^{-1}Z = I \quad \mbox{(type 3)}.
+\]
+
+\begin{funcdesc}{sygv}{A, B, W\optional{, itype=1\optional{, 
+jobz='N'\optional{, uplo='L'}}}}
+Solves the generalized eigenproblem~(\ref{e-gevd}) for real symmetric 
+matrices of order {\it n}, stored in real matrices \var{A} and \var{B}.
+\var{itype} is an integer with possible values 1, 2, 3, and specifies
+the type of eigenproblem.
+\var{W} is a real matrix of length at least {\it n}.
+On exit, it contains the eigenvalues in ascending order.
+On exit, \var{B} contains the Cholesky factor of {\it B}.
+If \var{jobz} is \code{'V'}, the eigenvectors are computed
+and returned in \var{A}.
+If \var{jobz} is \code{'N'}, the eigenvectors are not returned and the 
+contents of \var{A} are destroyed.
+\end{funcdesc}
+
+\begin{funcdesc}{hegv}{A, B, W\optional{, itype=1\optional{, 
+jobz='N'\optional{, uplo='L'}}}}
+Generalized eigenvalue problem~(\ref{e-gevd}) of real symmetric or 
+complex Hermitian matrix of order \var{n}.
+The calling sequence is identical to \function{sygv()},
+except that \var{A} and \var{B} can be real or complex.
+\end{funcdesc}
+
+
+\section{Singular Value Decomposition}
+
+\begin{funcdesc}{gesvd}{A, S\optional{, jobu='N'\optional{, 
+jobvt='N'\optional{, U=\None\optional{, Vt=\None}}}}}
+Singular value decomposition 
+\[
+ A = U \Sigma V^T, \qquad A = U \Sigma V^H
+\]
+of a real or complex {\it m} by {\it n} matrix \var{A}.
+
+\var{S} is a real matrix of length at least min\{{\it m}, {\it n}\}.
+On exit, its first  min\{{\it m}, {\it n}\} elements are the 
+singular values in descending order.
+
+The argument \var{jobu} controls how many left singular vectors are
+computed.  The possible values are \code{'N'}, \code{'A'}, \code{'S'} 
+and \code{'O'}. 
+If \var{jobu} is \code{'N'}, no left singular vectors are 
+computed.
+If \var{jobu} is \code{'A'}, all left singular vectors are computed 
+and returned as columns of \var{U}.
+If \var{jobu} is \code{'S'}, the first min\{{\it m},{\it n}\} left 
+singular vectors are computed and returned as columns of \var{U}.
+If \var{jobu} is \code{'O'}, the first min\{{\it m},{\it n}\} left 
+singular vectors are computed and returned as columns of \var{A}.
+The argument \var{U} is \None\ (if \var{jobu} is \code{'N'}
+or \code{'A'}) or a matrix of the same type as \var{A}.
+
+The argument \var{jobvt} controls how many right singular vectors are
+computed.  The possible values are \code{'N'}, \code{'A'}, \code{'S'} 
+and \code{'O'}. 
+If \var{jobvt} is \code{'N'}, no right singular vectors are 
+computed.  If \var{jobvt} is \code{'A'}, all right singular vectors 
+are computed and returned as rows of \var{Vt}.
+If \var{jobvt} is \code{'S'}, the first min\{{\it m},{\it n}\} right 
+singular vectors are computed and their (conjugate) transposes are
+returned as rows of \var{Vt}.
+If \var{jobvt} is \code{'O'}, the first min\{{\it m}, {\it n}\} right 
+singular vectors are computed and their (conjugate) transposes 
+are returned as rows of \var{A}.
+Note that the (conjugate) transposes of the right singular vectors 
+(\ie, the matrix $V^H$) are returned in \var{Vt} or \var{A}.
+The argument \var{Vt} can be \None\ (if \var{jobvt} is \code{'N'}
+or \code{'A'}) or a matrix of the same type as \var{A}.
+
+On exit, the contents of \var{A} are destroyed.
+\end{funcdesc}
+
+\begin{funcdesc}{gesdd}{A, S\optional{, jobz='N'\optional{, 
+U=\None\optional{, Vt=\None}}}} 
+Singular value decomposition of a real or complex {\it m} by {\it n} 
+matrix \var{A}.  This function is based on a divide-and-conquer 
+algorithm and is faster than \function{gesvd()}.
+
+\var{S} is a real matrix of length at least min\{{\it m}, {\it n}\}.
+On exit, its first min\{{\it m}, {\it n}\} elements are the 
+singular values in descending order.
+
+The argument \var{jobz} controls how many singular vectors are
+computed.  The possible values are \code{'N'}, \code{'A'}, \code{'S'} 
+and \code{'O'}. 
+If \var{jobz} is \code{'N'}, no singular vectors are computed.
+If \var{jobz} is \code{'A'}, all {\it m} left singular vectors are 
+computed and returned as columns of \var{U} and all {\it n} right 
+singular vectors are computed and returned as rows of \var{Vt}.
+If \var{jobz} is \code{'S'}, the first min\{{\it m}, {\it n}\} left 
+and right singular vectors are computed and returned as columns of 
+\var{U} and rows of \var{Vt}.
+If \var{jobz} is \code{'O'} and {\it m} is greater than or equal
+to {\it n}, the first {\it n} left singular vectors are returned as
+columns of \var{A} and the {\it n} right singular vectors are returned
+as rows of \var{Vt}.  If \var{jobz} is \code{'O'} and {\it m} is less 
+than {\it n}, the {\it m} left singular vectors are returned as columns
+of \var{U} and the first {\it m} right singular vectors are returned 
+as rows of \var{A}.  
+Note that the (conjugate) transposes of the right singular vectors 
+are returned in \var{Vt} or \var{A}.
+
+The argument \var{U} can be \None\ (if \var{jobz} is \code{'N'}
+or \code{'A'} of \var{jobz} is \code{'O'} and {\it m} is greater than
+or equal to  {\it n})  or a matrix of the same type as \var{A}.
+The argument \var{Vt} can be \None\ (if \var{jobz} is \code{'N'}
+or \code{'A'} or \var{jobz} is \code{'O'} and {\it m} is less than
+{\it n}) or a matrix of the same type as \var{A}.
+
+On exit, the contents of \var{A} are destroyed.
+\end{funcdesc}
+
+\section{Example: Analytic Centering}
+The analytic centering problem is defined as
+\[
+ \begin{array}{ll}
+  \mbox{minimize} & -\sum_{i=1}^m \log(b_i-a_i^Tx).
+ \end{array}
+\]
+In the code below we solve the problem using Newton's method.
+At each iteration the Newton direction is computed by solving 
+a positive definite set of linear equations
+\[
+ A^T \diag(b-Ax)^{-2} A v = -\diag(b-Ax)^{-1}\ones
+\]
+(where {\it A} has rows $a_i^T$), and a suitable step size is determined 
+by a backtracking line search.
+
+We use the level-3 BLAS function \function{syrk()} to form the Hessian 
+matrix and the LAPACK function \function{posv()} to solving the Newton
+system.   The code can be further optimized by replacing the 
+matrix-vector products with the level-2 BLAS function \function{gemv()}.
+
+\begin{verbatim}
+from cvxopt.base import matrix, log, mul, div
+from cvxopt import blas, lapack, random
+from math import sqrt
+
+def acent(A,b):
+    """  
+    Returns the analytic center of A*x <= b.
+    We assume that b > 0 and the feasible set is bounded.
+    """
+
+    MAXITERS = 100
+    ALPHA = 0.01
+    BETA = 0.5
+    TOL = 1e-8
+
+    m, n = A.size
+    x = matrix(0.0, (n,1))
+    H = matrix(0.0, (n,n))
+    g = matrix(0.0, (n,1))
+
+    for iter in xrange(MAXITERS):
+        
+        # Gradient is g = A^T * (1./(b-A*x)).
+        d = (b-A*x)**-1
+        g = A.T * d
+
+        # Hessian is H = A^T * diag(d)^2 * A.
+        Asc = mul( d[:,n*[0]], A )
+        blas.syrk(Asc, H, trans='T')
+
+        # Newton step is v = -H^-1 * g.
+        v = -g
+        lapack.posv(H, v)
+
+        # Terminate if Newton decrement is less than TOL.
+	lam = blas.dot(g, v)
+        if sqrt(-lam) < TOL: return x
+
+        # Backtracking line search.
+        y = mul(A*v, d)
+	step = 1.0
+        while 1-step*max(y) < 0: step *= BETA 
+	while True:
+            if -sum(log(1-step*y)) < ALPHA*step*lam: break
+	    step *= BETA
+        x += step*v
+\end{verbatim}
diff --git a/doc/modeling.tex b/doc/modeling.tex
new file mode 100644
index 0000000..e380dd5
--- /dev/null
+++ b/doc/modeling.tex
@@ -0,0 +1,747 @@
+\chapter{Modeling (\module{cvxopt.modeling})}
+\label{chap:modeling}
+The module \module{cvxopt.modeling} can be used to specify and solve 
+optimization problems  with convex piecewise-linear objective and 
+constraint functions.
+
+To specify an optimization problem one first defines 
+the optimization variables (see section~\ref{s-variables}),
+and then defines the objective and constraint functions 
+using linear operations (vector addition and subtraction,
+matrix-vector multiplication, indexing and slicing)
+and nested evaluations of \function{max()}, \function{min()}, 
+\function{abs()} and \function{sum()} (see section~\ref{s-functions}).
+
+\section{Variables} \label{s-variables}
+Optimization variables are represented by \pytype{variable} objects.
+
+\begin{classdesc}{variable}{\optional{size\optional{, name}}}
+A vector variable.  The first argument is the dimension of the
+vector (a positive integer with default value 1). 
+The second argument is a string with a name for the variable.
+The name is optional and has default value \code{""}. It is only used 
+when displaying variables (or objects that depend on variables, such 
+as functions or constraints) 
+using \function{print} statements, when calling the built-in functions
+\function{repr()}  or \function{str()}, or when writing linear programs
+to MPS files.
+\end{classdesc}
+The function \function{len()} returns the length of a 
+\pytype{variable}.  A \pytype{variable} \var{x} has two attributes.
+\begin{memberdesc}[variable]{name}
+The name of the variable.  
+\end{memberdesc}
+
+\begin{memberdesc}[variable]{value}
+Either \None\  or a dense \dtc\ matrix of size \code{len(\var{x})} by 1.
+
+The attribute \var{x}.\member{value} is set to \None\ when the 
+variable \var{x} is created.   It can be given a numerical value later, 
+typically by solving an LP that has \var{x} as one of its variables.   
+One can also make an explicit assignment 
+\code{\var{x}.\member{value} = \var{y}}.  The
+assigned value \var{y} must be an \intgr\ or \flt, or a 
+dense \dtc\ matrix of size (\code{len(\var{x})},1). 
+If \var{y} is an \intgr\ or \flt\, all the elements of 
+\var{x}.\member{value} are set to the value of \var{y}.
+\end{memberdesc}
+
+\begin{verbatim}
+>>> from cvxopt.base import matrix
+>>> from cvxopt.modeling import variable
+>>> x = variable(3,'a')
+>>> len(x)
+3
+>>> print x.name
+a
+>>> print x.value 
+None
+>>> x.value = matrix([1.,2.,3.])
+>>> print x.value
+ 1.0000e+00
+ 2.0000e+00
+ 3.0000e+00
+>>> x.value = 1
+>>> print x.value
+ 1.0000e+00
+ 1.0000e+00
+ 1.0000e+00
+\end{verbatim}
+
+
+\section{Functions} \label{s-functions}
+Objective and constraint functions can be defined via overloaded 
+operations on variables and other functions.  A function \var{f} is 
+interpreted as a column vector, with length \code{len(\var{f})} 
+and with a value that depends on the values of its variables.  
+Functions have two public attributes.  
+\begin{methoddesc}{variables}{}
+Returns a copy of the list of variables of the function.
+\end{methoddesc}
+
+\begin{methoddesc}{value}{}
+The function value.  If any of the variables of \var{f} has value 
+\None, then \var{f}.\method{value()} returns \None.
+Otherwise, it returns a dense \dtc\ matrix of size 
+(\code{len(\var{f})},1) with the function value computed from the 
+\member{value} attributes of the variables of \var{f}.  
+\end{methoddesc}
+
+Three types of functions are supported: affine, convex 
+piecewise-linear and concave piecewise-linear.
+
+\textbf{Affine functions} represent vector valued functions of the form
+\[
+ f(x_1,\ldots,x_n) = A_1 x_1 + \cdots + A_n x_n + b.
+\]
+The coefficients can be scalars or dense or sparse matrices. The 
+constant term is a scalar or a column vector.
+
+Affine functions result from the following operations.
+\begin{description}
+\item[Unary operations]
+For a variable \var{x}, the unary operation \code{+\var{x}} results in 
+an affine function with \var{x} as variable, coefficient 1.0, and 
+constant term 0.0.  The unary operation \code{-\var{x}} returns an 
+affine function with \var{x} as variable, coefficient -1.0, and 
+constant term 0.0.  For an affine function \var{f}, \code{+\var{f}} is 
+a copy of \var{f}, and \code{-\var{f}} is a copy of \var{f} with the 
+signs of its coefficients and constant term reversed.
+
+\item[Addition and subtraction]
+Sums and differences of affine functions, variables and constants 
+result in new affine functions.
+The constant terms in the sum can be of type \intgr\ or \flt, or
+dense or sparse \dtc\ matrices with one column. 
+
+The rules for addition and subtraction follow the conventions for 
+matrix addition and subtraction in sections~\ref{s-arithmetic}
+and~\ref{s-spmatrix-arith}, with variables and affine functions 
+interpreted as dense \dtc\ matrices with one column.
+In particular, a scalar term (\intgr, \flt, 1 by 1 dense \dtc\ matrix, 
+variable of length 1, or affine function of length 1) can be added 
+to an affine function or variable of length greater than 1.
+
+\item[Multiplication]
+Suppose \var{v} is an affine function or a variable, and \var{a} is 
+an \intgr, \flt, sparse or dense \dtc\ matrix.  The products 
+\code{\var{a}*\var{v}} and  \code{\var{v}*\var{a}} are 
+valid affine functions whenever the product is allowed under the rules 
+for matrix and scalar multiplication  of sections~\ref{s-arithmetic} 
+and~\ref{s-spmatrix-arith}, with \var{v} interpreted as a \dtc\ matrix 
+with one column.
+In particular, the product \code{\var{a}*\var{v}} is defined if 
+\var{a} is a scalar (\intgr, \flt\ or 1 by 1 dense \dtc\ matrix), 
+or a matrix (dense or sparse) with 
+\code{\var{a}.\member{size}[1] = len(\var{v})}.   
+The operation \code{\var{v}*\var{a}} is defined if \var{a} is scalar,
+or if \code{len(\var{v})} = 1 and \var{a} is a matrix with one 
+column.
+
+\item[Inner products]
+The following two functions return scalar affine functions defined
+as inner products of a constant vector with  a variable or affine
+function.
+\begin{funcdesc}{sum}{v}
+The argument is an affine function or a variable.  The result is an
+affine function of length 1, with the sum of the components of the
+argument \var{v}.  
+\end{funcdesc}
+
+\begin{funcdesc}{dot}{u,v}
+If \var{v} is a variable or affine function and \var{u} is a \dtc\
+matrix of size  (\code{len(\var{v})},1), then 
+\code{dot(\var{u},\var{v})} and \code{dot(\var{v},\var{u})} are 
+equivalent to \code{\var{u}.\method{trans()}*\var{v}}.
+
+If \var{u} and \var{v} are dense matrices, then 
+\code{dot(\var{u},\var{v})} 
+is equivalent to the function \code{blas.dot(\var{u},\var{v})} 
+defined in section~\ref{s-blas1}, \ie, it returns the inner product of 
+the two matrices.
+\end{funcdesc}
+\end{description}
+
+In the following example, the variable \var{x} has length 1 and
+\var{y} has length 2.
+The functions \var{f} and \var{g} are given by
+\BEAS
+ f(x,y) & = & \left[ \begin{array}{c} 2 \\ 2 \end{array}\right] x 
+  + y + \left[ \begin{array}{c} 3 \\ 3 \end{array}\right], \\
+ g(x,y) & = &
+  \left[ \begin{array}{cc} 1 & 3 \\ 2 & 4 \end{array}\right] f(x,y)
+  + \left[ \begin{array}{cc} 1 & 1 \\ 1 & 1 \end{array} \right] y + 
+  \left[ \begin{array}{c} 1 \\ -1 \end{array} \right] \\
+ & = & \left[ \begin{array}{c} 8 \\ 12 \end{array}\right] x 
+  + \left[ \begin{array}{cc} 2 & 4 \\ 3 & 5 \end{array}\right] y
+  + \left[ \begin{array}{c} 13 \\ 17\end{array}\right].
+\EEAS
+\begin{verbatim}
+>>> from cvxopt.modeling import variable
+>>> x = variable(1,'x')
+>>> y = variable(2,'y')
+>>> f = 2*x + y + 3  
+>>> A = matrix([[1., 2.], [3.,4.]])
+>>> b = matrix([1.,-1.])
+>>> g = A*f + sum(y) + b 
+>>> print g
+affine function of length 2
+constant term:
+ 1.3000e+01
+ 1.7000e+01
+linear term: linear function of length 2
+coefficient of variable(2,'y'):
+ 2.0000e+00   4.0000e+00
+ 3.0000e+00   5.0000e+00
+coefficient of variable(1,'x'):
+ 8.0000e+00
+ 1.2000e+01
+\end{verbatim}
+
+\begin{description}
+\item[In-place operations] 
+For an affine function \var{f} the operations \code{\var{f} += \var{u}} 
+and \code{\var{f} -= \var{u}}, with \var{u} a constant, a variable or 
+an affine function, are allowed if they do not change the length of 
+\var{f}, \ie, if \var{u} has length \code{len(\var{f})} or length 1.
+In-place multiplication \code{\var{f} *= \var{u}} and division 
+\code{\var{f} /= \var{u}} are allowed if \var{u} is an \intgr, \flt, or 
+1 by 1 matrix.
+\end{description}
+
+\begin{description}
+\item[Indexing and slicing] Variables and affine functions admit 
+single-argument indexing of the four types described in 
+section~\ref{s-indexing}.  The result of an indexing or slicing 
+operation is an affine function.  
+\end{description}
+
+\begin{verbatim}
+>>> x = variable(4,'x')
+>>> f = x[::2]
+>>> print f 
+>>> linear function of length 2
+linear term: linear function of length 2
+coefficient of variable(4,'x'):
+TYPE: general
+SIZE: (2,4)
+(0, 0)  1.0000e+00
+(1, 2)  1.0000e+00
+>>> y = variable(3,'x')
+>>> g = matrix(range(12),(3,4),'d')*x - 3*y + 1
+>>> print g[0] + g[2]
+affine function of length 1 
+constant term:
+ 2.0000e+00
+linear term: linear function of length 1
+coefficient of variable(4,'x'):
+ 2.0000e+00   8.0000e+00   1.4000e+01   2.0000e+01
+coefficient of variable(3,'y'):
+TYPE: general
+SIZE: (1,3)
+(0, 0) -3.0000e+00
+(0, 2) -3.0000e+00
+\end{verbatim}
+
+
+The general expression of a \textbf{convex piecewise-linear} function is
+\[
+ f(x_1,\ldots,x_n) = b + A_1 x_1 + \cdots + A_n x_n + 
+  \sum_{k=1}^K \max (y_1, y_2, \ldots, y_{m_k}).
+\]
+The maximum in this expression is a componentwise maximum of its 
+vector arguments, which can be constant vectors, variables, affine 
+functions or convex piecewise-linear functions.
+The general expression for a \textbf{concave piecewise-linear} function
+is
+\[
+ f(x_1,\ldots,x_n) = b + A_1 x_1 + \cdots + A_n x_n + 
+  \sum_{k=1}^K \min (y_1, y_2, \ldots, y_{m_k}).
+\]
+Here the arguments of the \function{min()} can be constants, variables, 
+affine functions or concave piecewise-linear functions.
+
+Piecewise-linear functions can be created using the following 
+operations.
+\begin{description}
+\item[\function{max}]  If the arguments in 
+\code{\var{f} = max(\var{y1},\var{y2}, \ldots)} 
+do not include any variables or functions, then the Python built-in 
+\function{max()} is evaluated.  
+
+If one or more of the arguments are variables or functions, 
+\function{max()} returns a piecewise-linear function defined as the 
+elementwise maximum of its arguments. 
+In other words, \var{f}[\var{k}] = 
+\code{max(\var{y1}[\var{k}],\var{y2}[\var{k}], \ldots)} 
+for \var{k}=0, \ldots, \code{len(\var{f})}-1.
+The length of \var{f} is equal to the maximum of the lengths of the 
+arguments.  Each argument must have length equal to 
+\code{len(\var{f})} or length one.  
+Arguments with length one are interpreted as vectors of 
+length \code{len(\var{f})} with identical entries.
+
+The arguments can be scalars of type \intgr\ or \flt, 
+dense \dtc\ matrices with one column, variables, affine functions or 
+convex piecewise-linear functions.
+ 
+With one argument, \code{\var{f} = max(\var{u})} is interpreted as
+\code{\var{f} = max(\var{u}[0],\var{u}[1],\ldots,
+\var{u}[\function{len}(\var{u})-1])}.  
+
+\item[\function{min}] Similar to \function{max()} but returns a concave 
+piecewise-linear function.  The arguments can be scalars of type 
+\intgr\ or \flt, dense \dtc\ matrices with one column, 
+variables, affine functions or concave piecewise-linear functions.
+
+\item[\function{abs}] 
+If \var{u} is a variable or affine function then 
+\code{\var{f} = abs(\var{u})} returns the convex piecewise-linear 
+function \code{max(\var{u},-\var{u})}.
+
+\item[Unary plus and minus] \code{+\var{f}}\ creates a copy of \var{f}.
+\code{-\var{f}}\ is a concave piecewise-linear function if \var{f} is 
+convex and a convex piecewise-linear function if \var{f} is concave.
+
+\item[Addition and subtraction]  Sums and differences involving 
+piecewise-linear functions are allowed if they result in convex
+or concave functions. For example, one can add two convex or two
+concave functions, but not a convex and a concave function.
+The command \code{sum(\var{f})} is equivalent
+to \code{\var{f}[0] + \var{f}[1] + \ldots + \var{f}[len(\var{f})-1]}.
+
+\item[Multiplication] Scalar multiplication \code{\var{a}*\var{f}} of a 
+piecewise-linear function \var{f} is defined if \var{a}
+is an \intgr, \flt, 1 by 1 \dtc\ matrix. 
+Matrix-matrix multiplications \code{\var{a}*\var{f}} or 
+\code{\var{f}*\var{a}} are only defined if \var{a} is a dense or 
+sparse 1 by 1 matrix.
+
+\item[Indexing and slicing] Piecewise-linear functions admit 
+single-argument indexing of the four types described in 
+section~\ref{s-indexing}.  The result of an indexing or slicing 
+operation is a new piecewise-linear function.
+\end{description}
+
+In the following example, \var{f} is the 1-norm of a vector
+variable \var{x} of length 10, \var{g} is its infinity-norm and 
+\var{h} is the function
+\[
+  h(x) = \sum_k  \phi(x[k]),\qquad
+  \phi(u) = \left\{\begin{array}{ll}
+     0 & |u| \leq 1 \\
+    |u|-1  & 1 \leq |u| \leq 2 \\
+    2|u|-3  & |u| \geq 2. \end{array}\right.
+\]
+\begin{verbatim}
+>>> f = sum(abs(x))    
+>>> g = max(abs(x))   
+>>> h = sum(max(0, abs(x)-1, 2*abs(x)-3))  
+\end{verbatim}
+
+\begin{description}
+\item[In-place operations]
+If \var{f} is piecewise-linear then the in-place operations  
+\code{\var{f} += \var{u}}, \code{\var{f} -= \var{u}}, 
+\code{\var{f} *= \var{u}}, \code{\var{f} /= \var{u}} are defined if the 
+corresponding expanded operations \code{\var{f} = \var{f}+\var{u}}, 
+\code{\var{f} = \var{f}-\var{u}}, \code{\var{f} = \var{f}*\var{u}}
+and \code{\var{f} = \var{f}/\var{u}} are defined and if they do not 
+change the length of \var{f}.
+\end{description}
+
+\section{Constraints}
+Linear equality and inequality constraints of the form
+\[
+  f(x_1,\ldots,x_n) = 0, \qquad f(x_1,\ldots,x_n) \preceq  0, 
+\]
+where $f$ is a convex function, are represented by \pytype{constraint}
+objects.  Equality constraints are created by expressions of the form 
+\begin{quote}
+\code{\var{f1} == \var{f2}}. 
+\end{quote}
+Here \var{f1} and \var{f2} can be any objects for which the 
+difference \code{\var{f1}-\var{f2}} yields an affine function.  
+Inequality constraints are created by expressions of the form 
+\begin{quote}
+\code{\var{f1} <= \var{f2}}, \qquad \code{\var{f2} >= \var{f1}},
+\end{quote}
+where \var{f1} and \var{f2} can be any objects for which the difference 
+\code{\var{f1}-\var{f2}} yields a convex piecewise-linear function.  
+The comparison operators first convert the expressions to 
+\code{\var{f1}-\var{f2} == 0}, resp.\, \code{\var{f1}-\var{f2} <= 0},
+and then return a new \pytype{constraint}\ object with constraint 
+function
+\code{\var{f1}-\var{f2}}.
+
+In the following example we create three constraints
+\[
+  0 \preceq x \preceq \ones, \qquad \ones^T x = 2,
+\]
+for a variable of length 5.
+\begin{verbatim}
+>>> x = variable(5,'x')
+>>> c1 = (x <= 1)
+>>> c2 = (x >= 0)
+>>> c3 = (sum(x) == 2)
+\end{verbatim}
+
+The built-in fucntion \function{len()} returns the dimension of the
+constraint function.
+
+Constraints have four public attributes.
+\begin{methoddesc}[constraint]{type}{}
+Returns \code{'='} if the constraint is an equality constraint,
+and \code{'<'} if the constraint is an inequality constraint.
+\end{methoddesc}
+
+\begin{methoddesc}[constraint]{value}{}
+Returns the value of the constraint function.  
+\end{methoddesc}
+
+\begin{memberdesc}[constraint]{multiplier}
+For a constraint \var{c}, \var{c}.\member{multiplier} is a 
+\pytype{variable} object of dimension \code{len(\var{c})}.   
+It is used to represent the Lagrange multiplier or dual variable 
+associated with the constraint.
+Its value is initialized as \None, and can be modified
+by making an assignment to \var{c}.\member{multiplier}.\member{value}.
+\end{memberdesc}
+
+\begin{memberdesc}[constraint]{name}
+The name of the constraint.  Changing the name of a constraint
+also changes the name of the multiplier of \var{c}.
+For example, the command \code{\var{c}.\member{name} = 'newname'} also 
+changes
+\var{c}.\member{multiplier}.\member{name} to \code{'newname\_mul'}.
+\end{memberdesc}
+
+
+\section{Optimization Problems} \label{s-lp}
+
+Optimization problems are be constructed by calling the following
+function.
+\begin{classdesc}{op}{\optional{objective\optional{, constraints\optional{, name}}}}
+The first argument specifies the objective function to be minimized.
+It can be an affine or convex piecewise-linear function with length 1, 
+a \pytype{variable} with length 1, or a scalar constant
+(\intgr, \flt\ or 1 by 1 dense \dtc\ matrix).  The default value is
+\code{0.0}.
+
+The second argument is a single \pytype{constraint}, or a list of 
+\pytype{constraint} objects.  The default value is an empty list.
+
+The third argument is a string with a name for the problem.
+The default value is the empty string.
+\end{classdesc}
+
+The following attributes and methods are useful for examining
+and modifying optimization problems.
+
+\begin{memberdesc}[op]{objective}
+The objective or cost function.  One can write to this 
+attribute to change the objective of an existing problem.  
+\end{memberdesc}
+
+\begin{methoddesc}[lp]{variables}{}
+Returns a list of the variables of the problem.
+\end{methoddesc}
+
+\begin{methoddesc}[lp]{constraints}{}
+Returns a list of the constraints.
+\end{methoddesc}
+
+\begin{methoddesc}[lp]{inequalities}{}
+Returns a list of the inequality constraints.
+\end{methoddesc}
+
+\begin{methoddesc}[lp]{equalities}{}
+Returns a list of the equality constraints.
+\end{methoddesc}
+
+\begin{methoddesc}[lp]{delconstraint}{c}
+Deletes constraint {\tt c} from the problem.
+\end{methoddesc}
+
+\begin{methoddesc}[lp]{addconstraint}{c}
+Adds constraint {\tt c} to the problem.
+\end{methoddesc}
+
+An optimization problem with convex piecewise-linear objective and
+constraints can be solved by calling the method \function{solve()}.
+
+\begin{methoddesc}[op]{solve}{\optional{format\optional{, solver}}} 
+This function converts the optimization problem to a linear program
+in matrix form and then solves it using the solver described in 
+section~\ref{s-lpsolver}.
+
+The first argument is either \code{'dense'} or \code{'sparse'}, and 
+denotes the matrix types used in the matrix representation of the LP.
+The default value is \code{'dense'}.
+
+The second argument is either \None. \code{'glpk'} or \code{'mosek'},
+and selects one of three available LP solvers: a default solver 
+written in Python, the GLPK solver (if installed) or the
+MOSEK LP solver (if installed); see section~\ref{s-lpsolver}.
+The default value  is \None.
+
+The solver reports the outcome of optimization by setting 
+the attribute \var{self}.\member{status} and by modifying  
+the \member{value} attributes of the variables and the constraint 
+multipliers of the problem.
+\BIT
+\item If the problem is solved to optimality, 
+\var{self}.\member{status} is set to \code{'optimal'}.  
+The \member{value} attributes of the variables in the problem  are set 
+to their computed solutions, and the \member{value} attributes of the 
+multipliers of the constraints of the problem are set to the computed 
+dual optimal solution.
+
+\item If it is determined that the problem is infeasible, 
+\var{self}.\member{status} is set to \code{'primal infeasible'}.  
+The \member{value} attributes of the variables are set to \None.
+The \member{value} attributes of the 
+multipliers of the constraints of the problem are set to a certificate 
+of primal infeasibility.
+With the \code{'glpk'} option, \function{solve()}
+does not provide certificates of infeasibility.
+
+\item If it is determined that the problem is dual infeasible, 
+\var{self}.\member{status} is set to \code{'dual infeasible'}.  
+The \member{value} attributes of the multipliers of the constraints of 
+the problem are set to \None.
+The \member{value} attributes of the 
+variables are set to a certificate of dual infeasibility. 
+With the \code{'glpk'} option, \function{solve()} does not provide 
+certificates of infeasibility.
+
+\item If the problem was not solved successfully,
+\var{self}.\member{status} is set to \code{'unknown'}.  
+The \member{value} attributes of the variables and the constraint
+multipliers are set to \None.
+\EIT
+\end{methoddesc}
+We refer to section~\ref{s-lpsolver} for details on the algorithms and
+the different solver options.
+
+As an example we solve the LP
+\[
+ \begin{array}{ll}
+  \mbox{minimize} & -4x - 5y \\
+  \mbox{subject to} &  2x +y \leq 3 \\
+ &  x +2y \leq 3 \\
+ & x \geq 0, \quad y \geq 0.
+ \end{array}
+\]
+\begin{verbatim}
+>>> x = variable()
+>>> y = variable()
+>>> c1 = ( 2*x+y <= 3 ) 
+>>> c2 = ( x+2*y <= 3 )
+>>> c3 = ( x >= 0 )
+>>> c4 = ( y >= 0 ) 
+>>> lp1 = op(-4*x-5*y, [c1,c2,c3,c4]) 
+>>> lp1.solve()
+>>> print lp1.status
+optimal
+>>> print lp1.objective.value()
+-9.0000e+00
+>>> print x.value
+ 1.0000e-00
+>>> print y.value
+ 1.0000e-00
+>>> print c1.multiplier.value
+ 1.0000e-00
+>>> print c2.multiplier.value
+ 2.0000e-00
+>>> print c3.multiplier.value
+ 8.8912e-09
+>>> print c4.multiplier.value
+ 9.8567e-09
+\end{verbatim}
+
+We can solve the same LP in  matrix form as follows.
+\begin{verbatim}
+>>> x = variable(2)
+>>> A = matrix([[2.,1.,-1.,0.], [1.,2.,0.,-1.]])
+>>> b = matrix([3.,3.,0.,0.])
+>>> c = matrix([-4.,-5.])
+>>> ineq = ( A*x <= b )
+>>> lp2 = op(dot(c,x), ineq)
+>>> lp2.solve()
+>>> print lp2.objective.value()
+-9.0000e+00
+>>> print x.value
+ 1.0000e-00
+ 1.0000e-00
+>>> print ineq.multiplier.value
+ 1.0000e+00
+ 2.0000e+00
+ 8.8912e-09
+ 9.8567e-09
+\end{verbatim}
+
+The \pytype{op} class also includes two methods for writing and reading
+files in 
+\ulink{MPS format}{http://www-fp.mcs.anl.gov/otc/Guide/OptWeb/continuous/constrained/linearprog/mps.html}.
+
+\begin{methoddesc}[op]{tofile}{filename}
+If the problem is an LP, writes it to the file \code{'filename'} using 
+the MPS format.  Row and column labels are assigned based on the 
+variable and constraint names in the LP.  
+\end{methoddesc}
+
+\begin{methoddesc}[lp]{fromfile}{filename}
+Reads the LP from the file \code{'filename'}.  The file must be 
+a fixed-format MPS file.  Some features of the MPS format are not 
+supported: comments beginning with dollar signs,
+the row types 'DE', 'DL', 'DG', and 'DN', and the capability of
+reading multiple righthand side, bound or range vectors.
+\end{methoddesc}
+
+
+\section{Examples}
+
+\begin{description}
+\item[Norm and Penalty Approximation]
+
+In the first example we solve the norm approximation problems
+\[
+ \begin{array}{ll} 
+ \mbox{minimize} & \|Ax - b\|_\infty,
+ \end{array} \qquad
+ \begin{array}{ll} 
+ \mbox{minimize} & \|Ax - b\|_1
+ \end{array},
+\]
+and the penalty approximation problem
+\[
+ \begin{array}{ll} 
+ \mbox{minimize} & \sum_k \phi((Ax-b)_k), 
+ \end{array} \qquad
+ \phi(u) = \left\{\begin{array}{ll}
+    0 & |u| \leq 3/4 \\
+   |u|-3/4  & 3/4 \leq |u| \leq 3/2 \\
+   2|u|-9/4  & |u| \geq 3/2.\end{array}\right.
+\]
+We use randomly generated data.
+
+The code uses the \ulink{Matplotlib}{http://matplotlib.sourceforge.net}
+package for plotting the histograms of the residual vectors for the
+two solutions.  It generates the figure shown below.
+
+\begin{verbatim}
+from cvxopt.random import normal
+from cvxopt.modeling import variable, op, max, sum
+import pylab
+
+m, n = 500, 100
+A = normal(m,n)
+b = normal(m)
+
+x1 = variable(n)
+op(max(abs(A*x1-b))).solve()
+
+x2 = variable(n)
+op(sum(abs(A*x2-b))).solve()
+
+x3 = variable(n)
+op(sum(max(0, abs(A*x3-b)-0.75, 2*abs(A*x3-b)-2.25))).solve()
+
+pylab.subplot(311)
+pylab.hist(A*x1.value-b, m/5)
+pylab.subplot(312)
+pylab.hist(A*x2.value-b, m/5)
+pylab.subplot(313)
+pylab.hist(A*x3.value-b, m/5)
+pylab.show()
+\end{verbatim}
+
+\begin{center}
+\includegraphics[width=\linewidth]{figures/normappr.eps}
+\end{center}
+
+Equivalently, we can formulate and solve the problems as LPs.
+\begin{verbatim}
+t = variable()
+x1 = variable(n)
+op(t, [-t <= A*x1-b, A*x1-b<=t]).solve()
+
+u = variable(m)
+x2 = variable(n)
+op(sum(u), [-u <= A*x2+b, A*x2+b <= u]).solve()
+
+v = variable(m)
+x3 = variable(n)
+op(sum(v), [v >= 0, v >= A*x3+b-0.75, v >= -(A*x3+b)-0.75, v >= 2*(A*x3-b)-2.25, v >= -2*(A*x3-b)-2.25]).solve()
+\end{verbatim}
+
+
+\item[Robust Linear Programming]
+The robust LP
+\[
+ \begin{array}{ll}
+ \mbox{minimize} & c^T x \\
+ \mbox{subject to} & \sup_{\|v\|_\infty \leq 1} 
+    (a_i+v)^T x \leq b_i, \qquad i=1,\ldots,m
+ \end{array}
+\]
+is equivalent to the problem
+\[
+ \begin{array}{ll}
+ \mbox{minimize} & c^Tx \\
+ \mbox{subject to} & a_i^Tx + \|x\|_1 \leq b_i, \qquad i=1,\ldots,m.
+ \end{array}
+\]
+The following code computes the solution and the solution of
+the equivalent LP
+\[
+ \begin{array}{ll}
+ \mbox{minimize} & c^Tx \\
+ \mbox{subject to} & a_i^Tx + \ones^Ty \leq b_i, \qquad i=1,\ldots,m \\
+& -y \preceq x \preceq y
+\end{array}
+\]
+for randomly generated data.
+
+\begin{verbatim}
+from cvxopt.random import normal, uniform
+from cvxopt.modeling import variable, dot, op, sum 
+from cvxopt.blas import nrm2
+
+m, n = 500, 100
+A = normal(m,n)
+b = uniform(m)
+c = normal(n)
+
+x = variable(n)
+op(dot(c,x), A*x+sum(abs(x)) <= b).solve()
+
+x2 = variable(n)
+y = variable(n)
+op(dot(c,x2), [A*x2+sum(y) <= b, -y <= x2, x2 <= y]).solve()
+\end{verbatim}
+
+
+\item[1-Norm Support Vector Classifier]
+
+The following problem arises in classification:
+\[
+\begin{array}{ll}
+\mbox{minimize} & \|x\|_1 + \ones^Tu \\
+\mbox{subject to} & Ax \succeq \ones -u \\
+& u \succeq 0.
+\end{array}
+\]
+It can be solved as follows.
+\begin{verbatim}
+x = variable(A.size[1],'x')
+u = variable(A.size[0],'u')
+op(sum(abs(x)) + sum(u), [A*x >= 1-u, u >= 0]).solve()
+\end{verbatim}
+An equivalent unconstrained formulation is
+\begin{verbatim}
+x = variable(A.size[1],'x')
+op(sum(abs(x)) + sum(max(0,1-A*x))).solve()
+\end{verbatim}
+\end{description}
diff --git a/doc/python.sty b/doc/python.sty
new file mode 100644
index 0000000..3fdb8b7
--- /dev/null
+++ b/doc/python.sty
@@ -0,0 +1,1330 @@
+%
+% python.sty for the Python docummentation  [works only with Latex2e]
+%
+
+\NeedsTeXFormat{LaTeX2e}[1995/12/01]
+\ProvidesPackage{python}
+             [1998/01/11 LaTeX package (Python markup)]
+
+\RequirePackage{longtable}
+
+% Uncomment these two lines to ignore the paper size and make the page 
+% size more like a typical published manual.
+%\renewcommand{\paperheight}{9in}
+%\renewcommand{\paperwidth}{8.5in}   % typical squarish manual
+%\renewcommand{\paperwidth}{7in}     % O'Reilly ``Programmming Python''
+
+% These packages can be used to add marginal annotations which indicate
+% index entries and labels; useful for reviewing this messy documentation!
+%
+%\RequirePackage{showkeys}
+%\RequirePackage{showidx}
+
+% If we ever want to indent paragraphs, this needs to be changed.
+% This is used inside the macros defined here instead of coding
+% \noindent directly.
+\let\py at parindent=\noindent
+
+% for PDF output, use maximal compression & a lot of other stuff
+% (test for PDF recommended by Tanmoy Bhattacharya <tanmoy at qcd.lanl.gov>)
+%
+\newif\ifpy at doing@page at targets
+\py at doing@page at targetsfalse
+
+\newif\ifpdf\pdffalse
+\ifx\pdfoutput\undefined\else\ifcase\pdfoutput
+\else
+  \pdftrue
+  \input{pdfcolor}
+  \let\py at LinkColor=\NavyBlue
+  \let\py at NormalColor=\Black
+  \pdfcompresslevel=9
+  \pdfpagewidth=\paperwidth    % page width of PDF output
+  \pdfpageheight=\paperheight  % page height of PDF output
+  %
+  % Pad the number with '0' to 3 digits wide so no page name is a prefix
+  % of any other.
+  %
+  \newcommand{\py at targetno}[1]{\ifnum#1<100 0\fi\ifnum#1<10 0\fi#1}
+  \newcommand{\py at pageno}{\py at targetno\thepage}
+  %
+  % This definition allows the entries in the page-view of the ToC to be
+  % active links.  Some work, some don't.
+  %
+  \let\py at OldContentsline=\contentsline
+  %
+  % Backward compatibility hack: pdfTeX 0.13 defined \pdfannotlink,
+  % but it changed to \pdfstartlink in 0.14.  This let's us use either
+  % version and still get useful behavior.
+  %
+  \@ifundefined{pdfstartlink}{
+    \let\pdfstartlink=\pdfannotlink
+  }{}
+  %
+  % The \py at parindent here is a hack -- we're forcing pdfTeX into
+  % horizontal mode since \pdfstartlink requires that.
+  \def\py at pdfstartlink{%
+    \ifvmode\py at parindent\fi%
+    \pdfstartlink%
+  }
+  %
+  % Macro that takes two args: the name to link to and the content of
+  % the link.  This takes care of the PDF magic, getting the colors
+  % the same for each link, and avoids having lots of garbage all over 
+  % this style file.
+  \newcommand{\py at linkToName}[2]{%
+    \py at pdfstartlink attr{/Border [0 0 0]} goto name{#1}%
+      \py at LinkColor#2\py at NormalColor%
+    \pdfendlink%
+  }
+  % Compute the padded page number separately since we end up with a pair of
+  % \relax tokens; this gets the right string computed and works.
+  \renewcommand{\contentsline}[3]{%
+    \def\my at pageno{\py at targetno{#3}}%
+    \py at OldContentsline{#1}{\py at linkToName{page\my at pageno}{#2}}{#3}%
+  }
+  \AtEndDocument{
+    \def\_{\string_}
+    \InputIfFileExists{\jobname.bkm}{\pdfcatalog{/PageMode /UseOutlines}}{}
+  }
+  \newcommand{\py at target}[1]{%
+    \ifpy at doing@page at targets%
+      {\pdfdest name{#1} xyz}%
+    \fi%
+  }
+  \let\py at OldLabel=\label
+  \renewcommand{\label}[1]{%
+    \py at OldLabel{#1}%
+    \py at target{label-#1}%
+  }
+  % This stuff adds a page# destination to every PDF page, where # is three
+  % digits wide, padded with leading zeros.  This doesn't really help with
+  % the frontmatter, but does fine with the body.
+  %
+  % This is *heavily* based on the hyperref package.
+  %
+  \def\@begindvi{%
+    \unvbox \@begindvibox
+    \@hyperfixhead
+  }
+  \def\@hyperfixhead{%
+   \let\H at old@thehead\@thehead
+       \global\def\@foo{\py at target{page\py at pageno}}%
+     \expandafter\ifx\expandafter\@empty\H at old@thehead
+       \def\H at old@thehead{\hfil}\fi
+    \def\@thehead{\@foo\relax\H at old@thehead}%
+  }
+\fi\fi
+
+% Increase printable page size (copied from fullpage.sty)
+\topmargin 0pt
+\advance \topmargin by -\headheight
+\advance \topmargin by -\headsep
+
+% attempt to work a little better for A4 users
+\textheight \paperheight
+\advance\textheight by -2in
+
+\oddsidemargin 0pt
+\evensidemargin 0pt
+%\evensidemargin -.25in  % for ``manual size'' documents
+\marginparwidth 0.5in
+
+\textwidth \paperwidth
+\advance\textwidth by -2in
+
+
+% Style parameters and macros used by most documents here
+\raggedbottom
+\sloppy
+\parindent = 0mm
+\parskip = 2mm
+\hbadness = 5000                % don't print trivial gripes
+
+\pagestyle{empty}               % start this way; change for
+\pagenumbering{roman}           % ToC & chapters
+
+% Use this to set the font family for headers and other decor:
+\newcommand{\py at HeaderFamily}{\sffamily}
+
+% Set up abstract ways to get the normal and smaller font sizes that
+% work even in footnote context.
+\newif\ifpy at infootnote \py at infootnotefalse
+\let\py at oldmakefntext\@makefntext
+\def\@makefntext#1{%
+  \bgroup%
+    \py at infootnotetrue
+    \py at oldmakefntext{#1}%
+  \egroup%
+}
+\def\py at defaultsize{%
+  \ifpy at infootnote\footnotesize\else\normalsize\fi%
+}
+\def\py at smallsize{%
+  \ifpy at infootnote\scriptsize\else\small\fi%
+}
+
+% Redefine the 'normal' header/footer style when using "fancyhdr" package:
+\@ifundefined{fancyhf}{}{
+  % Use \pagestyle{normal} as the primary pagestyle for text.
+  \fancypagestyle{normal}{
+    \fancyhf{}
+    \fancyfoot[LE,RO]{{\py at HeaderFamily\thepage}}
+    \fancyfoot[LO]{{\py at HeaderFamily\nouppercase{\rightmark}}}
+    \fancyfoot[RE]{{\py at HeaderFamily\nouppercase{\leftmark}}}
+    \renewcommand{\headrulewidth}{0pt}
+    \renewcommand{\footrulewidth}{0.4pt}
+  }
+  % Update the plain style so we get the page number & footer line,
+  % but not a chapter or section title.  This is to keep the first
+  % page of a chapter and the blank page between chapters `clean.'
+  \fancypagestyle{plain}{
+    \fancyhf{}
+    \fancyfoot[LE,RO]{{\py at HeaderFamily\thepage}}
+    \renewcommand{\headrulewidth}{0pt}
+    \renewcommand{\footrulewidth}{0.4pt}
+  }
+  % Redefine \cleardoublepage so that the blank page between chapters
+  % gets the plain style and not the fancy style.  This is described
+  % in the documentation for the fancyhdr package by Piet von Oostrum.
+  \@ifundefined{chapter}{}{
+    \renewcommand{\cleardoublepage}{
+      \clearpage\if at openright \ifodd\c at page\else
+      \hbox{}
+      \thispagestyle{plain}
+      \newpage
+      \if at twocolumn\hbox{}\newpage\fi\fi\fi
+    }
+  }
+}
+
+% This sets up the {verbatim} environment to be indented and a minipage,
+% and to have all the other mostly nice properties that we want for
+% code samples.
+
+\let\py at OldVerbatim=\verbatim
+\let\py at OldEndVerbatim=\endverbatim
+\RequirePackage{verbatim}
+\let\py at OldVerbatimInput=\verbatiminput
+
+% Variable used by begin code command
+\newlength{\py at codewidth}
+
+\renewcommand{\verbatim}{%
+  \setlength{\parindent}{1cm}%
+  % Calculate the text width for the minipage:
+  \setlength{\py at codewidth}{\linewidth}%
+  \addtolength{\py at codewidth}{-\parindent}%
+  %
+  \par\indent%
+  \begin{minipage}[t]{\py at codewidth}%
+    \small%
+    \py at OldVerbatim%
+}
+\renewcommand{\endverbatim}{%
+    \py at OldEndVerbatim%
+  \end{minipage}%
+}
+\renewcommand{\verbatiminput}[1]{%
+  {\setlength{\parindent}{1cm}%
+   % Calculate the text width for the minipage:
+   \setlength{\py at codewidth}{\linewidth}%
+   \addtolength{\py at codewidth}{-\parindent}%
+   %
+   \small%
+   \begin{list}{}{\setlength{\leftmargin}{1cm}}
+     \item%
+     \py at OldVerbatimInput{#1}%
+   \end{list}
+  }%
+}
+
+% This does a similar thing for the {alltt} environment:
+\RequirePackage{alltt}
+\let\py at OldAllTT=\alltt
+\let\py at OldEndAllTT=\endalltt
+
+\renewcommand{\alltt}{%
+  \setlength{\parindent}{1cm}%
+  % Calculate the text width for the minipage:
+  \setlength{\py at codewidth}{\linewidth}%
+  \addtolength{\py at codewidth}{-\parindent}%
+  \let\e=\textbackslash%
+  %
+  \par\indent%
+  \begin{minipage}[t]{\py at codewidth}%
+    \small%
+    \py at OldAllTT%
+}
+\renewcommand{\endalltt}{%
+    \py at OldEndAllTT%
+  \end{minipage}%
+}
+
+
+\newcommand{\py at modulebadkey}{{--just-some-junk--}}
+
+
+%%  Lots of index-entry generation support.
+
+% Command to wrap around stuff that refers to function / module /
+% attribute names  in the index.  Default behavior: like \code{}.  To
+% just keep the index entries in the roman font, uncomment the second
+% definition; it matches O'Reilly style more.
+%
+\newcommand{\py at idxcode}[1]{\texttt{#1}}
+%\renewcommand{\py at idxcode}[1]{#1}
+
+% Command to generate two index entries (using subentries)
+\newcommand{\indexii}[2]{\index{#1!#2}\index{#2!#1}}
+
+% And three entries (using only one level of subentries)
+\newcommand{\indexiii}[3]{\index{#1!#2 #3}\index{#2!#3, #1}\index{#3!#1 #2}}
+
+% And four (again, using only one level of subentries)
+\newcommand{\indexiv}[4]{
+\index{#1!#2 #3 #4}
+\index{#2!#3 #4, #1}
+\index{#3!#4, #1 #2}
+\index{#4!#1 #2 #3}
+}
+
+% Command to generate a reference to a function, statement, keyword,
+% operator.
+\newcommand{\kwindex}[1]{\indexii{keyword}{#1@{\py at idxcode{#1}}}}
+\newcommand{\stindex}[1]{\indexii{statement}{#1@{\py at idxcode{#1}}}}
+\newcommand{\opindex}[1]{\indexii{operator}{#1@{\py at idxcode{#1}}}}
+\newcommand{\exindex}[1]{\indexii{exception}{#1@{\py at idxcode{#1}}}}
+\newcommand{\obindex}[1]{\indexii{object}{#1}}
+\newcommand{\bifuncindex}[1]{%
+  \index{#1@{\py at idxcode{#1()}} (built-in function)}}
+
+% Add an index entry for a module
+\newcommand{\py at refmodule}[2]{\index{#1@{\py at idxcode{#1}} (#2module)}}
+\newcommand{\refmodindex}[1]{\py at refmodule{#1}{}}
+\newcommand{\refbimodindex}[1]{\py at refmodule{#1}{built-in }}
+\newcommand{\refexmodindex}[1]{\py at refmodule{#1}{extension }}
+\newcommand{\refstmodindex}[1]{\py at refmodule{#1}{standard }}
+
+% Refer to a module's documentation using a hyperlink of the module's
+% name, at least if we're building PDF:
+\ifpdf
+  \newcommand{\refmodule}[2][\py at modulebadkey]{%
+    \ifx\py at modulebadkey#1\def\py at modulekey{#2}\else\def\py at modulekey{#1}\fi%
+    \py at linkToName{label-module-\py at modulekey}{\module{#2}}%
+  }
+\else
+  \newcommand{\refmodule}[2][\py at modulebadkey]{\module{#2}}
+\fi
+
+% support for the module index
+\newif\ifpy at UseModuleIndex
+\py at UseModuleIndexfalse
+
+\newcommand{\makemodindex}{
+  \newwrite\modindexfile
+  \openout\modindexfile=mod\jobname.idx
+  \py at UseModuleIndextrue
+}
+
+% Add the defining entry for a module
+\newcommand{\py at modindex}[2]{%
+  \renewcommand{\py at thismodule}{#1}
+  \setindexsubitem{(in module #1)}%
+  \index{#1@{\py at idxcode{#1}} (#2module)|textbf}%
+  \ifpy at UseModuleIndex%
+    \@ifundefined{py at modplat@\py at thismodulekey}{
+      \write\modindexfile{\protect\indexentry{#1@{\texttt{#1}}}{\thepage}}%
+    }{\write\modindexfile{\protect\indexentry{#1@{\texttt{#1} %
+        \emph{(\py at platformof[\py at thismodulekey]{})}}}{\thepage}}%
+    }
+  \fi%
+}
+
+% *** XXX *** THE NEXT FOUR MACROS ARE NOW OBSOLETE !!! ***
+
+% built-in & Python modules in the main distribution
+\newcommand{\bimodindex}[1]{\py at modindex{#1}{built-in }%
+  \typeout{*** MACRO bimodindex IS OBSOLETE -- USE declaremodule INSTEAD!}}
+\newcommand{\stmodindex}[1]{\py at modindex{#1}{standard }%
+  \typeout{*** MACRO stmodindex IS OBSOLETE -- USE declaremodule INSTEAD!}}
+
+% Python & extension modules outside the main distribution
+\newcommand{\modindex}[1]{\py at modindex{#1}{}%
+  \typeout{*** MACRO modindex IS OBSOLETE -- USE declaremodule INSTEAD!}}
+\newcommand{\exmodindex}[1]{\py at modindex{#1}{extension }%
+  \typeout{*** MACRO exmodindex IS OBSOLETE -- USE declaremodule INSTEAD!}}
+
+% Additional string for an index entry
+\newif\ifpy at usingsubitem\py at usingsubitemfalse
+\newcommand{\py at indexsubitem}{}
+\newcommand{\setindexsubitem}[1]{\renewcommand{\py at indexsubitem}{ #1}%
+                                 \py at usingsubitemtrue}
+\newcommand{\ttindex}[1]{%
+  \ifpy at usingsubitem
+    \index{#1@{\py at idxcode{#1}}\py at indexsubitem}%
+  \else%
+    \index{#1@{\py at idxcode{#1}}}%
+  \fi%
+}
+\newcommand{\withsubitem}[2]{%
+  \begingroup%
+    \def\ttindex##1{\index{##1@{\py at idxcode{##1}} #1}}%
+    #2%
+  \endgroup%
+}
+
+
+% Module synopsis processing -----------------------------------------------
+%
+\newcommand{\py at thisclass}{}
+\newcommand{\py at thismodule}{}
+\newcommand{\py at thismodulekey}{}
+\newcommand{\py at thismoduletype}{}
+
+\newcommand{\py at standardIndexModule}[1]{\py at modindex{#1}{standard }}
+\newcommand{\py at builtinIndexModule}[1]{\py at modindex{#1}{built-in }}
+\newcommand{\py at extensionIndexModule}[1]{\py at modindex{#1}{extension }}
+\newcommand{\py at IndexModule}[1]{\py at modindex{#1}{}}
+
+\newif\ifpy at HaveModSynopsis       \py at HaveModSynopsisfalse
+\newif\ifpy at ModSynopsisFileIsOpen \py at ModSynopsisFileIsOpenfalse
+\newif\ifpy at HaveModPlatform       \py at HaveModPlatformfalse
+
+% \declaremodule[key]{type}{name}
+\newcommand{\declaremodule}[3][\py at modulebadkey]{
+  \py at openModSynopsisFile
+  \renewcommand{\py at thismoduletype}{#2}
+  \ifx\py at modulebadkey#1
+    \renewcommand{\py at thismodulekey}{#3}
+  \else
+    \renewcommand{\py at thismodulekey}{#1}
+  \fi
+  \@ifundefined{py@#2IndexModule}{%
+    \typeout{*** MACRO declaremodule called with unknown module type: `#2'}
+    \py at IndexModule{#3}%
+  }{%
+    \csname py@#2IndexModule\endcsname{#3}%
+  }
+  \label{module-\py at thismodulekey}
+}
+\newif\ifpy at ModPlatformFileIsOpen \py at ModPlatformFileIsOpenfalse
+\newcommand{\py at ModPlatformFilename}{\jobname.pla}
+\newcommand{\platform}[1]{
+  \ifpy at ModPlatformFileIsOpen\else
+    \newwrite\py at ModPlatformFile
+    \openout\py at ModPlatformFile=\py at ModPlatformFilename
+    \py at ModPlatformFileIsOpentrue
+  \fi
+}
+\InputIfFileExists{\jobname.pla}{}{}
+\newcommand{\py at platformof}[2][\py at modulebadkey]{%
+  \ifx\py at modulebadkey#1 \def\py at key{#2}%
+  \else \def\py at key{#1}%
+  \fi%
+  \csname py at modplat@\py at key\endcsname%
+}
+\newcommand{\ignorePlatformAnnotation}[1]{}
+
+% \moduleauthor{name}{email}
+\newcommand{\moduleauthor}[2]{}
+
+% \sectionauthor{name}{email}
+\newcommand{\sectionauthor}[2]{}
+
+
+\newcommand{\py at defsynopsis}{Module has no synopsis.}
+\newcommand{\py at modulesynopsis}{\py at defsynopsis}
+\newcommand{\modulesynopsis}[1]{
+  \py at HaveModSynopsistrue
+  \renewcommand{\py at modulesynopsis}{#1}
+}
+
+% define the file
+\newwrite\py at ModSynopsisFile
+
+% hacked from \addtocontents from latex.ltx:
+\long\def\py at writeModSynopsisFile#1{%
+  \protected at write\py at ModSynopsisFile%
+      {\let\label\@gobble \let\index\@gobble \let\glossary\@gobble}%
+      {\string#1}%
+}
+\newcommand{\py at closeModSynopsisFile}{
+  \ifpy at ModSynopsisFileIsOpen
+    \closeout\py at ModSynopsisFile
+    \py at ModSynopsisFileIsOpenfalse
+  \fi
+}
+\newcommand{\py at openModSynopsisFile}{
+  \ifpy at ModSynopsisFileIsOpen\else
+    \openout\py at ModSynopsisFile=\py at ModSynopsisFilename
+    \py at ModSynopsisFileIsOpentrue
+  \fi
+}
+
+\newcommand{\py at ProcessModSynopsis}{
+  \ifpy at HaveModSynopsis
+    \py at writeModSynopsisFile{\modulesynopsis%
+      {\py at thismodulekey}{\py at thismodule}%
+      {\py at thismoduletype}{\py at modulesynopsis}}%
+    \py at HaveModSynopsisfalse
+  \fi
+  \renewcommand{\py at modulesynopsis}{\py at defsynopsis}
+}
+\AtEndDocument{\py at ProcessModSynopsis\py at closeModSynopsisFile}
+
+
+\long\def\py at writeModPlatformFile#1{%
+  \protected at write\py at ModPlatformFile%
+    {\let\label\@gobble \let\index\@gobble \let\glossary\@gobble}%
+    {\string#1}%
+}
+
+
+\newcommand{\localmoduletable}{
+  \IfFileExists{\py at ModSynopsisFilename}{
+    \begin{synopsistable}
+      \input{\py at ModSynopsisFilename}
+    \end{synopsistable}
+  }{}
+}
+
+\ifpdf
+  \newcommand{\py at ModSynopsisSummary}[4]{%
+    \py at linkToName{label-module-#1}{\bfcode{#2}} & #4\\
+  }
+\else
+  \newcommand{\py at ModSynopsisSummary}[4]{\bfcode{#2} & #4\\}
+\fi
+\newenvironment{synopsistable}{
+  % key, name, type, synopsis
+  \let\modulesynopsis=\py at ModSynopsisSummary
+  \begin{tabular}{ll}
+}{
+  \end{tabular}
+}
+%
+% --------------------------------------------------------------------------
+
+
+\newcommand{\py at reset}{
+  \py at usingsubitemfalse
+  \py at ProcessModSynopsis
+  \renewcommand{\py at thisclass}{}
+  \renewcommand{\py at thismodule}{}
+  \renewcommand{\py at thismodulekey}{}
+  \renewcommand{\py at thismoduletype}{}
+}
+
+% Augment the sectioning commands used to get our own font family in place,
+% and reset some internal data items:
+\renewcommand{\section}{\py at reset%
+                        \@startsection{section}{1}{\z@}%
+                                    {-3.5ex \@plus -1ex \@minus -.2ex}%
+                                    {2.3ex \@plus.2ex}%
+                                    {\reset at font\Large\py at HeaderFamily}}
+\renewcommand{\subsection}{\@startsection{subsection}{2}{\z@}%
+                                    {-3.25ex\@plus -1ex \@minus -.2ex}%
+                                    {1.5ex \@plus .2ex}%
+                                    {\reset at font\large\py at HeaderFamily}}
+\renewcommand{\subsubsection}{\@startsection{subsubsection}{3}{\z@}%
+                                    {-3.25ex\@plus -1ex \@minus -.2ex}%
+                                    {1.5ex \@plus .2ex}%
+                                    {\reset at font\normalsize\py at HeaderFamily}}
+\renewcommand{\paragraph}{\@startsection{paragraph}{4}{\z@}%
+                                    {3.25ex \@plus1ex \@minus.2ex}%
+                                    {-1em}%
+                                    {\reset at font\normalsize\py at HeaderFamily}}
+\renewcommand{\subparagraph}{\@startsection{subparagraph}{5}{\parindent}%
+                                    {3.25ex \@plus1ex \@minus .2ex}%
+                                    {-1em}%
+                                    {\reset at font\normalsize\py at HeaderFamily}}
+
+
+% This gets the underscores closer to the right width; the only change
+% from standard LaTeX is the width specified.
+
+\DeclareTextCommandDefault{\textunderscore}{%
+  \leavevmode \kern.06em\vbox{\hrule\@width.55em}}
+
+% Underscore hack (only act like subscript operator if in math mode)
+%
+% The following is due to Mark Wooding (the old version didn't work with
+% Latex 2e.
+
+%%\DeclareRobustCommand\hackscore{%
+%%  \ifmmode_\else\textunderscore\fi%
+%%}
+%%\begingroup
+%%\catcode`\_\active
+%%\def\next{%
+%%  \AtBeginDocument{\catcode`\_\active\def_{\hackscore{}}}%
+%%}
+%%\expandafter\endgroup\next
+
+
+% Now for a lot of semantically-loaded environments that do a ton of magical
+% things to get the right formatting and index entries for the stuff in
+% Python modules and C API.
+
+
+% {fulllineitems} is used in one place in libregex.tex, but is really for
+% internal use in this file.
+%
+\newcommand{\py at itemnewline}[1]{%
+  \@tempdima\linewidth%
+  \advance\@tempdima \leftmargin\makebox[\@tempdima][l]{#1}%
+}
+
+\newenvironment{fulllineitems}{
+  \begin{list}{}{\labelwidth \leftmargin \labelsep 0pt
+                 \rightmargin 0pt \topsep -\parskip \partopsep \parskip
+                 \itemsep -\parsep
+                 \let\makelabel=\py at itemnewline}
+}{\end{list}}
+
+% \optional is mostly for use in the arguments parameters to the various
+% {*desc} environments defined below, but may be used elsewhere.  Known to
+% be used in the debugger chapter.
+%
+% Typical usage:
+%
+%     \begin{funcdesc}{myfunc}{reqparm\optional{, optparm}}
+%                                    ^^^       ^^^
+%                          No space here       No space here
+%
+% When a function has multiple optional parameters, \optional should be
+% nested, not chained.  This is right:
+%
+%     \begin{funcdesc}{myfunc}{\optional{parm1\optional{, parm2}}}
+%
+\let\py at badkey=\@undefined
+
+\newcommand{\optional}[1]{%
+  {\textnormal{\Large[}}{#1}\hspace{0.5mm}{\textnormal{\Large]}}}
+
+% This can be used when a function or method accepts an varying number 
+% of arguments, such as by using the *args syntax in the parameter list.
+\newcommand{\py at moreargs}{...}
+
+% This can be used when you don't want to document the parameters to a 
+% function or method, but simply state that it's an alias for
+% something else.
+\newcommand{\py at unspecified}{...}
+
+
+\newlength{\py at argswidth}
+\newcommand{\py at sigparams}[1]{%
+  \parbox[t]{\py at argswidth}{\py at varvars{#1}\code{)}}}
+\newcommand{\py at sigline}[2]{%
+  \settowidth{\py at argswidth}{#1\code{(}}%
+  \addtolength{\py at argswidth}{-2\py at argswidth}%
+  \addtolength{\py at argswidth}{\textwidth}%
+  \item[#1\code{(}\py at sigparams{#2}]}
+
+% C functions ------------------------------------------------------------
+% \begin{cfuncdesc}[refcount]{type}{name}{arglist}
+% Note that the [refcount] slot should only be filled in by
+% tools/anno-api.py; it pulls the value from the refcounts database.
+\newcommand{\cfuncline}[3]{
+  \py at sigline{\code{#1 \bfcode{#2}}}{#3}%
+  \index{#2@{\py at idxcode{#2()}}}
+}
+\newenvironment{cfuncdesc}[4][\py at badkey]{
+  \begin{fulllineitems}
+    \cfuncline{#2}{#3}{#4}
+    \ifx#1\@undefined\else%
+      \emph{Return value: \textbf{#1}.}\\
+    \fi
+}{\end{fulllineitems}}
+
+% C variables ------------------------------------------------------------
+% \begin{cvardesc}{type}{name}
+\newenvironment{cvardesc}[2]{
+  \begin{fulllineitems}
+    \item[\code{#1 \bfcode{#2}}\index{#2@{\py at idxcode{#2}}}]
+}{\end{fulllineitems}}
+
+% C data types -----------------------------------------------------------
+% \begin{ctypedesc}[index name]{typedef name}
+\newenvironment{ctypedesc}[2][\py at badkey]{
+  \begin{fulllineitems}
+    \item[\bfcode{#2}%
+    \ifx#1\@undefined%
+      \index{#2@{\py at idxcode{#2}} (C type)}
+    \else%
+      \index{#2@{\py at idxcode{#1}} (C type)}
+    \fi]
+}{\end{fulllineitems}}
+
+% C type fields ----------------------------------------------------------
+% \begin{cmemberdesc}{container type}{ctype}{membername}
+\newcommand{\cmemberline}[3]{
+  \item[\code{#2 \bfcode{#3}}]
+  \index{#3@{\py at idxcode{#3}} (#1 member)}
+}
+\newenvironment{cmemberdesc}[3]{
+  \begin{fulllineitems}
+    \cmemberline{#1}{#2}{#3}
+}{\end{fulllineitems}}
+
+% Funky macros -----------------------------------------------------------
+% \begin{csimplemacrodesc}{name}
+% -- "simple" because it has no args; NOT for constant definitions!
+\newenvironment{csimplemacrodesc}[1]{
+  \begin{fulllineitems}
+    \item[\bfcode{#1}\index{#1@{\py at idxcode{#1}} (macro)}]
+}{\end{fulllineitems}}
+
+% simple functions (not methods) -----------------------------------------
+% \begin{funcdesc}{name}{args}
+\newcommand{\funcline}[2]{%
+  \funclineni{#1}{#2}%
+  \index{#1@{\py at idxcode{#1()}} (in module \py at thismodule)}}
+\newenvironment{funcdesc}[2]{
+  \begin{fulllineitems}
+    \funcline{#1}{#2}
+}{\end{fulllineitems}}
+
+% similar to {funcdesc}, but doesn't add to the index
+\newcommand{\funclineni}[2]{%
+  \py at sigline{\bfcode{#1}}{#2}}
+\newenvironment{funcdescni}[2]{
+  \begin{fulllineitems}
+    \funclineni{#1}{#2}
+}{\end{fulllineitems}}
+
+% classes ----------------------------------------------------------------
+% \begin{classdesc}{name}{constructor args}
+\newenvironment{classdesc}[2]{
+  % Using \renewcommand doesn't work for this, for unknown reasons:
+  \global\def\py at thisclass{#1}
+  \begin{fulllineitems}
+    \py at sigline{\strong{class }\bfcode{#1}}{#2}%
+    \index{#1@{\py at idxcode{#1}} (class in \py at thismodule)}
+}{\end{fulllineitems}}
+
+% \begin{classdesc*}{name}
+\newenvironment{classdesc*}[1]{
+  % Using \renewcommand doesn't work for this, for unknown reasons:
+  \global\def\py at thisclass{#1}
+  \begin{fulllineitems}
+    \item[\strong{class }\code{\bfcode{#1}}%
+      \index{#1@{\py at idxcode{#1}} (class in \py at thismodule)}]
+}{\end{fulllineitems}}
+
+% \begin{excclassdesc}{name}{constructor args}
+% but indexes as an exception
+\newenvironment{excclassdesc}[2]{
+  % Using \renewcommand doesn't work for this, for unknown reasons:
+  \global\def\py at thisclass{#1}
+  \begin{fulllineitems}
+    \py at sigline{\strong{exception }\bfcode{#1}}{#2}%
+    \index{#1@{\py at idxcode{#1}} (exception in \py at thismodule)}
+}{\end{fulllineitems}}
+
+% There is no corresponding {excclassdesc*} environment.  To describe
+% a class exception without parameters, use the {excdesc} environment.
+
+
+\let\py at classbadkey=\@undefined
+
+% object method ----------------------------------------------------------
+% \begin{methoddesc}[classname]{methodname}{args}
+\newcommand{\methodline}[3][\@undefined]{
+  \methodlineni{#2}{#3}
+  \ifx#1\@undefined
+    \index{#2@{\py at idxcode{#2()}} (\py at thisclass\ method)}
+  \else
+    \index{#2@{\py at idxcode{#2()}} (#1 method)}
+  \fi
+}
+\newenvironment{methoddesc}[3][\@undefined]{
+  \begin{fulllineitems}
+    \ifx#1\@undefined
+      \methodline{#2}{#3}
+    \else
+      \def\py at thisclass{#1}
+      \methodline{#2}{#3}
+    \fi
+}{\end{fulllineitems}}
+
+% similar to {methoddesc}, but doesn't add to the index
+% (never actually uses the optional argument)
+\newcommand{\methodlineni}[3][\py at classbadkey]{%
+  \py at sigline{\bfcode{#2}}{#3}}
+\newenvironment{methoddescni}[3][\py at classbadkey]{
+  \begin{fulllineitems}
+    \methodlineni{#2}{#3}
+}{\end{fulllineitems}}
+
+% object data attribute --------------------------------------------------
+% \begin{memberdesc}[classname]{membername}
+\newcommand{\memberline}[2][\py at classbadkey]{%
+  \ifx#1\@undefined
+    \memberlineni{#2}
+    \index{#2@{\py at idxcode{#2}} (\py at thisclass\ attribute)}
+  \else
+    \memberlineni{#2}
+    \index{#2@{\py at idxcode{#2}} (#1 attribute)}
+  \fi
+}
+\newenvironment{memberdesc}[2][\py at classbadkey]{
+  \begin{fulllineitems}
+    \ifx#1\@undefined
+      \memberline{#2}
+    \else
+      \def\py at thisclass{#1}
+      \memberline{#2}
+    \fi
+}{\end{fulllineitems}}
+
+% similar to {memberdesc}, but doesn't add to the index
+% (never actually uses the optional argument)
+\newcommand{\memberlineni}[2][\py at classbadkey]{\item[\bfcode{#2}]}
+\newenvironment{memberdescni}[2][\py at classbadkey]{
+  \begin{fulllineitems}
+    \memberlineni{#2}
+}{\end{fulllineitems}}
+
+% For exceptions: --------------------------------------------------------
+% \begin{excdesc}{name}
+%  -- for constructor information, use excclassdesc instead
+\newenvironment{excdesc}[1]{
+  \begin{fulllineitems}
+    \item[\strong{exception }\bfcode{#1}%
+          \index{#1@{\py at idxcode{#1}} (exception in \py at thismodule)}]
+}{\end{fulllineitems}}
+
+% Module data or constants: ----------------------------------------------
+% \begin{datadesc}{name}
+\newcommand{\dataline}[1]{%
+  \datalineni{#1}\index{#1@{\py at idxcode{#1}} (data in \py at thismodule)}}
+\newenvironment{datadesc}[1]{
+  \begin{fulllineitems}
+    \dataline{#1}
+}{\end{fulllineitems}}
+
+% similar to {datadesc}, but doesn't add to the index
+\newcommand{\datalineni}[1]{\item[\bfcode{#1}]\nopagebreak}
+\newenvironment{datadescni}[1]{
+  \begin{fulllineitems}
+    \datalineni{#1}
+}{\end{fulllineitems}}
+
+% bytecode instruction ---------------------------------------------------
+% \begin{opcodedesc}{name}{var}
+% -- {var} may be {}
+\newenvironment{opcodedesc}[2]{
+  \begin{fulllineitems}
+    \item[\bfcode{#1}\quad\var{#2}]
+}{\end{fulllineitems}}
+
+
+\newcommand{\nodename}[1]{\label{#1}}
+
+% For these commands, use \command{} to get the typography right, not 
+% {\command}.  This works better with the texinfo translation.
+\newcommand{\ABC}{{\sc abc}}
+\newcommand{\UNIX}{{\sc Unix}}
+\newcommand{\POSIX}{POSIX}
+\newcommand{\ASCII}{{\sc ascii}}
+\newcommand{\Cpp}{C\protect\raisebox{.18ex}{++}}
+\newcommand{\C}{C}
+\newcommand{\EOF}{{\sc eof}}
+\newcommand{\NULL}{\constant{NULL}}
+\newcommand{\infinity}{\ensuremath{\infty}}
+\newcommand{\plusminus}{\ensuremath{\pm}}
+
+% \guilabel{Start}
+\newcommand{\guilabel}[1]{\textsf{#1}}
+% \menuselection{Start \sub Programs \sub Python}
+\newcommand{\menuselection}[1]{\guilabel{{\def\sub{ \ensuremath{>} }#1}}}
+
+% Also for consistency: spell Python "Python", not "python"!
+
+% code is the most difficult one...
+\newcommand{\code}[1]{\textrm{\@vobeyspaces\@noligs\def\{{\char`\{}\def\}{\char`\}}\def\~{\char`\~}\def\^{\char`\^}\def\e{\char`\\}\def\${\char`\$}\def\#{\char`\#}\def\&{\char`\&}\def\%{\char`\%}%
+\texttt{#1}}}
+
+\newcommand{\bfcode}[1]{\code{\bfseries#1}} % bold-faced code font
+\newcommand{\csimplemacro}[1]{\code{#1}}
+\newcommand{\kbd}[1]{\code{#1}}
+\newcommand{\samp}[1]{`\code{#1}'}
+\newcommand{\var}[1]{%
+  \ifmmode%
+    \hbox{\py at defaultsize\textrm{\textit{#1\/}}}%
+  \else%
+    \py at defaultsize\textrm{\textit{#1\/}}%
+  \fi%
+}
+\renewcommand{\emph}[1]{{\em #1}}
+\newcommand{\dfn}[1]{\emph{#1}}
+\newcommand{\strong}[1]{{\bf #1}}
+% let's experiment with a new font:
+\newcommand{\file}[1]{`\filenq{#1}'}
+\newcommand{\filenq}[1]{{\py at smallsize\textsf{\let\e=\textbackslash#1}}}
+
+% Use this def/redef approach for \url{} since hyperref defined this already,
+% but only if we actually used hyperref:
+\ifpdf
+  \newcommand{\url}[1]{{%
+    \py at pdfstartlink attr{/Border [0 0 0]} user{/S /URI /URI (#1)}%
+    \py at LinkColor%                              color of the link text
+    \py at smallsize\sf #1%
+    \py at NormalColor%                    Turn it back off; these are declarative
+    \pdfendlink}%                       and don't appear bound to the current
+  }%                                    formatting "box".
+\else
+  \newcommand{\url}[1]{\mbox{\py at smallsize\textsf{#1}}}
+\fi
+\newcommand{\email}[1]{{\py at smallsize\textsf{#1}}}
+\newcommand{\newsgroup}[1]{{\py at smallsize\textsf{#1}}}
+
+\newcommand{\py at varvars}[1]{{%
+  {\let\unspecified=\py at unspecified%
+   \let\moreargs=\py at moreargs%
+   \var{#1}}}}
+
+% I'd really like to get rid of this!
+\newif\iftexi\texifalse
+
+% This is used to get l2h to put the copyright and abstract on
+% a separate HTML page.
+\newif\ifhtml\htmlfalse
+
+
+% These should be used for all references to identifiers which are
+% used to refer to instances of specific language constructs.  See the
+% names for specific semantic assignments.
+%
+% For now, don't do anything really fancy with them; just use them as
+% logical markup.  This might change in the future.
+%
+\newcommand{\module}[1]{\texttt{#1}}
+\newcommand{\keyword}[1]{\texttt{#1}}
+\newcommand{\exception}[1]{\texttt{#1}}
+\newcommand{\class}[1]{\texttt{#1}}
+\newcommand{\function}[1]{\texttt{#1}}
+\newcommand{\member}[1]{\texttt{#1}}
+\newcommand{\method}[1]{\texttt{#1}}
+
+\newcommand{\pytype}[1]{#1}             % built-in Python type
+
+\newcommand{\cfunction}[1]{\texttt{#1}}
+\newcommand{\ctype}[1]{\texttt{#1}}     % C struct or typedef name
+\newcommand{\cdata}[1]{\texttt{#1}}     % C variable, typically global
+
+\newcommand{\mailheader}[1]{{\py at smallsize\textsf{#1:}}}
+\newcommand{\mimetype}[1]{{\py at smallsize\textsf{#1}}}
+% The \! is a "negative thin space" in math mode.
+\newcommand{\regexp}[1]{%
+  {\tiny$^{^\lceil}\!\!$%
+   {\py at defaultsize\code{#1}}%
+   $\!\rfloor\!$%
+  }}
+\newcommand{\envvar}[1]{%
+  #1%
+  \index{#1}%
+  \index{environment variables!{#1}}%
+}
+\newcommand{\makevar}[1]{#1}            % variable in a Makefile
+\newcommand{\character}[1]{\samp{#1}}
+
+% constants defined in Python modules or C headers, not language constants:
+\newcommand{\constant}[1]{\code{#1}}    % manifest constant, not syntactic
+
+\newcommand{\manpage}[2]{{\emph{#1}(#2)}}
+\newcommand{\pep}[1]{PEP #1\index{Python Enhancement Proposals!PEP #1}}
+\newcommand{\rfc}[1]{RFC #1\index{RFC!RFC #1}}
+\newcommand{\program}[1]{\strong{#1}}
+\newcommand{\programopt}[1]{\strong{#1}}
+% Note that \longprogramopt provides the '--'!
+\newcommand{\longprogramopt}[1]{\strong{-{}-#1}}
+
+% \ulink{link text}{URL}
+\ifpdf
+  \newcommand{\ulink}[2]{{%
+    % For PDF, we *should* only generate a link when the URL is absolute.
+    \py at pdfstartlink attr{/Border [0 0 0]} user{/S /URI /URI (#2)}%
+    \py at LinkColor%                              color of the link text
+    #1%
+    \py at NormalColor%                    Turn it back off; these are declarative
+    \pdfendlink}%                       and don't appear bound to the current
+  }%                                    formatting "box".
+\else
+  \newcommand{\ulink}[2]{#1}
+\fi
+
+% cited titles:  \citetitle{Title of Work}
+%       online:  \citetitle[url-to-resource]{Title of Work}
+\ifpdf
+  \newcommand{\citetitle}[2][\py at modulebadkey]{%
+    \ifx\py at modulebadkey#1\emph{#2}\else\ulink{\emph{#2}}{#1}\fi%
+  }
+\else
+  \newcommand{\citetitle}[2][URL]{\emph{#2}}
+\fi
+
+
+
+% This version is being checked in for the historical record; it shows
+% how I've managed to get some aspects of this to work.  It will not
+% be used in practice, so a subsequent revision will change things
+% again.  This version has problems, but shows how to do something
+% that proved more tedious than I'd expected, so I don't want to lose
+% the example completely.
+%
+\newcommand{\grammartoken}[1]{\texttt{#1}}
+\newenvironment{productionlist}[1][\py at badkey]{
+  \def\optional##1{{\Large[}##1{\Large]}}
+  \def\production##1##2{\code{##1}&::=&\code{##2}\\}
+  \def\productioncont##1{& &\code{##1}\\}
+  \def\token##1{##1}
+  \let\grammartoken=\token
+  \parindent=2em
+  \indent
+  \begin{tabular}{lcl}
+}{%
+  \end{tabular}
+}
+
+\newlength{\py at noticelength}
+
+\newcommand{\py at heavybox}{
+  \setlength{\fboxrule}{2pt}
+  \setlength{\fboxsep}{7pt}
+  \setlength{\py at noticelength}{\linewidth}
+  \addtolength{\py at noticelength}{-2\fboxsep}
+  \addtolength{\py at noticelength}{-2\fboxrule}
+  \setlength{\shadowsize}{3pt}
+  \Sbox
+  \minipage{\py at noticelength}
+}
+\newcommand{\py at endheavybox}{
+  \endminipage
+  \endSbox
+  \fbox{\TheSbox}
+}
+
+% a 'note' is as plain as it gets:
+\newcommand{\py at noticelabel@note}{Note:}
+\newcommand{\py at noticestart@note}{}
+\newcommand{\py at noticeend@note}{}
+
+% a 'warning' gets more visible distinction:
+\newcommand{\py at noticelabel@warning}{Warning:}
+\newcommand{\py at noticestart@warning}{\py at heavybox}
+\newcommand{\py at noticeend@warning}{\py at endheavybox}
+
+\newenvironment{notice}[1][note]{
+  \def\py at noticetype{#1}
+  \csname py at noticestart@#1\endcsname
+  \par\strong{\csname py at noticelabel@#1\endcsname}
+}{\csname py at noticeend@\py at noticetype\endcsname}
+\newcommand{\note}[1]{\strong{\py at noticelabel@note} #1}
+\newcommand{\warning}[1]{\strong{\py at noticelabel@warning} #1}
+
+% Deprecation stuff.
+% Should be extended to allow an index / list of deprecated stuff.  But
+% there's a lot of stuff that needs to be done to make that automatable.
+%
+% First parameter is the release number that deprecates the feature, the
+% second is the action the should be taken by users of the feature.
+%
+% Example:
+%  \deprecated{1.5.1}{Use \method{frobnicate()} instead.}
+%
+\newcommand{\deprecated}[2]{%
+  \strong{Deprecated since release #1.}  #2\par}
+
+% New stuff.
+% This should be used to mark things which have been added to the
+% development tree but that aren't in the release, but are documented.
+% This allows release of documentation that already includes updated
+% descriptions.  Place at end of descriptor environment.
+%
+% Example:
+%  \versionadded{1.5.2}
+%  \versionchanged[short explanation]{2.0}
+%
+\newcommand{\versionadded}[2][\py at badkey]{%
+  \ifx#1\@undefined%
+    {  New in version #2.  }%
+  \else%
+    {  New in version #2:\ #1.  }%
+  \fi%
+}
+\newcommand{\versionchanged}[2][\py at badkey]{%
+  \ifx#1\@undefined%
+    {  Changed in version #2.  }%
+  \else%
+    {  Changed in version #2:\ #1.  }%
+  \fi%
+}
+
+
+% Tables.
+%
+\newenvironment{tableii}[4]{%
+  \begin{center}%
+    \def\lineii##1##2{\csname#2\endcsname{##1}&##2\\}%
+    \begin{tabular}{#1}\strong{#3}&\strong{#4} \\* \hline%
+}{%
+    \end{tabular}%
+  \end{center}%
+}
+
+\newenvironment{longtableii}[4]{%
+  \begin{center}%
+    \def\lineii##1##2{\csname#2\endcsname{##1}&##2\\}%
+    \begin{longtable}[c]{#1}\strong{#3}&\strong{#4} \\* \hline\endhead%
+}{%
+    \end{longtable}%
+  \end{center}%
+}
+
+\newenvironment{tableiii}[5]{%
+  \begin{center}%
+    \def\lineiii##1##2##3{\csname#2\endcsname{##1}&##2&##3\\}%
+    \begin{tabular}{#1}\strong{#3}&\strong{#4}&\strong{#5} \\%
+      \hline%
+}{%
+    \end{tabular}%
+  \end{center}%
+}
+
+\newenvironment{longtableiii}[5]{%
+  \begin{center}%
+    \def\lineiii##1##2##3{\csname#2\endcsname{##1}&##2&##3\\}%
+    \begin{longtable}[c]{#1}\strong{#3}&\strong{#4}&\strong{#5} \\%
+      \hline\endhead%
+}{%
+    \end{longtable}%
+  \end{center}%
+}
+
+\newenvironment{tableiv}[6]{%
+  \begin{center}%
+    \def\lineiv##1##2##3##4{\csname#2\endcsname{##1}&##2&##3&##4\\}%
+    \begin{tabular}{#1}\strong{#3}&\strong{#4}&\strong{#5}&\strong{#6} \\%
+      \hline%
+}{%
+    \end{tabular}%
+  \end{center}%
+}
+
+\newenvironment{longtableiv}[6]{%
+  \begin{center}%
+    \def\lineiv##1##2##3##4{\csname#2\endcsname{##1}&##2&##3&##4\\}%
+    \begin{longtable}[c]{#1}\strong{#3}&\strong{#4}&\strong{#5}&\strong{#6}%
+      \\%
+      \hline\endhead%
+}{%
+    \end{longtable}%
+  \end{center}%
+}
+
+\newenvironment{tablev}[7]{%
+  \begin{center}%
+    \def\linev##1##2##3##4##5{\csname#2\endcsname{##1}&##2&##3&##4&##5\\}%
+    \begin{tabular}{#1}\strong{#3}&\strong{#4}&\strong{#5}&\strong{#6}&\strong{#7} \\%
+      \hline%
+}{%
+    \end{tabular}%
+  \end{center}%
+}
+
+\newenvironment{longtablev}[7]{%
+  \begin{center}%
+    \def\linev##1##2##3##4##5{\csname#2\endcsname{##1}&##2&##3&##4&##5\\}%
+    \begin{longtable}[c]{#1}\strong{#3}&\strong{#4}&\strong{#5}&\strong{#6}&\strong{#7}%
+      \\%
+      \hline\endhead%
+}{%
+    \end{longtable}%
+  \end{center}%
+}
+
+% XXX Don't think we can use this yet, though it cleans up some
+% tedious markup.  There's no equivalent for the HTML transform yet,
+% and that needs to exist.  I don't know how to write it.
+%
+% This should really have something that makes it easier to bind a
+% table's ``Notes'' column and an associated tablenotes environment,
+% and generates the right magic for getting the numbers right in the
+% table.
+%
+% So this is quite incomplete.
+%
+\newcounter{py at tablenotescounter}
+\newenvironment{tablenotes}{%
+  \noindent Notes:
+  \par
+  \setcounter{py at tablenotescounter}{0}
+  \begin{list}{(\arabic{py at tablenotescounter})}%
+              {\usecounter{py at tablenotescounter}}
+}{\end{list}}
+
+
+% Cross-referencing (AMK, new impl. FLD)
+% Sample usage:
+%  \begin{seealso}
+%    \seemodule{rand}{Uniform random number generator.}; % Module xref
+%    \seetext{\emph{Encyclopedia Britannica}}.           % Ref to a book
+% 
+%    % A funky case: module name contains '_'; have to supply an optional key
+%    \seemodule[copyreg]{copy_reg}{Interface constructor registration for
+%                                  \module{pickle}.}
+%  \end{seealso}
+%
+% Note that the last parameter for \seemodule and \seetext should be complete
+% sentences and be terminated with the proper punctuation.
+
+\ifpdf
+  \newcommand{\py at seemodule}[3][\py at modulebadkey]{%
+    \par%
+    \ifx\py at modulebadkey#1\def\py at modulekey{#2}\else\def\py at modulekey{#1}\fi%
+    \begin{fulllineitems}
+      \item[\py at linkToName{label-module-\py at modulekey}{Module \module{#2}}
+            (section \ref{module-\py at modulekey}):]
+      #3
+    \end{fulllineitems}
+  }
+\else
+  \newcommand{\py at seemodule}[3][\py at modulebadkey]{%
+    \par%
+    \ifx\py at modulebadkey#1\def\py at modulekey{#2}\else\def\py at modulekey{#1}\fi%
+    \begin{fulllineitems}
+      \item[Module \module{#2} (section \ref{module-\py at modulekey}):]
+      #3
+    \end{fulllineitems}
+  }
+\fi
+
+% \seelink{url}{link text}{why it's interesting}
+\newcommand{\py at seelink}[3]{%
+  \par
+  \begin{fulllineitems}
+    \item[\ulink{#2}{#1}]
+    #3
+  \end{fulllineitems}
+}
+% \seetitle[url]{title}{why it's interesting}
+\newcommand{\py at seetitle}[3][\py at modulebadkey]{%
+  \par
+  \begin{fulllineitems}
+    \item[\citetitle{#2}]
+    \ifx\py at modulebadkey#1\else
+      \item[{\small{(\url{#1})}}]
+    \fi
+    #3
+  \end{fulllineitems}
+}
+% \seepep{number}{title}{why it's interesting}
+\newcommand{\py at seepep}[3]{%
+  \par%
+  \begin{fulllineitems}
+    \item[\pep{#1}, ``\emph{#2}'']
+    #3
+  \end{fulllineitems}
+}
+% \seerfc{number}{title}{why it's interesting}
+\newcommand{\py at seerfc}[3]{%
+  \par%
+  \begin{fulllineitems}
+    \item[\rfc{#1}, ``\emph{#2}'']
+    #3
+  \end{fulllineitems}
+}
+% \seeurl{url}{why it's interesting}
+\newcommand{\py at seeurl}[2]{%
+  \par%
+  \begin{fulllineitems}
+    \item[\url{#1}]
+    #2
+  \end{fulllineitems}
+}
+
+\newenvironment{seealso*}{
+  \par
+  \def\seetext##1{\par{##1}}
+  \let\seemodule=\py at seemodule
+  \let\seepep=\py at seepep
+  \let\seerfc=\py at seerfc
+  \let\seetitle=\py at seetitle
+  \let\seeurl=\py at seeurl
+  \let\seelink=\py at seelink
+}{\par}
+\newenvironment{seealso}{
+  \par
+  \strong{See Also:}
+  \par
+  \def\seetext##1{\par{##1}}
+  \let\seemodule=\py at seemodule
+  \let\seepep=\py at seepep
+  \let\seerfc=\py at seerfc
+  \let\seetitle=\py at seetitle
+  \let\seeurl=\py at seeurl
+  \let\seelink=\py at seelink
+}{\par}
+
+% Allow the Python release number to be specified independently of the
+% \date{}.  This allows the date to reflect the document's date and
+% release to specify the Python release that is documented.
+%
+\newcommand{\py at release}{}
+\newcommand{\version}{}
+\newcommand{\shortversion}{}
+\newcommand{\releaseinfo}{}
+\newcommand{\releasename}{Release}
+\newcommand{\release}[1]{%
+  \renewcommand{\py at release}{\releasename\space\version}%
+  \renewcommand{\version}{#1}}
+\newcommand{\setshortversion}[1]{%
+  \renewcommand{\shortversion}{#1}}
+\newcommand{\setreleaseinfo}[1]{%
+  \renewcommand{\releaseinfo}{#1}}
+
+% Allow specification of the author's address separately from the
+% author's name.  This can be used to format them differently, which
+% is a good thing.
+%
+\newcommand{\py at authoraddress}{}
+\newcommand{\authoraddress}[1]{\renewcommand{\py at authoraddress}{#1}}
+\let\developersaddress=\authoraddress
+\let\developer=\author
+\let\developers=\author
+
+% This sets up the fancy chapter headings that make the documents look
+% at least a little better than the usual LaTeX output.
+%
+\@ifundefined{ChTitleVar}{}{
+  \ChNameVar{\raggedleft\normalsize\py at HeaderFamily}
+  \ChNumVar{\raggedleft \bfseries\Large\py at HeaderFamily}
+  \ChTitleVar{\raggedleft \rm\Huge\py at HeaderFamily}
+  % This creates chapter heads without the leading \vspace*{}:
+  \def\@makechapterhead#1{%
+    {\parindent \z@ \raggedright \normalfont
+      \ifnum \c at secnumdepth >\m at ne
+        \DOCH
+      \fi
+      \interlinepenalty\@M
+      \DOTI{#1}
+    }
+  }
+}
+
+
+% Definition lists; requested by AMK for HOWTO documents.  Probably useful
+% elsewhere as well, so keep in in the general style support.
+%
+\newenvironment{definitions}{%
+  \begin{description}%
+  \def\term##1{\item[##1]\mbox{}\\*[0mm]}
+}{%
+  \end{description}%
+}
+
+% Tell TeX about pathological hyphenation cases:
+\hyphenation{Base-HTTP-Re-quest-Hand-ler}
diff --git a/doc/solvers.tex b/doc/solvers.tex
new file mode 100644
index 0000000..90c014f
--- /dev/null
+++ b/doc/solvers.tex
@@ -0,0 +1,1578 @@
+\chapter{Optimization Routines (\module{cvxopt.solvers})}
+\label{chap:solvers}
+
+\section{Linear Programming} \label{s-lpsolver}
+
+\begin{funcdesc}{lp}{c, G, h\optional{, A, b\optional{, 
+solver\optional{, primalstart\optional{, dualstart}}}}}
+Solves the pair of primal and dual LPs
+\BEQ \label{e-lp}
+\mbox{Primal:}\quad \begin{array}[t]{ll}
+\mbox{minimize} & c^Tx \\
+\mbox{subject to} &  Gx + s = h \\ & Ax=b \\ & s \succeq 0
+\end{array} \qquad\qquad
+\mbox{Dual:}\quad
+\begin{array}[t]{ll}
+\mbox{maximize}   & -h^T z - b^T y \\
+\mbox{subject to} & G^Tz + A^T y  + c = 0 \\ & z \succeq 0.
+\end{array}
+\EEQ 
+\var{c}, \var{h} and \var{b} are real single-column dense matrices.
+\var{G} and \var{A} are real dense or sparse matrices.
+The default values for \var{A} and \var{b} are sparse matrices with 
+zero rows, meaning that there are no equality constraints.  
+
+The \var{solver} argument is used to choose among three solvers.  
+When it is omitted or \None, the default CVXOPT solver is used.   
+The external solvers GLPK and MOSEK (if installed) can be selected by 
+setting \code{\var{solver}='glpk'} or 
+\code{\var{solver}='mosek'}; see section~\ref{s-external}.
+
+The optional arguments \var{primalstart} and \var{dualstart} are only
+referenced by the default solver.  
+\var{primalstart} is a dictionary with keys \code{'x'} and \code{'s'}, 
+used as an optional primal starting point. 
+\var{dualstart} is a dictionary with keys \code{'y'} and \code{'z'}, 
+used as an optional dual starting point.
+
+\function{lp()} returns a dictionary with keys \code{'status'}, 
+\code{'x'}, \code{'s'}, \code{'y'}, \code{'z'}.  
+The possible values of the \code{'status'} item are as follows.
+\begin{description}
+\item[\code{'optimal'.}] In this case the \code{'x'}, \code{'s'}, 
+\code{'y'} and \code{'z'} entries contain the primal and dual solutions,
+which approximately satisfy
+\[
+ Gx + s = h, \qquad Ax=b, \qquad G^T z  + A^T y + c = 0, \qquad 
+ s \succeq 0, \qquad z \succeq 0,  \qquad s^T z =0.
+\]
+
+\item[\code{'primal infeasible'.}]  
+The \code{'x'} and \code{'s'} entries are \None, and the \code{'y'}, 
+\code{'z'} entries provide an approximate certificate of 
+infeasibility, \ie, vectors that approximately satisfy
+\[
+ G^T z + A^T y = 0, \qquad h^T z + b^T y = -1, \qquad z \succeq 0.
+\]
+With the \code{'glpk'} option, no proof of infeasibility is returned
+(all entries of the dictionary are \None).
+
+\item[\code{'dual infeasible'.}]  The LP is dual infeasible.
+The \code{'y'} and \code{'z'} entries are \None, and the \code{'x'} 
+and \code{'s'} entries contain an approximate certificate of dual 
+infeasibility 
+\[
+ Gx + s = 0, \qquad Ax=0, \qquad  c^T x = -1, \qquad s \succeq 0.
+\]
+With the \code{'glpk'} option, no proof of dual infeasibility is 
+returned.
+
+\item[\code{'unknown'}.] The \code{'x'}, \code{'s'}, \code{'y'}, 
+\code{'z'} entries are \None.
+\end{description}
+
+%The default solver requires that
+%\[
+% \Rank(A) = p, \qquad \Rank (\left[ \begin{array}{c} G \\ A\end{array}
+% \right]) = n
+%\]
+%where \var{p} is the number of equality constraints and \var{n}
+%is the number of primal variables (dimension of \var{x}).
+\end{funcdesc}
+
+As a simple example we solve the LP
+\[
+ \begin{array}[t]{ll}
+  \mbox{minimize} & -4x_1 - 5x_2 \\
+  \mbox{subject to} &  2x_1 + x_2 \leq 3 \\
+ & x_1 + 2x_2 \leq 3 \\
+ & x_1 \geq 0, \quad x_2 \geq 0.
+ \end{array} 
+\]
+\begin{verbatim}
+>>> from cvxopt.base import matrix
+>>> from cvxopt import solvers 
+>>> c = matrix([-4., -5.])
+>>> G = matrix([[2., 1., -1., 0.], [1., 2., 0., -1.]])
+>>> h = matrix([3., 3., 0., 0.])
+>>> sol = solvers.lp(c,G,h)
+>>> print sol['x']
+   1.0000e-00
+   1.0000e-00
+\end{verbatim}
+
+\section{Quadratic Programming}
+\begin{funcdesc}{qp}{P, q, \optional{, G, h \optional{, A, b\optional{,
+solver}}}}
+Solves a convex quadratic program  
+\[
+\begin{array}{ll}
+\mbox{minimize} & (1/2) x^TPx + q^T x \\
+\mbox{subject to} & Gx \preceq h \\ & Ax = b.
+\end{array}
+\]
+
+\var{P} is a square dense or sparse real matrix, representing a 
+symmetric matrix in \code{'L'} storage, \ie, only the lower 
+triangular part of \var{P} is referenced.
+\var{G} and \var{A} are dense or sparse real matrices.
+Their default values are sparse matrices with zero columns.
+\var{q}, \var{h} and \var{b} are single-column real dense matrices.
+The default values of \var{h} and \var{b} are matrices of size (0,1).
+
+The default CVXOPT solver is used when the \var{solver} argument
+is absent or \None.  The MOSEK solver (if installed) can be 
+selected by setting \var{solver}=\code{'mosek'}.
+
+\function{qp()} returns a dictionary with keys 
+\code{'status'}, \code{'x'}, \code{'s'}, \code{'y'}, \code{'z'}.
+The possible values of the \code{'status'} key are as follows.
+\begin{description}
+\item[\code{'optimal'}]  In this case the 
+\code{'x'} entry is the primal optimal solution,
+the \code{'s'} entry is the corresponding slack in the inequality
+constraints, the \code{'z'} and \code{'y'} entries are the optimal 
+values of the dual variables associated with the linear inequality 
+and linear equality constraints.
+These values (approximately) satisfy the optimality conditions
+\[
+ Px + q + G^T z + A^T y = 0, \qquad Gx + s = h, \qquad
+ Ax = b, \qquad s \succeq 0, \qquad z \succeq 0, \qquad s^T z = 0. 
+\]
+
+\item [\code{'primal infeasible'}]  This only applies when
+\var{solver} is \code{'mosek'}, and means that a certificate of
+primal infeasibility has been found.   The \code{'x'} and \code{'s'} 
+entries are \None, and the
+\code{'z'} and \code{'y'} entries are vectors that approximately satisfy
+\[
+ G^Tz + A^T y = 0, \qquad h^Tz + b^Ty = -1, \qquad z \succeq 0.
+\]
+
+\item [\code{'dual infeasible'}]  This only applies when
+\var{solver} is \code{'mosek'}, and means that a certificate of
+dual infeasibility has been found.   The \code{'z'} and \code{'y'}
+entries are \None, and the \code{'x'} and \code{'s'} entries are
+vectors that approximately satisfy
+\[
+ Px = 0, \qquad q^Tx = -1, \qquad Gx + s = 0, \qquad Ax=0, \qquad
+ s \succeq  0.
+\]
+
+\item[\code{'unknown'}] This means that the algorithm reached
+the maximum number of iterations before a solution was found.
+The \code{'x'}, \code{'s'}, \code{'y'}, \code{'z'} entries are \None. 
+\end{description}
+\end{funcdesc}
+
+As an example we compute the trade-off curve on page 187
+of the book \citetitle[http://www.stanford.edu/\~{}boyd/cvxbook]{Convex 
+Optimization}, by solving the quadratic program 
+\[
+\begin{array}{ll}
+\mbox{minimize} & -\bar p^T x + \mu x^T S x \\
+\mbox{subject to} & \ones^T x = 1, \quad x \succeq 0
+\end{array}
+\]
+for a sequence of positive values of {\it mu}. 
+The code below computes the trade-off curve and produces two figures 
+using the \ulink{Matplotlib}{http://matplotlib.sourceforge.net} package.
+\begin{center}
+\includegraphics[width=10cm]{figures/portfolio1.eps}
+\hspace*{\fill}
+\includegraphics[width=10cm]{figures/portfolio2.eps}
+\end{center}
+
+\begin{verbatim}
+from math import sqrt
+from cvxopt.base import matrix
+from cvxopt.blas import dot 
+from cvxopt.solvers import qp
+import pylab
+
+# Problem data.
+n = 4
+S = matrix([[ 4e-2,  6e-3, -4e-3,    0.0 ], 
+            [ 6e-3,  1e-2,  0.0,     0.0 ],
+            [-4e-3,  0.0,   2.5e-3,  0.0 ],
+            [ 0.0,   0.0,   0.0,     0.0 ]])
+pbar = matrix([.12, .10, .07, .03])
+G = matrix(0.0, (n,n))
+G[::n+1] = -1.0
+h = matrix(0.0, (n,1))
+A = matrix(1.0, (1,n))
+b = matrix(1.0)
+
+# Compute trade-off.
+N = 100
+mus = [ 10**(5.0*t/N-1.0) for t in xrange(N) ]
+portfolios = [ qp(mu*S, -pbar, G, h, A, b)['x'] for mu in mus ]
+returns = [ dot(pbar,x) for x in portfolios ]
+risks = [ sqrt(dot(x, S*x)) for x in portfolios ]
+
+# Plot trade-off curve and optimal allocations.
+pylab.figure(1, facecolor='w')
+pylab.plot(risks, returns)
+pylab.xlabel('standard deviation')
+pylab.ylabel('expected return')
+pylab.axis([0, 0.2, 0, 0.15])
+pylab.title('Risk-return trade-off curve (fig 4.12)')
+pylab.yticks([0.00, 0.05, 0.10, 0.15])
+
+pylab.figure(2, facecolor='w')
+c1 = [ x[0] for x in portfolios ] 
+c2 = [ x[0] + x[1] for x in portfolios ]
+c3 = [ x[0] + x[1] + x[2] for x in portfolios ] 
+c4 = [ x[0] + x[1] + x[2] + x[3] for x in portfolios ]
+pylab.fill(risks + [.20], c1 + [0.0], '#F0F0F0') 
+pylab.fill(risks[-1::-1] + risks, c2[-1::-1] + c1, '#D0D0D0') 
+pylab.fill(risks[-1::-1] + risks, c3[-1::-1] + c2, '#F0F0F0') 
+pylab.fill(risks[-1::-1] + risks, c4[-1::-1] + c3, '#D0D0D0') 
+pylab.axis([0.0, 0.2, 0.0, 1.0])
+pylab.xlabel('standard deviation')
+pylab.ylabel('allocation')
+pylab.text(.15,.5,'x1')
+pylab.text(.10,.7,'x2')
+pylab.text(.05,.7,'x3')
+pylab.text(.01,.7,'x4')
+pylab.title('Optimal allocations (fig 4.12)')
+pylab.show()
+\end{verbatim}
+
+
+\section{Geometric Programming}
+\begin{funcdesc}{gp}{K, F, g \optional{, G, h \optional{, A, b}}}
+Solves a geometric program in convex form
+\[
+\begin{array}{ll}
+\mbox{minimize} & f_0(x) = \lse(F_0x+g_0) \\ 
+\mbox{subject to} & f_i(x) = \lse(F_ix+g_i) \leq 0,\quad i=1,\ldots,m \\
+ & Gx \preceq h \\
+ & Ax=b
+\end{array}
+\]
+where
+\[
+ \lse(u) = \log \sum_k \exp(u_k), \qquad
+ F = \left[ \begin{array}{cccc}
+ F_0^T & F_1^T & \cdots & F_m^T \end{array}\right]^T, \qquad
+ g = \left[ \begin{array}{cccc}
+ g_0^T & g_1^T & \cdots & g_m^T \end{array}\right]^T. 
+\]
+\var{K} is a list of \var{m}+1 positive integers with 
+\code{\var{K}[\var i]}
+equal to the number of rows in {\it Fi}.
+\var{F} is a dense or sparse real matrix of size 
+\code{(sum(\var K),\var n)}.
+\var{g} is a dense real matrix of size \code{(sum(\var K),1)}.
+\var{G} and \var{A} are dense or sparse real matrices.
+Their default values are sparse matrices with zero rows.
+\var{h} and \var{b} are dense real matrices with one column.
+Their default values are matrices of size (0,1).
+
+\function{gp()} returns a dictionary with keys 
+\code{'status'}, \code{'x'}, \code{'snl'}, \code{'sl'}, 
+\code{'y'}, \code{'znl'} and \code{'zl'}.
+The possible values of the \code{'status'} key are:
+\begin{description}
+\item[\code{'optimal'}]  In this case the 
+\code{'x'} entry is the primal optimal solution,
+the \code{'snl'} and \code{'sl'} entries are the corresponding slacks 
+in the nonlinear and linear inequality constraints. 
+The \code{'znl'}, \code{'zl'} and \code{'y'} entries are the optimal 
+values of the dual variables associated with the nonlinear and linear 
+inequality constraints and the linear equality constraints.
+These values approximately satisfy
+\[
+ \nabla f_0(x) + \sum_{k=1}^m z_{\mathrm{nl},k} 
+ \nabla f_k(x) + G^T z_\mathrm{l} + A^T y = 0, \qquad
+ f_k(x) + s_{\mathrm{nl},k} = 0, \quad k=1,\ldots,m,   \qquad 
+ Gx + s_\mathrm{l} = h, \qquad Ax=b
+\]
+and
+\[
+s_\mathrm{nl}\succeq 0, \qquad s_\mathrm{l}\succeq 0, \qquad 
+z_\mathrm{nl} \succeq 0, \qquad z_\mathrm{l} \succeq 0, \qquad
+s_\mathrm{nl}^T z_\mathrm{nl} + s_\mathrm{l}^T z_\mathrm{l} = 0.
+\]
+
+\item[\code{'unknown'}] This means that the algorithm reached
+the maximum number of iterations before a solution was found.
+The \code{'x'}, \code{'snl'}, \code{'sl'}, \code{'y'}, \code{'znl'} 
+and \code{'zl'} entries are \None. 
+\end{description}
+\end{funcdesc}
+
+As an example, we solve the small GP on page~8 of the paper 
+\citetitle[http://www.stanford.edu/\~{}boyd/gp\_tutorial]{A Tutorial on Geometric Programming}.  
+The  posynomial form of the problem is
+\[
+ \begin{array}{ll}
+ \mbox{minimize} & w^{-1} h^{-1} d^{-1} \\ 
+ \mbox{subject to} 
+  & (2/A_\mathrm{wall}) hw + (2/A_\mathrm{wall})hd \leq 1  \\
+  &  (1/A_\mathrm{flr}) wd \leq 1 \\
+  &  \alpha wh^{-1} \leq 1 \\
+  &  (1/\beta) hw^{-1} \leq 1 \\
+  &  \gamma wd^{-1} \leq 1 \\
+  &   (1/\delta)dw^{-1} \leq 1
+ \end{array}
+\]
+with variables {\it h}, {\it w}, {\it d}.
+
+\begin{verbatim}
+from cvxopt.base import matrix, log, exp
+from cvxopt import solvers
+
+Aflr  = 1000.0
+Awall = 100.0
+alpha = 0.5
+beta  = 2.0
+gamma = 0.5
+delta = 2.0
+
+F = matrix( [[-1., 1., 1., 0., -1.,  1.,  0.,  0.], 
+             [-1., 1., 0., 1.,  1., -1.,  1., -1.], 
+             [-1., 0., 1., 1.,  0.,  0., -1.,  1.]])
+g = log( matrix( [1.0, 2/Awall, 2/Awall, 1/Aflr, alpha, 1/beta, gamma, 1/delta]) )
+K = [1, 2, 1, 1, 1, 1, 1]
+h, w, d = exp( solvers.gp(K, F, g)['x'] )
+\end{verbatim}
+
+\section{Semidefinite Programming} \label{s-sdpsolver}
+We use the following notation for a pair of primal and dual 
+semidefinite programs (SDPs): 
+\BEQ \label{e-sdp}
+\mbox{Primal:}\quad \begin{array}[t]{ll}
+\mbox{minimize} & c^Tx \\
+\mbox{subject to} &  G_\mathrm{l}x + s_\mathrm{l} = h_\mathrm{l} \\ 
+ & G_\mathrm{s}(x) + S_\mathrm{s} = H_\mathrm{s} \\
+ & Ax=b \\ & s_\mathrm{l} \succeq 0, \quad S_\mathrm{s} \succeq 0 
+\end{array} \qquad\qquad
+\mbox{Dual:}\quad
+\begin{array}[t]{ll}
+\mbox{maximize}   & -h_\mathrm{l}^T z_\mathrm{l} - 
+ \Tr(H_\mathrm{s} Z_\mathrm{s}) - b^T y \\
+\mbox{subject to} & G_\mathrm{l}^Tz_\mathrm{l} + 
+  G_\mathrm{s}^T(Z_\mathrm{s}) + A^T y  + c = 0 \\
+ & z_\mathrm{l} \succeq 0, \quad Z_\mathrm{s} \succeq 0.
+\end{array}
+\EEQ 
+The dimensions of the primal and dual variables are
+\[
+ x\in \reals^n, \qquad s_\mathrm{l} \in \reals^m, 
+\qquad S_\mathrm{s} \in \symm^{m_0} \times \cdots \times 
+\symm^{m_{N-1}}, \qquad
+ y \in\reals^p, \qquad z_\mathrm{l}\in \reals^m, 
+\qquad Z_\mathrm{s} \in \symm^{m_0} \times \cdots \times 
+\symm^{m_{N-1}},
+\]
+where $\symm^n$ is the set of real symmetric matrices
+of order {\it n}.  The problem data are the matrices
+\[
+c\in\reals^n, \qquad G_\mathrm{l} \in\reals^{m\times n},
+\qquad h_\mathrm{l} \in \reals^{m}, \qquad
+ H_\mathrm{s} \in \symm^{m_0} \times \cdots \times \symm^{m_{N-1}}, 
+\qquad
+A \in \reals^{p\times n}, \qquad b \in \reals^{p}, 
+\]
+and the linear mapping
+$G_\mathrm{s} : \reals^n \rightarrow \symm^{m_1} \times \cdots \times 
+\symm^{m_N}$ and its adjoint $G_\mathrm{s}^T$.
+As for LPs we store vector variables as dense real matrices with one 
+column.
+Block-diagonal symmetric matrices are stored as lists of square 
+dense real matrices, with the lower triangular part of each matrix 
+representing the lower triangular part of a diagonal block.  Entries 
+above the diagonal are not referenced.
+
+\begin{funcdesc}{sdp}{c\optional{, Gl, hl\optional{, 
+ Gs, hs\optional{, A, b\optional{, solver\optional{, 
+ primalstart\optional{, dualstart}}}}}}}
+
+Solves the pair of primal and dual SDPs~(\ref{e-sdp}).
+
+\var{c} is a dense real matrix with one column.
+\var{Gl} and \var{A} are dense or sparse real matrices.
+\var{hl} and \var{b} are dense real matrices with one column.
+The default values for \var{Gl}, \var{hl}, \var{A} and \var{b} are 
+empty matrices, \ie, matrices with zero rows. 
+
+\var{Gs} and \var{hs} are lists of length {\it N} that specify the 
+linear matrix inequality constraints.
+\var{hs} is a list of square dense real matrices \code{\var{hs}[k]} of 
+order {\it m\_k}.
+\var{Gs} is a list of dense or sparse real matrices 
+\code{\var{Gs}[k]} with {\it m\_k}*{\it m\_k} rows and {\it n} columns,
+such that the product \code{\var{Gs}[k]*\var{x}} 
+is the {\it k}th diagonal block of {\it Gs}(\var{x}), stored 
+columnwise.
+
+The \var{solver} argument is used to choose between two
+solvers: the default solver (used when \var{solver} is absent or
+equal to \None) and the external solver DSDP5 
+(\code{\var{solver}='dsdp'}); see section~\ref{s-external}.
+With the \code{'dsdp'} option the code does not accept problems with 
+equality constraints.
+
+The optional argument \var{primalstart} is a dictionary with keys 
+\code{'x'}, \code{'sl'}, and \code{'ss'}, used as an optional primal 
+starting point. 
+\var{dualstart} is a dictionary with keys \code{'y'}, \code{'zl'}, 
+\code{'zs'}, used as an optional dual starting point.
+These two arguments are ignored when the DSDP solver is used.
+
+\function{sdp()} returns a dictionary with keys \code{'status'}, 
+\code{'x'}, \code{'sl'}, \code{'ss'}, \code{'y'}, \code{'zl'},  
+\code{'ss'}.
+The possible values of the \code{'status'} item are as follows.
+\begin{description}
+\item[\code{'optimal'.}] In this case the \code{'x'}, \code{'sl'}, 
+\code{'ss'}, \code{'y'}, \code{'zl'}, \code{'zs'} entries contain 
+primal and dual optimal solutions, which approximately satisfy
+\[
+ G_\mathrm{l}x+s_\mathrm{l} = h_\mathrm{l},
+\qquad 
+G_\mathrm{s}(x)+S_\mathrm{s} = H_\mathrm{s}, 
+\qquad
+Ax=b, \qquad
+G_\mathrm{l}^Tz_\mathrm{l} + G_\mathrm{s}^T(Z_\mathrm{s}) + A^Ty+c = 0
+\]
+and
+\[
+ s_\mathrm{l} \succeq 0, \qquad S_\mathrm{s} \succeq 0, \qquad 
+ z_\mathrm{l} \succeq 0, \qquad Z_\mathrm{s} \succeq 0, \qquad
+ s_\mathrm{l}^T z_\mathrm{l} + \Tr(S_\mathrm{s}Z_\mathrm{s}) = 0.
+\]
+
+\item[\code{'primal infeasible'.}]  
+The \code{'x'}, \code{'sl'} and \code{'ss'} entries are \None, 
+and the \code{'y'}, \code{'zl'}, \code{'zs'} entries provide an 
+approximate certificate of infeasibility: 
+\[
+G_\mathrm{l}^Tz_\mathrm{l} + G_\mathrm{s}^T(Z_\mathrm{s}) +A^Ty = 0
+\qquad h_\mathrm{l}^Tz_\mathrm{l} + \Tr(H_\mathrm{s} Z_\mathrm{s}) 
+ +b^Ty = -1, \qquad
+z_\mathrm{l} \succeq 0, \qquad Z_\mathrm{s} \succeq 0. 
+\]
+
+\item[\code{'dual infeasible'.}]  The SDP is dual infeasible.
+The \code{'y'}, \code{'zl'} and \code{'zs'} entries are \None, 
+and the \code{'x'}, \code{'sl'}, \code{'ss'} entries contain an 
+approximate certificate of dual infeasibility:
+\[
+G_\mathrm{l}x+s_\mathrm{l} = 0, \qquad
+G_\mathrm{s}(x)+S_\mathrm{s} = 0, \qquad
+Ax = 0, \qquad c^Tx = -1, \qquad
+s_\mathrm{l} \succeq 0, \qquad S_\mathrm{s} \succeq 0. 
+\]
+
+\item[\code{'unknown'}.] The \code{'x'}, \code{'sl'}, \code{'ss'},
+\code{'y'}, \code{'zl'} and \code{'zs'} entries are \None.
+\end{description}
+\end{funcdesc}
+
+We illustrate the calling sequence with a small example.
+\[
+\begin{array}{ll}
+\mbox{minimize} & x_1 - x_2 + x_3 \\
+\mbox{subject to} & 
+  x_1 \left[ \begin{array}{cc} -7 &  -11 \\ -11 &  3
+ \end{array}\right] + 
+  x_2 \left[ \begin{array}{cc}
+  7 & -18 \\ -18 & 8 \end{array}\right] + 
+  x_3 \left[ \begin{array}{cc}
+  -2 & -8 \\ -8 & 1 
+ \end{array}\right] \preceq  
+ \left[ \begin{array}{cc} 
+ 33 & -9 \\ -9 & 26 \end{array}\right] \\*[1ex]
+& x_1 \left[ \begin{array}{ccc} 
+ -21 & -11 & 0  \\ -11 & 10 & 8 \\ 0 & 8 & 5
+ \end{array}\right] + 
+ x_2 \left[ \begin{array}{ccc} 
+ 0 & 10  & 16 \\
+10 & -10 & -10 \\
+16 & -10 & 3 
+ \end{array}\right] + 
+ x_3 \left[ \begin{array}{ccc} 
+ -5  & 2 & -17 \\
+ 2  & -6 & -7 \\
+ -17 & 8 & 6 
+ \end{array}\right]  
+\preceq  \left[ \begin{array}{ccc}
+ 14 &  9 & 40 \\
+  9  & 91 & 10 \\
+ 40 & 10 & 15
+\end{array} \right]
+\end{array}
+\]
+\begin{verbatim}
+>>> from cvxopt.base import matrix
+>>> from cvxopt import solvers
+>>> c = matrix([1.,-1.,1.])
+>>> G = [ matrix([[-7., -11., -11., 3.], 
+                  [ 7., -18., -18., 8.], 
+                  [-2.,  -8.,  -8., 1.]]) ]
+>>> G += [ matrix([[-21., -11.,   0., -11.,  10.,   8.,   0.,   8., 5.], 
+                   [ 0.,  10.,  16.,  10., -10., -10.,  16., -10., 3.], 
+                   [ -5.,   2., -17.,   2.,  -6.,   8., -17.,  -7., 6.]]) ]
+>>> h = [ matrix([[33., -9.], [-9., 26.]]) ]
+>>> h += [ matrix([[14., 9., 40.], [9., 91., 10.], [40., 10., 15.]]) ]
+>>> sol = solvers.sdp(c, Gs=G, hs=h)  
+>>> print sol['x']
+  -3.6775e-01
+   1.8983e+00
+  -8.8747e-01
+>>> print sol['zs'][0]
+   3.9613e-03   0.0000e+00
+  -4.3390e-03   4.7526e-03
+>>> print sol['zs'][1]
+   5.5803e-02   0.0000e+00   0.0000e+00
+  -2.4103e-03   1.0411e-04   0.0000e+00
+   2.4214e-02  -1.0459e-03   1.0507e-02
+\end{verbatim}
+Note that only the lower triangular parts of the dual variables are
+returned (in the example the returned values of the upper triangular 
+elements happen to be zero, but this is not necessarily the case).
+
+Only the entries in \var{Gs} and \var{hs} that correspond to lower 
+triangular entries need to be provided, so in the example \var{h} and 
+\var{G} can also be defined as follows.
+\begin{verbatim}
+>>> G = [ matrix([[-7., -11., 0., 3.], 
+                  [ 7., -18., 0., 8.], 
+                  [-2.,  -8., 0., 1.]]) ]
+>>> G += [ matrix([[-21., -11.,   0., 0.,  10.,   8., 0., 0., 5.], 
+                   [  0.,  10.,  16., 0., -10., -10., 0., 0., 3.], 
+                   [ -5.,   2., -17., 0.,  -6.,   8., 0., 0., 6.]]) ]
+>>> h = [ matrix([[33., -9.], [0., 26.]]) ]
+>>> h += [ matrix([[14., 9., 40.], [0., 91., 10.], [0., 0., 15.]]) ]
+\end{verbatim}
+
+
+\section{Nonlinear Convex Programming}
+\begin{funcdesc}{cp}{F\optional{, G, h\optional{, A, b}}}
+Solves an optimization problem
+\BEQ \label{e-nlcp}
+ \begin{array}{ll}
+ \mbox{minimize} & f_0(x) \\
+ \mbox{subject to} & f_k(x) \leq 0, \quad k=1,\ldots,m \\
+  & G x \preceq h  \\ 
+  & A x = b,
+ \end{array}
+\EEQ
+with $f=(f_0,\ldots,f_m)$ convex and twice differentiable.
+
+\var{F} is a function that evaluates the objective and nonlinear 
+constraint functions.  It must handle the following calling sequences.
+
+\begin{itemize}
+\item \code{F()} returns a tuple (\var{m}, \var{x0}), where \var{m} is 
+ the number of nonlinear constraints and \var{x0} is a point in the 
+ domain of {\it f}.  \var{x0} is a dense real matrix of size 
+ (\var{n},1).
+
+\item \code{F(x)}, with \var{x} a dense real matrix of size 
+ (\var{n},1), returns a tuple (\var{f}, \var{Df}).  
+ \var{f} is a dense real matrix of size (\var{m}+1,1), with 
+ \code{\var{f}[\var{k}]} equal to {\it f\_k(x)}. 
+ (If {\it m} is zero, \var{f} can also be returned as a number.)
+ \var{Df} is a dense or sparse real matrix of size (\var{m}+1,\var{n}) 
+ with \code{\var{Df}[\var{k},:]} equal to the transpose of the gradient
+ of {\it f\_k} at {\it x}.
+ If \var{x} is not in the domain of {\it f}, \code{F(x)} returns 
+ \None\ or a tuple (\None,\None).
+
+\item \code{F(x,z)}, with \var{x} a dense real matrix of size 
+ (\var{n},1) and \var{z} a positive dense real matrix of size 
+ (\var{m}+1,1) returns a tuple (\var{f}, \var{Df}, \var{H}).  
+ \var{f} and \var{Df} are defined as above.  
+ \var{H} is a square dense or sparse real matrix of size 
+ ({\it n}, {\it n}), whose lower triangular part contains the lower 
+ triangular part of
+ \[
+  z_0 \nabla^2f_0(x) + z_1 \nabla^2f_1(x) + \cdots + z_m \nabla^2f_m(x).
+ \]
+ If \var{F} is called with two arguments, it can be assumed that 
+ \var{x} is in the domain of {\it f}.
+\end{itemize}
+
+\var{G} and \var{A} are dense or sparse real matrices with \var{n} 
+columns.  Their default values are matrices of size (0,\var{n}).
+\var{h} and \var{b} are dense real matrices with one column, and the 
+same number of rows as \var{G} and \var A, respectively.
+Their default values are matrices of size (0,1).
+
+\function{cp()} returns a dictionary with keys \code{'status'}, 
+\code{'x'}, \code{'snl'}, \code{'sl'}, \code{'y'}, \code{'znl'}, 
+\code{'zl'}. 
+The possible values of the \code{'status'} key are:
+\begin{description}
+\item[\code{'optimal'}]  In this case the 
+\code{'x'} entry of the dictionary is the primal optimal solution,
+  the \code{'snl'} and \code{'sl'} entries are the corresponding
+ slacks in the nonlinear and linear inequality constraints, and the 
+\code{'znl'}, \code{'zl'} and \code{'y'} entries are the optimal 
+values of the dual variables associated with the nonlinear 
+inequalities, the linear inequalities, and the linear equality 
+constraints.  These vectors approximately satisfy the Karush-
+Kuhn-Tucker (KKT) conditions
+\[
+ \nabla f_0(x) +  D\tilde f(x)^T z_\mathrm{nl} + 
+ G^T z_\mathrm{l} + A^T y = 0, \qquad
+\tilde f(x) + s_\mathrm{nl} = 0, \quad k=1,\ldots,m, \qquad
+ Gx + s_\mathrm{l} = h, \qquad
+ Ax = b, 
+\]
+where $\tilde f = (f_1,\ldots, f_m)$,
+\[
+s_\mathrm{nl}\succeq 0, \qquad s_\mathrm{l}\succeq 0, \qquad 
+z_\mathrm{nl} \succeq 0, \qquad z_\mathrm{l} \succeq 0, \qquad
+s_\mathrm{nl}^T z_\mathrm{nl} +  s_\mathrm{l}^T z_\mathrm{l} = 0.
+\]
+
+\item[\code{'unknown'}] This indicates that the algorithm reached
+the maximum number of iterations before a solution was found.
+The \code{'x'}, \code{'snl'}, \code{'sl'}, 
+\code{'y'}, \code{'znl'} and \code{'zl'} entries are \None. 
+\end{description}
+
+%\function{cp()} requires that the problem is solvable and that the 
+%Karush-Kuhn-Tucker matrix
+%\[
+%\left[\begin{array}{cccc}
+%\sum_{k=0}^m z_k \nabla^2 f_k(x) & D\tilde f(x)^T & G^T & A^T\\
+%D\tilde f(x) & -\diag(d_1) & 0 & 0 \\
+% G & 0 & -\diag(d_2) & 0 \\ 
+% A & 0 & 0 & 0 \end{array}\right]
+%%\]
+%is nonsingular for all {\it x}, all nonnegative {\it z}, and all 
+%positive {\it d\_1}, {\it d\_2}.  
+\end{funcdesc}
+
+
+\begin{description}
+\item[Example: equality constrained analytic centering]
+
+The equality constrained analytic centering problem is defined as
+\[
+ \begin{array}{ll}
+ \mbox{minimize} & -\sum_{i=1}^m \log x_i \\
+ \mbox{subject to} & Ax = b. 
+ \end{array}
+\]
+The function \function{acent()} defined  below solves the problem, 
+assumping it is solvable.
+
+\begin{verbatim}
+from cvxopt import solvers 
+from cvxopt.base import matrix, spmatrix, log
+
+def acent(A, b):
+    m, n = A.size
+    def F(x=None, z=None):
+        if x is None: return 0, matrix(1.0, (n,1))
+        if min(x) <= 0.0: return None
+        f = -sum(log(x))
+        Df = -(x**-1).T 
+        if z is None: return f, Df
+        H = z[0] * spmatrix(x**-2, range(n), range(n))
+        return f, Df, H
+    return solvers.cp(F, A=A, b=b)['x']
+\end{verbatim}
+
+\item[Example: robust least-squares]
+
+The function \function{robls()} defined below solves the unconstrained 
+problem
+\[
+\begin{array}{ll}
+\mbox{minimize} &  \sum_{k=1}^m \phi((Ax-b)_k), 
+\end{array} \qquad \mbox{where} \quad A \in\reals^{m\times n}, \quad
+\phi(u) = \sqrt{\rho + u^2}.
+\]
+
+\begin{verbatim}
+from cvxopt import solvers 
+from cvxopt.base import matrix, spmatrix, sqrt, div
+
+def robls(A, b, rho): 
+    m, n = A.size
+    def F(x=None, z=None):
+        if x is None: return 0, matrix(0.0, (n,1))
+        y = A*x-b
+        w = sqrt(rho + y**2)
+        f = sum(w)
+        Df = div(y, w).T * A 
+        if z is None: return f, Df 
+        H = A.T * spmatrix(z[0]*rho*(w**-3), range(m), range(m)) * A
+        return f, Df, H
+    return solvers.cp(F)['x']
+\end{verbatim}
+
+\item[Example: floor planning]
+
+This example is the floor planning problem of section 8.8.2 in the book 
+\citetitle[http://www.stanford.edu/\~{}boyd/cvxbook]{Convex Optimization}: 
+\[
+\begin{array}{ll}
+ \mbox{minimize} & W + H \\
+ \mbox{subject to} & A_{\mathrm{min}, k}/h_k - w_k \leq 0, 
+        \quad k=1,\ldots, 5  \\ 
+   &  x_1 \geq 0, \quad x_2 \geq 0,  \quad x_4 \geq 0 \\
+   & x_1 + w_1 + \rho \leq x_3, \quad x_2 + w_2 + \rho \leq x_3, \quad 
+     x_3 + w_3 + \rho \leq x_5, \quad x_4 + w_4 + \rho \leq x_5, \quad
+     x_5 + w_5 \leq W \\
+   & y_2 \geq 0,  \quad y_3 \geq 0, \quad y_5 \geq 0  \\
+   & y_2 + h_2 + \rho \leq y_1, \quad y_1 + h_1 + \rho \leq y_4, \quad 
+     y_3 + h_3 + \rho \leq y_4, \quad y_4 + h_4 \leq H, \quad
+     y_5 + h_5 \leq H \\
+   & h_k/\gamma \leq w_k \leq \gamma h_k, \quad k=1,\ldots,5.
+\end{array}
+\]
+This problem has 22 variables 
+\[
+W, \qquad H, \qquad x\in\reals^5, \qquad y\in\reals^5, \qquad
+w\in\reals^5, \qquad h\in\reals^5,
+\]
+5 nonlinear inequality constraints, and 26 linear inequality 
+constraints.  The code belows defines a function
+\function{floorplan()} that solves the problem by calling
+\function{cp()},  then applies it to  4 instances, and creates 
+a figure.
+
+\begin{verbatim}
+import pylab
+from cvxopt import solvers
+from cvxopt.base import matrix, spmatrix, mul, div
+
+def floorplan(Amin):
+
+    #     minimize    W+H
+    #     subject to  Amink / hk <= wk, k = 1,..., 5 
+    #                 x1 >= 0,  x2 >= 0, x4 >= 0
+    #                 x1 + w1 + rho <= x3  
+    #                 x2 + w2 + rho <= x3 
+    #                 x3 + w3 + rho <= x5  
+    #                 x4 + w4 + rho <= x5
+    #                 x5 + w5 <= W
+    #                 y2 >= 0,  y3 >= 0,  y5 >= 0 
+    #                 y2 + h2 + rho <= y1 
+    #                 y1 + h1 + rho <= y4 
+    #                 y3 + h3 + rho <= y4
+    #                 y4 + h4 <= H  
+    #                 y5 + h5 <= H
+    #                 hk/gamma <= wk <= gamma*hk,  k = 1, ..., 5
+    #
+    # 22 Variables W, H, x (5), y (5), w (5), h (5).
+    #
+    # W, H:  scalars; bounding box width and height
+    # x, y:  5-vectors; coordinates of bottom left corners of blocks
+    # w, h:  5-vectors; widths and heigths of the 5 blocks
+
+    rho, gamma = 1.0, 5.0   # min spacing, min aspect ratio
+
+    # The objective is to minimize W + H.  There are five nonlinear 
+    # constraints 
+    #
+    #     -wk + Amink / hk <= 0,  k = 1, ..., 5
+
+    def F(x=None, z=None):
+        if x is None:  return 5, matrix(17*[0.0] + 5*[1.0])
+        if min(x[17:]) <= 0.0:  return None 
+        f = matrix(0.0, (6,1))
+        f[0] = x[0] + x[1]  
+        f[1:] = -x[12:17] + div(Amin, x[17:]) 
+        Df = matrix(0.0, (6,22))
+        Df[0, [0,1]] = 1.0
+        Df[1:,12:17] = spmatrix(-1.0, range(5), range(5))
+        Df[1:,17:] = spmatrix(-div(Amin, x[17:]**2), range(5), range(5))
+        if z is None: return f, Df
+        H = spmatrix( 2.0* mul(z[1:], div(Amin, x[17::]**3)), range(17,22), range(17,22) )
+        return f, Df, H
+
+    G = matrix(0.0, (26,22)) 
+    h = matrix(0.0, (26,1))
+    G[0,2] = -1.0                                       # -x1 <= 0
+    G[1,3] = -1.0                                       # -x2 <= 0 
+    G[2,5] = -1.0                                       # -x4 <= 0
+    G[3, [2, 4, 12]], h[3] = [1.0, -1.0, 1.0], -rho     # x1 - x3 + w1 <= -rho 
+    G[4, [3, 4, 13]], h[4] = [1.0, -1.0, 1.0], -rho     # x2 - x3 + w2 <= -rho 
+    G[5, [4, 6, 14]], h[5] = [1.0, -1.0, 1.0], -rho     # x3 - x5 + w3 <= -rho 
+    G[6, [5, 6, 15]], h[6] = [1.0, -1.0, 1.0], -rho     # x4 - x5 + w4 <= -rho 
+    G[7, [0, 6, 16]] = -1.0, 1.0, 1.0                   # -W + x5 + w5 <= 0
+    G[8,8] = -1.0                                       # -y2 <= 0 
+    G[9,9] = -1.0                                       # -y3 <= 0 
+    G[10,11] = -1.0                                     # -y5 <= 0 
+    G[11, [7, 8, 18]], h[11] = [-1.0, 1.0, 1.0], -rho   # -y1 + y2 + h2 <= -rho 
+    G[12, [7, 10, 17]], h[12] = [1.0, -1.0, 1.0], -rho  #  y1 - y4 + h1 <= -rho 
+    G[13, [9, 10, 19]], h[13] = [1.0, -1.0, 1.0], -rho  #  y3 - y4 + h3 <= -rho 
+    G[14, [1, 10, 20]] = -1.0, 1.0, 1.0                 # -H + y4 + h4 <= 0  
+    G[15, [1, 11, 21]] = -1.0, 1.0, 1.0                 # -H + y5 + h5 <= 0
+    G[16, [12, 17]] = -1.0, 1.0/gamma                   # -w1 + h1/gamma <= 0 
+    G[17, [12, 17]] = 1.0, -gamma                       #  w1 - gamma * h1 <= 0
+    G[18, [13, 18]] = -1.0, 1.0/gamma                   # -w2 + h2/gamma <= 0 
+    G[19, [13, 18]] = 1.0, -gamma                       #  w2 - gamma * h2 <= 0
+    G[20, [14, 18]] = -1.0, 1.0/gamma                   # -w3 + h3/gamma <= 0  
+    G[21, [14, 19]] = 1.0, -gamma                       #  w3 - gamma * h3 <= 0
+    G[22, [15, 19]] = -1.0, 1.0/gamma                   # -w4  + h4/gamma <= 0 
+    G[23, [15, 20]] = 1.0, -gamma                       #  w4 - gamma * h4 <= 0
+    G[24, [16, 21]] = -1.0, 1.0/gamma                   # -w5 + h5/gamma <= 0 
+    G[25, [16, 21]] = 1.0, -gamma                       #  w5 - gamma * h5 <= 0.0
+
+    # solve and return W, H, x, y, w, h 
+    sol = solvers.cp(F, G, h)  
+    return  sol['x'][0], sol['x'][1], sol['x'][2:7], sol['x'][7:12], sol['x'][12:17], sol['x'][17:] 
+
+pylab.figure(facecolor='w')
+pylab.subplot(221)
+Amin = matrix([100., 100., 100., 100., 100.])
+W, H, x, y, w, h =  floorplan(Amin)
+for k in xrange(5):
+    pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], 
+               [y[k], y[k]+h[k], y[k]+h[k], y[k]], '#D0D0D0')
+    pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1))
+pylab.axis([-1.0, 26, -1.0, 26])
+pylab.xticks([])
+pylab.yticks([])
+
+pylab.subplot(222)
+Amin = matrix([20., 50., 80., 150., 200.])
+W, H, x, y, w, h =  floorplan(Amin)
+for k in xrange(5):
+    pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], 
+               [y[k], y[k]+h[k], y[k]+h[k], y[k]], '#D0D0D0')
+    pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1))
+pylab.axis([-1.0, 26, -1.0, 26])
+pylab.xticks([])
+pylab.yticks([])
+
+pylab.subplot(223)
+Amin = matrix([180., 80., 80., 80., 80.])
+W, H, x, y, w, h =  floorplan(Amin)
+for k in xrange(5):
+    pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], 
+               [y[k], y[k]+h[k], y[k]+h[k], y[k]],'#D0D0D0')
+    pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1))
+pylab.axis([-1.0, 26, -1.0, 26])
+pylab.xticks([])
+pylab.yticks([])
+
+pylab.subplot(224)
+Amin = matrix([20., 150., 20., 200., 110.])
+W, H, x, y, w, h =  floorplan(Amin)
+for k in xrange(5):
+    pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], 
+               [y[k], y[k]+h[k], y[k]+h[k], y[k]],'#D0D0D0')
+    pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1))
+pylab.axis([-1.0, 26, -1.0, 26])
+pylab.xticks([])
+pylab.yticks([])
+
+pylab.show()
+\end{verbatim}
+
+\begin{center}
+\includegraphics[width=15cm]{figures/floorplan.eps}
+\end{center}
+\end{description}
+
+\section{Exploiting Structure in LPs and SDPs}
+The solvers \function{lp()} and \function{sdp()} are interfaces to
+a common function \function{conelp()}, which can also be called 
+directly.  When calling \function{conelp()}, the user must provide 
+functions for evaluating the constraint functions and for 
+solving the linear equations (KKT equations) that are solved in 
+each iteration of the algorithm.
+This is useful for LPs and SDPs that possess some interesting 
+structure that makes it possible to solve the KKT equations fast.
+
+\begin{funcdesc}{conelp}{c, kktsolver\optional{, Gl, hl\optional{, 
+Gs, hs\optional{, A, b\optional{, primalstart\optional{, dualstart}}}}}}
+Solves the pair of primal and dual SDPs~(\ref{e-sdp}).
+The arguments \var{c}, \var{hl}, \var{hs}, \var{b}, 
+\var{primalstart}, \var{dualstart} have the same meaning as in
+\function{sdp()}.
+The arguments \var{kktsolver}, \var{Gl}, \var{Gs}, \var{A} are  
+functions that must handle the following calling sequences.
+
+\begin{itemize}
+\item \function{kktsolver}(\var{d}, \var{R}) with \var{d} a positive 
+dense real matrix of size ({\it ml},{\it 1}), and 
+\var{R} a list of {\it N} square dense real matrices 
+\code{\var{R}[k]} of order {\it m\_k}, returns a function for 
+solving the equation 
+\BEAS
+ A^T u_y + G_\mathrm{l}^T u_{z_\mathrm{l}} + 
+ G_\mathrm{s}^T(u_{z_\mathrm{s}}) & = & b_x \\
+ A u_x  & = & b_y \\
+G_\mathrm{l}u_x  - \diag(d)^{-2} u_{z_\mathrm{l}} & = & 
+ b_{z_\mathrm{l}} \\
+G_\mathrm{s}(u_x) - R^{-T} R^{-1} u_{z_\mathrm{s}} R^{-T} R^{-1}
+  & = & b_{z_\mathrm{s}}.
+\EEAS
+The function created by \samp{f = kktsolver(d, R)} will be 
+called as \samp{f(bx, by, bzl, bzs)}.
+On entry, \var{bx}, \var{by}, \var{bzl} and \var{bzs} contain the 
+righthand side.  On exit, they should contain the solution of the KKT 
+system, with {\it uzl} and {\it uzs} scaled:
+\[
+  b_x := u_x, \qquad
+  b_y := u_y, \qquad
+  b_{z_\mathrm{l}}  := \diag(d)^{-1} u_{z_\mathrm{l}}, \qquad
+  b_{z_\mathrm{s}}  := R^{-1} u_{z_\mathrm{s}} R^{-T}.
+\]
+
+\item\function{Gl}(\var{x}, \var{y}\optional{, 
+\var{alpha}=1.0\optional{, \var{beta}=0.0\optional{, 
+\var{trans}=\code{'N'}}}}) evaluates the matrix-vector products
+\[
+y := \alpha G_\mathrm{l}x + \beta y \quad 
+  (\mathrm{trans} = \mathrm{'N'}), \qquad
+y := \alpha G_\mathrm{l}^T x + \beta y \quad 
+ (\mathrm{trans} = \mathrm{'T'}).
+\]
+
+\item \function{Gs}(\var{x}, \var{y}\optional{, 
+\var{alpha}=1.0\optional{, \var{beta}=0.0\optional{, 
+\var{trans}=\code{'N'}}}})
+evaluates the linear mappings
+\[
+y := \alpha G_\mathrm{s}(x) + \beta y \quad 
+  (\mathrm{trans} = \mathrm{'N'}), \qquad
+y := \alpha G_\mathrm{s}^T(x) + \beta y \quad 
+ (\mathrm{trans} = \mathrm{'T'}).
+\]
+
+\item \function{A}(\var{x}, \var{y}\optional{, 
+\var{alpha}=1.0\optional{, \var{beta}=0.0\optional{, 
+\var{trans}=\code{'N'}}}})  
+evaluates the matrix vector products 
+\[
+y := \alpha Ax + \beta y \quad 
+  (\mathrm{trans} = \mathrm{'N'}), \qquad
+y := \alpha A^Tx + \beta y \quad 
+ (\mathrm{trans} = \mathrm{'T'}).
+\]
+\end{itemize}
+\end{funcdesc}
+
+\begin{description}
+\item[Example: 1-norm approximation]
+
+The optimization problem
+\[
+ \begin{array}{ll}
+ \mbox{minimize} & \|Pu-q\|_1
+ \end{array}
+\]
+can be formulated as an LP
+\[
+ \begin{array}{ll}
+ \mbox{minimize} & \ones^T v \\
+ \mbox{subject to} & -v \preceq Pu - q  \preceq v.
+ \end{array}
+\]
+By exploiting the structure in the inequalities, the cost of 
+an iteration of an interior-point method can be reduced
+to the cost of least-squares problem of the same dimensions. 
+(See section 11.8.2 in the book 
+\citetitle[http://www.ee.ucla.edu/\~{}vandenbe/cvxbook]{Convex Optimization}.) 
+The code belows taks advantage of this fact.
+
+\begin{verbatim}
+from cvxopt import base, blas, lapack, solvers
+from cvxopt.base import matrix, spmatrix, mul, div
+
+def l1(P, q):
+    """
+
+    Returns the solution u, w of the l1 approximation problem
+
+        (primal) minimize    ||P*u - q||_1       
+    
+        (dual)   maximize    q'*w
+                 subject to  P'*w = 0
+                             ||w||_infty <= 1.
+    """
+
+    m, n = P.size
+
+    # Solve equivalent LP 
+    #
+    #     minimize    [0; 1]' * [u; v]
+    #     subject to  [P, -I; -P, -I] * [u; v] <= [q; -q]
+    #
+    #     maximize    -[q; -q]' * z 
+    #     subject to  [P', -P']*z  = 0
+    #                 [-I, -I]*z + 1 = 0 
+    #                 z >= 0 
+    
+    c = matrix(n*[0.0] + m*[1.0])
+    h = matrix([q, -q])
+
+    def Fi(x, y, alpha=1.0, beta=0.0, trans='N'):    
+        if trans=='N':
+            # y := alpha * [P, -I; -P, -I] * x + beta*y
+            u = P*x[:n]
+            y[:m] = alpha * ( u - x[n:]) + beta*y[:m]
+            y[m:] = alpha * (-u - x[n:]) + beta*y[m:]
+
+        else:
+            # y := alpha * [P', -P'; -I, -I] * x + beta*y
+            y[:n] =  alpha * P.T * (x[:m] - x[m:]) + beta*y[:n]
+            y[n:] = -alpha * (x[:m] + x[m:]) + beta*y[n:]
+
+
+    def kktsolver(d, R): 
+
+        # Returns a function f(x,y,zl,zs) that solves
+        #
+        # [ 0  0  P'      -P'      ] [ x[:n] ]   [ bx[:n]  ]
+        # [ 0  0 -I       -I       ] [ x[n:] ]   [ bx[n:]  ]
+        # [ P -I -D1^{-1}  0       ] [ zl[:m]] = [ bzl[:m] ]
+        # [-P -I  0       -D2^{-1} ] [ zl[m:]]   [ bzl[m:] ]
+        #
+        # where D1 = diag(d[:m])^2, D2 = diag(d[m:])^2.
+        #
+        # On entry bx, bzl are stored in x, zl.
+        # On exit x, zl contain the solution, with zl scaled: zl./d is
+        # returned instead of zl. 
+
+        # Factor A = 4*P'*D*P where D = d1.*d2 ./(d1+d2) and
+        # d1 = d[:m].^2, d2 = d[m:].^2.
+
+        d1, d2 = d[:m]**2, d[m:]**2
+        D = div( mul(d1,d2), d1+d2 )  
+        A = P.T * spmatrix(4*D, range(m), range(m)) * P
+        lapack.potrf(A)
+
+        def f(x, y, zl, zs):
+
+            # Solve for x[:n]:
+            #
+            #    A*x[:n] = bx[:n] + P' * ( ((D1-D2)*(D1+D2)^{-1})*bx[n:]
+            #              + (2*D1*D2*(D1+D2)^{-1}) * (bzl[:m] - bzl[m:]) ).
+            x[:n] += P.T * ( mul(div(d1-d2, d1+d2), x[n:]) + mul(2*D, zl[:m]-zl[m:]) )
+            lapack.potrs(A, x)
+
+            # x[n:] := (D1+D2)^{-1} * (bx[n:] - D1*bzl[:m] - D2*bzl[m:] + (D1-D2)*P*x[:n])
+            u = P*x[:n]
+            x[n:] =  div(x[n:] - mul(d1, zl[:m]) - mul(d2, zl[m:]) + mul(d1-d2, u), d1+d2)
+
+            # z[:m] := d1[:m] .* ( P*x[:n] - x[n:] - bzl[:m])
+            # z[m:] := d2[m:] .* (-P*x[:n] - x[n:] - bzl[m:]) 
+            zl[:m] = mul(d[:m],  u-x[n:]-zl[:m])
+            zl[m:] = mul(d[m:], -u-x[n:]-zl[m:])
+
+        return f
+
+    sol = solvers.conelp(c, kktsolver, Gl=Fi, hl=h) 
+    return sol['x'][:n],  sol['zl'][m:] - sol['zl'][:m]    
+\end{verbatim}
+
+\item[Example: SDP with diagonal linear term]
+
+The SDP
+\[
+ \begin{array}{ll}
+ \mbox{minimize} & \ones^T x \\
+ \mbox{subject to} & W + \diag(x) \succeq 0 
+ \end{array} 
+\]
+can be solved efficiently by exploiting properties of the diag operator.
+
+\begin{verbatim}
+from cvxopt import base, blas, lapack, solvers
+from cvxopt.base import matrix
+
+def mcsdp(w):
+    """
+    Returns solution x, z to 
+
+        (primal)  minimize    sum(x)
+                  subject to  w + diag(x) >= 0
+
+        (dual)    maximize    -tr(w*z)
+                  subject to  diag(z) = 1
+                              z >= 0.
+    """
+
+    n = w.size[0]
+
+    def Fs(x, y, alpha=1.0, beta=0.0, trans='N'):
+        """
+            y := alpha*(-diag(x)) + beta*y.   
+        """
+        if trans=='N':
+            # x is a vector; y[0] is a matrix.
+            y[0] *= beta
+            y[0][::n+1] -= alpha * x
+        else:   
+            # x[0] is a matrix; y is a vector.
+            y *= beta
+            y -= alpha * x[::n+1] 
+	 
+
+    def cngrnc(r, x, alpha=1.0):
+        """
+        Congruence transformation
+
+	    x := alpha * r'*x*r.
+
+        r and x are square 'd' matrices.  
+        """
+
+        # Scale diagonal of x by 1/2.  
+        x[::n+1] *= 0.5
+    
+        # a := tril(x)*r 
+        a = +r
+        blas.trmm(x, a, side='L')
+
+        # x := alpha*(a*r' + r*a') 
+        blas.syr2k(r, a, x, trans='T', alpha=alpha)
+
+
+    def kktsolver(d, r):
+
+        # t = r*r' as a nonsymmetric matrix.
+        t = matrix(0.0, (n,n))
+        blas.gemm(r[0], r[0], t, transB='T') 
+
+        # Cholesky factorization of tsq = t.*t.
+        tsq = t**2
+	lapack.potrf(tsq)
+
+	def f(x, y, zl, zs):
+            """
+            Solve
+                          -diag(zs)               = bx
+                -diag(x) - inv(r*r')*zs*inv(r*r') = bs.
+
+            On entry, x and zs contain bx and bs.  
+            On exit, they contain the solution, with zs scaled 
+            (inv(r)'*zs*inv(r) is returned instead of zs).
+
+            We solve 
+
+                ((r*r') .* (r*r')) * x = bx - diag(t*bs*t)
+
+            and take zs  = -r' * (diag(x) + bs) * r.
+            """
+
+            # tbst := t * zs * t = t * bs * t
+            tbst = +zs[0]
+            cngrnc(t, tbst) 
+
+            # x := x - diag(tbst) = bx - diag(r*r' * bs * r*r')
+            x -= tbst[::n+1]
+
+            # x := (t.*t)^{-1} * x = (t.*t)^{-1} * (bx - diag(t*bs*t))
+            lapack.potrs(tsq, x)
+
+            # zs := zs + diag(x) = bs + diag(x)
+            zs[0][::n+1] += x 
+
+            # zs := -r' * zs * r = -r' * (diag(x) + bs) * r 
+            cngrnc(r[0], zs[0], alpha=-1.0)
+
+	return f
+
+    c = matrix(1.0, (n,1))
+    sol = solvers.conelp(c, kktsolver, Gs=Fs, hs=[w]) 
+    return sol['x'], sol['zs'][0]
+\end{verbatim}
+\end{description}
+
+
+\section{Exploiting Structure in Nonlinear Convex Programs}
+The solvers \function{gp()}, \function{gp()} and \function{cp()} are 
+interfaces to \function{nlcp()}, which can also be called directly
+but requires user-provided functions for evaluating the constraint 
+and for solving the KKT equations.
+
+\begin{funcdesc}{nlcp}{kktsolver, F\optional{, G, h\optional{, A, b}}}
+Solves the nonlinear convex optimization problem~(\ref{e-nlcp}).
+
+The meaning of the arguments \var{h} and \var{b} is the same 
+as for \function{cp()}.
+The arguments \var{kktsolver}, \var{F}, \var{G} and \var{A} are  
+functions that must handle the following calling sequences.
+\begin{itemize}
+\item \function{kktsolver}(\var{x}, \var{z}, \var{dnl}, \var{dl}),
+returns a function for solving KKT systems
+\BEAS
+ \sum_{k=0}^m z_k \nabla^2 f_k(x)u_x + A^T u_y + 
+ D \tilde f(x)^T u_{z_\mathrm{nl}} + 
+ G_\mathrm{l}^T u_{z_\mathrm{l}} & = & b_x \\
+ A x  & = & b_y \\
+ D\tilde f(x) x  - \diag(d_\mathrm{nl})^{-2} z_\mathrm{nl} & = & 
+    b_{z_\mathrm{nl}} \\
+ G_\mathrm{l}x  - \diag(d_\mathrm{l})^{-2} z_\mathrm{l} & = & 
+    b_{z_\mathrm{l}}
+\EEAS
+where $\tilde f = (f_1, \ldots, f_m)$.
+The arguments are single-column real dense matrices. \var{x} is in the 
+domain of the objective and constraint functions.  \var{z}, \var{dnl}
+and \var{dl} are positive vectors.
+
+The function \var{f} created by 
+\samp{f = kktsolver(bx, by, bznl, bzl)} will be 
+called as \samp{f(bx, by, bznl, bzl)}.
+On entry, the arguments contain the righthand sides.  On exit, they
+should be replaced by the solution. 
+
+\item Called with no arguments, \code{\function{F}()} returns a tuple
+(\var{m}, \var{x0}), where \var{m} is the number of nonlinear 
+inequality constraints) and \var{x0} is a point in the domain
+of {\it f}).
+
+Called with one argument, \function{F(\var{x})} returns a tuple 
+(\var{f}, \var{Df}).  \var{f} is a dense matrix of size ({\it m}+1,1)
+with the function values of the objective function and the 
+nonlinear constraint functions at \var{x}.
+\var{Df} is a dense or sparse real matrix of size (\var{m}+1,\var{n}) 
+with \code{\var{Df}[\var{k},:]} equal to the transpose of the gradient
+of {\it f\_k} at {\it x}.
+Alternatively, \var{Df} can be given as a function.  In that case
+the function call \function{Df}(\var{u},\var{v}), 
+where \var{u} and \var{v} are dense column vectors, should evaluate
+\[
+  v :=  \sum_{k=0}^m u_k \nabla f_k(x) + v.
+\]
+
+If \var{x} is not in the domain of {\it f}, \function{F}(\var{x})
+returns \None\ or (\None,\None).
+
+\item 
+\function{G}(\var{x}, \var{y}\optional{, 
+\var{alpha}=1.0\optional{, \var{beta}=0.0\optional{, 
+\var{trans}=\code{'N'}}}}) evaluates the matrix-vector products
+\[
+y := \alpha G x + \beta y \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+y := \alpha G^T x + \beta y \quad (\mathrm{trans} = \mathrm{'T'}).
+\]
+Alternatively, \var{G} can be specified as a real sparse or dense 
+matrix. 
+
+\item \function{A}(\var{x}, \var{y}\optional{, 
+\var{alpha}=1.0\optional{, \var{beta}=0.0\optional{, 
+\var{trans}=\code{'N'}}}})  evaluates the matrix vector products 
+\[
+y := \alpha Ax + \beta y \quad 
+  (\mathrm{trans} = \mathrm{'N'}), \qquad
+y := \alpha A^Tx + \beta y \quad 
+ (\mathrm{trans} = \mathrm{'T'}).
+\]
+Alternatively, \var{A} can be specified as a real sparse or dense 
+matrix. 
+\end{itemize}
+\end{funcdesc}
+
+As an example, we consider the 1-norm regularized least-squares problem
+\[
+\begin{array}{ll}
+\mbox{minimize} & \|Ax - y\|_2^2 + \|x\|_1
+\end{array}
+\]
+with variable {\it x}.  The problem is equivalent to the quadratic 
+program
+\[
+ \begin{array}{ll}
+ \mbox{minimize} & \|Ax - y\|_2^2 + \ones^T u \\
+ \mbox{subject to} & -u \preceq x \preceq u
+ \end{array}
+\]
+with variables {\it x} and {\it u}.  The implementation below is 
+efficient when {\it A} has many more columns than rows. 
+
+\begin{verbatim}
+from cvxopt.base import matrix, spmatrix, mul, div
+from cvxopt import blas, lapack, solvers
+
+m, n = A.size
+def F(x=None):
+    """
+    Function and gradient evaluation of
+
+	f = || A*x[:n] - y ||_2^2 +  sum(x[n:])
+    """
+
+    nvars = 2*n
+    if x is None: return 0, matrix(0.0, (nvars,1))
+    r = A*x[:n] - y
+    f = blas.nrm2(r)**2 + sum(x[n:])
+    gradf = matrix(1.0, (1,2*n))
+    blas.gemv(A, r, gradf, alpha=2.0, trans='T')  
+    return f, +gradf
+
+
+def G(u, v, alpha=1.0, beta=0.0, trans='N'):
+    """
+	v := alpha*[I, -I; -I, -I] * u + beta * v  (trans = 'N' or 'T')
+    """
+
+    v *= beta
+    v[:n] += alpha*(u[:n] - u[n:])
+    v[n:] += alpha*(-u[:n] - u[n:])
+
+h = matrix(0.0, (2*n,1))
+
+
+# Customized solver for the KKT system 
+#
+#     [  2.0*z[0]*A'*A  0    I      -I     ] [x[:n] ]     [bx[:n] ]
+#     [  0              0   -I      -I     ] [x[n:] ]  =  [bx[n:] ].
+#     [  I             -I   -D1^-1   0     ] [zl[:n]]     [bzl[:n]]
+#     [ -I             -I    0      -D2^-1 ] [zl[n:]]     [bzl[n:]]
+#
+#    
+# We first eliminate zl and x[n:]:
+#
+#     ( 2*z[0]*A'*A + 4*D1*D2*(D1+D2)^-1 ) * x[:n] = bx[:n] - (D2-D1)*(D1+D2)^-1 * bx[n:] 
+#         + D1 * ( I + (D2-D1)*(D1+D2)^-1 ) * bzl[:n] - D2 * ( I - (D2-D1)*(D1+D2)^-1 ) * bzl[n:]           
+#
+#     x[n:] = (D1+D2)^-1 * ( bx[n:] - D1*bzl[:n]  - D2*bzl[n:] ) - (D2-D1)*(D1+D2)^-1 * x[:n]         
+#     zl[:n] = D1 * ( x[:n] - x[n:] - bzl[:n] )
+#     zl[n:] = D2 * (-x[:n] - x[n:] - bzl[n:] ).
+#
+# The first equation has the form
+#
+#     (z[0]*A'*A + D)*x[:n]  =  rhs
+#
+# and is equivalent to
+#
+#     [ D    A'       ] [ x:n] ]  = [ rhs ]
+#     [ A   -1/z[0]*I ] [ v    ]    [ 0   ].
+#
+# It can be solved as 
+#
+#     ( A*D^-1*A' + 1/z[0]*I ) * v = A * D^-1 * rhs
+#     x[:n] = D^-1 * ( rhs - A'*v ).
+
+S = matrix(0.0, (m,m))
+Asc = matrix(0.0, (m,n))
+v = matrix(0.0, (m,1))
+def kktsolver(x, z, dnl, dl):
+
+    # Factor 
+    #
+    #     S = A*D^-1*A' + 1/z[0]*I 
+    #
+    # where D = 2*D1*D2*(D1+D2)^-1, D1 = dl[:n]**2, D2 = dl[n:]**2.
+
+    d1, d2 = dl[:n]**2, dl[n:]**2    # d1 = diag(D1), d2 = diag(D2)
+    # ds is square root of diagonal of D
+    ds = sqrt(2.0) * div( mul(dl[:n], dl[n:]), sqrt(d1+d2) )
+    d3 =  div(d2 - d1, d1 + d2)
+ 
+    # Asc = A*diag(d)^-1/2
+    Asc = A * spmatrix( ds**-1, range(n), range(n))
+
+    # S = 1/z[0]*I + A * D^-1 * A'
+    blas.syrk(Asc, S)
+    S[::m+1] += 1.0 / z[0] 
+    lapack.potrf(S)
+
+    def g(x, y, znl, zl):
+
+        x[:n] = 0.5 * ( x[:n] - mul(d3, x[n:]) + mul(d1, zl[:n] + mul(d3, zl[:n])) - mul(d2, zl[n:] - mul(d3, zl[n:])) )
+        x[:n] = div( x[:n], ds) 
+
+        # Solve
+        #
+        #     S * v = 0.5 * A * D^-1 * ( bx[:n] - (D2-D1)*(D1+D2)^-1 * bx[n:] 
+        #             + D1 * ( I + (D2-D1)*(D1+D2)^-1 ) * bzl[:n] - D2 * ( I - (D2-D1)*(D1+D2)^-1 ) * bzl[n:] )
+	    
+        blas.gemv(Asc, x, v)
+        lapack.potrs(S, v)
+	
+        # x[:n] = D^-1 * ( rhs - A'*v ).
+        blas.gemv(Asc, v, x, alpha=-1.0, beta=1.0, trans='T')
+        x[:n] = div(x[:n], ds)
+
+        # x[n:] = (D1+D2)^-1 * ( bx[n:] - D1*bzl[:n]  - D2*bzl[n:] ) - (D2-D1)*(D1+D2)^-1 * x[:n]         
+        x[n:] = div( x[n:] - mul(d1, zl[:n]) - mul(d2, zl[n:]), d1+d2 ) - mul( d3, x[:n] )
+	    
+        # zl[:n] = D1 * (  x[:n] - x[n:] - bzl[:n] )
+        # zl[n:] = D2 * ( -x[:n] - x[n:] - bzl[n:] ).
+        zl[:n] = mul( d1,  x[:n] - x[n:] - zl[:n] ) 
+        zl[n:] = mul( d2, -x[:n] - x[n:] - zl[n:] ) 
+
+    return g
+
+x = solvers.nlcp(kktsolver, F, G, h)['x'][:n]
+\end{verbatim}
+
+\section{Optional Solvers} \label{s-external}
+CVXOPT includes optional interfaces to several other optimization 
+libraries.
+
+\begin{description}
+\item[GLPK] \function{lp()} with the \code{solver='glpk'} option uses 
+the the simplex algorithm in 
+\ulink{GLPK (GNU Linear Programming Kit)}{http://www.gnu.org/software/glpk/glpk.html}.   
+
+\item[MOSEK] \function{lp()} and \function{qp()} with the 
+\code{solver='mosek'} option call routines from  
+\ulink{MOSEK}{http://www.mosek.com} version 4.  
+
+\item[DSDP] \function{sdp()} with the \code{solver='dsdp'} option uses 
+the 
+\ulink{DSDP5.8}{http://www-unix.mcs.anl.gov/DSDP} solver.  
+\end{description}
+GLPK, MOSEK and DSDP are not included in the CVXOPT distribution and 
+need to be installed separately.  
+
+\section{Algorithm Parameters} \label{s-parameters}
+In this section we list some algorithm control parameters that can 
+be modified without editing the source code.  
+These control parameters are accessible via the dictionary 
+\member{solvers.options}.  By default the dictionary 
+is empty and the default values of the parameters are used.
+
+One can change the parameters in the \textbf{default} solvers by 
+adding entries with the following key values.  
+\begin{description}
+\item[\code{'show\_progress'}]  
+\True\  or \False; turns the output to the screen on or off  
+(default: \True).
+\item[\code{'maxiters'}] maximum number of iterations (default: 100).
+\item[\code{'abstol'}] absolute accuracy (default: \code{1e-7}).
+\item[\code{'reltol'}] relative accuracy (default: \code{1e-7}).
+\item[\code{'feastol'}] tolerance for feasibility conditions (default:
+\code{1e-7}).
+\item[\code{'refinement'}] \True\ or \False.  If \True, 
+one step of iterative refinement is applied after solving KKT equations
+in \function{conelp()}, \function{lp()}, and \function{sdp()} 
+(default: \True). 
+\end{description}
+For example the command
+\begin{verbatim}
+>>> from cvxopt import solvers
+>>> solvers.options['show_progress'] = False
+\end{verbatim}
+turns off the screen output during calls to the solvers.
+The tolerances \var{abstol}, \var{reltol} and \var{feastol} have the
+following meaning.   \function{conelp()} terminates with 
+status \code{'optimal'}, if
+\[
+s_\mathrm{l} \succeq 0, \qquad S_\mathrm{s} \succeq 0, 
+\qquad 
+ \frac{\|G_\mathrm{l}x+s_\mathrm{l}-h_\mathrm{l}\|_2}
+ {\max\{1,\|h_\mathrm{l}\|_2\}} \leq \epsilon_\mathrm{feas}, 
+\qquad 
+\frac{\|G_\mathrm{s}(x)+S_\mathrm{s}-H_\mathrm{s}\|_F}
+{\max\{1,\|H_\mathrm{s}\|_F\}} \leq \epsilon_\mathrm{feas}, 
+\qquad
+\frac{\|Ax-b\|_2}{\max\{1,\|b\|_2\}} \leq \epsilon_\mathrm{feas}, 
+\]
+\[
+z_\mathrm{l} \succeq 0, \qquad Z_\mathrm{s} \succeq 0, \qquad
+\frac{\|G_\mathrm{l}^Tz_\mathrm{l}+
+G_\mathrm{s}^T(Z_\mathrm{s}) + A^Ty+c\|_2}{\max\{1,\|c\|_2\}} 
+\leq \epsilon_\mathrm{feas}, 
+\]
+and
+\[
+ s_\mathrm{l}^T z_\mathrm{l} + \Tr(S_\mathrm{s}Z_\mathrm{s}) \leq 
+ \epsilon_\mathrm{abs} \qquad \mbox{or} \qquad
+\left( \min\left\{c^Tx,  
+ h_\mathrm{l}^T z_\mathrm{l} + \Tr(H_\mathrm{s} Z_\mathrm{s})
+ + b^Ty \right\} < 0, \quad 
+ \frac{s_\mathrm{l}^Tz_\mathrm{l} + \Tr(S_\mathrm{s}Z_\mathrm{s})}
+ {-\min\{c^Tx, h_\mathrm{l}^Tz_\mathrm{l} + 
+ \Tr(H_\mathrm{s} Z_\mathrm{s}) + b^T y\}} \leq \epsilon_\mathrm{rel}
+\right).
+\]
+It returns with status  \code{'primal infeasible'} if 
+\[
+z_\mathrm{l} \succeq 0, \qquad
+Z_\mathrm{s} \succeq 0, \qquad
+\qquad \|G_\mathrm{l}^Tz_\mathrm{l} + G_\mathrm{s}^T(Z_\mathrm{s})
+ +A^Ty\|_2 \leq \epsilon_\mathrm{feas}, 
+ \qquad h_\mathrm{l}^Tz_\mathrm{l} + \Tr(H_\mathrm{s} Z_\mathrm{s}) 
+ +b^Ty = -1.
+\]
+It returns with status \code{'dual infeasible'} if 
+\[
+s_\mathrm{l} \succeq 0, \qquad
+S_\mathrm{s} \succeq 0, \qquad
+\qquad
+\|G_\mathrm{l}x+s_\mathrm{l}\|_2 \leq \epsilon_\mathrm{feas}, \qquad
+\|G_\mathrm{s}(x)+S_\mathrm{s}\|_F \leq \epsilon_\mathrm{feas}, \qquad
+\|Ax\|_2 \leq \epsilon_\mathrm{feas},  \qquad
+c^Tx = -1.
+\]
+The functions \function{lp()} and \function{sdp()} call 
+\function{conelp()} and hence use the same stopping criteria.
+
+\function{nlcp()} returns with status \code{'optimal'} if
+\[
+\frac{\| \nabla f_0(x) +  D\tilde f(x)^Tz_\mathrm{nl} + 
+ G^Tz_\mathrm{l} + A^T y \|_2 }
+{\max\{ 1, 
+\| \nabla f_0(x_0) + D\tilde f(x_0)^T\ones + G^T\ones \|_2 \}} 
+\leq \epsilon_\mathrm{feas}, \qquad
+\frac{\| ( \tilde f(x) + s_{\mathrm{nl}},  Gx + s_\mathrm{l} - h, 
+ Ax-b ) \|_2} 
+{\max\{1, \| ( \tilde f(x_0) + \ones,  
+Gx_0 + \ones-h, Ax_0-b) \|_2 \}} \leq \epsilon_\mathrm{feas}  
+\]
+where {\it x0} is the point returned by \code{F()}, and
+\[
+\mathrm{gap} \leq \epsilon_\mathrm{abs}
+\qquad \mbox{or} \qquad \left( f_0(x) < 0, \quad
+\frac{\mathrm{gap}} {-f_0(x)} \leq \epsilon_\mathrm{rel} \right)
+\qquad \mbox{or} \qquad
+\left( L(x,y,z) > 0, \quad \frac{\mathrm{gap}}
+{L(x,y,z)} \leq \epsilon_\mathrm{rel} \right)
+\]
+where
+\[
+ \mathrm{gap} = 
+\left[\begin{array}{c} s_\mathrm{nl} \\ s_\mathrm{l} 
+\end{array}\right]^T
+\left[\begin{array}{c} z_\mathrm{nl} \\ z_\mathrm{l} 
+\end{array}\right],
+\qquad
+L(x,y,z) = f_0(x) + z_\mathrm{nl}^T \tilde f(x) + 
+ z_\mathrm{l}^T (Gx-h) + y^T(Ax-b).
+\]
+The functions \function{qp()}, \function{gp()} and \function{cp()}
+call \function{nlcp()} and hence use the same stopping criteria
+(with {\it x0}=0 for \function{qp()} and \function{gp()}).
+
+The control parameters listed in the \textbf{GLPK} documentation are 
+set to their default values and can also be customized by making 
+an entry in \member{solvers.options}.
+The keys in the dictionary are strings with the name of the GLPK 
+parameter.  The command
+\begin{verbatim}
+>>> from cvxopt import solvers 
+>>> solvers.options['LPX_K_MSGLEV'] = 0
+\end{verbatim}
+turns off the screen output subsequent calls \function{lp()} with 
+the \code{'glpk'} option.
+
+The \textbf{MOSEK} \ulink{control parameters}{http://www.mosek.com/products/3/tools/doc/html/tools/node22.html}
+are set to their default values.
+The corresponding keys in \code{solvers.options} are strings with the 
+name of the MOSEK parameter.  For example the command
+\begin{verbatim}
+>>> from cvxopt import solvers 
+>>> solvers.options['MSK_IPAR_LOG'] = 0
+\end{verbatim}
+turns off the screen output during calls of  \function{lp()} 
+and \function{qp()} with the \code{'mosek'} option.
+
+The following control parameters affect the \textbf{DSDP} algorithm:
+\begin{description}
+\item[\code{'DSDP\_Monitor'}] the interval (in number of iterations)
+ at which output is printed to the screen
+(default: 0).
+\item[\code{'DSDP\_MaxIts'}] maximum number of iterations.
+\item[\code{'DSDP\_GapTolerance'}] relative accuracy (default: 
+\code{1e-5}).
+\end{description}
diff --git a/doc/spsolvers.tex b/doc/spsolvers.tex
new file mode 100644
index 0000000..56b556f
--- /dev/null
+++ b/doc/spsolvers.tex
@@ -0,0 +1,566 @@
+\chapter{Sparse Linear Equation Solvers} \label{c-spsolvers}
+In this section we describe routines for solving sparse sets of linear 
+equations.
+
+A real symmetric or complex Hermitian sparse matrix is stored as
+an \spmtrx\ object \var{X}  of size ({\it n}, {\it n}) and an 
+additional character argument \code{uplo} with possible values 
+\code{'L'} and \code{'U'}.  
+If \code{uplo} is \code{'L'}, the lower triangular part
+of \var{X} contains the lower triangular part of the
+symmetric or Hermitian matrix, and the upper triangular matrix
+of \var{X} is ignored.
+If \code{uplo} is \code{'U'}, the upper triangular part
+of \var{X} contains the upper triangular part of the
+matrix, and the lower triangular matrix of \var{X} is ignored.
+
+A general sparse square matrix of order {\it n} is represented by an
+\spmtrx\ object of size ({\it n}, {\it n}).
+
+Dense matrices, which appear as righthand sides of equations, are 
+stored using the same conventions as in the BLAS and LAPACK modules.
+
+\section{Matrix Orderings (\module{cvxopt.amd})} \label{s-orderings}
+
+CVXOPT includes an interface to the AMD library for computing 
+approximate minimum degree orderings of sparse matrices.
+
+\begin{seealso}
+\seelink{http://www.cise.ufl.edu/research/sparse/amd}{AMD code, 
+documentation, copyright and license.}{}
+\seetext{P.\ R.\ Amestoy, T.\ A.\ Davis, I.\ S.\ Duff,
+Algorithm 837: AMD, An Approximate Minimum Degree Ordering Algorithm,
+ACM Transactions on Mathematical Software, 30(3), 381-388, 2004.}
+\end{seealso}
+
+\begin{funcdesc}{order}{A\optional{, uplo='L'}}
+Computes the approximate mimimum degree ordering of a symmetric  sparse
+matrix {\it A}.  
+The ordering is returned as an integer dense matrix with length equal 
+to the order of \var{A}.  Its entries specify a permutation that 
+reduces fill-in during the Cholesky factorization.
+More precisely, if \code{\var{p} = order(\var{A})}, then  
+\code{\var{A}[\var{p},\var{p}]} has sparser Cholesky factors 
+than \code{\var{A}}.   
+\end{funcdesc}
+
+As an example we consider the matrix 
+\[
+\left[ \begin{array}{rrrr}
+ 10 &  0 & 3 &  0 \\
+  0 &  5 & 0 & -2 \\
+  3 &  0 & 5 &  0 \\
+  0 & -2 & 0 &  2 
+\end{array}\right].
+\]
+\begin{verbatim}
+>>> from cvxopt.base import spmatrix
+>>> from cvxopt import amd 
+>>> A = spmatrix([10,3,5,-2,5,2], [0,2,1,2,2,3], [0,0,1,1,2,3])
+>>> P = amd.order(A)
+>>> print P
+ 1
+ 0
+ 2
+ 3
+\end{verbatim}
+
+\section{General Linear Equations (\module{cvxopt.umfpack})} 
+\label{s-umfpack}
+The module \module{cvxopt.umfpack} includes four functions for solving 
+sparse non-symmetric sets of linear equations.  
+They call routines from the UMFPACK library, with all control options 
+set to the default values described in the UMFPACK user guide.  
+
+\begin{seealso}
+\seelink{http://www.cise.ufl.edu/research/sparse/umfpack}{UMFPACK code, documentation, copyright and license.}{}
+\seetext{T.\ A.\ Davis,
+Algorithm 832: UMFPACK -- an unsymmetric-pattern multifrontal method 
+with a column pre-ordering strategy,
+ACM Transactions on Mathematical Software, 30(2), 196-199, 2004.}
+\end{seealso}
+
+\begin{funcdesc}{linsolve}{A, B\optional{, trans='N'}}
+Solves a sparse set of linear equations 
+\[
+ AX = B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+ A^TX = B \quad (\mathrm{trans} = \mathrm{'T'}), \qquad
+ A^HX = B \quad (\mathrm{trans} = \mathrm{'C'}),
+\]
+where {\var A} is a sparse matrix and \var{B} is a dense matrix of
+the same type (\dtc\ or \ztc) as \var{A}.  On exit \var{B} contains 
+the solution.
+Raises an \code{ArithmeticError} exception if the coefficient matrix 
+is singular.
+\end{funcdesc}
+In the following example we solve an equation with 
+coefficient matrix 
+\BEQ \label{e-sp-Adef}
+A = \left[\begin{array}{rrrrr}
+ 2 & 3 & 0 & 0 & 0 \\
+ 3 & 0 & 4 & 0 & 6 \\
+ 0 &-1 &-3 & 2 & 0 \\
+ 0 & 0 & 1 & 0 & 0 \\
+ 0 & 4 & 2 & 0 & 1 
+ \end{array}\right].
+\EEQ
+\begin{verbatim}
+>>> from cvxopt.base import spmatrix, matrix
+>>> from cvxopt import umfpack 
+>>> V = [2,3, 3,-1,4, 4,-3,1,2, 2, 6,1]
+>>> I = [0,1, 0, 2,4, 1, 2,3,4, 2, 1,4]
+>>> J = [0,0, 1, 1,1, 2, 2,2,2, 3, 4,4]
+>>> A = spmatrix(V,I,J)
+>>> B = matrix(1.0, (5,1))
+>>> umfpack.linsolve(A,B)
+>>> print B
+ 5.7895e-01
+-5.2632e-02
+ 1.0000e+00
+ 1.9737e+00
+-7.8947e-01
+\end{verbatim}
+The function \function{umfpack.linsolve()} is equivalent to the 
+following three functions called in sequence.  
+\begin{funcdesc}{symbolic}{A}
+Reorders the columns of \var{A} to reduce fill-in and performs a 
+symbolic LU factorization.  \var{A} is a sparse, possibly rectangular,
+matrix.
+Returns the symbolic factorization as an opaque C object that can be 
+passed on to \function{umfpack.numeric()}.
+\end{funcdesc}
+
+\begin{funcdesc}{numeric}{A, F}
+Performs a numeric LU factorization of a sparse, possibly rectangular,
+matrix \var{A}.   The argument \var{F} is the symbolic factorization
+computed by \function{umfpack.symbolic()} applied to the matrix \var{A},
+or another sparse matrix with the same sparsity pattern, dimensions,
+and type.  The numeric factorization is returned as an opaque C object 
+that that can be passed on to \function{umfpack.solve()}.  Raises an
+\code{ArithmeticError} if the matrix is singular.
+\end{funcdesc}
+
+\begin{funcdesc}{solve}{A, F, B\optional{, trans='N'}}
+Solves a set of linear equations
+\[
+ AX = B \quad (\mathrm{trans} = \mathrm{'N'}), \qquad
+ A^TX = B \quad (\mathrm{trans} = \mathrm{'T'}), \qquad
+ A^HX = B \quad (\mathrm{trans} = \mathrm{'C'}),
+\]
+where {\var A} is a sparse matrix and \var{B} is a dense matrix of 
+the same type as \var{A}.
+The argument \var{F} is a numeric factorization computed by 
+\function{umfpack.numeric()}.
+On exit \var{B} is overwritten by the solution.
+\end{funcdesc}
+These separate functions are useful for solving several sets
+of linear equations with the same coefficient matrix and different 
+righthand sides, or with coefficient matrices that share the same 
+sparsity pattern.
+The symbolic factorization depends only on the sparsity pattern of
+the matrix, and not on the numerical values of the nonzero 
+coefficients. 
+The numerical factorization on the other hand depends on the sparsity 
+pattern of the matrix and on its the numerical values.
+
+As an example, suppose {\it A} is the matrix~(\ref{e-sp-Adef}) and 
+\[
+B = \left[\begin{array}{rrrrr}
+ 4 & 3 & 0 & 0 & 0 \\
+ 3 & 0 & 4 & 0 & 6 \\
+ 0 &-1 &-3 & 2 & 0 \\
+ 0 & 0 & 1 & 0 & 0 \\
+ 0 & 4 & 2 & 0 & 2 
+ \end{array}\right],
+\]
+which differs from {\it A} in its first and last entries.
+The following code computes
+\[
+ x = A^{-T}B^{-1}A^{-1}\ones.
+\]
+\begin{verbatim}
+>>> from cvxopt.base import spmatrix, matrix
+>>> from cvxopt import umfpack
+>>> VA = [2,3, 3,-1,4, 4,-3,1,2, 2, 6,1]
+>>> VB = [4,3, 3,-1,4, 4,-3,1,2, 2, 6,2]
+>>> I =  [0,1, 0, 2,4, 1, 2,3,4, 2, 1,4]
+>>> J =  [0,0, 1, 1,1, 2, 2,2,2, 3, 4,4]
+>>> A = spmatrix(VA, I, J)
+>>> B = spmatrix(VB, I, J)
+>>> x = matrix(1.0, (5,1))
+>>> Fs = umfpack.symbolic(A)
+>>> FA = umfpack.numeric(A, Fs)
+>>> FB = umfpack.numeric(B, Fs)
+>>> umfpack.solve(A, FA, x)
+>>> umfpack.solve(B, FB, x)
+>>> umfpack.solve(A, FA, x, trans='T')
+>>> print x
+ 5.8065e-01
+-2.3660e-01
+ 1.6280e+00
+ 8.0656e+00
+-1.3075e-01
+\end{verbatim}
+
+\section{Positive Definite Linear Equations (\module{cvxopt.cholmod})} 
+\label{s-cholmod}
+
+\module{cvxopt.cholmod} is an interface to the Cholesky factorization 
+routines of the CHOLMOD package.
+It includes functions for Cholesky factorization of sparse positive
+definite matrices, and for solving sparse sets of linear equations with 
+positive definite matrices. 
+The routines can also be used for computing LDL$\mathrm{{}^T}$ 
+(or LDL$\mathrm{{}^H}$) factorizations of symmetric indefinite matrices 
+(with L unit lower-triangular and D diagonal and nonsingular) if 
+such a factorization exists.  
+
+\begin{seealso}
+\seelink{http://www.cise.ufl.edu/research/sparse/cholmod}{CHOLMOD code, documentation, copyright and license.}{}
+\end{seealso}
+
+
+\begin{funcdesc}{linsolve}{A, B\optional{, p=\None\optional{, 
+uplo='L'}}}
+Solves
+\[
+ AX = B 
+\]
+with {\it A} sparse and real symmetric or complex Hermitian.
+\var{B} is a dense matrix of the same type as \var{A}.  On exit it 
+is overwritten with the solution.
+The argument \var{p} is an integer matrix with length equal to the 
+order of \var{A}, and specifies an optional reordering of \var{A}.
+If \var{p} is not specified, CHOLMOD used a reordering from the
+AMD library.
+Raises an \code{ArithmeticError} if the factorization does not exist.
+\end{funcdesc}
+
+As an  example, we solve 
+\BEQ \label{e-A-pd}
+\left[ \begin{array}{rrrr}
+ 10 &  0 & 3 &  0 \\
+  0 &  5 & 0 & -2 \\
+  3 &  0 & 5 &  0 \\
+  0 & -2 & 0 &  2 
+  \end{array}\right] X = \left[ \begin{array}{cc}
+   0 & 4 \\ 1 & 5 \\ 2 & 6 \\ 3 & 7\end{array} \right].
+\EEQ
+\begin{verbatim}
+>>> from cvxopt.base import matrix, spmatrix
+>>> from cvxopt import cholmod
+>>> A = spmatrix([10,3, 5,-2, 5, 2], [0,2, 1,3, 2, 3], [0,0, 1,1, 2, 3])
+>>> X = matrix(range(8), (4,2), 'd')
+>>> cholmod.linsolve(A,X)
+>>> print X
+-1.4634e-01   4.8780e-02
+ 1.3333e+00   4.0000e+00
+ 4.8780e-01   1.1707e+00
+ 2.8333e+00   7.5000e+00
+\end{verbatim}
+
+\begin{funcdesc}{splinsolve}{A, B\optional{, p=\None\optional{, 
+uplo='L'}}}
+Similar to \function{linsolve()} except that \var{B} is a sparse 
+matrix and that the solution is returned as an output 
+argument (as a new sparse matrix).  \var{B} is not modified.
+\end{funcdesc}
+
+The following code computes the inverse of the coefficient matrix 
+in~(\ref{e-A-pd}) as a sparse matrix.
+\begin{verbatim}
+>>> X = cholmod.splinsolve(A, spmatrix(1.0,range(4),range(4)))
+>>> print X
+SIZE: (4,4)
+(0, 0)  1.2195e-01
+(2, 0) -7.3171e-02
+(1, 1)  3.3333e-01
+(3, 1)  3.3333e-01
+(0, 2) -7.3171e-02
+(2, 2)  2.4390e-01
+(1, 3)  3.3333e-01
+(3, 3)  8.3333e-01
+\end{verbatim}
+
+The functions \function{linsolve()} and \function{splinsolve()} are
+equivalent to \function{symbolic()} and \function{numeric()} called in
+sequence, followed by \function{solve()}, respectively, 
+\function{spsolve()}.
+
+\begin{funcdesc}{symbolic}{A\optional{, p=\None\optional{, uplo='L'}}}
+Performs a symbolic analysis of a sparse real symmetric or
+complex Hermitian matrix \var{A} for one of the two factorizations:
+\BEQ \label{e-chol-ll}
+   PAP^T = LL^T, \qquad PAP^T = LL^H, 
+\EEQ
+and 
+\BEQ \label{e-chol-ldl}
+   PAP^T = LDL^T, \qquad PAP^T = LDL^H,
+\EEQ
+where {\it P} is a permutation matrix, {\it L} is lower triangular 
+(unit lower triangular in the second factorization), and 
+{\it D} is nonsingular diagonal.  The type of factorization depends 
+on the value of \code{options['supernodal']}.
+
+If \var{uplo} is \code{'L'}, only the lower triangular part of \var{A} 
+is accessed and the upper triangular part is ignored.
+If \var{uplo} is \code{'U'}, only the upper triangular part of \var{A} 
+is accessed and the lower triangular part is ignored.
+
+The symbolic factorization is returned as an opaque C object that 
+can be passed to \function{cholmod.numeric()}.
+\end{funcdesc}
+
+\begin{funcdesc}{numeric}{A, F}
+Performs a numeric factorization of a sparse symmetric matrix 
+as~(\ref{e-chol-ll}) or~(\ref{e-chol-ldl}).  
+The argument \var{F} is the symbolic factorization
+computed by \function{cholmod.symbolic()} applied to the matrix \var{A},
+or to another sparse  matrix with the same sparsity pattern and 
+typecode, or by
+\function{cholmod.numeric()} applied to a matrix with the same
+sparsity pattern and typecode as \var{A}.
+
+If \var{F} was created by a \function{cholmod.symbolic} with 
+\var{uplo} equal to \code{'L'}, then only the lower triangular part 
+of \var{A} is accessed and the upper triangular part is ignored.
+If it was created with \var{uplo} is \code{'U'}, then only the upper 
+triangular part of \var{A} is accessed and the lower triangular part 
+is ignored.
+
+On successful exit, the factorization is stored in \var{F}.
+Raises an \code{ArithmeticError} if the factorization does not
+exist.
+\end{funcdesc}
+
+\begin{funcdesc}{solve}{F, B\optional{, sys=0}}
+Solves one of the following linear equations where \var{B} is a dense 
+matrix and \var{F} is the numeric 
+factorization~(\ref{e-chol-ll}) or~(\ref{e-chol-ldl}) computed by 
+\function{cholmod\_numeric()}.  
+\var{sys} is an integer with values between 0 and 8. 
+
+\begin{center}
+\begin{tabular}{c|c|} 
+ \var{sys} & equation \\ \hline
+ 0 & $AX=B$     \\ 1 & $LDL^TX=B$ \\ 2 & $LDLX=B$   \\ 
+ 3 & $DL^TX=B$  \\ 4 & $LX=B$     \\ 5 & $L^TX=B$  \\
+ 6 & $DX=B$     \\ 7 & $P^TX=B$   \\ 8 & $PX=B$    
+\end{tabular}
+\end{center}
+
+(If \var{F} is a Cholesky factorization of the form~(\ref{e-chol-ll}), 
+{\it D} is an identity matrix in this table. 
+If \var{A} is complex, $L^T$ should be replaced by $L^H$.)
+
+The matrix \var{B} is a dense \dtc\ or \ztc\ matrix, with the same type
+as \var{A}.  On exit it is overwritten by the solution.
+\end{funcdesc}
+
+\begin{funcdesc}{spsolve}{F, B\optional{, sys=0}}
+Similar to \function{solve()}, except that \var{B} is a 
+sparse matrix, and the solution is returned as an output argument
+(as a sparse matrix).  \var{B} must have the same typecode as \var{A}.
+\end{funcdesc}
+
+For the same example as above:
+\begin{verbatim}
+>>> X = matrix(range(8), (4,2), 'd')
+>>> F = cholmod.symbolic(A)
+>>> cholmod.numeric(A,F)
+>>> cholmod.solve(F,X)
+>>> print X
+-1.4634e-01   4.8780e-02
+ 1.3333e+00   4.0000e+00
+ 4.8780e-01   1.1707e+00
+ 2.8333e+00   7.5000e+00
+\end{verbatim}
+
+\begin{funcdesc}{diag}{F}
+Returns the diagonal elements of the Cholesky factor {\it L} 
+in~(\ref{e-chol-ll}), as a dense matrix of the same type as \var{A}.
+Note that this only applies to Cholesky factorizations.
+The matrix {\it D} in an LDL$\mathrm{{}^T}$ factorization can be 
+retrieved via \function{cholmod.solve()} with \var{sys} equal to 6.
+\end{funcdesc}
+
+In the functions listed above, the default values of the control 
+parameters described in the CHOLMOD user guide are used, except for 
+\ctype{Common->print} which is set to 0 instead of 3
+and 
+\ctype{Common->supernodal} which is set to 2 instead of 1.
+These parameters (and a few others) can be modified by making an 
+entry in the dictionary \member{cholmod.options}. 
+The meaning of these parameters is as follows.
+\begin{description}
+\item[\code{options['supernodal']}] If equal to 0, a 
+factorization~(\ref{e-chol-ldl}) is computed using a simplicial 
+algorithm.
+If equal to 2, a factorization~(\ref{e-chol-ll}) is
+computed using a supernodal algorithm.
+If equal to 1, the most efficient of the two factorizations is
+selected, based on the sparsity pattern.  Default: 2.
+
+\item[\code{options['print']}] A nonnegative integer that controls the 
+amount of output printed to the screen.
+Default: 0 (no output).
+\end{description}
+
+As an example that illustrates \function{diag()} and the use of 
+\member{cholmod.options}, we compute the logarithm of the determinant 
+of the coefficient matrix in~(\ref{e-A-pd}) by two methods.
+\begin{verbatim}
+>>> import math
+>>> from cvxopt.cholmod import options
+>>> from cvxopt.base import log
+>>> options['supernodal'] = 2
+>>> F = cholmod.symbolic(A)
+>>> cholmod.numeric(A,F)
+>>> print 2.0 * sum(log(cholmod.diag(F)))
+5.50533153593
+\end{verbatim}
+\begin{verbatim}
+>>> options['supernodal'] = 0
+>>> F = cholmod.symbolic(A)
+>>> cholmod.numeric(A,F)
+>>> Di = matrix(1.0, (4,1))
+>>> cholmod.solve(F,Di,sys=6)
+>>> print -sum(log(Di))
+5.50533153593
+\end{verbatim}
+
+\section{Example: Covariance Selection}
+This example illustrates the use of the routines for sparse Cholesky 
+factorization.  We consider the problem 
+\BEQ \label{e-covsel}
+ \begin{array}{ll}
+ \mbox{minimize} & -\log\det K + \Tr(KY)\\
+ \mbox{subject to} & K_{ij}=0,\quad (i,j) \not \in S.
+ \end{array}
+\EEQ
+The optimization variable is a symmetric matrix {\it K} of order {\it n}
+and the domain of the problem is the set of positive definite matrices.
+The matrix $Y$ and the index set  $S$ are given.  We assume that all 
+the diagonal positions are included in $S$.
+This problem arises in maximum likelihood estimation of the covariance
+matrix of a zero-mean normal distribution, with constraints 
+that specify that pairs of variables are conditionally independent.
+
+We can express {\it K} as
+\[
+   K(x) = E_1\diag(x)E_2^T+E_2\diag(x)E_1^T
+\]
+where {\it x} are the nonzero elements in the lower triangular part
+of {\it K}, with the diagonal elements scaled by 1/2,
+and
+\[
+ E_1 = \left[ \begin{array}{cccc}
+  e_{i_1} & e_{i_2} & \cdots & e_{i_q} \end{array}\right], \qquad
+ E_2 = \left[ \begin{array}{cccc}
+  e_{j_1} & e_{j_2} & \cdots & e_{j_q} \end{array}\right], 
+\]
+where ({\it i\_k}, {\it j\_k}) are the positions of the nonzero 
+entries in the lower-triangular part of {\it K}.
+With this notation, we can solve problem~(\ref{e-covsel}) by solving
+the unconstrained problem
+\[
+ \begin{array}{ll}
+   \mbox{minimize} & f(x) = -\log\det K(x) + \Tr(K(x)Y).
+ \end{array}
+\]
+The code below implements Newton's method with a backtracking line
+search.  The gradient and Hessian of the objective function are given 
+by
+\begin{eqnarray*}
+\nabla f(x) 
+&=& 2 \diag( E_1^T (Y - K(x)^{-1}) E_2)) \\
+&=& 2\diag(Y_{IJ} - \left(K(x)^{-1}\right)_{IJ})\\
+\nabla^2 f(x) & = & 
+ 2 (E_1^T K(x)^{-1} E_1) \circ (E_2^T K(x)^{-1} E_2) 
+   + 2 (E_1^T K(x)^{-1} E_2) \circ (E_2^T K(x)^{-1} E_1) \\
+&=& 2 \left(K(x)^{-1}\right)_{II} \circ 
+      \left(K(x)^{-1}\right)_{JJ}
+   +2 \left(K(x)^{-1}\right)_{IJ} \circ 
+      \left(K(x)^{-1}\right)_{JI},
+\end{eqnarray*} 
+where \code{o} denotes Hadamard product.
+
+\begin{verbatim}
+from cvxopt.base import matrix, spmatrix, log, mul
+from cvxopt import blas, lapack, amd, cholmod
+
+def covsel(Y):
+    """
+    Returns the solution of
+
+         minimize    -logdet K + Tr(KY)
+         subject to  K_{ij}=0,  (i,j) not in indices listed in I,J.
+
+    Y is a symmetric sparse matrix with nonzero diagonal elements.
+    I = Y.I,  J = Y.J.
+    """
+
+    I, J = Y.I, Y.J
+    n, m = Y.size[0], len(I) 
+    N = I + J*n         # non-zero positions for one-argument indexing 
+    D = [k for k in xrange(m) if I[k]==J[k]]  # position of diagonal elements
+
+    # starting point: symmetric identity with nonzero pattern I,J
+    K = spmatrix(0, I, J) 
+    K[::n+1] = 1
+
+    # Kn is used in the line search
+    Kn = spmatrix(0, I, J)
+
+    # symbolic factorization of K 
+    F = cholmod.symbolic(K)
+
+    # Kinv will be the inverse of K
+    Kinv = matrix(0.0, (n,n))
+    
+    for iters in xrange(100):
+
+        # numeric factorization of K
+        cholmod.numeric(K, F)
+        d = cholmod.diag(F)
+
+        # compute Kinv by solving K*X = I 
+        Kinv[:] = 0
+        Kinv[::n+1] = 1
+        cholmod.solve(F, Kinv)
+
+        # solve Newton system
+        grad = 2*(Y.V - Kinv[N])
+        hess = 2*(mul(Kinv[I,J],Kinv[J,I]) + mul(Kinv[I,I],Kinv[J,J]))
+        v = -grad
+        lapack.posv(hess,v) 
+        
+        # stopping criterion
+        sqntdecr = -blas.dot(grad,v) 
+        print "Newton decrement squared:%- 7.5e" %sqntdecr
+        if (sqntdecr < 1e-12):
+            print "number of iterations: ", iters+1 
+            break
+
+        # line search
+        dx = +v
+        dx[D] *= 2      # scale the diagonal elems        
+        f = -2.0 * sum(log(d))    # f = -log det K
+        s = 1
+        for lsiter in xrange(50):
+            Kn.V = K.V + s*dx
+            try: 
+                cholmod.numeric(Kn, F)
+            except ArithmeticError:
+                s *= 0.5
+            else:
+                d = cholmod.diag(F)
+                fn = -2.0 * sum(log(d)) + 2*s*blas.dot(v,Y.V)
+                if (fn < f - 0.01*s*sqntdecr): 
+                     break
+                s *= 0.5
+            
+        K.V = Kn.V
+
+    return K
+\end{verbatim}
diff --git a/examples/book/README b/examples/book/README
new file mode 100644
index 0000000..6ca767c
--- /dev/null
+++ b/examples/book/README
@@ -0,0 +1,7 @@
+This directory contains examples from the book "Convex Optimization" 
+by Boyd and Vandenberghe (Cambridge University Press, 2004, and
+www.stanford.edu/~boyd/cvxbook).
+
+The scripts require the plotting library Matplotlib, available at
+matplotlib.sourceforge.net.  They were tested with Matplotlib 
+version 0.83.2-2.
diff --git a/examples/book/chap4/portfolio b/examples/book/chap4/portfolio
new file mode 100755
index 0000000..7d0046d
--- /dev/null
+++ b/examples/book/chap4/portfolio
@@ -0,0 +1,57 @@
+#!/usr/bin/python
+ 
+# Figure 4.12, page 187.
+# Risk-return trade-off.
+
+from math import sqrt
+from cvxopt.base import matrix
+from cvxopt.blas import dot 
+from cvxopt.solvers import qp, options 
+import pylab
+
+n = 4
+S = matrix( [[ 4e-2,  6e-3, -4e-3,   0.0 ], 
+             [ 6e-3,  1e-2,  0.0,    0.0 ],
+             [-4e-3,  0.0,   2.5e-3, 0.0 ],
+             [ 0.0,   0.0,   0.0,    0.0 ]] )
+pbar = matrix([.12, .10, .07, .03])
+
+G = matrix(0.0, (n,n))
+G[::n+1] = -1.0
+h = matrix(0.0, (n,1))
+A = matrix(1.0, (1,n))
+b = matrix(1.0)
+
+N = 100
+mus = [ 10**(5.0*t/N-1.0) for t in xrange(N) ]
+options['show_progress'] = False
+xs = [ qp(mu*S, -pbar, G, h, A, b)['x'] for mu in mus ]
+returns = [ dot(pbar,x) for x in xs ]
+risks = [ sqrt(dot(x, S*x)) for x in xs ]
+
+pylab.figure(1, facecolor='w')
+pylab.plot(risks, returns)
+pylab.xlabel('standard deviation')
+pylab.ylabel('expected return')
+pylab.axis([0, 0.2, 0, 0.15])
+pylab.title('Risk-return trade-off curve (fig 4.12)')
+pylab.yticks([0.00, 0.05, 0.10, 0.15])
+
+pylab.figure(2, facecolor='w')
+c1 = [ x[0] for x in xs ] 
+c2 = [ x[0] + x[1] for x in xs ]
+c3 = [ x[0] + x[1] + x[2] for x in xs ] 
+c4 = [ x[0] + x[1] + x[2] + x[3] for x in xs ]
+pylab.fill(risks + [.20], c1 + [0.0], '#F0F0F0') 
+pylab.fill(risks[-1::-1] + risks, c2[-1::-1] + c1 , '#D0D0D0') 
+pylab.fill(risks[-1::-1] + risks, c3[-1::-1] + c2, '#F0F0F0') 
+pylab.fill(risks[-1::-1] + risks, c4[-1::-1] + c3,  '#D0D0D0') 
+pylab.axis([0.0, 0.2, 0.0, 1.0])
+pylab.xlabel('standard deviation')
+pylab.ylabel('allocation')
+pylab.text(.15,.5,'x1')
+pylab.text(.10,.7,'x2')
+pylab.text(.05,.7,'x3')
+pylab.text(.01,.7,'x4')
+pylab.title('Optimal allocations (fig 4.12)')
+pylab.show()
diff --git a/examples/book/chap4/rls b/examples/book/chap4/rls
new file mode 100755
index 0000000..50ddc05
--- /dev/null
+++ b/examples/book/chap4/rls
@@ -0,0 +1,79 @@
+#!/usr/bin/python
+ 
+# Figure 4.11, page 185.
+# Regularized least-squares.
+
+import pylab
+from pickle import load
+from cvxopt import blas, lapack
+from cvxopt.base import matrix
+from cvxopt import solvers 
+solvers.options['show_progress'] = 0
+
+data = load(open("rls.pic",'r'))
+A, b = data['A'], data['b']
+m, n = A.size
+
+# LS solution
+xls = +b
+lapack.gels(+A, xls)
+xls = xls[:n]
+
+# We compute the optimal values of
+#
+#     minimize/maximize  || A*x - b ||_2^2
+#     subject to         x'*x = alpha
+#
+# via the duals.
+#
+# Lower bound:
+#
+#     maximize    -t - u*alpha
+#     subject to  [u*I, 0; 0, t] + [A, b]'*[A, b] >= 0
+#
+# Upper bound:
+#
+#     minimize    t + u*alpha
+#     subject to  [u*I, 0; 0, t] - [A, b]'*[A, b] >= 0.
+#
+# Two variables (t, u).
+
+G = matrix(0.0, ((n+1)**2, 2)) 
+G[-1, 0] = -1.0    # coefficient of t
+G[: (n+1)**2-1 : n+2, 1] = -1.0    # coefficient of u
+h = matrix( [ [ A.T * A,  b.T * A ], [ A.T * b, b.T * b ] ] ) 
+c = matrix(1.0, (2,1))
+
+nopts = 40
+alpha1 = [ 2.0/(nopts/2-1) * alpha for alpha in xrange(nopts/2) ] + \
+    [ 2.0 + (15.0 - 2.0)/(nopts/2) * alpha for alpha in 
+    xrange(1,nopts/2+1) ]
+lbnds = [ blas.nrm2(b)**2 ]
+for alpha in alpha1[1:]:  
+    c[1:] = alpha
+    lbnds += [ -blas.dot(c, solvers.sdp(c, Gs=[G], hs=[h])['x']) ]
+
+nopts = 10
+alpha2 = [ 1.0/(nopts-1) * alpha for alpha in xrange(nopts) ] 
+ubnds = [ blas.nrm2(b)**2 ]
+for alpha in alpha2[1:]:  
+    c[1:] = alpha
+    ubnds += [ blas.dot(c, solvers.sdp(c, Gs=[G], hs=[-h])['x']) ]
+
+pylab.figure(1, facecolor='w')
+pylab.plot(lbnds, alpha1, '-', ubnds, alpha2, '-')
+kmax = max([ k for k in xrange(len(alpha1)) if alpha1[k] < 
+    blas.nrm2(xls)**2 ])
+pylab.plot( [ blas.nrm2(b)**2 ] + lbnds[:kmax] + 
+    [ blas.nrm2(A*xls-b)**2 ], [0.0] + alpha1[:kmax] + 
+    [ blas.nrm2(xls)**2 ], '-', linewidth=2)
+pylab.plot([ blas.nrm2(b)**2, blas.nrm2(A*xls-b)**2 ], 
+    [0.0, blas.nrm2(xls)**2], 'o')
+pylab.fill(lbnds[-1::-1] + ubnds + [ubnds[-1]], 
+    alpha1[-1::-1] + alpha2+ [alpha1[-1]], '#D0D0D0')
+pylab.axis([0, 15, -1.0, 15])
+pylab.xlabel('||A*x-b||_2^2')
+pylab.ylabel('||x||_2^2')
+pylab.grid()
+pylab.title('Regularized least-squares (fig. 4.11)')
+pylab.show()
diff --git a/examples/book/chap4/rls.pic b/examples/book/chap4/rls.pic
new file mode 100644
index 0000000..c84e402
--- /dev/null
+++ b/examples/book/chap4/rls.pic
@@ -0,0 +1,1125 @@
+(dp0
+S'A'
+p1
+ccvxopt.base
+matrix
+p2
+((lp3
+F-0.047121492889140526
+aF-0.18144060807472698
+aF0.013653087886340971
+aF0.031338060875565184
+aF-0.12489097623978924
+aF0.12973250054160473
+aF0.12954172641598308
+aF-0.0040995849133497603
+aF0.035653627548439031
+aF0.019024333249689017
+aF-0.020339118395864945
+aF0.079064069126614622
+aF-0.064088324013841361
+aF0.23782557495695772
+aF-0.014858299759211343
+aF0.012411119529011944
+aF0.11620850643937246
+aF0.006457832089142761
+aF-0.010419469033861289
+aF-0.090672075692189394
+aF0.032071673010384889
+aF-0.14555711014719719
+aF0.07781501960401431
+aF0.17686290293608883
+aF-0.075358658263208797
+aF0.093465957100732716
+aF0.13660477573812255
+aF-0.17361309774242523
+aF-0.15697161077767993
+aF0.062218025991932782
+aF-0.043561577143116731
+aF0.075164936108880781
+aF0.088849899162438697
+aF0.077551807520013061
+aF0.14055349171253498
+aF0.072834065866027101
+aF0.129724069901409
+aF-0.13098979129424682
+aF-0.0021557775409096467
+aF-0.017072015304311697
+aF-0.17474122810953441
+aF0.028029463658557609
+aF-0.11508698868103193
+aF0.15415858545699271
+aF-0.087702607205726243
+aF0.057598675082274363
+aF0.023891720366797896
+aF-0.10042744966489837
+aF-0.23646265258303609
+aF-0.0064476318414473039
+aF-0.1100934882911646
+aF0.066936596360841566
+aF0.055310795442402944
+aF0.18436502454233675
+aF0.064411430316731702
+aF-0.070110110574056847
+aF0.041432078209956348
+aF-0.10992810496200837
+aF-0.0021253968215440878
+aF-0.0052529366981838637
+aF4.7051077752639194e-06
+aF-0.034626052495573517
+aF0.1192843465666204
+aF-0.20414332429808865
+aF0.046644189537202396
+aF0.097566470336184194
+aF0.07962691394933645
+aF0.062948950331545558
+aF0.0043916132417927533
+aF0.073758781316401206
+aF0.061973203227714539
+aF-0.027848760032708052
+aF-0.04111962006497568
+aF-0.032232493208965825
+aF-0.16069393135009905
+aF-0.025491255353614174
+aF0.012902800686174306
+aF0.034293755997786383
+aF0.15724872125227904
+aF-0.038233469749768739
+aF0.067892044618562922
+aF0.087044444611906774
+aF0.10249594389065429
+aF-0.10807361675269353
+aF0.023098071430485846
+aF0.025913708435641641
+aF-0.10978081024929962
+aF-0.080834722518353636
+aF0.11789991367740858
+aF-0.014324933864518793
+aF0.042471671834554331
+aF0.0095848846381839225
+aF-0.069224470658927173
+aF-0.060957176075504237
+aF0.048329439181683309
+aF-0.10347786943300687
+aF0.085098101072843255
+aF0.061979787322346581
+aF-0.089513532125449186
+aF-0.028933910070392262
+aF-0.12939061325337353
+aF-0.23991003719032941
+aF0.10744676662947422
+aF-0.056497565080437621
+aF0.035661819759381631
+aF0.025497025122240103
+aF0.0023384160791418435
+aF-0.10936479526342273
+aF-0.10317745541269685
+aF-0.040788483438399976
+aF-0.12918463846813083
+aF-0.11502489517503948
+aF0.16040475533374124
+aF0.0060724601390490197
+aF-0.13260860386657536
+aF-0.0044910821108667892
+aF-0.1229162566211242
+aF-0.14698368997736475
+aF-0.028443132558503413
+aF0.10386585781600347
+aF0.014013894413311603
+aF0.071512357138380681
+aF-0.1272165243778198
+aF-0.050176073301293853
+aF-0.028588923652406405
+aF-0.13215484719392676
+aF-0.143733007094201
+aF0.10144227718402329
+aF0.0012249639611970841
+aF-0.070279026763985675
+aF0.087772150168862265
+aF0.025232203658383471
+aF-0.10781957313251977
+aF0.14592790810398251
+aF0.031536934346781835
+aF0.16110598402803841
+aF0.12397120035282824
+aF-0.07452670817303754
+aF-0.14073718789332237
+aF-0.0079442315158470417
+aF-0.036013823484595628
+aF-0.091900664917866998
+aF0.054224590318273258
+aF0.16214886479654383
+aF-0.059530408630335957
+aF-0.092241688955862169
+aF-0.026834695396231682
+aF0.072226604526381688
+aF-0.09305208013744444
+aF-0.13086535478608774
+aF-0.013057988655794779
+aF-0.0071128103212818256
+aF0.052865722032410432
+aF-0.064869863626206767
+aF-0.016304071293831084
+aF-0.047359746993677239
+aF-0.0086418461244810851
+aF0.16723197232862141
+aF-0.066067273571916107
+aF-0.14677509349552206
+aF0.051132299150553714
+aF-0.098430159196267006
+aF0.0039085521896310704
+aF-0.068360178940379573
+aF0.058323632023784482
+aF0.060228423673130756
+aF-0.022189043650150651
+aF-0.22378807347929303
+aF0.014440517111852723
+aF0.17352716181453826
+aF0.11094079448199717
+aF-0.17216131120280773
+aF-0.0085690443950981032
+aF-0.074256361186558609
+aF-0.11160979424013918
+aF-0.13446442494947738
+aF0.031461222727192907
+aF-0.046766167605753001
+aF0.006078708475653909
+aF-0.040074345386600665
+aF-0.05065192228046999
+aF0.040410629917476265
+aF0.079335577156967305
+aF0.23008838853301072
+aF-0.14785737130078022
+aF-0.11139814279937914
+aF0.11305657675264319
+aF-0.04246285449537273
+aF-0.15046831491058235
+aF0.034373669633165738
+aF0.16920264130784787
+aF0.077114494202908709
+aF0.21322791258756341
+aF0.054962373945926908
+aF0.20311266344110002
+aF-0.037017431437695113
+aF-0.12416198814588042
+aF-0.022998758696266174
+aF0.12965945635232845
+aF-0.12159431752427582
+aF0.069203654170072057
+aF-0.065514892742524575
+aF0.06004336410791386
+aF-0.11981123472051891
+aF0.0093673942549961069
+aF-0.21836731464692877
+aF-0.053714583772163024
+aF0.050333248387719944
+aF-0.034968679644933755
+aF0.13470431896234991
+aF-0.068768515289858168
+aF-0.25329711699930729
+aF-0.13416845429946414
+aF0.11499716731057563
+aF-0.012334067098716265
+aF0.041310764915469943
+aF0.10285649577612264
+aF-0.23098890258340468
+aF-0.070228164947500171
+aF-0.076723182292484052
+aF-0.11091088392794095
+aF-0.019835107338657735
+aF0.16569173593403685
+aF-0.0041873307557215873
+aF0.13371217478733299
+aF-0.075841142552102808
+aF0.00081968072468956946
+aF-0.085284535497225145
+aF0.063938213204799282
+aF-0.0273653015663179
+aF0.052303645971496691
+aF0.072785538409090356
+aF-0.0085319276901602136
+aF0.096862111986689495
+aF0.25156247329468068
+aF0.057151569335613946
+aF-0.0012840533648383926
+aF0.099473090284227142
+aF0.0060939036930459014
+aF-0.12059877453397955
+aF0.052887743415860555
+aF-0.00054522823192128592
+aF-0.030089821336726406
+aF0.13905048343871038
+aF0.20298974027402311
+aF-0.056925052061492877
+aF0.01126655292117313
+aF-0.087981342365869075
+aF0.074123648135745263
+aF-0.25758684186969244
+aF0.10785826692162294
+aF0.023845798578945508
+aF0.028504227406500666
+aF0.13218670270320201
+aF-0.029920876835725915
+aF-0.014503015294160303
+aF-0.13840207228874429
+aF-0.18122514256394176
+aF-0.076641756908064698
+aF0.030597745331824355
+aF-0.058956694838592179
+aF-0.1452683092198872
+aF0.11685319054521937
+aF-0.077571103085402243
+aF-0.0012293937905002597
+aF-8.9003160703675995e-05
+aF-0.027172367706111301
+aF0.043200973733066972
+aF-0.028760322372627802
+aF-0.18126919854557264
+aF-0.11209150985942504
+aF0.026481546539927601
+aF-0.13688677454289985
+aF-0.037820437007946864
+aF-0.10254847813891957
+aF-0.12795084682853158
+aF-0.11123817623942317
+aF-0.04375560765388805
+aF0.018918287729728357
+aF-0.012649380192028931
+aF0.11591993055331405
+aF-0.026731181846773856
+aF-0.1653132836256232
+aF0.0010603916403064677
+aF0.0077750104820258651
+aF0.034481861908635551
+aF0.054448561286509302
+aF0.13922822991158412
+aF-0.059676409138558852
+aF0.028411190151574905
+aF-0.0014354021257452765
+aF-0.063211119633508089
+aF0.23271898099751898
+aF-0.028063547380331507
+aF-0.15354713309711385
+aF0.19282612550218259
+aF0.035463385826031861
+aF-0.12190269293450637
+aF0.067577907184326144
+aF0.13832381804641797
+aF-0.097610483953971053
+aF0.014725351182560374
+aF-0.015146338004887164
+aF-0.12673458775376073
+aF0.12894861162379193
+aF-0.0016808318167076777
+aF0.058413039472488555
+aF-0.078044226896787625
+aF-0.071413430514105217
+aF0.034245140430225592
+aF0.011635802509755055
+aF0.20133562660191837
+aF-0.029968665465767808
+aF0.2410248095114626
+aF0.164331410680021
+aF-0.2118873402834307
+aF-0.18307010286194636
+aF-0.062478000756624734
+aF-0.020241942801833085
+aF0.00097323882365007953
+aF0.091173223707965781
+aF-0.078680631082447258
+aF-0.07859564042940495
+aF-0.021915673178974578
+aF-0.0022292655246742323
+aF0.030380911247260761
+aF0.11528545606273045
+aF0.067722043900426313
+aF-0.19070345915690118
+aF0.0759656283006334
+aF0.088399297212447978
+aF0.069320303280407711
+aF0.14271373872014315
+aF0.035632402034600837
+aF-0.073312580542513731
+aF-0.016267006740299402
+aF-0.26678400460112717
+aF0.051557417564956375
+aF0.012739487327996155
+aF-0.064391958352890494
+aF-0.071320648914749735
+aF-0.11772201154673698
+aF-0.00519956679273489
+aF0.041323936760450208
+aF-0.035987915002732372
+aF-0.05445646816548369
+aF-0.0039193334123252621
+aF-0.019037534918053985
+aF-0.10427977126792852
+aF0.1408038403997238
+aF0.048030537959775722
+aF0.13953943528531315
+aF-0.054220248277118056
+aF-0.12186751367406615
+aF0.08798139558526144
+aF0.0044880803988166882
+aF-0.082377663368142451
+aF-0.0097092930183985734
+aF-0.21883431946095702
+aF0.11807672458987292
+aF-0.10688609639962256
+aF-0.075000581577427367
+aF0.1459163371476368
+aF-0.099048498563631557
+aF-0.044974699755641584
+aF-0.055138939455148785
+aF0.17644739554527483
+aF0.0088129274186113399
+aF-0.11776500158360284
+aF-0.12249946516810253
+aF0.189076083528436
+aF0.21105725441858653
+aF0.17811632703103841
+aF-0.13681597314575153
+aF-0.023261730525026118
+aF-0.021670683441533216
+aF0.033497454991407542
+aF-0.062346333333855579
+aF-0.10650022689755148
+aF-0.048673229346148268
+aF0.11787779415825507
+aF0.25846465199197088
+aF0.024977548823577698
+aF-0.02904461916020331
+aF0.076436731823846332
+aF-0.053115721056811678
+aF0.20288942325829168
+aF0.12057494122875574
+aF-0.13372500006643015
+aF-0.072974004377627202
+aF0.14607428983794427
+aF0.042275896557660717
+aF0.042817915428542047
+aF-0.18598856149033577
+aF0.024821805241696551
+aF0.074689486917569617
+aF-0.069368797409821409
+aF-0.10921894068898159
+aF-0.020220607376157947
+aF-0.11482116372717897
+aF-0.007793161691459943
+aF0.030414508987519139
+aF0.14959789275756513
+aF0.019591001610441611
+aF-0.059044630151178341
+aF0.1780207214689784
+aF0.089894898655458591
+aF0.025137989117187506
+aF0.073164513996255509
+aF-0.055347516929667565
+aF0.093286750630726833
+aF0.029249451733341019
+aF0.068081736044857913
+aF-0.11409186755203307
+aF0.16728841327795888
+aF0.047324213097212589
+aF-0.20884339422840931
+aF0.051192911141795451
+aF0.13882157365397593
+aF0.069559688550145576
+aF0.15041568317065221
+aF0.14377721924748746
+aF-0.099068768787591702
+aF-0.25116132699664229
+aF0.19485551588175759
+aF0.042571600028842756
+aF0.0022139618067442235
+aF-0.044225147227447005
+aF-0.16720389786495465
+aF0.02411530200928385
+aF-0.14972897564654417
+aF-0.091427656893414269
+aF-0.022728499012089131
+aF0.08234546141490133
+aF0.040930671806609718
+aF-0.14656270183041825
+aF0.16142834351606136
+aF0.0035661145637065753
+aF0.20375797374688584
+aF-0.13170150892157881
+aF-0.085256084203139335
+aF-0.083585744805455955
+aF-0.011677854602788697
+aF-0.10643577053217325
+aF-0.10501214608766023
+aF-0.25917538854437566
+aF-0.091308087961901305
+aF0.028033973606397342
+aF-0.020025975991481974
+aF-0.018259189784959537
+aF-0.012744198980566546
+aF0.018354276792395773
+aF-0.054598960199194871
+aF-0.076807573784959879
+aF0.055356972886135496
+aF-0.045853131429437137
+aF0.024960667800576597
+aF-0.10452290870943119
+aF-0.015909164589905343
+aF0.081106327692884408
+aF-0.097006278322856201
+aF0.01514871808610499
+aF-0.025724403656486667
+aF-0.0082201480966062387
+aF-0.039061068740104107
+aF-0.22632736979755652
+aF-0.015637166926041612
+aF0.15178379898882005
+aF0.07100434675126939
+aF-0.041083083472510461
+aF-0.072054368716034142
+aF0.027120263119125541
+aF-0.041778372612671755
+aF-0.05757000259232347
+aF0.0060337372424810456
+aF0.13657941014069577
+aF-0.27451685946657306
+aF0.063711362510221234
+aF-0.10981360250779883
+aF0.10286576591665671
+aF-0.26405402335554562
+aF-0.024383100024041291
+aF0.0063258487363441309
+aF-0.046255372045695138
+aF-0.022104887553545578
+aF-0.16482719862185519
+aF-0.12269925753297119
+aF-0.088782345111137737
+aF0.039937163732216334
+aF-0.063847600902896387
+aF0.16747781270608153
+aF0.01525870657873942
+aF-0.20292068115794726
+aF-0.049477572422454284
+aF-0.071033760708656801
+aF0.011254943705492577
+aF-0.024034528767243057
+aF-0.030397618260174054
+aF-0.079921547960864217
+aF-0.0070299722908437317
+aF-0.15730273362219824
+aF0.066705353642745754
+aF-0.14417593327352196
+aF-0.072068924309443019
+aF-0.015916998855392411
+aF0.027025160816212056
+aF-0.008347975635986004
+aF0.18934772710557662
+aF0.17668967818305148
+aF0.06824085979940521
+aF0.010001723033531109
+aF-0.087976757898622901
+aF-0.050255804506895166
+aF-0.15315940091384242
+aF-0.040799424630402037
+aF-0.051298764678507455
+aF0.19077757184164942
+aF0.082052602319217419
+aF0.0070796206965107328
+aF-0.031892305071236172
+aF0.0090223155036073463
+aF0.083465148875494208
+aF0.24367147492332181
+aF0.035609439521581
+aF0.09404410509610385
+aF0.074009050366022316
+aF0.060432579873736771
+aF0.10911271513564805
+aF0.13718907384598433
+aF0.0048096008945879816
+aF-0.03422062038389511
+aF0.024696420519342288
+aF0.10857473973271953
+aF0.13245547001126098
+aF-0.059119344311806966
+aF0.099373689674528462
+aF-0.018752212216090598
+aF-0.036597253474640323
+aF0.058986918507246473
+aF0.10153963232292151
+aF-0.062120531673706021
+aF-0.16325073330027248
+aF-0.0054844079856175018
+aF0.06024381144998503
+aF0.0090958510001425911
+aF0.17184768846501866
+aF-0.036032922346402055
+aF0.086620274611331857
+aF-0.085492286299660727
+aF-0.13759827102485228
+aF0.072622130481076311
+aF-0.15170653459972169
+aF-0.14167690782769218
+aF-0.065908152043950979
+aF-0.16215692964682762
+aF0.060844935422510842
+aF-0.030213618687332022
+aF-0.14092768433196676
+aF-0.096781779206510751
+aF-0.10746666746651859
+aF-0.0078016755711929715
+aF-0.26303371546111293
+aF-0.075638981993101567
+aF-0.15157110718952155
+aF0.035910217419041844
+aF0.065202505395937485
+aF0.016032567345209772
+aF-0.011050267039152576
+aF-0.28704191305119819
+aF0.0030560015917348747
+aF-0.095460935057567309
+aF-0.028919813495361529
+aF-0.035684733847812442
+aF-0.12617381081517315
+aF0.06318815704056259
+aF0.026117815167530572
+aF-0.038223685204595535
+aF0.097180841418793421
+aF0.17193214840177426
+aF-0.12071904300093587
+aF-0.00282480130863415
+aF-0.12098634611228755
+aF0.081792199509522989
+aF0.054485747848417435
+aF-0.056347868466662218
+aF-0.060917544136144149
+aF-0.08206850721072427
+aF0.10085350234227369
+aF-0.027072586888005842
+aF-0.016322238773978457
+aF-0.13708561051422924
+aF0.034055278801554907
+aF0.29306559879887312
+aF0.031558095816077221
+aF-0.15499319401696574
+aF0.026883627672430774
+aF-0.15640606864830528
+aF0.016184829110890087
+aF-0.18443503698625646
+aF0.078344872239879043
+aF0.12437914246514728
+aF0.16906034015175589
+aF0.15072589090650571
+aF-0.082582858851427673
+aF0.048221511951321405
+aF0.099250544970391236
+aF-0.11700562881270533
+aF0.021978954654336528
+aF0.083102584830475612
+aF-0.14032880679491039
+aF-0.10381099582364391
+aF0.084770520429373691
+aF-0.00068967572326516569
+aF0.057135025339246769
+aF0.14861709041888826
+aF0.052511004775865427
+aF-0.085739099970632227
+aF0.081919118538924598
+aF-0.018179951896739256
+aF-0.088915894410867849
+aF0.22811720996929766
+aF0.008731424476144202
+aF-0.10210433619592615
+aF0.069254270332745421
+aF0.18323189512109797
+aF0.064667600514845033
+aF0.086075386003257939
+aF0.011465838775142515
+aF-0.017274772159821834
+aF0.094872394093905785
+aF-0.021216084178903347
+aF0.0082218209454432371
+aF-0.057369021790076642
+aF-0.074673312534012187
+aF-0.029236836531086646
+aF-0.12945259166809472
+aF0.027078977095147207
+aF0.011160577614654736
+aF-0.004467088424104604
+aF-0.24484061389055975
+aF-0.055641488757311945
+aF0.027151273139604592
+aF0.04021848262191545
+aF0.019520802558325334
+aF-0.0040614724075353735
+aF-0.17465672758504019
+aF0.036969528476953034
+aF-0.014285184711580721
+aF0.052854200678004122
+aF0.065224969749770476
+aF-0.0093717836003376891
+aF0.03543572304234175
+aF-0.03650886269521731
+aF-0.03512603766345572
+aF-0.04165396523517316
+aF-0.10385556206650205
+aF0.025444582246111947
+aF0.13456150491767382
+aF-0.063022400198104289
+aF-0.054635025640397558
+aF0.078745212584835772
+aF0.004302771621922408
+aF0.16789936321638935
+aF-0.1853043687096679
+aF-0.11261071723849231
+aF-0.083194571109282078
+aF0.2370891893945862
+aF0.047017709151465102
+aF-0.04834160633984682
+aF0.003267603037140058
+aF-0.034387639133045184
+aF0.10652172390375617
+aF0.0019929539991309139
+aF0.089104866662205948
+aF0.076509601069335187
+aF-0.025193483058833576
+aF-0.01238478627198507
+aF0.013937213747456701
+aF-0.087083779066319394
+aF-0.025993218355501287
+aF-0.0097456871140634751
+aF-0.11146938927188198
+aF0.10213079153096691
+aF-0.12328395822386423
+aF-0.077420405915042137
+aF-0.1273996984528642
+aF0.11606350652495633
+aF-0.074118763497391382
+aF-0.18799722449492529
+aF0.088585983261250945
+aF0.15706989054637469
+aF0.073234042505101585
+aF0.015105481392371061
+aF-0.09363341801796965
+aF-0.08194649306358677
+aF0.13394824748765219
+aF0.12535754555504958
+aF-0.066235268060271815
+aF0.087818896732836729
+aF0.023653389946325647
+aF-0.040683020672773434
+aF-0.090637322238969392
+aF0.031249810436904411
+aF-0.1981411488444646
+aF-0.17136051864498461
+aF0.21957675131751392
+aF-0.007841369294604543
+aF0.28638052178590517
+aF-0.026505757237590941
+aF0.018875892987523662
+aF0.10056965927981314
+aF-0.019450689550622312
+aF-0.056831978473320478
+aF0.15599092702035544
+aF-0.094786334837419176
+aF0.087969649391793997
+aF-0.055626038278359935
+aF0.080994789724214603
+aF0.092365890345922824
+aF-0.090405321274879213
+aF0.058061804263721102
+aF0.11251344969759916
+aF-0.11460234047431879
+aF0.039446897887691255
+aF-0.0040073539490906064
+aF-0.13373260957475469
+aF-0.029967924537691308
+aF-0.017477029773429138
+aF-0.11803933598894803
+aF-0.21288236983954736
+aF-0.099075089325871932
+aF-0.00060771927913954899
+aF-0.18774855079991873
+aF0.13759345245432611
+aF-0.065408272257620442
+aF-0.22483386511406242
+aF0.012082094842997404
+aF0.16205341435466533
+aF0.0057737938332414196
+aF0.017645389232648179
+aF-0.0029279488857894358
+aF0.018908540531605893
+aF0.096099036437980942
+aF0.019858261505830404
+aF0.082278185661047012
+aF0.05534279702140401
+aF0.014366377125894229
+aF0.030513169913774653
+aF-0.10706660103823593
+aF-0.10284426286600654
+aF-0.0014224218474195866
+aF0.038600639614610167
+aF-0.097465199369841007
+aF0.088467398894731819
+aF0.011932462914636116
+aF0.29757192091411333
+aF0.044780950612495159
+aF-0.14236314497595079
+aF0.041810000501406826
+aF0.054413485350940212
+aF-0.055642481230219518
+aF0.025591257844392486
+aF-0.065124141234068358
+aF0.0022626712863536478
+aF0.045692040637950036
+aF0.12975301114626756
+aF0.08401230427747082
+aF-0.28804859100671387
+aF0.031093335721601369
+aF0.089990485664747127
+aF-0.00088482457201784605
+aF0.093514050802549806
+aF0.084401637789930123
+aF0.14226329038712243
+aF0.13415385696408311
+aF0.10442123304903894
+aF-0.18023832538139095
+aF-0.10788889283528291
+aF0.074646257621031137
+aF-0.1061975667014108
+aF-0.066093720530668296
+aF0.074815947893808299
+aF0.0021840242439781594
+aF0.11588522422991687
+aF-0.14608740639825177
+aF0.052235519677218498
+aF-0.17799712748374791
+aF-0.15715686453250796
+aF0.032003109827795924
+aF-0.015290576115307311
+aF-0.12313378708968675
+aF-0.031867663311352976
+aF-0.063458606261120945
+aF-0.09764379306223156
+aF0.027081384859451677
+aF-0.16227663700789621
+aF0.034152098847243434
+aF-0.22060278072985975
+aF0.057625548703312407
+aF0.037416038262748898
+aF0.082593791066940689
+aF-0.075376576199407574
+aF0.074095321559523336
+aF-0.11683736900745113
+aF0.098016766072835285
+aF-0.23127929226245159
+aF0.031015161333826851
+aF-0.079884609929352771
+aF-0.084247754874148192
+aF0.016540893941334234
+aF-0.036694041244855015
+aF0.10574992010134951
+aF-0.011681803786322513
+aF0.11040484364061344
+aF-0.051781948715113942
+aF0.0075108733765325382
+aF0.043420668516944733
+aF0.1216071149484908
+aF0.067588908146396121
+aF-0.031337849919446673
+aF-0.14943427090853711
+aF-0.074715149074777568
+aF0.036132111294399409
+aF-0.10868693012735398
+aF0.031745660829168645
+aF0.12059970080144922
+aF0.026684591378337098
+aF0.017971653563712095
+aF0.044252853113847315
+aF0.13246303973315673
+aF0.15778425671071256
+aF-0.11167345813968702
+aF0.022377232847357344
+aF0.064149942323049713
+aF-0.028761441031593438
+aF0.27182770513610582
+aF0.093242748409891343
+aF-0.092698722904248618
+aF0.0884421064747095
+aF0.076280904353520515
+aF0.082783960858972813
+aF-0.18659594209756156
+aF0.16743556929369902
+aF-0.17536882991248864
+aF0.1208663294991984
+aF-0.12088572408209365
+aF0.04199114858719967
+aF0.10514751722115181
+aF0.089141293760822415
+aF0.0040359125975843197
+aF-0.10087525746777923
+aF-0.012191871410870258
+aF-0.08747812321495145
+aF-0.18137759635861819
+aF-0.098194168883553548
+aF0.064091932843957547
+aF0.060367398507673149
+aF-0.045226871133904056
+aF0.0067316294046476498
+aF0.049830355875853154
+aF0.021679601060003162
+aF0.02805708827761523
+aF0.22666451320399861
+aF-0.24807099638694616
+aF0.036931443851006322
+aF0.031579621227516771
+aF0.072143454900635132
+aF-0.06327607031837619
+aF0.096707346505539651
+aF0.018722789931641753
+aF0.092466452429488505
+aF0.10498828036095313
+aF0.14400327494914161
+aF-0.0070094187551511533
+aF0.14347331532442872
+aF0.024839091586394583
+aF-0.15573767433949129
+aF-0.016307693677312111
+aF-0.055008693850193489
+aF-0.18836420747296501
+aF-0.045477380151625252
+aF-0.066991660350122981
+aF0.078517882628457034
+aF0.036968630226676728
+aF0.096172821362334002
+aF0.03096428173460071
+aF-0.015854561720605394
+aF-0.0097655854800728237
+aF0.03149976947477498
+aF0.12689096969094771
+aF0.087772210782490659
+aF-0.14767716163243502
+aF0.013169480327563
+aF-0.024202974260102598
+aF0.06228172216203063
+aF-0.032695829164779429
+aF0.12356256463592434
+aF-0.019538209050082016
+aF-0.15981506431457013
+aF0.15200213438740301
+aF0.048022479997309978
+aF0.061590170091398132
+aF-0.075559849635879653
+aF0.090837633315973457
+aF-0.24372904871434006
+aF0.11957197391032559
+aF-0.00017613890291797655
+aF-0.17588371118407306
+aF-0.13385148185046231
+aF0.022593639626333196
+aF0.024068339945346
+aF-0.1095966739401696
+aF-0.049354910650388516
+aF0.15244958751340484
+aF-0.050324094602053074
+aF0.0035639104883209423
+aF0.087015531333936844
+aF0.097694721319296643
+aF0.015021249497558165
+aF-0.17638188646122324
+aF-0.17937316676669177
+aF0.046701228497931131
+aF-0.080310317967462699
+aF0.061540288116242736
+aF-0.15078434188818388
+aF0.050139341325869051
+aF0.068561973420778036
+aF0.041378706770063077
+aF-0.11038719362728393
+aF-0.037826928719204171
+aF0.048139762705270837
+aF-0.17323299225540204
+aF-0.07640890212034912
+aF-0.1173885387007613
+aF0.10917690534684521
+aF0.18840114013527673
+aF0.077238497404089029
+aF-0.081472222807072517
+aF0.024931147936774797
+aF-0.024346627056021936
+aF-0.092951629686625431
+aF0.037650891797097068
+aF0.01195720516792574
+aF-0.12342771664204136
+aF-0.074416134441641676
+aF-0.030268297223749529
+aF0.071329601029644571
+aF-0.13599393575199947
+aF-0.065092976687179921
+aF-0.052486300166637155
+aF0.10712374986977127
+aF0.19195679963661544
+aF0.15549414879972454
+aF0.099323001153812235
+aF0.035602459829127055
+aF0.0075839028778393837
+aF-0.16337680091885587
+aF-0.04555918692992033
+aF-0.0022916457452067125
+aF0.024883450017052007
+aF-0.10982791358719954
+aF-0.07240068492889018
+aF0.060805023761267278
+aF-0.12947395321345848
+aF-0.084477157965542365
+aF0.029525996633624037
+aF0.16721273307434836
+aF-0.11463052433105551
+aF0.068145288251539038
+aF-0.086889479441911055
+aF-0.034153550859299407
+aF-0.065601782333039163
+aF0.13715586768769539
+aF0.0935190718890163
+aF-0.22934019038356929
+aF-0.03931872946836952
+aF0.060301759526809898
+aF-0.16954483645838328
+aF-0.022513152030377195
+aF-0.04635924501556437
+aF0.053789784671182859
+aF-0.094872411493646253
+aF0.0086960342054503703
+aF-0.056822635373481714
+aF-0.15401908223176772
+aF-0.041863017871182261
+aF-0.049883804319587707
+aF-0.031751389755047807
+aF-0.032813869340476386
+aF-0.17305363128762391
+aF0.1192062316993875
+aF0.14424825493758009
+aF-0.013778071229778749
+aF-0.080303017172008759
+aF0.023281483842316576
+aF-0.043631683044651148
+aF0.0070740001985779575
+aF-0.19150743327754091
+aF0.18374607203251675
+aF0.035665375877475605
+a(I100
+I10
+tp4
+S'd'
+p5
+tp6
+Rp7
+sS'b'
+p8
+g2
+((lp9
+F-0.16143195583510889
+aF-0.67768343369526307
+aF0.16084359462457573
+aF0.10428881011413052
+aF-0.2655660443561319
+aF0.35919523061889325
+aF0.16074025143663787
+aF-0.11421264589574148
+aF0.098575589230285338
+aF-0.021461162957776336
+aF1.2870291537691783
+aF0.22335913212959874
+aF-0.18518011941716028
+aF0.72719403274095085
+aF-0.054520392271940908
+aF0.055706624603291927
+aF0.37152784451573234
+aF-0.0026790126321343567
+aF-0.065305446670940251
+aF-0.28319748376470066
+aF0.12179419200875374
+aF-0.46190759357216132
+aF0.24532948045493169
+aF0.57741574009209129
+aF-0.20038800518743327
+aF0.28434957039940145
+aF0.41205424755274606
+aF-0.52413630165258562
+aF-0.43005085334118509
+aF0.21446375085140315
+aF-0.10612113952760373
+aF0.25388213127924197
+aF0.25844013670185351
+aF0.2311036000053617
+aF0.4426226427094434
+aF0.25002892502222307
+aF0.41806883402445871
+aF-0.41824718377434011
+aF-0.049830631694555358
+aF-0.090913971598374915
+aF-0.52843704660670243
+aF0.091982740793313131
+aF-0.34299336373036504
+aF0.51841960641550788
+aF-0.24989594994933934
+aF0.15668483679512873
+aF0.086065466792963577
+aF-0.30200799730645128
+aF-0.69916629701899902
+aF-0.035171689140503309
+aF-0.34615218824469418
+aF0.18552621575276762
+aF0.1765564681877021
+aF0.56172664224590207
+aF0.16514178827701431
+aF-0.26105954348224142
+aF0.13476505078644202
+aF-0.27374501099003851
+aF-0.017102093695764001
+aF-0.068996860348989178
+aF0.051640117356078631
+aF-0.12095289663013524
+aF0.40856213778679173
+aF-0.67228595777644418
+aF0.1363984331429296
+aF0.31097275492788917
+aF0.26695864898146232
+aF0.18710267994878738
+aF-0.0029622200880384877
+aF0.25177200926602317
+aF0.18701557903892782
+aF-0.10280763300825679
+aF-0.15555116047213355
+aF-0.089792732233990868
+aF-0.48911861854845107
+aF-0.12748333832274483
+aF0.071923350466736591
+aF0.11594797486324034
+aF0.48429640311993932
+aF-0.13201718008527658
+aF0.23117313315298862
+aF0.2262593150867224
+aF0.33708782380681585
+aF-0.32833055771415132
+aF0.054518808290491542
+aF0.063110698981614963
+aF-0.28119470239217825
+aF-0.24684768490375322
+aF0.30522250706068588
+aF0.008667421388934643
+aF0.15682379142847355
+aF0.037458202825196588
+aF-0.14092181857921926
+aF-0.17069068456403164
+aF0.14970644989506304
+aF-0.2752575961425312
+aF0.28359094471774626
+aF0.20607585138147697
+aF-0.24478992166892741
+aF-0.081555771076436148
+a(I100
+I1
+tp10
+g5
+tp11
+Rp12
+s.
\ No newline at end of file
diff --git a/examples/book/chap6/basispursuit b/examples/book/chap6/basispursuit
new file mode 100755
index 0000000..ee686ae
--- /dev/null
+++ b/examples/book/chap6/basispursuit
@@ -0,0 +1,249 @@
+#!/usr/bin/python
+
+# Figures 6.21-23, pages 335-337.
+# Basis pursuit.
+
+from cvxopt.base import matrix, mul, div, cos, sin, exp, sqrt
+from cvxopt import blas, lapack, solvers
+import pylab
+
+# Basis functions are Gabor pulses:  for k = 0,...,K-1,
+#
+#     exp(-(t - k * tau)^2/sigma^2 ) * cos (l*omega0*t),  l = 0,...,L
+#     exp(-(t - k * tau)^2/sigma^2 ) * sin (l*omega0*t),  l = 1,...,L
+
+sigma = 0.05 
+tau = 0.002    
+omega0 = 5.0
+K = 501
+L = 30  
+N = 501       # number of samples of each signal in [0,1] 
+
+# Build dictionary matrix
+ts = (1.0/N) * matrix(range(N), tc='d')
+B = ts[:, K*[0]] - tau * matrix(range(K), (1,K), 'd')[N*[0],:]
+B = exp(-(B/sigma)**2)
+A = matrix(0.0, (N, K*(2*L+1)))
+
+# First K columns are DC pulses for k = 0,...,K-1
+A[:,:K] = B
+for l in xrange(L):
+
+    # Cosine pulses for omega = (l+1)*omega0 and k = 0,...,K-1.
+    A[:, K+l*(2*K) : K+l*(2*K)+K] = \
+        mul(B, cos((l+1)*omega0*ts)[:, K*[0]])
+
+    # Sine pulses for omega = (l+1)*omega0 and k = 0,...,K-1.
+    A[:, K+l*(2*K)+K : K+(l+1)*(2*K)] = \
+        mul(B, sin((l+1)*omega0*ts)[:,K*[0]])
+
+
+pylab.figure(1, facecolor='w')
+pylab.subplot(311)
+# DC pulse for k = 250 (tau = 0.5)
+pylab.plot(ts, A[:,250])
+pylab.ylabel('f(0.5, 0, c)')
+pylab.axis([0, 1, -1, 1])
+pylab.title('Three basis elements (fig. 6.21)')
+# Cosine pulse for k = 250 (tau = 0.5) and l = 15  (omega = 75)
+pylab.subplot(312)
+pylab.ylabel('f(0.5, 75, c)')
+pylab.plot(ts, A[:, K + 14*(2*K) + 250])
+pylab.axis([0, 1, -1, 1])
+pylab.subplot(313)
+# Cosine pulse for k = 250 (tau = 0.5) and l = 30  (omega = 150)
+pylab.plot(ts, A[:, K + 29*(2*K) + 250])
+pylab.ylabel('f(0.5, 150, c)')
+pylab.axis([0, 1, -1, 1])
+pylab.xlabel('t')
+
+# Signal.
+y = mul( 1.0 + 0.5 * sin(11*ts), sin(30 * sin(5*ts)))
+
+
+# Basis pursuit problem
+#
+#     minimize    ||A*x - y||_2^2 + ||x||_1
+#
+#     minimize    ||A*x - y||_2^2 + 1'*u
+#     subject to  -u <= x <= u
+#
+# Variables x (n),  u (n).
+
+m, n = A.size
+r = matrix(0.0, (m,1))
+gradf = matrix(1.0, (1,2*n))
+
+def F(x=None):
+    """
+    Function and gradient evaluation of
+
+	f = || A*x[:n] - y ||_2^2 +  sum(x[n:])
+    """
+
+    nvars = 2*n
+    if x is None: return 0, matrix(0.0, (nvars,1))
+    blas.copy(y, r)
+    blas.gemv(A, x, r, beta=-1.0)      # r = A*x[:n] - y
+    f = blas.nrm2(r)**2 + blas.asum(x, offset=n)
+    blas.gemv(A, r, gradf, alpha=2.0, trans='T')  #gradf = [2*A'*r; 1.0]
+    return f, +gradf
+
+
+def G(u, v, alpha=1.0, beta=0.0, trans='N'):
+    """
+	v := alpha*[I, -I; -I, -I] * u + beta * v  (trans = 'N' or 'T')
+    """
+
+    blas.scal(beta, v) 
+    blas.axpy(u, v, n=n) 
+    blas.axpy(u, v, n=n, alpha=-1.0, offsetx=n) 
+    blas.axpy(u, v, n=n, alpha=-1.0, offsety=n) 
+    blas.axpy(u, v, n=n, alpha=-1.0, offsetx=n, offsety=n) 
+
+h = matrix(0.0, (2*n,1))
+
+
+# Customized solver for the KKT system 
+#
+#     [  2.0*z[0]*A'*A  0    I      -I     ] [x[:n] ]     [bx[:n] ]
+#     [  0              0   -I      -I     ] [x[n:] ]  =  [bx[n:] ].
+#     [  I             -I   -D1^-1   0     ] [zl[:n]]     [bzl[:n]]
+#     [ -I             -I    0      -D2^-1 ] [zl[n:]]     [bzl[n:]]
+#
+#    
+# We first eliminate zl and x[n:]:
+#
+#     ( 2*z[0]*A'*A + 4*D1*D2*(D1+D2)^-1 ) * x[:n] = 
+#         bx[:n] - (D2-D1)*(D1+D2)^-1 * bx[n:] 
+#         + D1 * ( I + (D2-D1)*(D1+D2)^-1 ) * bzl[:n]
+#         - D2 * ( I - (D2-D1)*(D1+D2)^-1 ) * bzl[n:]           
+#
+#     x[n:] = (D1+D2)^-1 * ( bx[n:] - D1*bzl[:n]  - D2*bzl[n:] ) 
+#              - (D2-D1)*(D1+D2)^-1 * x[:n]         
+#
+#     zl[:n] = D1 * ( x[:n] - x[n:] - bzl[:n] )
+#     zl[n:] = D2 * (-x[:n] - x[n:] - bzl[n:] ).
+#
+#
+# The first equation has the form
+#
+#     (z[0]*A'*A + D)*x[:n]  =  rhs
+#
+# and is equivalent to
+#
+#     [ D    A'       ] [ x:n] ]  = [ rhs ]
+#     [ A   -1/z[0]*I ] [ v    ]    [ 0   ].
+#
+# It can be solved as 
+#
+#     ( A*D^-1*A' + 1/z[0]*I ) * v = A * D^-1 * rhs
+#     x[:n] = D^-1 * ( rhs - A'*v ).
+
+S = matrix(0.0, (m,m))
+Asc = matrix(0.0, (m,n))
+v = matrix(0.0, (m,1))
+
+def kktsolver(x, z, dnl, dl):
+
+    # Factor 
+    #
+    #     S = A*D^-1*A' + 1/z[0]*I 
+    #
+    # where D = 2*D1*D2*(D1+D2)^-1, D1 = dl[:n]**2, D2 = dl[n:]**2.
+
+    d1 = dl[:n]**2    # d1 = diag(D1)
+    d2 = dl[n:]**2    # d2 = diag(D2)
+    # ds is square root of diagonal of D
+    ds = sqrt(2.0) * div( mul(dl[:n], dl[n:]), sqrt(d1+d2) )
+    d3 =  div(d2 - d1, d1 + d2)
+ 
+    # Asc = A*diag(d)^-1/2
+    blas.copy(A, Asc)
+    for k in xrange(m):
+        blas.tbsv(ds, Asc, n=n, k=0, ldA=1, incx=m, offsetx=k)
+
+    # S = 1/z[0]*I + A * D^-1 * A'
+    blas.syrk(Asc, S)
+    S[::m+1] += 1.0 / z[0] 
+    lapack.potrf(S)
+
+    def g(x, y, znl, zl):
+
+        x[:n] = 0.5 * ( x[:n] - mul(d3, x[n:]) + \
+                mul(d1, zl[:n] + mul(d3, zl[:n])) - \
+                mul(d2, zl[n:] - mul(d3, zl[n:])) )
+        x[:n] = div( x[:n], ds) 
+
+        # Solve
+        #
+        #     S * v = 0.5 * A * D^-1 * ( bx[:n] 
+        #             - (D2-D1)*(D1+D2)^-1 * bx[n:] 
+        #             + D1 * ( I + (D2-D1)*(D1+D2)^-1 ) * bzl[:n]
+        #             - D2 * ( I - (D2-D1)*(D1+D2)^-1 ) * bzl[n:] )
+	    
+        blas.gemv(Asc, x, v)
+        lapack.potrs(S, v)
+	
+        # x[:n] = D^-1 * ( rhs - A'*v ).
+        blas.gemv(Asc, v, x, alpha=-1.0, beta=1.0, trans='T')
+        x[:n] = div(x[:n], ds)
+
+        # x[n:] = (D1+D2)^-1 * ( bx[n:] - D1*bzl[:n]  - D2*bzl[n:] )
+        #         - (D2-D1)*(D1+D2)^-1 * x[:n]         
+        x[n:] = div( x[n:] - mul(d1, zl[:n]) - mul(d2, zl[n:]), d1+d2 )\
+                - mul( d3, x[:n] )
+	    
+        # zl[:n] = D1 * (  x[:n] - x[n:] - bzl[:n] )
+        # zl[n:] = D2 * ( -x[:n] - x[n:] - bzl[n:] ).
+        zl[:n] = mul( d1,  x[:n] - x[n:] - zl[:n] ) 
+        zl[n:] = mul( d2, -x[:n] - x[n:] - zl[n:] ) 
+
+    return g
+
+x = solvers.nlcp(kktsolver, F, G, h)['x'][:n]
+
+I = [ k for k in xrange(n) if abs(x[k]) > 1e-2 ]
+xls = +y
+lapack.gels(A[:,I], xls)
+ybp = A[:,I]*xls[:len(I)]
+
+print "Sparse basis contains %d basis functions." %len(I)
+print "Relative RMS error = %.1e." %(blas.nrm2(ybp-y) / blas.nrm2(y))
+
+pylab.figure(2, facecolor='w')
+pylab.subplot(211)
+pylab.plot(ts, y, '-', ts, ybp, 'r--')
+pylab.xlabel('t')
+pylab.ylabel('y(t), yhat(t)')
+pylab.axis([0, 1, -1.5, 1.5])
+pylab.title('Signal and basis pursuit approximation (fig. 6.22)')
+pylab.subplot(212)
+pylab.plot(ts, y-ybp, '-')
+pylab.xlabel('t')
+pylab.ylabel('y(t)-yhat(t)')
+pylab.axis([0, 1, -0.05, 0.05])
+       
+pylab.figure(3, facecolor='w')
+pylab.subplot(211)
+pylab.plot(ts, y, '-')
+pylab.xlabel('t')
+pylab.ylabel('y(t)')
+pylab.axis([0, 1, -1.5, 1.5])
+pylab.title('Signal and time-frequency plot (fig. 6.23)')
+pylab.subplot(212)
+omegas, taus = [], []
+for i in I:
+    if i < K: 
+        omegas += [0.0]
+        taus += [i*tau]
+    else:
+        l = (i-K)/(2*K)+1
+        k = ((i-K)%(2*K)) %K
+        omegas += [l*omega0]
+        taus += [k*tau]
+pylab.plot(ts, 150*abs(cos(5.0*ts)), '-', taus, omegas, 'ro')
+pylab.xlabel('t')
+pylab.ylabel('omega(t)')
+pylab.axis([0, 1, -5, 155])
+pylab.show()
diff --git a/examples/book/chap6/consumerpref b/examples/book/chap6/consumerpref
new file mode 100755
index 0000000..fc404b4
--- /dev/null
+++ b/examples/book/chap6/consumerpref
@@ -0,0 +1,135 @@
+#!/usr/bin/python
+
+# Figures 6.25 and 6.26, page 342.
+# Consumer preference analysis.
+
+import pylab
+from cvxopt import solvers
+from cvxopt.base import matrix, sqrt
+from cvxopt.modeling import variable, op
+solvers.options['show_progress'] = 0
+
+def utility(x, y): 
+    return (1.1 * sqrt(x) + 0.8 * sqrt(y)) / 1.9
+
+B = matrix([ 
+    4.5e-01,  9.6e-01,
+    2.1e-01,  3.4e-01,
+    2.8e-01,  8.7e-01,
+    9.6e-01,  3.0e-02,
+    8.0e-02,  9.2e-01,
+    2.0e-02,  2.2e-01,
+    0.0e+00,  3.9e-01,
+    2.6e-01,  6.4e-01,
+    3.5e-01,  9.7e-01,
+    9.1e-01,  7.8e-01,
+    1.2e-01,  1.4e-01,
+    5.8e-01,  8.4e-01,
+    3.2e-01,  7.3e-01,
+    4.9e-01,  2.7e-01,
+    7.0e-02,  8.0e-01,
+    9.3e-01,  8.7e-01,
+    4.4e-01,  8.6e-01,
+    3.3e-01,  4.2e-01,
+    8.9e-01,  9.0e-01,
+    4.9e-01,  7.0e-02,
+    9.5e-01,  3.3e-01,
+    6.6e-01,  2.6e-01,
+    9.5e-01,  7.3e-01,
+    4.2e-01,  9.1e-01,
+    6.8e-01,  2.0e-01,
+    8.7e-01,  1.7e-01,
+    5.2e-01,  6.2e-01,
+    7.7e-01,  6.3e-01,
+    2.0e-02,  2.9e-01,
+    9.8e-01,  2.0e-02,
+    5.0e-02,  7.9e-01,
+    7.9e-01,  1.9e-01,
+    6.2e-01,  6.0e-02, 
+    6.9e-01,  1.0e-01,
+    6.9e-01,  3.7e-01,
+    0.0e+00,  7.2e-01,
+    6.3e-01,  4.0e-02,
+    4.0e-02,  4.6e-01,
+    3.6e-01,  9.5e-01,
+    8.2e-01,  6.7e-01 ], (2, 40)) 
+m = B.size[1]
+
+# Plot some contour lines.
+nopts = 200
+a = (1.0/nopts)*matrix(range(nopts), tc='d')
+X, Y = a[:,nopts*[0]].T,  a[:,nopts*[0]]
+pylab.figure(1, facecolor='w')
+pylab.plot(B[0,:], B[1,:], 'wo', markeredgecolor='b')
+pylab.contour(pylab.array(X), pylab.array(Y), pylab.array(utility(X,Y)),
+    [.1*(k+1) for k in xrange(9)], colors='k')
+pylab.xlabel('x1')
+pylab.ylabel('x2')
+pylab.title('Goods baskets and utility function (fig. 6.25)')
+print "Close figure to start analysis."
+pylab.show()
+
+
+# P are basket indices in order of increasing preference 
+l = zip(utility(B[0,:], B[1,:]), range(m))
+l.sort()
+P = [ e[1] for e in l ]
+
+# baskets with known preference relations 
+u = variable(m)    
+gx = variable(m)  
+gy = variable(m)  
+
+# comparison basket at (.5, .5) has utility 0
+gxc = variable(1)
+gyc = variable(1)
+
+monotonicity = [ gx >= 0, gy >= 0, gxc >= 0, gyc >= 0 ]
+preferences = [ u[P[j+1]] >= u[P[j]] + 1.0 for j in xrange(m-1) ]
+concavity = [ u[j] <= u[i] + gx[i] * ( B[0,j] - B[0,i] ) + 
+    gy[i] * ( B[1,j] - B[1,i] ) for i in xrange(m) for j in 
+    xrange(m) ] 
+concavity += [ 0 <= u[i] + gx[i] * ( 0.5 - B[0,i] ) + 
+    gy[i] * ( 0.5 - B[1,i] ) for i in xrange(m) ]  
+concavity += [ u[j] <= gxc * ( B[0,j] - 0.5 ) + 
+    gyc * ( B[1,j] - 0.5 ) for j in xrange(m) ]  
+
+preferred, rejected, neutral = [], [], []
+for k in xrange(m):
+    p = op(-u[k], monotonicity + preferences + concavity)
+    p.solve()
+    if p.status == 'optimal' and p.objective.value()[0] > 0:
+        rejected += [k]
+        print "Basket (%1.2f, %1.2f) rejected." %(B[0,k],B[1,k])
+    else: 
+        p = op(u[k], monotonicity + preferences + concavity)
+        p.solve()
+        if p.status == 'optimal' and p.objective.value()[0] > 0: 
+            print "Basket (%1.2f, %1.2f) preferred." %(B[0,k],B[1,k])
+            preferred += [k]
+        else:
+            print "No conclusion about basket (%1.2f, %1.2f)." \
+                %(B[0,k],B[1,k])
+            neutral += [k]
+
+pylab.figure(1, facecolor='w')
+pylab.plot(B[0,:], B[1,:], 'wo', markeredgecolor='b')
+pylab.contour(pylab.array(X), pylab.array(Y), pylab.array(utility(X,Y)),
+    [.1*(k+1) for k in xrange(9)], colors='k')
+pylab.xlabel('x1')
+pylab.ylabel('x2')
+pylab.title('Goods baskets and utility function (fig. 6.25)')
+
+pylab.figure(2, facecolor='w')
+pylab.plot(B[0,preferred], B[1,preferred], 'go')
+pylab.plot(B[0,rejected], B[1,rejected], 'ro')
+pylab.plot(B[0,neutral], B[1,neutral], 'ys')
+pylab.plot([0.5], [0.5], '+')
+pylab.plot([0.5, 0.5], [0,1], ':', [0,1], [0.5,0.5], ':')
+pylab.axis([0,1,0,1])
+pylab.contour(pylab.array(X), pylab.array(Y), pylab.array(utility(X,Y)),
+    [utility(0.5,0.5)], colors='k')
+pylab.xlabel('x1')
+pylab.ylabel('x2')
+pylab.title('Result of preference analysis (fig. 6.26)')
+pylab.show()
diff --git a/examples/book/chap6/cvxfit b/examples/book/chap6/cvxfit
new file mode 100755
index 0000000..f649289
--- /dev/null
+++ b/examples/book/chap6/cvxfit
@@ -0,0 +1,58 @@
+#!/usr/bin/python
+
+# Figure 6.24, page 339.
+# Least-squares fit of a convex function.
+
+import pylab
+from cvxopt import solvers 
+from cvxopt.base import matrix, spmatrix, mul
+from pickle import load
+solvers.options['show_progress'] = 0
+
+data = load(open('cvxfit.pic','r'))
+u, y = data['u'], data['y']
+m = len(u)
+
+# minimize     (1/2) * || yhat - y ||_2^2
+# subject to   yhat[j] >= yhat[i] + g[i]' * (u[j] - u[i]), 
+#                  j, i = 0,...,m-1  
+#
+# Variables  yhat (m), g (m).
+
+nvars = 2*m
+P = spmatrix(1.0, range(m), range(m), (nvars, nvars))
+q = matrix(0.0, (nvars,1))
+q[:m] = -y
+
+# m blocks (i = 0,...,m-1) of linear inequalities 
+#
+#     yhat[i] + g[i]' * (u[j] - u[i]) <= yhat[j], j = 0,...,m-1. 
+
+G = spmatrix([],[],[], (m**2, nvars))
+I = spmatrix(1.0, range(m), range(m))
+for i in xrange(m):  
+    # coefficients of yhat[i]
+    G[range(i*m, (i+1)*m), i] = 1.0
+
+    # coefficients of g[i]
+    G[range(i*m, (i+1)*m), m+i] = u - u[i]
+
+    # coefficients of yhat[j]
+    G[range(i*m, (i+1)*m), range(m)] -= I
+
+h = matrix(0.0, (m**2,1))
+
+sol = solvers.qp(P, q, G, h)
+yhat = sol['x'][:m]
+g = sol['x'][m:]
+
+nopts = 1000
+ts = [ 2.2/nopts * t for t in xrange(1000) ]
+f = [ max(yhat + mul(g, t-u)) for t in ts ]
+pylab.figure(1, facecolor='w')
+pylab.plot(u, y, 'wo', markeredgecolor='b') 
+pylab.plot(ts, f, '-g')
+pylab.axis([-0.1, 2.3, -1.1, 7.2])
+pylab.axis('off')
+pylab.title('Least-squares fit of convex function (fig. 6.24)')
+pylab.show()
diff --git a/examples/book/chap6/cvxfit.pic b/examples/book/chap6/cvxfit.pic
new file mode 100644
index 0000000..ca2be7e
--- /dev/null
+++ b/examples/book/chap6/cvxfit.pic
@@ -0,0 +1,127 @@
+(dp0
+S'y'
+p1
+ccvxopt.base
+matrix
+p2
+((lp3
+F5.2057354002832819
+aF5.168529540303874
+aF4.4693174707257226
+aF3.1676414922996394
+aF3.2186726818679299
+aF2.7558774192658637
+aF1.6360627918193327
+aF0.72527756034765778
+aF0.24583926693470126
+aF-0.58044829477967541
+aF-0.87676552269878805
+aF-0.82548372091436673
+aF-0.79731422846855127
+aF-0.059483960079878162
+aF-0.049755248937001624
+aF0.70500263843069
+aF0.82600210585526379
+aF0.14030590460768733
+aF0.51054544095596399
+aF0.38582234301290158
+aF0.83860085513607274
+aF0.41632982151136116
+aF0.81154681718230726
+aF0.23060126778692916
+aF0.84177419098779471
+aF0.34454158681673575
+aF0.37408513903614865
+aF0.86597228912388624
+aF0.21207009757657225
+aF0.71788999284982635
+aF0.80995602827825564
+aF1.0691093387601871
+aF0.64850168698870958
+aF1.0924843876810013
+aF0.76143044835863438
+aF1.2122857008556023
+aF1.177289163343745
+aF0.84659501315421903
+aF0.95866894737433894
+aF1.82113177659879
+aF1.801593575785722
+aF1.6354388665511546
+aF1.7742952550818938
+aF2.5264766809146635
+aF2.6522776387129992
+aF3.750115148675202
+aF4.0564222166126189
+aF4.6247681095994553
+aF4.9123027288568162
+aF5.8068945924150048
+aF7.0260934631317404
+a(I51
+I1
+tp4
+S'd'
+p5
+tp6
+Rp7
+sS'u'
+p8
+g2
+((lp9
+F0.0
+aF0.040000000000000001
+aF0.080000000000000002
+aF0.12
+aF0.16
+aF0.20000000000000001
+aF0.23999999999999999
+aF0.28000000000000003
+aF0.32000000000000001
+aF0.35999999999999999
+aF0.40000000000000002
+aF0.44
+aF0.47999999999999998
+aF0.52000000000000002
+aF0.56000000000000005
+aF0.59999999999999998
+aF0.64000000000000001
+aF0.68000000000000005
+aF0.71999999999999997
+aF0.76000000000000001
+aF0.80000000000000004
+aF0.83999999999999997
+aF0.88
+aF0.92000000000000004
+aF0.95999999999999996
+aF1.0
+aF1.04
+aF1.0800000000000001
+aF1.1200000000000001
+aF1.1600000000000001
+aF1.2
+aF1.24
+aF1.28
+aF1.3199999999999998
+aF1.3599999999999999
+aF1.3999999999999999
+aF1.4399999999999999
+aF1.48
+aF1.52
+aF1.5600000000000001
+aF1.6000000000000001
+aF1.6400000000000001
+aF1.6799999999999999
+aF1.72
+aF1.76
+aF1.8
+aF1.8400000000000001
+aF1.8799999999999999
+aF1.9199999999999999
+aF1.96
+aF2.0
+a(I51
+I1
+tp10
+g5
+tp11
+Rp12
+s.
\ No newline at end of file
diff --git a/examples/book/chap6/huber b/examples/book/chap6/huber
new file mode 100755
index 0000000..14d0b3b
--- /dev/null
+++ b/examples/book/chap6/huber
@@ -0,0 +1,83 @@
+#!/usr/bin/python
+
+# Figure 6.5, page 300.
+# Robust regression.
+
+from cvxopt import solvers, lapack
+from cvxopt.base import matrix, spmatrix
+import pylab
+from pickle import load
+solvers.options['show_progress'] = 0
+
+data = load(open('huber.pic','r'))
+u, v = data['u'], data['v']
+m, n = len(u), 2
+
+A = matrix( [m*[1.0], [u]] )
+b = +v
+
+# Least squares solution.
+xls = +b
+lapack.gels(+A, xls)
+xls = xls[:2]
+
+
+# Robust least squares.
+# 
+# minimize  sum( h( A*x-b ))
+#
+# where h(u) = u^2           if |u| <= 1.0
+#            = 2*(|u| - 1.0) if |u| > 1.0.
+# 
+# Solve as a QP (see exercise 4.5): 
+#
+# minimize    (1/2) * u'*u + 1'*v
+# subject to  -u - v <= A*x-b <= u + v
+#             0 <= u <= 1
+#             v >= 0
+#
+# Variables  x (n), u (m), v(m)
+
+novars = n+2*m
+P = spmatrix([],[],[], (novars, novars))
+P[n:n+m,n:n+m] = spmatrix(1.0, range(m), range(m))
+q = matrix(0.0, (novars,1))
+q[-m:] = 1.0
+
+G = spmatrix([], [], [], (5*m, novars))
+h = matrix(0.0, (5*m,1))
+
+# A*x - b <= u+v
+G[:m,:n] = A
+G[:m,n:n+m] = spmatrix(-1.0, range(m), range(m))
+G[:m,n+m:] = spmatrix(-1.0, range(m), range(m))
+h[:m] = b
+
+# -u - v <= A*x - b 
+G[m:2*m,:n] = -A
+G[m:2*m,n:n+m] = spmatrix(-1.0, range(m), range(m))
+G[m:2*m,n+m:] = spmatrix(-1.0, range(m), range(m))
+h[m:2*m] = -b
+
+# u >= 0
+G[2*m:3*m,n:n+m] = spmatrix(-1.0, range(m), range(m))
+
+# u <= 1
+G[3*m:4*m,n:n+m] = spmatrix(1.0, range(m), range(m))
+h[3*m:4*m] = 1.0
+
+# v >= 0
+G[4*m:,n+m:] = spmatrix(-1.0, range(m), range(m))
+
+xh = solvers.qp(P, q, G, h)['x'][:n]
+
+pylab.figure(1,facecolor='w')
+pylab.plot(u, v,'o', 
+    [-11,11], [xh[0]-11*xh[1], xh[0]+11*xh[1]], '-g', 
+    [-11,11], [xls[0]-11*xls[1], xls[0]+11*xls[1]], '--r',
+    markerfacecolor='w', markeredgecolor='b') 
+pylab.axis([-11, 11, -20, 25])
+pylab.xlabel('t')
+pylab.ylabel('f(t)')
+pylab.title('Robust regression (fig. 6.5)')
+pylab.show()
diff --git a/examples/book/chap6/huber.pic b/examples/book/chap6/huber.pic
new file mode 100644
index 0000000..4b382a5
--- /dev/null
+++ b/examples/book/chap6/huber.pic
@@ -0,0 +1,109 @@
+(dp0
+S'u'
+p1
+ccvxopt.base
+matrix
+p2
+((lp3
+F0.2581787157143367
+aF-0.79032498914297911
+aF-2.9920925260484657
+aF-8.0990852965503386
+aF-1.3265791215591971
+aF4.184703954581499
+aF-7.6806353487449863
+aF-8.4383063569843326
+aF-2.6149418356897964
+aF-9.3274324384180041
+aF-6.1569924914077827
+aF-0.57280309059322043
+aF-7.1015436002526169
+aF4.3567105542666784
+aF3.234285560079984
+aF-1.3625917357218409
+aF-1.0793022769872564
+aF0.16663067516248198
+aF0.56175745584152459
+aF1.457560328514111
+aF-2.7835586633456675
+aF-3.2704548506394282
+aF-6.5346746968732559
+aF-8.2776303488191356
+aF-2.1332726032162421
+aF6.0873577446152254
+aF-9.7783862518977305
+aF-5.3377356451646127
+aF8.677011718357452
+aF-5.4640495662875708
+aF5.7189394048037663
+aF-1.7854234631105435
+aF-7.6121444989052343
+aF2.6874068997276055
+aF7.247763721853385
+aF-6.8351268101647156
+aF2.0237015616259075
+aF-7.6478537533655082
+aF2.5219671859042574
+aF6.7024934928410183
+aF-9.5
+aF9.0
+a(I42
+I1
+tp4
+S'd'
+p5
+tp6
+Rp7
+sS'v'
+p8
+g2
+((lp9
+F5.4936896400312936
+aF5.4274168025687288
+aF2.5957278032779536
+aF-2.7682391951102887
+aF4.4450599912428901
+aF8.8287508575062894
+aF-2.9443247093129354
+aF-3.5593049753212678
+aF2.2284579997026248
+aF-3.9802154202240274
+aF-2.1188068795744126
+aF4.9546317086933325
+aF-2.300988118339931
+aF9.3075747131227526
+aF7.7935911147364498
+aF3.1937903207238514
+aF4.303236510004866
+aF4.9477606964246261
+aF5.0033964014225072
+aF6.0324219885427803
+aF2.4207250219709726
+aF1.0605990066305857
+aF-1.4556289000445948
+aF-3.0969998656187521
+aF2.6304308708244863
+aF11.358429048442082
+aF-5.143167335848978
+aF0.23615669383315208
+aF13.58831462050204
+aF0.094486689236513599
+aF10.53303094377349
+aF3.3789693568024424
+aF-1.8187583043782631
+aF6.9619442099217848
+aF12.761815572041129
+aF-2.4380182798326717
+aF6.0830273125621552
+aF-2.2168483473403287
+aF7.387425622245142
+aF11.458313858767751
+aF20.0
+aF-15.0
+a(I42
+I1
+tp10
+g5
+tp11
+Rp12
+s.
\ No newline at end of file
diff --git a/examples/book/chap6/inputdesign b/examples/book/chap6/inputdesign
new file mode 100755
index 0000000..efe9f0f
--- /dev/null
+++ b/examples/book/chap6/inputdesign
@@ -0,0 +1,93 @@
+#!/usr/bin/python
+
+# Figure 6.6, page 309.
+# Input design.
+
+from math import cos, sqrt
+from cvxopt import lapack
+from cvxopt.base import matrix 
+import pylab
+
+m, n = 201, 201
+
+# Jtrack = 1/n * ||H*u-ydes||_2^2.
+H = matrix(0.0, (m,m))
+for t in xrange(m):
+    H[t::m+1] = (1.0/9.0) * .9**t * (1.0 - 0.4 * cos(2*t))
+ydes = matrix( 40*[0.0] + 50*[1.0] + 50*[-1.0] + 61*[0.0] )
+
+# Jmag = 1/n * ||I*u||_2^2
+I = matrix(0.0, (n,n))
+I[::n+1] = 1.0
+
+# Jder = 1/(n-1) * ||D*u||_2^2
+D = matrix(0.0, (n-1,n))
+D[::n] = -1.0
+D[n-1::n] = 1.0
+
+AA = matrix(0.0, (m + 2*n - 1, n))
+bb = matrix(0.0, (m + 2*n - 1, 1))
+AA[:n,:] = H
+bb[:n] = ydes 
+
+delta, eta = 0.0, 0.005
+AA[n:2*n,:] = sqrt(eta)*I
+AA[2*n:,:] = sqrt(delta)*D
+x = +bb
+lapack.gels(+AA, x)
+u1 = x[:n]
+
+pylab.figure(1, facecolor='w', figsize=(10,10))
+ts = matrix(range(n), tc='d')
+pylab.subplot(321)
+pylab.plot(ts, u1, '-')
+pylab.xlabel('t')
+pylab.ylabel('u(t)')
+pylab.axis([0, 200, -10, 5])
+pylab.title('Optimal input (fig. 6.6.)')
+pylab.subplot(322)
+pylab.plot(ts, H*u1, '-', ts, ydes, 'g--')
+pylab.xlabel('t')
+pylab.ylabel('y(t)')
+pylab.axis([0, 200, -1.1, 1.1])
+pylab.title('Output')
+
+
+delta, eta = 0.0, 0.05
+AA[n:2*n,:] = sqrt(eta)*I
+AA[2*n:,:] = sqrt(delta)*D
+x = +bb
+lapack.gels(+AA, x)
+u2 = x[:n]
+
+pylab.subplot(323)
+pylab.plot(ts, u2, '-')
+pylab.xlabel('t')
+pylab.ylabel('u(t)')
+pylab.axis([0, 200, -4, 4])
+pylab.subplot(324)
+pylab.plot(ts, H*u2, '-', ts, ydes, 'g--')
+pylab.ylabel('y(t)')
+pylab.xlabel('t')
+pylab.axis([0, 200, -1.1, 1.1])
+
+
+delta, eta = 0.3, 0.05
+AA[n:2*n,:] = sqrt(eta)*I
+AA[2*n:,:] = sqrt(delta)*D
+x = +bb
+lapack.gels(+AA, x)
+u3 = x[:n]
+
+pylab.subplot(325)
+pylab.plot(ts, u3, '-')
+pylab.xlabel('t')
+pylab.ylabel('u(t)')
+pylab.axis([0, 200, -4, 4])
+pylab.subplot(326)
+pylab.plot(ts, H*u3, '-', ts, ydes, 'g--')
+pylab.ylabel('y(t)')
+pylab.xlabel('t')
+pylab.axis([0, 200, -1.1, 1.1])
+
+pylab.show()
diff --git a/examples/book/chap6/penalties b/examples/book/chap6/penalties
new file mode 100755
index 0000000..98c45a4
--- /dev/null
+++ b/examples/book/chap6/penalties
@@ -0,0 +1,98 @@
+#!/usr/bin/python
+
+# Figure 6.2, page 297.
+# Penalty approximation.
+#
+# The problem data are not the same as in the book figure.
+
+import pylab
+from cvxopt import random, lapack, solvers
+from cvxopt.base import matrix, spmatrix, log, div
+from cvxopt.modeling import variable, op, max, sum 
+solvers.options['show_progress'] = 0
+
+m, n = 100, 30
+A = random.normal(m,n)
+b = random.normal(m,1)
+b /= (1.1 * max(abs(b)))   # Make x = 0 feasible for log barrier.
+
+
+# l1 approximation
+#
+# minimize || A*x + b ||_1
+
+x = variable(n)
+op(sum(abs(A*x+b))).solve()
+x1 = x.value
+
+pylab.figure(1, facecolor='w', figsize=(10,10))
+pylab.subplot(411)
+nbins = 100
+bins = [-1.5 + 3.0/(nbins-1)*k for k in xrange(nbins)]
+pylab.hist( A*x1+b ,  bins)
+nopts = 200
+xs = -1.5 + 3.0/(nopts-1) * matrix(range(nopts))
+pylab.plot(xs, (35.0/1.5) * abs(xs), 'g-')
+pylab.axis([-1.5, 1.5, 0, 40])
+pylab.ylabel('l1')
+pylab.title('Penalty function approximation (fig. 6.2)')
+
+
+
+# l2 approximation
+#
+# minimize || A*x + b ||_2
+
+x = matrix(0.0, (m,1))
+lapack.gels(+A, x)
+x2 = x[:n]
+
+pylab.subplot(412)
+pylab.hist( A*x2+b ,  bins)
+pylab.plot(xs, (8.0/1.5**2) * xs**2 , 'g-')
+pylab.ylabel('l2')
+pylab.axis([-1.5, 1.5, 0, 10])
+
+
+# Deadzone approximation
+#
+# minimize sum(max(abs(A*x+b)-0.5, 0.0))
+
+x = variable(n)
+op(sum(max(abs(A*x+b)-0.5, 0.0))).solve()
+xdz = x.value
+
+pylab.subplot(413)
+pylab.hist( A*xdz+b ,  bins)
+pylab.plot(xs, 15.0/1.0 * matrix([ max(abs(xk)-0.5, 0.0) for xk 
+    in xs ]), 'g-')
+pylab.ylabel('Deadzone')
+pylab.axis([-1.5, 1.5, 0, 20])
+
+
+# Log barrier
+#
+# minimize -sum (log ( 1.0 - A*x+b)**2)
+
+def F(x=None, z=None):
+    if x is None: return 0, matrix(0.0, (n,1))
+    y = A*x+b
+    if max(abs(y)) >= 1.0: return None
+    f = -sum(log(1.0 - y**2))
+    gradf = 2.0 * A.T * div(y, 1-y**2)
+    if z is None: return f, gradf.T
+    H = A.T * spmatrix(2.0 * div( 1.0+y**2, (1.0 - y**2)**2 ), range(m),
+        range(m)) * A
+    return f, gradf.T, z[0]*H
+xlb = solvers.cp(F)['x']
+
+pylab.subplot(414)
+pylab.hist( A*xlb+b ,  bins)
+nopts = 200
+pylab.plot(xs, (8.0/1.5**2) * xs**2, 'g--')
+xs2 = -0.99999 + (2*0.99999 /(nopts-1)) * matrix(range(nopts))
+pylab.plot(xs2, -3.0 * log(1.0 - abs(xs2)**2), 'g-')
+pylab.ylabel('Log barrier')
+pylab.xlabel('residual')
+pylab.axis([-1.5, 1.5, 0, 10])
+pylab.show()
diff --git a/examples/book/chap6/polapprox b/examples/book/chap6/polapprox
new file mode 100755
index 0000000..1d9524b
--- /dev/null
+++ b/examples/book/chap6/polapprox
@@ -0,0 +1,148 @@
+#!/usr/bin/python
+
+# Figures 6.19 and 6.20, page 332.
+# Polynomial and spline fitting.
+
+from cvxopt import lapack, solvers 
+from cvxopt.base import matrix, mul
+from cvxopt.modeling import op, variable, max
+import pylab
+from pickle import load
+solvers.options['show_progress'] = 0
+
+data = load(open('polapprox.pic','r'))
+t, y = data['t'], data['y']
+m = len(t)
+
+# LS fit of 5th order polynomial
+#
+#     minimize ||A*x - y ||_2
+
+n = 6
+A = matrix( [[t**k] for k in xrange(n)] )
+xls = +y
+lapack.gels(+A,xls)
+xls = xls[:n]
+
+# Chebyshev fit of 5th order polynomial
+#
+#     minimize ||A*x - y ||_inf
+
+xinf = variable(n)
+op( max(abs(A*xinf - y)) ).solve()
+xinf = xinf.value
+
+pylab.figure(1, facecolor='w')
+pylab.plot(t, y, 'bo', mfc='w', mec='b')
+nopts = 1000
+ts = -1.1 + (1.1 - (-1.1))/nopts * matrix(range(nopts), tc='d')
+yls = sum( xls[k] * ts**k  for k in xrange(n) )
+yinf = sum( xinf[k] * ts**k  for k in xrange(n) )
+pylab.plot(ts,yls,'g-', ts, yinf, '--r')
+pylab.axis([-1.1, 1.1, -0.1, 0.25])
+pylab.xlabel('u')
+pylab.ylabel('p(u)')
+pylab.title('Polynomial fitting (fig. 6.19)')
+
+
+# Fit of cubic spline
+#
+#     f(t) = p1(t)   -1   <= t <= -1/3 
+#          = p2(t)   -1/3 <= t <=  1/3 
+#          = p3(t)    1/3 <= t <=  1
+#
+#     p1(t) = x0 + x1*t + x2*t^2 + x3*t^3    -1   <= t <= -1/3 
+#     p2(t) = x4 + x5*t + x6*t^2 + x7*t^3    -1/3 <= t <=  1/3 
+#     p3(t) = x8 + x9*t + x10*t^2 + x11*t^3   1/3 <= t <=  1
+#
+# with constraints 
+#
+#     p1(-1/3) = p2(-1/3), 
+#     p1'(-1/3) = p2'(-1/3)
+#     p1''(-1/3) = p2''(-1/3)
+#     p2(1/3) = p3(1/3), 
+#     p2'(1/3) = p3'(1/3)
+#     p2''(1/3) = p3''(1/3)
+
+
+n = 12
+u1, u2 = -1.0/3, 1.0/3
+I1 = [ k for k in xrange(m) if -1.0  <= t[k] < u1 ]
+I2 = [ k for k in xrange(m) if  u1 <= t[k] < u2 ]
+I3 = [ k for k in xrange(m) if  u2 <= t[k] <= 1.0 ]
+m1, m2, m3 = len(I1), len(I2), len(I3)
+A = matrix(0.0, (m,n))
+for k in xrange(4):   
+    A[I1,k] = t[I1]**k
+    A[I2,k+4] = t[I2]**k
+    A[I3,k+8] = t[I3]**k
+
+G = matrix(0.0, (6,n))
+
+# p1(u1) = p2(u1),  p1(u2) = p2(u2)
+G[0, range(8)]  =  1.0,  u1,  u1**2,  u1**3, -1.0, -u1, -u1**2, -u1**3
+G[1, range(4,12)] =  1.0,  u2,  u2**2,  u2**3, -1.0, -u2, -u2**2, -u2**3
+
+# p1'(u1) = p2'(u1),  p1'(u2) = p2'(u2)
+G[2, [1,2,3,5,6,7]] = 1.0,  2*u1,  3*u1**2, -1.0, -2*u1, -3*u1**2
+G[3, [5,6,7,9,10,11]]  =  1.0,  2*u2,  3*u2**2,  -1.0, -2*u2, -3*u2**2
+
+# p1''(u1) = p2''(u1),  p1''(u2) = p2''(u2)
+G[4, [2,3,6,7]]  =  2,  6*u1, -2, -6*u1
+G[5, [6,7,10,11]]  =  2,  6*u2, -2, -6*u2
+
+
+# LS fit
+#
+#     minimize    (1/2) * || A*x - y ||_2^2
+#     subject to  G*x = h
+#
+# Solve as a linear equation 
+#
+#     [ A'*A  G' ] [ x ]   [ A'*y ]
+#     [ G     0  ] [ y ] = [ 0    ].
+ 
+K = matrix(0.0, (n+6,n+6))
+K[:n,:n] = A.T * A
+K[n:,:n] = G
+xls = matrix(0.0, (n+6,1))
+xls[:n] = A.T * y
+lapack.sysv(K, xls)
+xls = xls[:n]
+
+
+# Chebyshev fit
+#
+#     minimize    || A*x - y ||_inf
+#     subject to  G*x = h
+
+xcheb = variable(12)
+op( max(abs(A*xcheb - y)), [G*xcheb == 0]).solve()
+xcheb = xcheb.value
+
+pylab.figure(2, facecolor='w')
+nopts  = 100
+ts = -1.0 + (1.0 - (-1.0))/nopts * matrix(range(nopts), tc='d')
+I1 = [ k for k in xrange(nopts) if -1.0  <= ts[k] < u1 ]
+I2 = [ k for k in xrange(nopts) if  u1 <= ts[k] < u2 ]
+I3 = [ k for k in xrange(nopts) if  u2 <= ts[k] <= 1.0 ]
+yls = matrix(0.0, (nopts,1))
+yls[I1] = sum( xls[k]*ts[I1]**k for k in xrange(4) )
+yls[I2] = sum( xls[k+4]*ts[I2]**k for k in xrange(4) )
+yls[I3] = sum( xls[k+8]*ts[I3]**k for k in xrange(4) )
+ycheb = matrix(0.0, (nopts,1))
+ycheb[I1] = sum( xcheb[k]*ts[I1]**k for k in xrange(4) )
+ycheb[I2] = sum( xcheb[k+4]*ts[I2]**k for k in xrange(4) )
+ycheb[I3] = sum( xcheb[k+8]*ts[I3]**k for k in xrange(4) )
+
+pylab.plot(t, y, 'bo', mfc='w', mec='b')
+pylab.plot([-1.0, -1.0], [-0.1, 0.25], 'k--', 
+    [-1./3,-1./3], [-0.1, 0.25], 'k--', 
+    [1./3,1./3], [-0.1, 0.25], 'k--', [1,1], [-0.1, 0.25], 'k--')
+pylab.plot(ts, yls, '-g', ts, ycheb, '--r')
+pylab.axis([-1.1, 1.1, -0.1, 0.25])
+pylab.xlabel('u')
+pylab.ylabel('p(u)')
+pylab.title('Cubic spline fitting (fig. 6.20)')
+
+pylab.show()
diff --git a/examples/book/chap6/polapprox.pic b/examples/book/chap6/polapprox.pic
new file mode 100644
index 0000000..7474e93
--- /dev/null
+++ b/examples/book/chap6/polapprox.pic
@@ -0,0 +1,105 @@
+(dp0
+S'y'
+p1
+ccvxopt.base
+matrix
+p2
+((lp3
+F-0.082103425893059981
+aF-0.077658017081031816
+aF-0.044154955666689109
+aF-0.027978495767535284
+aF-0.028653493677588893
+aF0.0076713634401920257
+aF0.020080899761448615
+aF0.019932321303742423
+aF0.035638548853098133
+aF0.046383747342975547
+aF0.055565245592635898
+aF0.078338990521136007
+aF0.080026173863524147
+aF0.12401050741944375
+aF0.11860999883627903
+aF0.14015932722458307
+aF0.16910670293333385
+aF0.17713978855464221
+aF0.18995845130900052
+aF0.19062838398418774
+aF0.20189935838561909
+aF0.17764415001158707
+aF0.18411166959318781
+aF0.17583110060882948
+aF0.13456015420480544
+aF0.13304152533273264
+aF0.1221260708609055
+aF0.081351196920178989
+aF0.073236116455466155
+aF0.086269618897523839
+aF0.071862897042482929
+aF0.08028786841829133
+aF0.081146142657454193
+aF0.081671563556176829
+aF0.090894683237619942
+aF0.089940590418169097
+aF0.10221834607855008
+aF0.087124543198926277
+aF0.10958163681660973
+aF0.12065504923390243
+a(I40
+I1
+tp4
+S'd'
+p5
+tp6
+Rp7
+sS't'
+p8
+g2
+((lp9
+F-1.0
+aF-0.94871794871794868
+aF-0.89743589743589747
+aF-0.84615384615384615
+aF-0.79487179487179493
+aF-0.74358974358974361
+aF-0.69230769230769229
+aF-0.64102564102564097
+aF-0.58974358974358976
+aF-0.53846153846153844
+aF-0.48717948717948723
+aF-0.4358974358974359
+aF-0.38461538461538458
+aF-0.33333333333333337
+aF-0.28205128205128205
+aF-0.23076923076923073
+aF-0.17948717948717952
+aF-0.12820512820512819
+aF-0.076923076923076872
+aF-0.025641025641025661
+aF0.02564102564102555
+aF0.076923076923076872
+aF0.12820512820512819
+aF0.17948717948717952
+aF0.23076923076923084
+aF0.28205128205128216
+aF0.33333333333333326
+aF0.38461538461538458
+aF0.4358974358974359
+aF0.48717948717948723
+aF0.53846153846153855
+aF0.58974358974358965
+aF0.64102564102564097
+aF0.69230769230769229
+aF0.74358974358974361
+aF0.79487179487179493
+aF0.84615384615384626
+aF0.89743589743589736
+aF0.94871794871794868
+aF1.0
+a(I40
+I1
+tp10
+g5
+tp11
+Rp12
+s.
\ No newline at end of file
diff --git a/examples/book/chap6/regsel b/examples/book/chap6/regsel
new file mode 100755
index 0000000..d583672
--- /dev/null
+++ b/examples/book/chap6/regsel
@@ -0,0 +1,127 @@
+#!/usr/bin/python
+
+# Figure 6.7, page 311.
+# Sparse regressor selection.
+#
+# The problem data are different from the book.
+
+import pylab
+from cvxopt import blas, lapack, solvers 
+from cvxopt.base import matrix, spmatrix, mul
+from pickle import load
+solvers.options['show_progress'] = 0
+
+data = load(open('regsel.pic','r'))
+A, b = data['A'], data['b']
+m, n = A.size 
+
+# In the heuristic, set x[k] to zero if abs(x[k]) <= tol * max(abs(x)).
+tol = 1e-1
+
+# Data for QP
+#
+#     minimize    (1/2) ||A*x - b|_2^2 
+#     subject to  -y <= x <= y
+#                 sum(y) <= alpha
+
+P = matrix(0.0, (2*n,2*n))
+P[:n,:n] = A.T*A
+q = matrix(0.0, (2*n,1))
+q[:n] = -A.T*b
+I = matrix(0.0, (n,n)) 
+I[::n+1] = 1.0
+G = matrix([[I, -I, matrix(0.0, (1,n))], [-I, -I, matrix(1.0, (1,n))]])
+h = matrix(0.0, (2*n+1,1))
+
+# Least-norm solution
+xln = matrix(0.0, (n,1))
+xln[:m] = b
+lapack.gels(+A, xln)
+
+nopts = 100
+res = [ blas.nrm2(b) ]
+card = [ 0 ]
+alphas = blas.asum(xln)/(nopts-1) * matrix(range(1,nopts), tc='d')
+for alpha in alphas:
+
+    #    minimize    ||A*x-b||_2
+    #    subject to  ||x||_1 <= alpha
+
+    h[-1] = alpha
+    x = solvers.qp(P, q, G, h)['x'][:n]
+    xmax = max(abs(x))
+    I = [ k for k in xrange(n) if abs(x[k]) > tol*xmax ]
+    if len(I) <= m:
+        xs = +b 
+        lapack.gels(A[:,I], xs)
+        x[:] = 0.0
+        x[I] = xs[:len(I)]
+        res += [ blas.nrm2(A*x-b) ]
+        card += [ len(I) ]
+
+# Eliminate duplicate cardinalities and make staircase plot.
+res2, card2 = [], []
+for c in xrange(m+1):
+    r = [ res[k] for k in xrange(len(res)) if card[k] == c ]
+    if r:  
+        res2 += [ min(r), min(r) ]
+        card2 += [ c, c+1 ]
+
+pylab.figure(1, facecolor='w')
+pylab.plot( res2[::2], card2[::2], 'o')
+pylab.plot( res2, card2, '-') 
+pylab.xlabel('||A*x-b||_2')
+pylab.ylabel('card(x)')
+pylab.title('Sparse regressor selection (fig 6.7)')
+print "Close figure to start exhaustive search."
+pylab.show()
+
+
+# Exhaustive search.
+
+def patterns(k,n):
+    """
+    Generates all 0-1 sequences of length n with exactly k nonzeros.
+    """
+    if k==0:
+        yield n*[0]
+    else:
+        for x in patterns(k-1,n-1): yield [1] + x
+        if k <= n-1:
+            for x in patterns(k,n-1): yield [0] + x
+
+             
+bestx = matrix(0.0, (n, m))   # best solution for each cardinality
+bestres = matrix(blas.nrm2(b), (1, m+1))   # best residual
+x = matrix(0.0, (n,1))
+for k in xrange(1,m):
+    for s in patterns(k,n):
+        I = [ i for i in xrange(n) if s[i] ]
+        s = [k] + s 
+        print ("%d nonzeros: " + n*"%d") %tuple(s)
+        x = +b
+        lapack.gels(A[:,I], x)
+        res = blas.nrm2(b - A[:,I] * x[:k])
+        if res < bestres[k]:
+            bestres[k] = res 
+            bestx[:,k][I] = x[:k] 
+bestres[m] = 0.0
+
+pylab.figure(1, facecolor='w')
+
+# heuristic result
+pylab.plot( res2[::2], card2[::2], 'o' )
+pylab.plot( res2, card2, '-') 
+
+# exhaustive result
+res2, card2 = [ bestres[0] ], [ 0 ] 
+for k in xrange(1,m+1):
+    res2 += [bestres[k-1], bestres[k]]
+    card2 += [ k, k]
+pylab.plot( bestres, range(m+1), 'go')
+pylab.plot( res2, card2, 'g-')
+
+pylab.xlabel('||A*x-b||_2')
+pylab.ylabel('card(x)')
+pylab.title('Sparse regressor selection (fig 6.7)')
+pylab.show()
diff --git a/examples/book/chap6/regsel.pic b/examples/book/chap6/regsel.pic
new file mode 100644
index 0000000..20f6469
--- /dev/null
+++ b/examples/book/chap6/regsel.pic
@@ -0,0 +1,235 @@
+(dp0
+S'A'
+p1
+ccvxopt.base
+matrix
+p2
+((lp3
+F0.3792236226850329
+aF0.94419972674730834
+aF-2.1204266882242115
+aF-0.6446789155419369
+aF-0.70430172843360894
+aF-1.0181372163990707
+aF-0.18208186841138524
+aF1.521013239005587
+aF-0.038438763886711559
+aF1.2274479890097165
+aF-0.69620480003288876
+aF0.0075244865230144464
+aF-0.78289304437828722
+aF0.58693855921443094
+aF-0.25120737456888181
+aF0.48013582284260076
+aF0.66815503443364055
+aF-0.078321196273411942
+aF0.88917261841259909
+aF2.3092874859523866
+aF0.52463867977109835
+aF-0.011787323951306753
+aF0.91314081776137068
+aF0.055940678888401998
+aF-1.1070698948260072
+aF0.48549770731281022
+aF-0.0050050737555313854
+aF-0.27621785935475895
+aF1.2764524736743927
+aF1.8634006131845375
+aF-0.52255930163639908
+aF0.10342444693731498
+aF-0.80764913089718049
+aF0.68043858374894572
+aF-2.364589847941581
+aF0.99011487204949045
+aF0.21889912088117661
+aF0.26166246016140166
+aF1.2134444949753469
+aF-0.27466698645678145
+aF-0.13313445081352937
+aF-1.2705002037083766
+aF-1.663606452829772
+aF-0.70355426153675493
+aF0.28088048852330211
+aF-0.54120932991619408
+aF-1.3335307297363925
+aF1.0726862678901432
+aF-0.71208545249435584
+aF-0.01128556123068556
+aF-0.0008170291956958361
+aF-0.24943628469543444
+aF0.39657531871165158
+aF-0.26401335492224315
+aF-1.664010876930589
+aF-1.028975099543801
+aF0.243094700224565
+aF-1.2565901078338166
+aF-0.34718318973352613
+aF-0.94137219342832856
+aF-1.1745602813024438
+aF-1.021141686935775
+aF-0.40166673459678831
+aF0.17366566856230725
+aF-0.11611849335051072
+aF1.0641191489863535
+aF-0.24538629675166962
+aF-1.5175391310895556
+aF0.0097341591259511185
+aF0.071372864855954732
+aF0.3165358137685082
+aF0.49982566779647836
+aF1.2780841467141097
+aF-0.54781614692115776
+aF0.26080839887907459
+aF-0.013176671873511559
+aF-0.58026400214195251
+aF2.1363084228053086
+aF-0.25761711565348083
+aF-1.4095284893691984
+aF1.7701008928516144
+aF0.32554598476071001
+aF-1.1190395753813116
+aF0.62035013944552475
+aF1.2697818471897746
+aF-0.89604250642191452
+aF0.13517544475843685
+aF-0.13904001004044259
+aF-1.1633952938372654
+aF1.1837195399368565
+aF-0.015429661783325022
+aF0.53621869471861705
+aF-0.71642862372585547
+aF-0.65555938950390591
+aF0.31436276331074814
+aF0.10681407593458775
+aF1.8482162180189687
+aF-0.27510567543881131
+aF2.2125540789896809
+aF1.5085257560961467
+aF-1.945078599919331
+aF-1.6805427775226454
+aF-0.57353413410587606
+aF-0.18581652736765947
+aF0.0089341156765677023
+aF0.83694989083729465
+aF-0.72227067243329512
+aF-0.72149047716441006
+aF-0.20118099951714263
+aF-0.020464161095144321
+aF0.27888999991245078
+aF1.05829481445
+aF0.6216732824024096
+aF-1.7506152884853836
+aF0.69734755148343741
+aF0.81148586331699257
+aF0.63634494760413318
+aF1.310080341410262
+aF0.32709751591819802
+aF-0.67299316385471109
+aF-0.14932749947673082
+aF-2.4490177537568125
+aF0.47328561224355359
+aF0.11694565679328851
+aF-0.59110383863220495
+aF-0.65470767508278371
+aF-1.0806618512116946
+aF-0.04773086529790517
+aF0.37934453728879497
+aF-0.33036104579865933
+aF-0.49989825118472925
+aF-0.035978607953005746
+aF-0.17476033119671699
+aF-0.95726507882166145
+aF1.2925479001322682
+aF0.440909642847022
+aF1.2809409427445406
+aF-0.49772980521188004
+aF-1.1187166376043225
+aF0.80764961943935132
+aF0.041199578638244888
+aF-0.75620860554670111
+aF-0.08912914780643004
+aF-2.0088503217891547
+aF1.0839180379588267
+aF-0.98119056314417352
+aF-0.68848863746469791
+aF1.3394794818077986
+aF-0.90924316031600994
+aF-0.41285772861879833
+aF-0.50616318564854024
+aF1.6197477991253717
+aF0.080900711206500039
+aF-1.0810564901769375
+aF-1.1245178115942032
+aF1.7356763426062964
+aF1.9374585965267537
+aF1.6350682185206411
+aF-1.2559401667743206
+aF-0.2135375062087026
+aF-0.19893204828268177
+aF0.3074991774798489
+aF-0.57232545648506006
+aF-0.97764836704205615
+aF-0.44680940665694829
+aF1.0820919008951635
+aF2.372647949389985
+aF0.2292883361044312
+aF-0.26662313612389132
+aF0.70167217691939954
+aF-0.48759049128980936
+aF1.8624797253190992
+aF1.1068511103913441
+aF-1.2275657222158463
+aF-0.66988511005648677
+aF1.3409294523313127
+aF0.38808331624114234
+aF0.39305892877699972
+aF-1.7073335778377412
+aF0.22785864470433817
+aF0.68563285776295124
+aF-0.63679011291329279
+aF-1.0026055542338093
+aF-0.1856206729110158
+aF-1.0540327142000288
+aF-0.071539488916578894
+aF0.27919841968634951
+aF1.3732753424840702
+aF0.1798410321847575
+aF-0.54201655650396363
+aF1.634190580750742
+aF0.82521515151758584
+aF0.23076114227231159
+aF0.67163394593208492
+aF-0.50807788041779367
+aF0.85635159733999011
+aF0.26850345353239546
+aF0.62497517619067067
+aF-1.0473379377146483
+aF1.5356703814685793
+a(I10
+I20
+tp4
+S'd'
+p5
+tp6
+Rp7
+sS'b'
+p8
+g2
+((lp9
+F1.7681714743362944
+aF0.44972610702627669
+aF-1.5918328806524971
+aF-2.2520492785828985
+aF-2.1770837388797588
+aF0.00033917950394704577
+aF-1.923579585243794
+aF1.4722144218103526
+aF-0.88923264442387262
+aF-3.2515796920953459
+a(I10
+I1
+tp10
+g5
+tp11
+Rp12
+s.
\ No newline at end of file
diff --git a/examples/book/chap6/robls b/examples/book/chap6/robls
new file mode 100755
index 0000000..6efcbf7
--- /dev/null
+++ b/examples/book/chap6/robls
@@ -0,0 +1,161 @@
+#!/usr/bin/python
+
+# Figures 6.15 and 6.16, pages 320 and 325.
+# Stochastic and worst-case robust approximation.
+
+from math import pi
+from cvxopt import random, blas, lapack, solvers
+from cvxopt.base import matrix, spmatrix, mul, cos, sin, sqrt
+import pylab
+from pickle import load
+solvers.options['show_progress'] = 0
+
+def wcls(A, Ap, b):
+    """
+    Solves the robust least squares problem
+
+        minimize sup_{||u||<= 1} || (A + sum_k u[k]*Ap[k])*x - b ||_2^2.
+
+    A is mxn.  Ap is a list of mxn matrices.  b is mx1.
+    """
+
+    (m, n), p = A.size, len(Ap)
+
+    # minimize    t + v
+    # subject to  [ I         *     *  ]
+    #             [ P(x)'     v*I  -*  ] >= 0.
+    #             [ (A*x-b)'  0     t  ]
+    #
+    # where P(x) = [Ap[0]*x, Ap[1]*x, ..., Ap[p-1]*x].
+    #
+    # Variables x (n), v (1), t(1). 
+
+    novars = n + 2
+    M = m + p + 1
+    c = matrix( n*[0.0] + 2*[1.0])
+    Fs = [spmatrix([],[],[], (M**2, novars))]
+    for k in xrange(n):
+        # coefficient of x[k]
+        S = spmatrix([], [], [], (M, M))
+        for j in xrange(p):
+            S[m+j, :m] = -Ap[j][:,k].T
+            S[-1, :m ] = -A[:,k].T
+        Fs[0][:,k] = S[:] 
+    # coefficient of v
+    Fs[0][(M+1)*m : (M+1)*(m+p) : M+1, -2] = -1.0
+    # coefficient of t
+    Fs[0][-1, -1] = -1.0
+
+    hs = [matrix(0.0, (M, M))]
+    hs[0][:(M+1)*m:M+1] = 1.0
+    hs[0][-1, :m] = -b.T
+
+    return solvers.sdp(c, None, None, Fs, hs)['x'][:n]
+    
+
+# Figure 6.15
+
+data = load(open('robls.pic','r'))['6.15']
+A, b, B = data['A'], data['b'], data['B']
+m, n = A.size
+
+# Nominal problem:  minimize || A*x - b ||_2
+xnom = +b
+lapack.gels(+A, xnom)
+xnom = xnom[:n]
+
+
+# Stochastic problem.
+#
+# minimize E || (A+u*B) * x - b ||_2^2 
+#          = || A*x - b||_2^2 + x'*P*x
+#
+# with P = E(u^2) * B'*B = (1/3) * B'*B
+
+S = A.T * A + (1.0/3.0) * B.T * B
+xstoch = A.T * b 
+lapack.posv(S, xstoch)
+
+
+# Worst case approximation.
+#
+# minimize max_{-1 <= u <= 1} ||A*u - b||_2^2.
+
+xwc = wcls(A, [B], b)
+
+pylab.figure(1, facecolor='w')
+nopts = 500
+us = -2.0 + (2.0 - (-2.0))/(nopts-1) * matrix(range(nopts),tc='d')
+rnom = [ blas.nrm2( (A+u*B)*xnom - b) for u in us ]
+rstoch = [ blas.nrm2( (A+u*B)*xstoch - b) for u in us ]
+rwc = [ blas.nrm2( (A+u*B)*xwc - b) for u in us ]
+pylab.plot(us, rnom, us, rstoch, us, rwc)
+pylab.plot([-1, -1], [0, 12], '--k', [1, 1], [0, 12], '--k')
+pylab.axis([-2.0, 2.0, 0.0, 12.0])
+pylab.xlabel('u')
+pylab.ylabel('r(u)')
+pylab.text(us[9], rnom[9], 'nominal')
+pylab.text(us[9], rstoch[9], 'stochastic')
+pylab.text(us[9], rwc[9], 'worst case')
+pylab.title('Robust least-squares (fig.6.15)')
+
+
+# Figure 6.16
+
+data = load(open('robls.pic','r'))['6.16']
+A, Ap, b = data['A0'], [data['A1'], data['A2']], data['b']
+(m, n), p = A.size, len(Ap)
+
+# least squares solution:  minimize || A*x - b ||_2^2
+xls = +b 
+lapack.gels(+A, xls)
+xls = xls[:n]
+
+# Tikhonov solution:  minimize || A*x - b ||_2^2 + 0.1*||x||^2_2
+xtik = A.T*b
+S = A.T*A
+S[::n+1] += 0.1
+lapack.posv(S, xtik)
+
+# Worst case solution
+xwc = wcls(A, Ap, b)
+
+notrials = 100000
+r = sqrt(random.uniform(1,notrials))
+theta = 2.0 * pi * random.uniform(1,notrials)
+u = matrix(0.0, (2,notrials))
+u[0,:] = mul(r, cos(theta))
+u[1,:] = mul(r, sin(theta))
+
+# LS solution 
+q = A*xls - b
+P = matrix(0.0, (m,2))
+P[:,0], P[:,1] = Ap[0]*xls, Ap[1]*xls
+r = P*u + q[:,notrials*[0]]
+resls = sqrt( matrix(1.0, (1,m)) * mul(r,r) )
+
+q = A*xtik - b
+P[:,0], P[:,1] = Ap[0]*xtik, Ap[1]*xtik
+r = P*u + q[:,notrials*[0]]
+restik = sqrt( matrix(1.0, (1,m)) * mul(r,r) )
+
+q = A*xwc - b
+P[:,0], P[:,1] = Ap[0]*xwc, Ap[1]*xwc
+r = P*u + q[:,notrials*[0]]
+reswc = sqrt( matrix(1.0, (1,m)) * mul(r,r) )
+
+pylab.figure(2, facecolor='w')
+pylab.hist(resls, [0.1*k for k in xrange(50)], fc='w', 
+    normed=True)
+pylab.text(4.4, 0.4, 'least-squares')
+pylab.hist(restik, [0.1*k for k in xrange(50)], fc='#D0D0D0', 
+    normed=True)
+pylab.text(2.9, 0.75, 'Tikhonov')
+pylab.hist(reswc, [0.1*k for k in xrange(50)], fc='#B0B0B0', 
+    normed=True)
+pylab.text(2.5, 2.0, 'robust least-squares')
+pylab.xlabel('residual')
+pylab.ylabel('frequency/binwidth')
+pylab.axis([0, 5, 0, 2.5])
+pylab.title('LS, Tikhonov and robust LS solutions (fig. 6.16)')
+pylab.show()
diff --git a/examples/book/chap6/robls.pic b/examples/book/chap6/robls.pic
new file mode 100644
index 0000000..d7dc67c
--- /dev/null
+++ b/examples/book/chap6/robls.pic
@@ -0,0 +1,3551 @@
+(dp0
+S'6.16'
+p1
+(dp2
+S'A1'
+p3
+ccvxopt.base
+matrix
+p4
+((lp5
+F0.060692158613671936
+aF0.13551661590847716
+aF-0.17502709536245181
+aF-0.063037297302464115
+aF0.014935075566241917
+aF0.044744644349989232
+aF-0.046890482800718794
+aF0.025285039094763633
+aF-0.1039788695383739
+aF-0.016078750634654217
+aF-0.025576092297782037
+aF0.081120696754861332
+aF-0.045213169012554906
+aF-0.076384272870508335
+aF-0.075661165259473848
+aF0.023626665153808794
+aF-0.063221676766965704
+aF0.13592483232601332
+aF0.048680559916581323
+aF0.027181736676694369
+aF-0.012832661620716198
+aF0.026767008849993876
+aF0.11390502495296238
+aF-0.18969994093555062
+aF0.10959905874785433
+aF-0.032081778936551592
+aF0.00021374045196674831
+aF0.074990571848910018
+aF0.049374041941245235
+aF-0.13683868137153848
+aF-0.12746500526414692
+aF0.048622601864251325
+aF-0.077185782423571589
+aF-0.13828259828092537
+aF-0.030443977256897424
+aF-0.033705728816664809
+aF-0.098443443885964016
+aF-0.094080449920338385
+aF0.024640157809006739
+aF-0.16193001279321245
+aF0.11145227630200073
+aF0.056398796214405474
+aF-0.023321328463359759
+aF-0.001951527057240684
+aF-0.07696872925322433
+aF-0.088470297688072422
+aF0.031662744440395622
+aF0.076422466932287825
+aF0.10838115056771372
+aF-0.010889181409712081
+aF0.051948575428524997
+aF0.16585309976092452
+aF0.19211540785366352
+aF-0.031700294366078068
+aF0.18971747616051238
+aF-0.013527531015241514
+aF-0.059616817272019874
+aF0.047765677876500615
+aF-0.0042636019623572396
+aF0.098637192455550443
+aF0.055846875878276254
+aF-0.13140027274671209
+aF-0.25677689245733221
+aF0.045824553840161798
+aF-0.085532309934380421
+aF0.076974724513215104
+aF0.13413109105577808
+aF-0.082996837801254067
+aF0.085439373818847059
+aF0.013435238914139938
+aF-0.049753534949874161
+aF0.13343415275593765
+aF-0.043796099641046443
+aF0.10408000507115905
+aF0.13426438776907818
+aF-0.17707932111697597
+aF0.2500315404872393
+aF0.11495805331632575
+aF0.089013755970966973
+aF-0.065032640077874043
+aF-0.021841107501475165
+aF-0.11629065823389129
+aF-0.10745856696286438
+aF-0.075864337491572009
+aF0.049936785629542943
+aF0.15619879824295907
+aF0.11426654118739148
+aF-0.04164325703106133
+aF-0.18459138854021614
+aF0.020090335181653159
+aF-0.062340457839723744
+aF-0.1508405333228898
+aF0.03797931323112097
+aF0.049269236947181307
+aF0.072614197542196154
+aF-0.022571006591697411
+aF-0.035388742616540347
+aF-0.017446086387622423
+aF-0.01477727630010401
+aF0.018443903308696562
+aF0.14277685169221338
+aF0.010132355635830433
+aF0.055156767481759419
+aF0.17632575933817657
+aF-0.028755929312239546
+aF0.061891308203607415
+aF0.024919614987087068
+aF-0.07197855066111282
+aF-0.21479395921623348
+aF-0.20166172670890611
+aF-0.029353635875443873
+aF-0.051788865031392364
+aF-0.034602211597310556
+aF-0.12000067646251812
+aF0.019253060882884386
+aF0.01762985486311416
+aF-0.061010172885885589
+aF0.064235100964646616
+aF-0.13928780038109934
+aF-0.089585533042703711
+aF-0.021333249194368877
+aF-0.11006818900338923
+aF0.10454243372279894
+aF0.12669861409093036
+aF0.02000037342338052
+aF-0.11904683573813117
+aF0.055845399300637588
+aF-0.21672289826114211
+aF-0.045347068774837809
+aF0.27147646941216608
+aF0.037230572727025985
+aF-0.09747658729717773
+aF0.075170619973478417
+aF-0.024022535453497394
+aF0.087764952014292158
+aF-0.030930520861569145
+aF0.11375963160646478
+aF0.085521570403032765
+aF0.018130027836889797
+aF-0.025368461123362121
+aF0.021688212561136601
+aF-0.01617619935056885
+aF-0.0067019179196910915
+aF0.059326050868915167
+aF-0.067522324374755791
+aF-0.067924418740172507
+aF-0.00064412956066938257
+aF-0.061611372824163436
+aF-0.1263830152585404
+aF0.073777841453974174
+aF-0.022521142763372703
+aF-0.13280802157396349
+aF-0.033453145248487519
+aF-0.012194502695457419
+aF-0.19787301290362988
+aF-0.11507795614984975
+aF-0.15391504435278744
+aF0.093960387529016295
+aF-0.01204700081950502
+aF0.094327849538079517
+aF0.047408542121791915
+aF0.040551172818206485
+aF-0.057591105037616191
+aF0.024156488566328512
+aF-0.11299227187336165
+aF-0.061371453859505952
+aF-0.056253085411093952
+aF0.016821930589098213
+aF-0.15215012858565732
+aF-0.11763233364319792
+aF0.0167647322849835
+aF0.12455420633608466
+aF0.031067453957930355
+aF-0.037533861826113617
+aF-0.0041166258993559704
+aF0.0065873155431801934
+aF0.16597110521193559
+aF-0.0061752823495857959
+aF0.079582468631965678
+aF-0.0067483505282747271
+aF-0.067896919902647151
+aF0.026229731090776417
+aF0.089162821628087502
+aF-0.14107438740291717
+aF-0.092465915558588435
+aF-0.016252923778101194
+aF0.039282305898183552
+aF-0.078339494298245424
+aF-0.055071133638965729
+aF0.052802359151763539
+aF-0.11317641516369061
+aF0.088812079377038763
+aF0.073183840654319876
+aF-0.054456897445780306
+aF0.055948759910867632
+aF0.10970157219852074
+aF0.02666671550528291
+aF0.072865588765081479
+aF0.010907297298841184
+aF0.0014044499857141974
+aF-0.0061712957107568894
+aF-0.084287168492835171
+aF-0.063353205133051829
+aF-0.0026120779459830067
+aF0.083782347160056017
+aF-0.050778352243772279
+aF0.12517436549185965
+aF-0.06898553106884743
+aF0.054679696229415556
+aF-0.11104123634084602
+aF-0.073531210307305556
+aF-0.04020052775877081
+aF0.018854215384806482
+aF0.15863113613205468
+aF0.0093247724511201276
+aF-0.034869168382521167
+aF0.043337715501156129
+aF-0.10164853147782818
+aF-0.0081684404914932531
+aF0.037791720028581291
+aF-0.025076923445044277
+aF-0.014240965623745452
+aF0.015219800926800453
+aF0.035697991390809099
+aF0.14221599010312022
+aF0.16928040275981268
+aF0.059081324507438492
+aF-0.11582756348756638
+aF0.030775160923186145
+aF-0.048068088028103167
+aF-0.088512426450381695
+aF0.059096152770960982
+aF0.041030641285688584
+aF-0.016424175460360287
+aF-0.032050972790676771
+aF-0.075137488792913126
+aF-0.15599262562488683
+aF-0.13802132182510918
+aF-0.099501497967098285
+aF-0.035214181262297632
+aF0.014842112970621482
+aF0.019448950691346882
+aF-0.10518953102545445
+aF0.059338999496764647
+aF0.036186145660405275
+aF0.12332299046287609
+aF-0.043248238133030061
+aF-0.0005642822946495406
+aF-0.044546057470140982
+aF0.060838920823669394
+aF0.092260909855835224
+aF0.042431576946535023
+aF0.23496328203278374
+aF-0.013589332447866096
+aF0.036407536815402645
+aF-0.16672617172773294
+aF-0.046285735240573792
+aF-0.1600783144894091
+aF-0.0091510809565981208
+aF-0.11156888978703662
+aF-0.057018677036310417
+aF-0.076493032996174382
+aF-0.013122181183092014
+aF0.080297278085604024
+aF0.1314245564979406
+aF0.03636951046889924
+aF-0.047538286773007768
+aF0.015199535954623649
+aF-0.065400438015545931
+aF-0.079970704911075122
+aF-0.11931898196846778
+aF-0.1615817963885863
+aF-0.005534858663651188
+aF0.056977732775431437
+aF0.017474977279779532
+aF-0.00068868222871107192
+aF0.0016989316921270619
+aF-0.047339250648454304
+aF0.15988202102080365
+aF-0.018647179945124447
+aF-0.11989761188078994
+aF-0.025669169045998391
+aF-0.048282504424823743
+aF-0.010299055676033406
+aF-0.033074578629890321
+aF-0.071569812093500051
+aF-0.14730880773943511
+aF-0.038105614814423323
+aF-0.1312175345165445
+aF-0.0081189057377445105
+aF0.076946516022511166
+aF0.20087002053953171
+aF0.044060486457657456
+aF0.034800014000183524
+aF0.089227130284174797
+aF0.036347794728549647
+aF0.10978396557052823
+aF-0.015771596018490274
+aF0.011082209841973709
+aF-0.055746720517846057
+aF-0.064362738519264856
+aF-0.050452262238833562
+aF0.068866724979258803
+aF0.0058949427060753911
+aF-0.15544077153240565
+aF0.15490467065651253
+aF0.055445632098017242
+aF-0.13094935474729463
+aF-0.031797805759427381
+aF0.017605638141093297
+aF-0.064900776847605063
+aF-0.009015677165866624
+aF0.028717317152062324
+aF0.087606027843657813
+aF-0.11908612593464568
+aF-0.087360934912493152
+aF-0.054538338525216105
+aF0.01447750047908085
+aF0.11400136999906689
+aF0.16413693797851017
+aF0.062842675285585875
+aF0.068831119131529825
+aF-0.012105797792438082
+aF-0.0084649560684905267
+aF-0.067826762758254874
+aF0.041812483258397322
+aF0.1049085352394634
+aF0.10985716627638997
+aF-0.023582551006749528
+aF0.01840576963004684
+aF0.053466506527030978
+aF-0.046500201772243219
+aF0.01946576330331445
+aF0.030119560406525168
+aF0.044189006351908935
+aF-0.052215529565619423
+aF0.11408310561316637
+aF0.082643702327128157
+aF-0.20157631115866284
+aF-0.092595351902511808
+aF-0.027610245429438171
+aF-0.17057558124234506
+aF0.13288982394623117
+aF0.019779878343450984
+aF0.054796690564769455
+aF-0.095739710563202005
+aF0.016702843720022439
+aF0.14384282514836819
+aF0.061545521533579083
+aF0.067182032792939259
+aF0.051146245585978842
+aF-0.0049509980245584706
+aF-0.093981100021881578
+aF0.18176529540679567
+aF-0.11467802504827994
+aF0.038741480310467098
+aF0.033159702531841535
+aF0.17572834558673328
+aF-0.027407543224982053
+aF0.12445287677037718
+aF-0.04258809764732701
+aF0.017767126023250038
+aF0.063984034675111892
+aF-0.080377531624257231
+aF0.051977000055399118
+aF0.14923698282993034
+aF0.0075243367679389593
+aF0.22002518272417992
+aF-0.057259250211893417
+aF0.23623605306560647
+aF-0.0014264026110324694
+aF0.023027715813956264
+aF-0.077488012866453404
+aF-0.16541677198780949
+aF-0.026907384444613741
+aF0.049872742131173473
+aF0.070273627960712959
+aF-0.14197627789973763
+aF-0.16295189306895741
+aF-0.037015639475495868
+aF0.0038124358270698461
+aF0.20485479422683522
+aF-0.026269376282158308
+aF0.015901324159782088
+aF0.080335984198454696
+aF-0.044563570878859503
+aF-0.094569326893292185
+aF-0.13498018926257177
+aF0.099590973780942754
+aF0.041125415974894136
+aF0.13948658844022743
+aF-0.038505130999862941
+aF0.085512794223961741
+aF0.1737269429074654
+aF0.051032957749205222
+aF0.0015139496359284235
+aF-0.13651501956920184
+aF0.10500840893836204
+aF0.057947331655385445
+aF-0.066180907119033502
+aF0.045010850610702813
+aF0.18094034628185204
+aF0.030038984011222229
+aF0.019641078955178828
+aF0.10918148455445278
+aF-0.0011434005921222093
+aF-0.1130270069027238
+aF-0.047160923345076301
+aF0.064051559528141983
+aF-0.077297412493438217
+aF0.11627696374053907
+aF0.02081770747911247
+aF0.010074394717554423
+aF0.032609988457247364
+aF-0.0059467833918880218
+aF-0.04902301833458788
+aF0.039783000153971501
+aF0.11017388303339844
+aF0.13858104496919635
+aF-0.059576749305072271
+aF0.068430444944692442
+aF-0.087096543685438982
+aF0.1097338119460885
+aF0.0012656390174823624
+aF0.018539524695327485
+aF0.14522616337109251
+aF-0.17621929892560381
+aF0.009571906524898274
+aF-0.092101354526515633
+aF-0.13209724016473276
+aF0.054032563996613797
+aF-0.034295728850524392
+aF-0.03418969314570483
+aF0.0071271181249787747
+aF-0.036904333551751656
+aF-0.047693246342666973
+aF0.074432919613793863
+aF-0.069057479358073326
+aF-0.021901298186428612
+aF0.041816744006189413
+aF-0.068043967778948569
+aF-0.00070601544350480975
+aF0.053198891727609054
+aF0.013086859960303046
+aF0.21876763635724522
+aF-0.11072986921392884
+aF0.086763820858365634
+aF0.065933350316867895
+aF-0.070687981106195424
+aF-0.049731168043798686
+aF0.0055662897508956359
+aF-0.0010461992090408613
+aF-0.0065261120634650715
+aF-0.13212068435617647
+aF0.14432914600174751
+aF-0.039755589177722407
+aF0.0080207946951718449
+aF0.024334901684386595
+aF0.077933161671949414
+aF0.043243990209341679
+aF0.020805801038295768
+aF-0.11872131591312268
+aF0.08219003289222708
+aF0.135096991028858
+aF-0.12189155281176342
+aF-0.13005597046444525
+aF-0.0063330915812549529
+aF0.006905278181827304
+aF-0.0714810410386503
+aF-0.047864275914533939
+aF-0.00239105326424011
+aF-0.10542802641028878
+aF0.062139401910918816
+aF0.0050505554731195678
+aF0.012642853338764004
+aF0.1352800372696647
+aF-0.065887136994321055
+aF0.13141626671591206
+aF0.089431975573895678
+aF-0.014127194362040683
+aF0.026658640521277664
+aF0.12033634216681247
+aF0.02774911739971328
+aF0.040320877381008757
+aF0.033802174546835533
+aF-0.0061686830346991883
+aF0.11145358925513027
+aF0.082928277135227532
+aF0.14598279002799822
+aF-0.034950625110999202
+aF0.047906058063113259
+aF0.062716802520371595
+aF0.018661015068952951
+aF0.11128602042569592
+aF0.053332880702688094
+aF-0.093923550981758461
+aF-0.037892091252976899
+aF-0.061542055138776496
+aF0.030012260878746581
+aF-0.042958816995269468
+aF-0.17833363035550301
+aF-0.056344976082441836
+aF0.1229251049586929
+aF-0.027957453549059132
+aF0.22903643297871723
+aF-0.13859298409387094
+aF-0.045464025601946789
+aF0.046387802920688379
+aF0.12652724660815373
+aF-0.0385907525643161
+aF-0.042080916901400048
+aF0.10471242190426343
+aF0.003469302835174042
+aF0.063447214089157516
+aF0.10433123595673768
+aF0.025846465598982474
+aF0.091362138885425034
+aF0.064861480791600298
+aF-0.11186017406424642
+aF-0.043163908298280235
+aF0.047056901027637855
+aF-0.16594696212785112
+aF-0.064463252809937824
+aF-0.20716707643514506
+aF-0.055894112420909893
+aF-0.0097297858442645605
+aF0.025437591301385478
+aF-0.049505024461236245
+aF-0.26055985662010733
+aF0.13148105375735658
+aF-0.034532453567345939
+aF0.12105895118270313
+aF-0.11471369210731686
+aF0.076629102383882583
+aF0.045917175333841473
+aF-0.039419541082836206
+aF0.20602515351017334
+aF0.17127505692769077
+aF0.067585651184054685
+aF0.0026275473385181697
+aF0.045838129559369646
+aF0.05797569433864299
+aF-0.050018399706294472
+aF-0.022131990528191613
+aF0.12860116343836114
+aF0.085384834173546975
+aF0.02572085732839572
+aF-0.069263522763915633
+aF-0.041638117881924681
+aF0.073534730420493674
+aF0.030583973692698923
+aF-0.0068129954400385087
+aF0.063517878779181219
+aF-0.15190428264301695
+aF0.10284454596076188
+aF-0.0051305898168892087
+aF-0.033273756202930958
+aF0.051671000918714939
+aF0.054555943048633315
+aF0.086424317595873462
+aF0.079211749472967719
+aF0.1041463369780436
+aF-0.021148839298916557
+aF-0.059981436811466178
+aF-0.050338213531734954
+aF-0.022235928378233065
+aF0.105355573835343
+aF-0.13129969459845792
+aF-0.032785484923501099
+aF0.023319947437186638
+aF0.070032697899465174
+aF-0.083012983071170429
+aF-0.0088411902079527181
+aF0.010837701391339166
+aF0.0053017946396145517
+aF0.031502397310720839
+aF-0.0088128550245095329
+aF-0.059065312256890379
+aF-0.03279077617109448
+aF0.0013676494536718306
+aF0.11606742390581588
+aF0.035338491274413963
+aF0.0058271317069686626
+aF0.024938120088625674
+aF0.040064849918990585
+aF0.15112156086572828
+aF0.022088989203976773
+aF0.12806366693813345
+aF0.026869260022235233
+aF0.068109999036359489
+aF0.049240376024558601
+aF0.15076975100167508
+aF-0.07952015812810817
+aF-0.077705878533295109
+aF0.031873835966120437
+aF0.077121596893619609
+aF0.01307569117065293
+aF-0.017145828619142961
+aF0.12619702803381153
+aF-0.052696015667808155
+aF0.068624071164436001
+aF0.16350287609613956
+aF0.03357356241578742
+aF-0.073020389591259172
+aF0.20615402846532951
+aF-0.071250276948019484
+aF0.023773684764816422
+aF0.069546273414915039
+aF0.10408237903911166
+aF-0.0053883717544810769
+aF0.054698791965274399
+aF-0.15015373410417304
+aF0.0050532490881743837
+aF-0.064439867077920446
+aF-0.14333690180899283
+aF0.093557754857865008
+aF0.12397540095471088
+aF0.020023656408213419
+aF-0.093050700129020322
+aF0.20473809953064015
+aF-0.034086873092778865
+aF0.077490439682654483
+aF-0.011525195546458956
+aF0.1114035021156886
+aF0.027326398021174318
+aF-0.040392342550446034
+aF0.0064561740610256475
+aF-0.0089132482634759255
+aF0.12011954388473595
+aF0.060009237660788958
+aF0.031188204161903394
+aF-0.05110283625319012
+aF-0.072232936090469962
+aF0.055534406101622143
+aF0.12462679490013441
+aF-0.068697513168427635
+aF-0.10817924270969785
+aF0.14599583892746293
+aF0.0086361139002748225
+aF-0.06798491050082546
+aF-0.10603289371503688
+aF0.10492069434700382
+aF0.12954178229736174
+aF0.15062888897443322
+aF0.053503768130484068
+aF0.0070577871139420089
+aF0.18141045129124281
+aF0.10710369020056738
+aF-0.14840134920816336
+aF-0.0012234276184989858
+aF0.20921981231497672
+aF-0.056724236834710035
+aF0.022033851747340617
+aF-0.031562049592165881
+aF0.11177314854268434
+aF-0.055361372480918582
+aF0.0052709246188267396
+aF-0.062379633056702778
+aF-0.015201200563663499
+aF0.091947365115619795
+aF0.011606182181487682
+aF-0.0013231007994532857
+aF-0.079555439479323115
+aF-0.12529658729593857
+aF0.030680709734648849
+aF0.040502148867473095
+aF0.027273879010424051
+aF-0.15916108841124027
+aF0.057687843234500352
+aF0.01978503757339773
+aF0.10507111102868678
+aF0.010652219857997457
+aF0.01523482924419089
+aF-0.051290720230629999
+aF-0.087893316070213223
+aF-0.025030591448970643
+aF0.12343412464934823
+aF0.15279918211996585
+aF-0.11304978302523035
+aF0.032827605250904404
+aF-0.0019334715866813482
+aF0.0093751815168604518
+aF0.068901570323773614
+aF-0.085540806021560431
+aF-0.085157087639798693
+aF0.023986230055884412
+aF0.024561990867361789
+aF-0.020963215828865334
+aF-0.018553022531374221
+aF0.076181277180358553
+aF-0.054440111868013084
+aF-0.015296220441686827
+aF0.060857134485161682
+aF0.025548362900100666
+aF0.13129908668318563
+aF-0.0037504068788064482
+aF-0.0025134766896098997
+aF-0.03239125800742329
+aF-0.046956311689330496
+aF0.079035562956049285
+aF-0.11154311272018648
+aF-0.025559660131229671
+aF-0.22036586336413011
+aF0.066126813923529718
+aF0.051111015471417796
+aF0.07992061052461355
+aF-0.086796627787950817
+aF-0.0057499013539242493
+aF0.0069307848478209174
+aF-0.14979001463013944
+aF-0.15099689282693654
+aF-0.055977870275147674
+aF0.11455894108654448
+aF0.18109902091080474
+aF0.014138147946993125
+aF-0.1445513119248315
+aF0.023441160629532477
+aF0.033442612957205332
+aF-0.0083544644568920995
+aF0.014957571688001596
+aF-0.15579403723262819
+aF-0.12734849773147863
+aF0.069442950814919788
+aF-0.019884196979826078
+aF-0.13830976965717573
+aF-0.026951512593014825
+aF-0.067501009967269834
+aF0.058558799242612272
+aF-0.003561177310472076
+aF0.027468818776133278
+aF0.042932063105236798
+aF-0.087193042560570908
+aF0.0084283238865058077
+aF-0.0098629819518493284
+aF0.058426447603696363
+aF0.15964565289906194
+aF0.027586937001231524
+aF-0.008071135692638268
+aF0.0026424057269274544
+aF-0.052031494457894109
+aF-0.1467579509858736
+aF0.040585532577076783
+aF-0.037962790099218227
+aF0.032790088153848748
+aF0.0044892888412030813
+aF-0.041205205556582747
+aF0.020723864026545798
+aF0.06089071498620479
+aF0.013010867267699896
+aF0.011340709518262054
+aF-0.085294573423006032
+aF0.11074878848297351
+aF0.10165027322656721
+aF-0.21847949931713775
+aF-0.17685212469530345
+aF0.032732214086609548
+aF-0.072989207595781661
+aF-0.10433497308751709
+aF0.22392329538825023
+aF-0.07666585730473402
+aF-0.1037018070012635
+aF0.025702533631265817
+aF-0.061890003476203694
+aF-0.096939905067002827
+aF-0.11979568314013399
+aF-0.050168116461114076
+aF0.043985854792137097
+aF-0.12654488764821717
+aF-0.0073481759028209345
+aF-0.0010698147751529716
+aF-0.029318209092495943
+aF0.083609107235781979
+aF0.054528516234050729
+aF0.24752226384892523
+aF-0.10584194668854276
+aF0.013318545224811365
+aF0.066860556332338769
+aF-0.048919044573621499
+aF0.044727309528119236
+aF0.14170870524600412
+aF0.067822353998618301
+aF0.074918197506626399
+aF-0.01900406112389046
+aF0.02517579830066639
+aF-0.044165556833188478
+aF-0.013169740429092119
+aF-0.008349657545852247
+aF0.084529644284431035
+aF0.036829790728294544
+aF-0.0021803457011865149
+aF-0.032206832948435682
+aF-0.020547752050636751
+aF-0.098766167303695307
+aF0.064137047337687311
+aF0.098685481144529963
+aF-0.086757753035005991
+aF0.14424292491166893
+aF-0.041890762728008853
+aF0.014640844305994865
+aF0.030013611500232285
+aF-0.020875178524990653
+aF-0.012354381080988136
+aF-0.099096228629806812
+aF-0.0018658699693476994
+aF0.052411106114578693
+aF0.15816847796746139
+aF0.0069404872125397093
+aF0.13630892422983251
+aF-0.032268896002916825
+aF-0.11016546141649186
+aF-0.061369593772120208
+aF-0.047893383181420127
+aF0.05269816843546915
+aF-0.11320725059711546
+aF-0.010435809748659271
+aF-0.093485087889862775
+aF-0.23338540370957814
+aF0.021363348505271076
+aF-0.072744807404919801
+aF0.096244213579992438
+aF-0.025253487129159018
+aF0.097852060372186758
+aF0.088675326558720596
+aF0.1802941041014951
+aF-0.055589610542498953
+aF-0.096837996665419548
+aF0.080449566688499494
+aF-0.034298449700141218
+aF-0.032579397436736227
+aF0.040860627772090118
+aF0.037618535462645257
+aF0.032305679219851745
+aF0.093445545185463857
+aF0.072600589611254332
+aF-0.099901627027582415
+aF0.034074770002985429
+aF-0.049524697653087514
+aF-0.083030571194750685
+aF0.0097574984683246289
+aF0.0058042471478626755
+aF-0.044919403247434965
+aF0.045869785890580571
+aF0.057789075488800107
+aF0.045653854164185582
+aF-0.043235459536005591
+aF-0.11207469264354167
+aF-0.051765266931553006
+aF-0.047920979079519761
+aF0.0073050121396616447
+aF0.058618239283889761
+aF0.18087703540260719
+aF-0.00024277330449130619
+aF-0.0075888325188455136
+aF-0.021614692373470995
+aF-0.074106542937693171
+aF0.035851398417501824
+aF-0.011308193087751193
+aF0.045739809095341144
+aF0.074187823198431285
+aF-0.10602765519924898
+aF0.073606266935643871
+aF-0.068223030611107988
+aF-0.063805443512156571
+aF-0.063222156271455721
+aF-0.026249196698221126
+aF-0.12900997595108368
+aF0.070064636476703093
+aF-0.051962637578769823
+aF0.081355708214592204
+aF0.16724920400391877
+aF0.025003435815136695
+aF-0.033284875521517092
+aF0.048821019534575634
+aF-0.09675756436619258
+aF0.0051767789035272295
+aF0.0010441644342627772
+aF-0.014251271665160117
+aF-0.058266231031919684
+aF-0.08397692859375247
+aF-0.0042182773610753019
+aF0.060974764946906644
+aF-0.023995149336591234
+aF-0.12079369782583743
+aF0.039125269686408046
+aF0.092524567598659055
+aF-0.088524382440316809
+aF-0.24098144167566674
+aF0.084500304590187814
+aF0.0064877652913161738
+aF-0.15824238114092493
+aF-0.052015763385524154
+aF0.099125536328423622
+aF-0.048743579670089666
+aF-0.022446537663845936
+aF0.00040030022701921709
+aF-0.003340782146976101
+aF-0.042841880749831182
+aF-0.098148873011380644
+aF0.060222582577696804
+aF0.061726792948278368
+aF0.073485332860663541
+aF0.2061229651066685
+aF0.0093419098741053409
+aF0.0022420735089034379
+aF0.082253885074872718
+aF-0.00044586489111074598
+aF0.11948618144546506
+aF0.14901215061100626
+aF0.07502199973148721
+aF0.096710322732612194
+aF0.0341804393843761
+aF0.016191707688190254
+aF-0.058798395035022238
+aF0.00093553367325094751
+aF-0.093720026108900165
+aF0.16173798904759176
+aF-0.014021860102841876
+aF-0.062087714371976639
+aF-0.083984612791904709
+aF0.075809828925531481
+aF0.037995961591287028
+aF0.075378643803652903
+aF0.090986245948041278
+aF-0.0088782885791222291
+aF0.13116548519145665
+aF0.014396750559270389
+aF0.068158784086680205
+aF-0.14614514359624745
+aF0.014761171691388363
+aF-0.04103563090057933
+aF-0.062019690562370722
+aF-0.18072053126198323
+aF-0.15346384472942995
+aF-0.0044366935815059001
+aF-0.0073081830393441497
+aF-0.10085348117103896
+aF-0.063928187780511167
+aF0.080300300538176772
+aF-0.015481283065111057
+aF-0.0056174830040653049
+aF0.076717922511472816
+aF0.12361226748358731
+aF-0.094770970196496468
+aF0.15371214535455696
+aF0.012779271665564576
+aF-0.023989243181445418
+aF0.13988007271292791
+aF0.056488567225205948
+aF-0.02936091032031115
+aF-0.022382700446627182
+aF-0.054621114865954265
+aF-0.076762216602686395
+aF0.060752567690271542
+aF-0.00062190250508732268
+aF-0.23860918715606941
+aF-0.012676912121993336
+aF0.048953937377515584
+aF0.063841331519094491
+aF-0.014155231533196191
+aF-0.049320261772552318
+aF0.031005105960339958
+aF-0.046531637028968287
+aF0.049059234557044265
+aF-0.16579214906114037
+aF0.044250214739530933
+aF0.13572748530086495
+aF0.062098697183810551
+aF0.047110425167358826
+aF-0.068946952604527545
+aF-0.045688612099235186
+aF0.11086805951540255
+aF-0.040907951030653526
+aF-0.14855408953374455
+aF-0.078544872902469462
+aF0.078194755348481096
+aF0.0034756649143118335
+aF0.035064686292288927
+aF0.050628091170084294
+aF0.1631194483389837
+aF0.060535514409109432
+aF-0.19601570981990263
+aF0.11704258583096482
+aF0.11788922308353303
+aF-0.038477214405094683
+aF-0.053261089617826662
+aF0.086738278574960526
+aF-0.041461676690827592
+aF-0.034111668919723941
+aF0.11865042585090992
+aF0.023783031761255121
+aF0.15944064278459366
+aF-0.06778792339688168
+aF-0.047530165596747574
+aF0.14486047209232189
+aF-0.054660237353212099
+aF-0.12058427072223894
+aF-0.064080402183069457
+aF0.013352882943200379
+aF0.032072225656970446
+aF0.01514533050804205
+a(I50
+I20
+tp6
+S'd'
+p7
+tp8
+Rp9
+sS'A0'
+p10
+g4
+((lp11
+F-0.33236911219158921
+aF-0.79703227835827628
+aF-0.20372554728732137
+aF0.13939855560831993
+aF-0.51156643333612128
+aF0.64767061820678473
+aF0.65758757746604812
+aF-0.15527744911247962
+aF0.30308544785884917
+aF0.27002323797135236
+aF0.038517847134462421
+aF0.55272726536563654
+aF-0.82934482432193379
+aF1.7435364698118763
+aF-0.0077497294047206089
+aF-0.08283571514259129
+aF0.038254910583614812
+aF0.025482190508746776
+aF0.076922791161107368
+aF-0.3438441796976946
+aF-0.26185210648914187
+aF-0.55417742336063314
+aF0.12367191470607991
+aF0.9014197180792719
+aF-0.14178699136287565
+aF0.5544777553122171
+aF0.57652246717331357
+aF-0.32403228003045664
+aF-0.55620594794914757
+aF0.33417609901187567
+aF-0.14508493328295438
+aF0.1716793424135884
+aF0.14889172624180408
+aF0.22505790202557141
+aF0.66759323308899599
+aF0.74250775431593419
+aF-0.097937946253113806
+aF-0.53758308552072842
+aF0.32973208718932079
+aF0.0010831611631716112
+aF-1.1644800496295651
+aF-0.11533738887763249
+aF-0.83512811756253802
+aF0.74788561065515469
+aF-0.28076547598512774
+aF0.043413561690396944
+aF0.18959436584054407
+aF-0.21499665426398107
+aF-1.0103534185971659
+aF-0.089113147278169422
+aF-0.09427527453627188
+aF0.50742093717453596
+aF0.034650396059268333
+aF0.65268282155369794
+aF0.38008459263530014
+aF-0.39060727007059659
+aF-0.018032009876167286
+aF-0.53006021531497227
+aF0.03973776649467009
+aF0.054784097596902434
+aF-0.1128922443884332
+aF0.067204252822741561
+aF0.44359821402253452
+aF-0.82127367505096505
+aF0.040950228242117845
+aF0.057873686823909379
+aF0.41387279131804572
+aF0.14810036925648801
+aF0.074232786229760567
+aF0.17671964609189639
+aF-0.036517192343637171
+aF-0.039107211338940455
+aF0.16920569487366222
+aF-0.031184549829823438
+aF-0.41795459720529515
+aF0.13721199927014835
+aF-0.051173192628256516
+aF0.041083079721396069
+aF0.4349356885221386
+aF0.10532637448906325
+aF0.24913674330355334
+aF0.03257709314654416
+aF0.35373662130497124
+aF-0.55776584189625467
+aF-0.0972613325715318
+aF0.27394034863535321
+aF-0.28557064925287023
+aF-0.37094006465511498
+aF0.21752359933381146
+aF0.043417192733970301
+aF0.31922217039518669
+aF0.042378854073401723
+aF-0.30415560800416624
+aF-0.44962354425221784
+aF0.016934220927334563
+aF-0.16445278057120388
+aF0.26963349345225474
+aF0.0039037226921592484
+aF0.18518209527942095
+aF0.21397927331888059
+aF-0.36058038972230411
+aF-1.3006537733927654
+aF0.12984648950636676
+aF-0.49158787775340385
+aF-0.29379094719974275
+aF0.047481297613304815
+aF0.08465235749369962
+aF-0.12256259240842024
+aF-0.52040063853966168
+aF-0.18949095232434524
+aF-0.13953944911831717
+aF-0.85614988845089413
+aF0.25887420679427242
+aF0.10276393358034562
+aF-0.32607282558736456
+aF0.30789107634008073
+aF-0.56822996927208391
+aF-0.69868020289789257
+aF-0.36588294487821721
+aF0.39864464758339924
+aF-0.10042868795281731
+aF0.12247725593204037
+aF-0.44818525539859139
+aF-0.50950728487152719
+aF0.083526634653080314
+aF-0.7102268232672907
+aF-0.47377296180734962
+aF0.32895397297381707
+aF0.22709844620795272
+aF-0.57115336944030581
+aF0.32542683409763173
+aF0.098132152834769226
+aF-0.42842319948411195
+aF0.99364559164172483
+aF0.33401289528467643
+aF0.50116534561251502
+aF0.58030646018812915
+aF0.21604654133247833
+aF-0.46193736375129918
+aF0.28749659011065881
+aF-0.26485105421461541
+aF-0.41398278510122394
+aF0.8784805001159427
+aF0.75033617721995582
+aF0.029438819564361098
+aF-0.11335754810649193
+aF-0.35336185854175028
+aF0.3915389324579383
+aF-0.52008447403615188
+aF-0.59868410455989318
+aF-0.065739733792704716
+aF-0.21974521501180577
+aF0.45261507947490276
+aF-0.75701707668470986
+aF0.07959334045679882
+aF-0.33435977837840752
+aF-0.33261985831639218
+aF1.4696731206490903
+aF-0.2530789212785059
+aF-0.54139304668069088
+aF0.18903407388928226
+aF-0.90212406124586186
+aF0.21608670457548546
+aF-0.76701420283161847
+aF-0.060114940895396859
+aF0.603112193368465
+aF-0.013306650995067833
+aF-1.3459322723376863
+aF-0.16977954985635116
+aF0.86408421606832941
+aF0.78080376397629536
+aF-0.22325393493764617
+aF0.27826154387223684
+aF-0.50640646636939302
+aF-0.0015880688968439565
+aF-1.1494870828850889
+aF0.058584598233548953
+aF-0.25414046801918611
+aF0.35953712890414996
+aF-0.70759790678082091
+aF-0.03400113407400171
+aF0.48137185093683826
+aF0.063442188601197644
+aF1.2582555051256989
+aF-0.54798395627051477
+aF-0.87608778139220767
+aF0.73783062037277158
+aF0.46578323019754903
+aF-0.89994319638532572
+aF0.081834123567553888
+aF0.91980845386355614
+aF0.38734690431425911
+aF1.1566215904462682
+aF0.50117636787657316
+aF1.1912295516829514
+aF-0.046726333991985419
+aF-0.66765920059408868
+aF0.16008344053842999
+aF0.7568539239800085
+aF-1.0018743257567908
+aF0.2099962485773878
+aF-0.51469114815714634
+aF0.093090543532692374
+aF-0.60269265541804473
+aF0.10246950753249626
+aF-1.0644419942065799
+aF-0.38733829737687753
+aF0.53033794389028677
+aF-0.4024739117730568
+aF0.52868078477237801
+aF-0.41215984968676683
+aF-1.3284052908096988
+aF-0.51949841142170483
+aF0.42088678124005624
+aF-0.54668645947595595
+aF0.35721059453774384
+aF0.88282118691419498
+aF-1.2966457276723009
+aF-0.52612197297586993
+aF-0.18229981152823777
+aF-0.47623279958278686
+aF-0.27586996854346407
+aF1.1274941252453545
+aF0.09211966564578962
+aF-0.00090258407439790418
+aF-0.62018800054550804
+aF0.19671529195554746
+aF-0.41950256499885785
+aF0.6176333278441567
+aF-0.31637044065822134
+aF0.63788552247247565
+aF0.64983096857787526
+aF-0.014477027731550216
+aF0.82405985454360919
+aF0.77995729889745347
+aF0.66723442596292026
+aF0.44675925299386393
+aF0.38388942955731969
+aF-0.5463495607861778
+aF-0.080718603962890337
+aF0.42716286921418445
+aF0.10772688298432206
+aF0.35659366458239511
+aF0.71210587744927245
+aF1.2039087132404789
+aF0.25195282612031489
+aF-0.19689831913854355
+aF-0.27886058708414607
+aF0.45070638897847515
+aF-1.4589162365756372
+aF0.74143709542244096
+aF0.12262151901826422
+aF-0.049584651529000871
+aF0.62368797580448043
+aF-0.38887684116765348
+aF-0.3103632649830228
+aF-0.79389272724360327
+aF-1.083922811820194
+aF-0.89644009480218623
+aF0.010675695976383324
+aF-0.35235871589270873
+aF-1.1317446004117653
+aF0.58824840323505723
+aF-0.63223869302764368
+aF-0.50564294228589235
+aF0.098825499086337809
+aF0.40018549544001769
+aF0.27501961539957837
+aF-0.60279111152047871
+aF-0.84947094700656389
+aF-0.89623336246436802
+aF0.22282761719322269
+aF-0.50141919512356359
+aF-0.21727423639331969
+aF-0.88222568550417457
+aF-0.58384227311424985
+aF-0.35473320904263145
+aF0.0068181322635614333
+aF0.3008811969557813
+aF-0.3295478739129486
+aF0.82433579333628415
+aF-0.48040855938749344
+aF-0.67262194791019914
+aF-0.53632879812737533
+aF0.051622265913358154
+aF0.35561880020807046
+aF0.4599468764410008
+aF0.54871601951288884
+aF-0.61056807509935584
+aF0.06697994849776201
+aF0.22087457235136618
+aF0.26388567718428096
+aF1.1843446118511902
+aF-0.48161645234123934
+aF-0.72867519671826997
+aF0.81302511631138441
+aF0.088134050129641511
+aF-0.5636515009024472
+aF0.34686619296313215
+aF0.40947395161422223
+aF-0.3558287680895772
+aF-0.16702390415818791
+aF0.11234231894431576
+aF-0.26548844159025631
+aF0.54905850778637622
+aF0.36153697523141798
+aF0.57641196100935399
+aF-0.38272963285610873
+aF0.28880207304816147
+aF-0.037399069930135108
+aF0.071470306572823161
+aF1.465500078772592
+aF-0.53672096285299031
+aF1.5107984906253049
+aF0.90727119476890739
+aF-0.6905553651072841
+aF-1.3648646383703178
+aF0.21464625994636058
+aF0.26073179718601652
+aF0.20847671626183706
+aF0.50726185388241696
+aF-0.49134753246606799
+aF-0.65945872077830781
+aF-0.0048850353557923195
+aF0.36270844858561541
+aF0.63084630348459103
+aF0.37001958974693977
+aF0.26999301400534853
+aF-0.77639042463703933
+aF0.78182782607893975
+aF-0.20123224512179194
+aF0.24990160288827518
+aF0.33183700536438587
+aF0.033303136344004572
+aF-0.085792399439643952
+aF-0.064942911986190011
+aF-1.0458834518960205
+aF-0.1415245789467475
+aF0.620156014370708
+aF-0.39134911488662899
+aF-0.77435343586755245
+aF-0.5036471512355597
+aF-0.67085461489604736
+aF0.33172606361283269
+aF-0.28629772705247675
+aF-0.71350964912660153
+aF-0.048028266764070154
+aF0.31468361533204775
+aF-0.62784781700531744
+aF0.70337283664003647
+aF0.39281124652648536
+aF0.85899657499118076
+aF-0.056042760232306033
+aF-0.48736177317759166
+aF0.26589901716098041
+aF-0.52503247906918615
+aF-0.78232709263502653
+aF0.30703003160446757
+aF-0.92859484822656246
+aF0.44386580935286807
+aF-0.464699288299458
+aF-0.99427346407075512
+aF0.99084447027223244
+aF-1.3185395906417607
+aF-0.54668080329375079
+aF-0.063871980647011328
+aF1.3492475675898334
+aF-0.29654147616475707
+aF-0.46895457764635928
+aF-0.5618291334286768
+aF0.49708541834596709
+aF0.90902975046680434
+aF1.0135070622106896
+aF-0.42238884810540483
+aF-0.24398978640135668
+aF-0.58694051258307289
+aF-0.099386636059589833
+aF-0.4058614147846607
+aF-0.1098244905104958
+aF-0.56380016969485436
+aF0.55538015610477187
+aF0.71991604038545565
+aF0.041312123560049145
+aF-0.19087917046566558
+aF0.15809868753944228
+aF-0.46304038179823648
+aF1.0046439578442692
+aF0.62900263452272953
+aF-0.97062108609687392
+aF-0.20514239491422365
+aF1.3301380754312131
+aF0.44874835028212134
+aF0.51490820725005515
+aF-0.76863554213560681
+aF0.40192522564003408
+aF0.65921746666073078
+aF-0.083214685157649862
+aF-0.69038434825838446
+aF0.57748145707426246
+aF-0.63015543316830069
+aF-0.26130864398261994
+aF0.13318180108952546
+aF0.67420308657842021
+aF-0.42290229393798368
+aF-0.19115430675965789
+aF1.5617240034958892
+aF0.53886128355696161
+aF0.43526210610579191
+aF0.61475581335039542
+aF-0.6227917587503482
+aF0.52176372701567364
+aF0.91493795716749182
+aF0.29984478194923925
+aF-0.21590171724947502
+aF1.159303041585988
+aF0.23254638970550606
+aF-1.8019793177778705
+aF0.41486856596376037
+aF0.84517765164167591
+aF0.63477683350091996
+aF1.5081884998767379
+aF0.74130023682203361
+aF-1.0616786862675232
+aF-0.98582549991022195
+aF1.3595009978625159
+aF0.277646308588546
+aF-0.25875640485683105
+aF0.093429869076259692
+aF-0.98572952768109146
+aF-0.026140292298743564
+aF-1.207110673762644
+aF-0.23347907530843007
+aF-0.30078849427711973
+aF0.43932411795991527
+aF-0.22379972307898041
+aF-1.4105159138356456
+aF0.2416586248988338
+aF0.11267852308998139
+aF0.96502917834863511
+aF-0.67488263312405117
+aF-0.55431257497597275
+aF-0.42795131427997835
+aF-0.17177115223556511
+aF-0.26538340091211032
+aF-0.42324465765920338
+aF-1.5280058697398644
+aF-0.38076375407118646
+aF0.48787398495758733
+aF-0.46571938357781445
+aF0.38860004955997501
+aF-0.10266314714548819
+aF0.43865109396575597
+aF-0.20102214660419518
+aF0.018339150310398161
+aF0.29666659141616825
+aF0.11487735278896487
+aF0.23771462984846237
+aF-0.45047587998114125
+aF0.1839924676431125
+aF0.25897436977195704
+aF-0.11046444973288277
+aF0.72812255317798347
+aF0.084613134721782279
+aF-0.033087320488508168
+aF0.15632344382835081
+aF-0.77858300766824573
+aF-0.18652922874830691
+aF0.77144168398563273
+aF0.40930734088154364
+aF-0.13266727525274122
+aF0.016808652256509439
+aF0.27238812059872708
+aF-0.19293425454716925
+aF-0.043335869700804636
+aF0.20654690754199453
+aF0.70116298840277524
+aF-0.57732320720285046
+aF0.20729314060106288
+aF-0.56810386765861021
+aF0.47858889944502292
+aF-0.73291004383064207
+aF-0.14456064732576696
+aF0.14839592965777187
+aF-0.61545773832772888
+aF-0.1053514890287463
+aF-0.48146092022151804
+aF-0.58870419938960716
+aF-0.34858553556488753
+aF0.41534337752233774
+aF-0.19658413091515811
+aF0.25208032379831602
+aF-0.067154357915307536
+aF-0.99607425646604986
+aF-0.46219734336884138
+aF-0.48919026554337069
+aF-0.12225344102247154
+aF0.18856934256870422
+aF-0.06749209194312232
+aF-0.25625565526454025
+aF0.50277622247763976
+aF-0.64433525275847026
+aF-0.20177441574164595
+aF-0.76060550922668635
+aF-0.52134284866502489
+aF-0.15421989311502865
+aF-0.15906084650024677
+aF0.21584817610729373
+aF0.85673621058676608
+aF0.43691378574919681
+aF0.3328456471106282
+aF0.18600394904312822
+aF-0.39415135673213064
+aF-0.12255916544625428
+aF-0.66939576526948441
+aF-0.32886498596357805
+aF-0.010188972176272982
+aF0.93284659621930288
+aF-0.067498126210697687
+aF-0.13644973678811628
+aF0.18111934163024626
+aF-0.032180576383043891
+aF0.28458249277238357
+aF1.1405285085570729
+aF0.15220507416858223
+aF0.48808540446994847
+aF0.14414485950691175
+aF-0.024731592735728065
+aF0.25976109255702329
+aF0.59996225692226823
+aF-0.3245954727017813
+aF-0.17906532838763536
+aF0.25772733880535476
+aF0.55608281760816691
+aF0.54056889515282225
+aF0.070458108817025383
+aF0.2917848930926798
+aF-0.0074846001493192784
+aF-0.089234166035346368
+aF0.0097579208229841598
+aF0.73550810636016462
+aF0.049002472199705716
+aF-0.43357105682508773
+aF-0.094255900555691968
+aF0.3193510841957764
+aF0.38067583462067139
+aF0.70533924388869695
+aF-0.052393432962281494
+aF0.36505681457317607
+aF-0.44206553716320218
+aF-0.59905919474311853
+aF0.11337864420001242
+aF-0.98329889964088046
+aF-0.68441867809080914
+aF-0.25676799768707725
+aF-0.99396635548732815
+aF0.37922476678294736
+aF-0.20476193482851432
+aF-0.48274104112571553
+aF-0.57096945980747649
+aF-0.40315993063483713
+aF0.078835537029294037
+aF-1.5473551711451718
+aF-0.050808102248647791
+aF-0.72215441715526596
+aF-0.12436862193703513
+aF0.42333237558442816
+aF-0.1034866561550655
+aF-0.17567804168499049
+aF-1.1627129840612267
+aF-0.02252359939772124
+aF-0.56652898623071379
+aF0.18036939349713302
+aF-0.42969835748825713
+aF-0.60774017859406548
+aF0.14226621977845164
+aF-0.44057323314868846
+aF-0.46526751277379813
+aF0.5565775462138054
+aF0.78695501145391045
+aF-0.89815700574207158
+aF0.1598199079448874
+aF-0.48799974257136808
+aF-0.17192804389833377
+aF0.54058935760962445
+aF-0.031356942657323139
+aF-0.0045221640554677679
+aF0.065190056374489685
+aF0.68742738034345385
+aF-0.38632043117353165
+aF0.36755650934489842
+aF-0.6183073335775644
+aF-0.071752367593108837
+aF1.6401259808034112
+aF0.36996802826669301
+aF-0.68877338278383615
+aF0.53698266582077803
+aF-0.61233405111800665
+aF0.15290292475309594
+aF-0.82767731844141068
+aF0.095714970450050063
+aF0.36169348207787555
+aF0.78084570939325948
+aF0.74564181446614319
+aF-0.074283929240185606
+aF0.33649647764102703
+aF0.746573869848841
+aF-0.13064634514836129
+aF0.16415065700384612
+aF0.42641408416003607
+aF-0.47292383514956154
+aF-0.035854291556667188
+aF0.90224185648281308
+aF-0.027148583131637868
+aF0.34148346346791242
+aF0.89381995310918394
+aF0.038256097479064562
+aF-1.0073527989287874
+aF0.29883633405273285
+aF0.39253158011855893
+aF-0.0014667357240155897
+aF1.1274248401774249
+aF0.11581116067164082
+aF-0.67941847856207305
+aF-0.11721189657491841
+aF0.64493225884308536
+aF0.27906613502435773
+aF0.30738418403850026
+aF-0.16078634446093829
+aF-0.64294845563625869
+aF0.44925476968453198
+aF-0.4670833454082931
+aF0.058800389459325607
+aF-0.22606510392236415
+aF-0.2782771739956299
+aF-0.31961432185003286
+aF-1.0381536340650956
+aF-0.10502456747033624
+aF0.11749503806061042
+aF0.38930377219317391
+aF-1.0352099662793435
+aF-0.23688462459142418
+aF0.16457413136032079
+aF-0.27854367825890647
+aF-0.22447778322567979
+aF-0.15804961089987821
+aF-1.0143074342478575
+aF-0.065678701536332082
+aF-0.051087132702834666
+aF0.30049776847157822
+aF0.48506187578506621
+aF0.15091605070238101
+aF0.68149489101167937
+aF-0.25901012082188252
+aF-0.0070398093909925762
+aF-0.064934546726028594
+aF-0.52700209267283604
+aF-0.3784822616367704
+aF0.42788723569632431
+aF-0.35733296262179354
+aF0.039899402793572021
+aF0.05129362381116849
+aF-0.4385819706433669
+aF0.93559516434539602
+aF-1.5179186572322856
+aF-0.65311158177948536
+aF-0.17866150724755786
+aF1.3305146431707415
+aF0.25712431431861549
+aF-0.14138625635245899
+aF-0.2178529992614428
+aF-0.070039099926381576
+aF0.57115584524923335
+aF0.52939730268009544
+aF0.1150695832427017
+aF-0.24950758694770306
+aF-0.28547162946513277
+aF-0.24534465542791323
+aF-0.090306252533540021
+aF0.017142998228557037
+aF-0.37231025471602858
+aF0.077662589149465291
+aF-0.20718560105016312
+aF0.2335341808233509
+aF-0.60004323642253932
+aF-0.33719617168316784
+aF-0.50619099572809101
+aF0.58342081060918205
+aF0.01190473844588898
+aF-0.78381118229243885
+aF0.39365018930731527
+aF1.1620793651540575
+aF0.46570783141279282
+aF0.21935633056684967
+aF-0.70728180579503419
+aF-0.047847719359155681
+aF0.88548497965396622
+aF0.32932792503793468
+aF-0.3697766794342644
+aF0.57381178077563266
+aF0.017068869178503601
+aF-0.33371431579756405
+aF-0.7155864913463571
+aF0.093004124564737972
+aF-1.1084997530191099
+aF-0.94077794963106598
+aF1.2543471983333037
+aF0.11640086356854168
+aF1.5421716913486754
+aF0.033101326112751885
+aF-0.3085679768144805
+aF0.58535495527584713
+aF-0.36327262486744483
+aF-0.1616553011742817
+aF0.32702795835250087
+aF-0.028889549238767239
+aF0.4556070165679193
+aF-0.75234378262379786
+aF-0.14080076077686754
+aF0.16541919355411958
+aF0.11556403136932027
+aF0.78836661240301087
+aF0.57879313390853016
+aF-0.55248899708714982
+aF-0.24803613837491487
+aF0.60657229593967543
+aF-0.74598227273584305
+aF-0.168153443505138
+aF0.012577547863989756
+aF-0.59029275911223655
+aF-1.0041151200996099
+aF-0.78650690250448407
+aF0.10057056243882588
+aF-0.69538788822697717
+aF1.1121133329654893
+aF-0.10979617926171287
+aF-1.3169252388058466
+aF0.54683957924370175
+aF0.82431427430085658
+aF-0.19859124534687933
+aF0.051855149964200827
+aF-0.26322444462427641
+aF0.041561648653942622
+aF0.66491431066059192
+aF0.59428152170360726
+aF0.20388483259342471
+aF0.093905395425005075
+aF-0.42924399612922809
+aF0.29741657406860256
+aF-0.63758333481670837
+aF-0.60542276309998877
+aF-0.15253100992351057
+aF0.22994173534287105
+aF-0.24766035699607539
+aF0.32488495281360091
+aF-0.035318642958775494
+aF1.14027231904655
+aF0.25150682381438594
+aF-0.45740263428169126
+aF0.42338624139241637
+aF0.18770521128901252
+aF-0.15311476595971732
+aF0.26727232583816757
+aF-0.21018645169645367
+aF-0.037219653043604299
+aF0.32604697108638137
+aF0.37915857222745758
+aF0.17830637789262038
+aF-0.87233606010802967
+aF0.2855585223916467
+aF0.30986395179708154
+aF0.19950022302573714
+aF0.20977316605503707
+aF0.39347993492613126
+aF0.55936525210970101
+aF0.45324956995834798
+aF0.49571149529857761
+aF-0.45902296531177844
+aF-0.40973714522267579
+aF0.08335767728394361
+aF-0.30838970278930061
+aF-0.44496253243138445
+aF0.17472548344635536
+aF0.16382406151862589
+aF0.26432546960952613
+aF-0.3168489613385867
+aF0.071383954536087479
+aF-0.74284020330484024
+aF-0.60517933652970368
+aF0.36578751334893589
+aF-0.21574581463511106
+aF-0.53022406859106375
+aF-0.083944553217584164
+aF-0.61717212738912786
+aF-0.14723961308071165
+aF0.034323575064721237
+aF-0.7006284128521556
+aF0.15105507254890177
+aF-0.68667917485012853
+aF-0.069348116159817855
+aF0.24659651600105117
+aF0.23898332019634855
+aF-0.21373051428761064
+aF0.17541689767236798
+aF0.040655498279898172
+aF0.49418471381325091
+aF-1.274199988348832
+aF0.060454019929226083
+aF-0.63897967651788101
+aF-0.29515801667715225
+aF0.21001702082302978
+aF-0.22246592416901659
+aF0.24433465760387502
+aF-0.09696132269136154
+aF0.50706339180358784
+aF-0.23789064401154067
+aF-0.18814654718140569
+aF0.19387817663814752
+aF0.3565442982615224
+aF0.081996598614815563
+aF-0.15887170046691879
+aF-0.85764352618065232
+aF-0.47595809150944224
+aF0.16854807139492187
+aF-0.22958405150103986
+aF-0.2422774519040676
+aF0.35203993159102642
+aF0.24360194147341563
+aF0.17737058646736692
+aF0.32142846847899031
+aF0.7040801620548417
+aF0.8376586515070964
+aF-0.31555519457073677
+aF0.13705342006036869
+aF-0.15481872511565686
+aF0.2786277693711432
+aF1.4084429335707278
+aF0.17467716549095261
+aF-0.37288575466330126
+aF0.2516709461683645
+aF0.30049924978968595
+aF0.22868024093693626
+aF-0.55735162471439326
+aF0.21905214815689839
+aF-0.36240103818329006
+aF0.32283722512690549
+aF-0.19380424590864026
+aF0.24840845781774204
+aF0.35826344962676221
+aF0.38744709040406994
+aF-0.033471695201945817
+aF-0.54719435744363321
+aF-0.034281572602260293
+aF-0.47654407985891761
+aF-0.62124839015946232
+aF-0.29335504303006066
+aF0.48842295797219215
+aF0.29267155811343376
+aF0.20300246152105339
+aF0.080829811890162417
+aF0.14354092747452143
+aF0.18439998497042789
+aF-0.087964761316127127
+aF0.81047013974474347
+aF-1.2835820691826927
+aF0.02133021752634974
+aF0.10004122934667385
+aF0.34938747248512392
+aF-0.14482254952823478
+aF0.21871785639978314
+aF0.31597599312056923
+aF0.5012831334154989
+aF0.83208899855256935
+aF0.51333626398630383
+aF-0.27189144711109836
+aF0.76702567947531464
+aF0.070740941023683057
+aF-0.72921137895230315
+aF0.11463588078127726
+aF-0.063760903448682002
+aF-0.75603754713528537
+aF-0.42481926072894921
+aF-0.029615390859620012
+aF0.2990897819359748
+aF0.31628437807413462
+aF0.039469137483556162
+aF-0.2641054368983401
+aF0.097258056387688058
+aF-0.046811827424160742
+aF0.057348188242144139
+aF0.51195823457791434
+aF0.29522117642710483
+aF-0.49890384117478831
+aF0.034516861222317528
+aF-0.24805164530345514
+aF0.0466490248130162
+aF-0.010963727177418016
+aF0.16828056011281478
+aF0.060284480864023202
+aF-0.57080955413416934
+aF0.16547387948909573
+aF0.48666780756607952
+aF-0.036416597785222514
+aF-0.31095180476139489
+aF0.86604903725371218
+aF-0.81808556833660218
+aF0.23988766066334352
+aF-0.10511792537630726
+aF-1.3694718758963416
+aF-0.54122426965118309
+aF0.30043433286894794
+aF-0.19375261004082192
+aF-0.36195872573487825
+aF-0.20636860246675404
+aF0.75122843007065376
+aF-0.46625170056814341
+aF-0.031967569647998073
+aF0.54949699481459657
+aF0.68264460796376947
+aF-0.18511277414083174
+aF-1.0908199733571788
+aF-1.2809727464384733
+aF-0.028681000152945252
+aF-0.34390528231595574
+aF0.5069649322795684
+aF-0.90112286791464602
+aF0.34543790384362055
+aF0.1383988002398677
+aF-0.056974462161271305
+aF-0.2073877803799046
+aF0.095020302163884185
+aF0.51518964250695254
+aF-0.72515335957861016
+aF-0.44609680401934027
+aF-0.83029901913376769
+aF0.55364396558153905
+aF1.1285491473169702
+aF0.154960495547007
+aF-0.28945785005176183
+aF0.12359596060556791
+aF-0.014314729538650423
+aF-0.62367171759306461
+aF0.16878857609727538
+aF-0.0081326714940393539
+aF-0.46994429160415829
+aF-0.83492398505076315
+aF0.33627278369331876
+aF0.4504192589729914
+aF-0.67927004718033746
+aF-0.32596541494218145
+aF0.3167661335133255
+aF0.84908670050638402
+aF1.4154114077048638
+aF0.4327909436677056
+aF0.87125687606519686
+aF0.4085374238778261
+aF-0.53634842164709451
+aF-0.93524765699934975
+aF-0.37129124250952855
+aF-0.35708686707859127
+aF0.2151526338855079
+aF-0.54446917252514559
+aF-0.46981568502545706
+aF0.49668410339162888
+aF-0.9115172564963594
+aF-0.45720497803599569
+aF0.15331644862724242
+aF1.3613943109695048
+aF-0.42262090884793196
+aF0.029031997139354261
+aF-0.54661373220639109
+aF-0.26087722621355502
+aF-0.084738873821703767
+aF0.70638807530975711
+aF0.50664236123045814
+aF-1.1223602095977336
+aF-0.25601684786380674
+aF0.17673289576195003
+aF-0.83194925576556145
+aF0.16865008004502596
+aF-0.037118928104466847
+aF0.55046585479450594
+aF-0.029685216765527031
+aF0.0060398490390555183
+aF-0.87514056493361325
+aF-0.46881250292758292
+aF-0.11862144632996857
+aF0.12666688435887946
+aF-0.13819894994841736
+aF-0.55926919891967797
+aF-0.57231305592277093
+aF1.08074732868838
+aF0.98114584777808045
+aF-0.073755456591349577
+aF-0.89177199804686402
+aF0.28342023583197268
+aF0.20746860305283493
+aF0.31764586853424565
+aF-1.1708725107784643
+aF1.459638128348888
+aF0.067484776411970607
+a(I50
+I20
+tp12
+g7
+tp13
+Rp14
+sS'A2'
+p15
+g4
+((lp16
+F-0.055177143862990309
+aF-0.090934983718903642
+aF0.1088346509003635
+aF0.21859497110484641
+aF0.2073827397972903
+aF0.21063695520785472
+aF-0.024722400297423574
+aF0.046028958244294108
+aF-0.010910564736127788
+aF-0.00017292450566805674
+aF-0.039604072069558974
+aF-0.017833746610335537
+aF0.090197620671043102
+aF0.042894655823724606
+aF-0.12494111241956032
+aF0.025053094003101243
+aF0.24227360935358752
+aF-0.004920542969672136
+aF0.043253018251401869
+aF-0.19040336002985572
+aF-0.073459159371673979
+aF-0.041814199423833992
+aF0.017745390654343485
+aF0.081425892862078811
+aF-0.14569914710592888
+aF-0.029473234727100107
+aF-0.064424627663900905
+aF-0.068130928005078237
+aF0.033987103823118862
+aF0.1315661712516851
+aF0.042099807780963824
+aF0.060483032589267502
+aF0.10292303300433443
+aF0.089653961556869929
+aF-0.12050421932662413
+aF-0.0021247386459149224
+aF0.012316214541374115
+aF0.22043635368439249
+aF0.082540753051030841
+aF0.0069738800353631985
+aF0.033113408603218777
+aF-0.18844764138149481
+aF-0.21347093755475399
+aF-0.033952095579280667
+aF0.11768966887688906
+aF0.050991169240989502
+aF-0.016497898435255641
+aF-0.00326569938335072
+aF0.17707318291438839
+aF0.11951038726361075
+aF-0.032568247070107768
+aF-0.02999559172835399
+aF0.0076055465350238147
+aF0.039671416813289777
+aF-0.11195301194112302
+aF-0.25044385117247736
+aF-0.048975710309696711
+aF0.20220914060071504
+aF-0.055448024371275113
+aF0.13137208542838394
+aF0.10936972845920152
+aF0.068026414468520133
+aF-0.011112761158783305
+aF-0.0028523400837438067
+aF-0.091815782400712032
+aF-0.095021943298575884
+aF0.057539681708335712
+aF0.079437925802282372
+aF0.18964517211746931
+aF-0.054411404639847033
+aF0.053667646650171208
+aF0.13965085878563877
+aF0.1961813466627286
+aF-0.068291621253356527
+aF-0.14019032668391324
+aF-0.019518166912356871
+aF0.045084993136515081
+aF-0.029592437461493627
+aF0.07526574838688288
+aF-0.12946242509858352
+aF0.10469317206722956
+aF0.0896182838137667
+aF0.045089130958460788
+aF0.11514204590153726
+aF0.054382952021918278
+aF0.041604243513167716
+aF-0.12978789887691822
+aF-0.084206705765249398
+aF-0.13256099013871966
+aF-0.13559176063294912
+aF0.0089064097135981048
+aF-0.020711413425595425
+aF-0.029037857714492171
+aF0.058038078263427842
+aF0.0035656343037088114
+aF-0.0015038298180660946
+aF0.041148293756015988
+aF-0.047811974225024458
+aF-0.096582124164248301
+aF-0.0043782848064951385
+aF-0.045680484707591118
+aF0.14897702535524496
+aF-0.021877487035356896
+aF-0.088030182538105961
+aF-0.013979620351963597
+aF0.1540624866980071
+aF0.14235608542881514
+aF-0.096136149045765784
+aF0.0088556295711976311
+aF0.023033583727620627
+aF0.20570683532114142
+aF0.028419071885841952
+aF0.1823066357459609
+aF-0.010917106396017345
+aF-0.024965168361472521
+aF0.13222334530162014
+aF-0.0068116866107957421
+aF-0.033183966120908015
+aF-0.071128382014544314
+aF-0.022894947917562657
+aF-0.038325610799607231
+aF0.12951611120504944
+aF-0.077568952880594205
+aF0.01520733912303863
+aF-0.0044112589446748439
+aF-0.27253086286362266
+aF0.09217925774366699
+aF0.080953922574883125
+aF-0.037152078716310495
+aF-0.23975519773914405
+aF-0.08866329465909116
+aF0.05083351747855034
+aF0.069519362858686415
+aF-0.052364446789599214
+aF0.10600616977521761
+aF-0.02819391818331984
+aF0.00029025834479629861
+aF-0.1287088493144905
+aF0.14866728928187239
+aF0.012780651577132906
+aF-0.16629295780313147
+aF-0.25531491161016767
+aF0.024021060302080694
+aF0.010913420283174668
+aF0.030418910122732224
+aF-0.040876244170439884
+aF0.00047977934854221208
+aF-0.018863263612910148
+aF0.0045352427438410522
+aF0.08476077123035769
+aF0.032108636515289536
+aF-0.072842676709623549
+aF-0.056959111288764311
+aF0.13088936711105964
+aF-0.19084927933178644
+aF0.003084430138521286
+aF-0.0014345953286697354
+aF-0.050739652007454658
+aF-0.10651407286607693
+aF0.0091567860711938391
+aF0.04377918968239515
+aF0.16245070738046274
+aF-0.04307340844096301
+aF-0.08469840047142177
+aF0.0001415740693069276
+aF0.058337469598007154
+aF-0.1436192928164296
+aF0.064093591930071386
+aF0.08913611375164017
+aF-0.0064513381888034417
+aF-0.0030830642731675588
+aF0.027687507517900056
+aF-0.060106504775543114
+aF-0.0047790728773195899
+aF0.070775058155850959
+aF-0.029278813853367114
+aF-0.10257715405244926
+aF0.13370339305999124
+aF0.037444987382623703
+aF0.10367524479590345
+aF0.052179466433580381
+aF-0.084006575526882302
+aF0.15570347362292775
+aF-0.0022701315539581193
+aF-0.070463249384634455
+aF-0.076665974880955681
+aF-0.0083995697792459863
+aF0.057681397272742851
+aF0.035200361909121645
+aF-0.055830440382640824
+aF-0.037867375942746209
+aF0.10234827161583543
+aF-0.06410735247966208
+aF-0.032044796103514045
+aF0.16630570838571404
+aF-0.1501328029736875
+aF0.025361899575715927
+aF-0.061744336891093266
+aF0.018664353285423155
+aF0.11967573437192655
+aF0.042299399284519819
+aF0.11794446268823212
+aF-0.087520298342840766
+aF0.10945564437222896
+aF-0.03712553951424246
+aF-0.055232394004153501
+aF0.16784634643019819
+aF-0.088359188106674202
+aF-0.036337061024538667
+aF0.0082230616675087256
+aF0.024162555225182618
+aF0.026744575183451375
+aF0.0715606323037416
+aF0.036982611675445205
+aF-0.029789238320601499
+aF-0.034222708035081678
+aF-0.026937392163425229
+aF-0.15725362483797686
+aF-0.0049370095995950889
+aF0.019942633126320681
+aF0.19893457326664765
+aF0.052398216069204667
+aF0.074605295930732507
+aF-0.098756527489276283
+aF-0.053082944870072146
+aF-0.17170035163118111
+aF0.083985741035467201
+aF-0.050065985076010899
+aF-0.055390480252292887
+aF0.0023128263850746367
+aF0.023936472969809809
+aF0.06805784972859423
+aF-0.014829699289401935
+aF0.039883932802202968
+aF0.07883920311198106
+aF0.0058653689446590655
+aF-0.15811083286471841
+aF0.065545433730221841
+aF0.003353204435138298
+aF-0.016923097062455667
+aF-0.074580464755409928
+aF0.090620459888375346
+aF-0.16309354432095163
+aF-0.004030481450426145
+aF0.081488174739785355
+aF-0.041753971603488503
+aF-0.17426237098117373
+aF-0.035892902291920922
+aF-0.10133350515793345
+aF0.16087743443398983
+aF-0.065835071049081512
+aF-0.020132144005941911
+aF0.052635829713815821
+aF0.0155749335405393
+aF-0.045382783887803931
+aF0.11009222832394563
+aF-0.010257645185249766
+aF0.051519457523845617
+aF-0.0028063982339499691
+aF-0.12109180008477191
+aF-0.099135598486534582
+aF0.014418712221900099
+aF-0.13423179001981422
+aF0.061656008926874339
+aF0.033185457581472629
+aF0.05552139698037848
+aF0.0067915813013809294
+aF0.098908927262848972
+aF-0.060636863738624404
+aF0.043517296821579565
+aF0.1138997204417688
+aF0.0027134074709325631
+aF0.063317195771388043
+aF-0.062758947028787121
+aF-0.0039482511609774049
+aF-0.14166970713897126
+aF-0.098112035039407894
+aF-0.020238649114106593
+aF-0.15339724769355365
+aF-0.15544519588330058
+aF-0.0099339971906280758
+aF-0.027532046203550636
+aF-0.12525375333502839
+aF0.067531675305338601
+aF-0.03701097461612872
+aF0.078428466566513783
+aF0.3060784739241097
+aF0.057344423823142386
+aF0.11713318574685919
+aF-0.067851776034082475
+aF0.094661244111924212
+aF-0.056591347130605416
+aF0.038790639159273096
+aF0.081917344989270766
+aF-0.021738164019051018
+aF-0.011711076888398755
+aF0.093321336138313282
+aF0.16004901707093555
+aF0.0903906214294313
+aF-0.038453329501291579
+aF-0.030543615843782283
+aF-0.078518294734387553
+aF-0.070629802249183277
+aF0.13404367156682456
+aF0.099945520370653337
+aF-0.01984602646748131
+aF0.129978162520516
+aF0.057381111380959832
+aF0.20335451438791494
+aF-0.11830406718083865
+aF0.10712955457337386
+aF-0.10791114684777595
+aF-0.051984303323715536
+aF0.10776844452836695
+aF0.020661246329662375
+aF0.069350308964136576
+aF-0.077658650741859042
+aF0.17021774995146344
+aF-0.0032914387918880038
+aF0.23722341718300341
+aF-0.063277314679489272
+aF-0.1443136368317515
+aF-0.05585036617481047
+aF0.034482158004221414
+aF0.11651195354702278
+aF-0.054169167126587751
+aF0.20592520763403246
+aF-0.0014943039150752987
+aF0.067349918473157064
+aF-0.05866290450849071
+aF0.13221306517740955
+aF-0.10609422163227407
+aF0.062823908593857267
+aF0.066860057733128989
+aF0.047097140555271526
+aF0.15523311731637512
+aF-0.061910263063460542
+aF0.31239876299135561
+aF-0.03613436768359822
+aF0.11038376403460366
+aF0.028175808072849088
+aF-0.044527181578319877
+aF-0.030301989507218779
+aF0.071096951457306989
+aF-0.030453449711826334
+aF0.1918964498563116
+aF0.035588994224299231
+aF-0.059730440013489823
+aF-0.0051960152853210845
+aF0.038678238649738343
+aF-0.0068541595576828854
+aF0.072012818193856631
+aF-0.012546847555840127
+aF0.058261314415236881
+aF0.14445363238058834
+aF-0.0028280262673769977
+aF0.028955891792536485
+aF0.18168291147144178
+aF-0.059045822038194605
+aF0.028676890756101837
+aF0.14576325978206323
+aF-0.089083774895590814
+aF-0.105062560892169
+aF-0.13588900044923549
+aF-0.088434310940037536
+aF-0.003630082808377337
+aF-0.19424024928677733
+aF-0.16810337150732782
+aF-0.14115372685309346
+aF-0.021547786054055981
+aF0.10979328046207114
+aF-0.0030365148048419285
+aF-0.049555828036475937
+aF-0.0061710361916060734
+aF0.20651195434172903
+aF0.019439612506736797
+aF0.017246604888145563
+aF0.026064620428664306
+aF-0.14001485134787167
+aF-0.21696813709120338
+aF-0.18601289527858506
+aF0.11169989941485885
+aF-0.033391918476632698
+aF-0.057922140860280788
+aF-0.020372283888836662
+aF0.016530051685272391
+aF0.082120300370432553
+aF-0.1126371589784901
+aF0.011476431743121334
+aF0.073907027921322352
+aF-0.097520247116770639
+aF-0.18391154716846431
+aF0.022258995677168825
+aF0.013681766429927904
+aF0.23871319687933606
+aF-0.0048718260420158015
+aF-0.0013456076727166753
+aF-0.047300610699094206
+aF0.11051610572849201
+aF0.01014140842819997
+aF0.15501804088894575
+aF0.04186086567213871
+aF0.097682442518753243
+aF-0.011677973819592305
+aF0.017213390587544685
+aF-0.041490874960699996
+aF-0.056762219388886447
+aF-0.17624407412633217
+aF-0.13048519736495875
+aF0.024531712645389833
+aF-0.033193321839847273
+aF-0.090080994909792697
+aF0.12494999843526937
+aF0.079359542740060934
+aF-0.03926509411950084
+aF0.088955591050133606
+aF-0.10466999274549041
+aF0.18743920904347805
+aF0.00071445274375956617
+aF0.068357333641444945
+aF0.049393815791289583
+aF-0.063326018357685643
+aF0.099233644705276874
+aF0.057612000173089949
+aF-0.069208550361688187
+aF0.021861975887379023
+aF-0.11014606958110534
+aF-0.028214485506583238
+aF-0.14077839229594691
+aF-0.056777847893192353
+aF-0.019666088170494162
+aF0.099042745655239794
+aF-0.015653647030877463
+aF-0.074172796647291817
+aF-0.00052293636900737771
+aF-0.10645346780937884
+aF-0.059230640150881239
+aF0.14392480396039037
+aF0.011918719638223909
+aF-0.073619906766106774
+aF-0.009376744675956358
+aF-0.061109880292916176
+aF-0.064595907275467504
+aF-0.020147819057824038
+aF-0.041251455158585713
+aF0.01289309011288358
+aF0.14475463399850988
+aF-0.027192563652361133
+aF-0.03215319259019267
+aF0.079871502012213075
+aF0.075173094233468421
+aF0.054673989542494007
+aF0.003628844549442658
+aF-0.10311844402707779
+aF0.062468022075953131
+aF-0.024888498523310456
+aF0.015015986547292569
+aF-0.043327708268808315
+aF0.041354694774414634
+aF-0.024813967244999895
+aF-0.052283351581727207
+aF-0.129674567742256
+aF-0.096751046699620216
+aF0.16171686780953431
+aF0.19294306057647123
+aF-0.093600374388917551
+aF-0.010261160848028044
+aF0.0057577819534901133
+aF-0.040213860167795615
+aF0.16797498801837432
+aF0.051255753225112055
+aF-0.056748876004360169
+aF-0.11414104626191252
+aF0.008710122124355877
+aF0.0060788452056667868
+aF-0.12561079461859961
+aF0.061792806544561762
+aF0.0051863321977621245
+aF0.12112336335368296
+aF-0.021281716088328368
+aF0.047146483982639688
+aF-0.059682342863964205
+aF0.0012858686314625328
+aF0.11103124290739934
+aF0.12915125571491284
+aF0.0079206558070611423
+aF0.23299766048779957
+aF-0.0078506266706653526
+aF0.11779450364331617
+aF0.022670513795018051
+aF-0.030393093512299817
+aF0.16881372691880644
+aF0.026279443194090969
+aF-0.024645841248289974
+aF-0.016680036435908308
+aF0.029951537033328746
+aF-0.00058006512683570096
+aF0.0058925426624881786
+aF-0.01541017869261063
+aF-0.088034882565110245
+aF-0.0025600514430933162
+aF-0.14115099942825041
+aF-0.014500104517212235
+aF0.0083428674551949758
+aF0.030812994374712993
+aF0.084126789159434293
+aF-0.10723477213499225
+aF-0.11103786465423179
+aF0.18455193651853941
+aF0.24753822354466984
+aF0.083804846179395764
+aF-0.051998163969302978
+aF0.053983445734529484
+aF0.017656892049984402
+aF-0.18927515957483063
+aF0.006311039824280773
+aF-0.011189587489128964
+aF0.041555733540402144
+aF0.0084194771753996599
+aF-0.32062907708065164
+aF-0.10358318766062508
+aF-0.13435805984141694
+aF-0.072539670511620719
+aF-0.17000685533299728
+aF-0.024311161217735418
+aF-0.084530917003306547
+aF0.053814232222157928
+aF-0.063939265848471663
+aF0.053628907299544393
+aF-0.1271343027239423
+aF-0.17497690674163796
+aF-0.090999956688566627
+aF0.056022733031139846
+aF0.10515395716141297
+aF-0.05600696117229155
+aF0.14263349713728926
+aF-0.011168363810599635
+aF0.011199974868446969
+aF-0.026598679079103186
+aF-0.050877799036847221
+aF0.023960478467587757
+aF0.052494320700415167
+aF-0.018973635403467057
+aF-0.24629790447570662
+aF0.19734100671280788
+aF-0.087641658119766694
+aF0.175998042185665
+aF0.093030428491602118
+aF-0.24494865231982749
+aF-0.00047850548219137087
+aF0.022977706341240512
+aF0.072500002257234547
+aF0.054213581483611592
+aF0.052860599932991414
+aF0.026610531484314432
+aF0.037439681825428971
+aF0.15333867599869866
+aF0.047103951026739269
+aF-0.016197989928733541
+aF0.000887566612119359
+aF0.057826391183464249
+aF-0.0034323735239749414
+aF-0.07256557276528397
+aF-0.095328068095131779
+aF0.027311900323211038
+aF0.089474974533514634
+aF0.11957053004191145
+aF0.082513534507027017
+aF-0.066955737401765664
+aF0.075039511692776076
+aF-0.091870361047227705
+aF-0.011436088854156033
+aF-0.12387820281903922
+aF0.12179285292682285
+aF0.04124951773942271
+aF0.084899417416483519
+aF-0.011615876511216441
+aF0.027813413828436002
+aF-0.098774666881408693
+aF-0.11946120379929558
+aF-0.094481027192023379
+aF0.16510134130548301
+aF0.03355565375248111
+aF-0.029167960923471334
+aF-0.046095379991226697
+aF-0.097030526480389595
+aF0.1190763062342894
+aF0.089723829062585428
+aF0.041429984511248713
+aF0.04081011694448098
+aF0.11869561692746541
+aF0.10376635033268418
+aF0.13380899284205736
+aF-0.091576421747627784
+aF-0.058445875412080413
+aF0.11022760303341736
+aF0.10005754671764959
+aF0.10009279294828914
+aF0.012395680527387086
+aF0.02340539261028873
+aF-0.029957013710068873
+aF-0.0034659213637663663
+aF0.1257486954128435
+aF0.028179340357867223
+aF0.022285311892012261
+aF0.037262075708562006
+aF-0.1521700003874745
+aF0.18697639636442398
+aF-0.048991377513423862
+aF0.19539263086094619
+aF-0.0023600970492098526
+aF0.058590947949117504
+aF-0.044773196244701163
+aF0.1478079445747382
+aF0.010261345510060046
+aF0.0017325564724354708
+aF0.051837239023821688
+aF0.10191233482160775
+aF-0.094138312631391871
+aF-0.12374078165417321
+aF0.065648947529419688
+aF0.026830402697505511
+aF-0.15994232298648936
+aF0.087695547497904994
+aF-0.054937986394894625
+aF0.04446814405009946
+aF0.10696613973706449
+aF0.085818833961108398
+aF-0.060413079703052604
+aF-0.0032115816633468729
+aF0.08460176771732654
+aF0.11305612191264475
+aF0.054220186574038876
+aF0.14074012367025315
+aF0.08543260876045293
+aF0.048359943835055028
+aF-0.065633638232130226
+aF0.027030767118143444
+aF0.06924993773478251
+aF0.096726699709739461
+aF-0.00087547557342555207
+aF-0.0091848975891697261
+aF0.10242903854621793
+aF0.1195092110506676
+aF0.0052871406290618426
+aF-0.063473657396276847
+aF0.0023317739197133988
+aF0.01902440536987764
+aF0.057856224662994192
+aF-0.30073752026478406
+aF0.13599636090340364
+aF-0.16216298961604714
+aF-0.079928384281358178
+aF-0.14412634398462026
+aF-0.072791083991654917
+aF-0.12177892972983285
+aF0.036862481859833193
+aF0.13174584370746006
+aF-0.081610183998520172
+aF-0.062117220607096325
+aF-0.11271114689035737
+aF0.063574701966689309
+aF-0.10932323126823337
+aF-0.0088927102260218643
+aF-0.079747647638977917
+aF-0.03550158481073943
+aF0.028243513065858417
+aF0.062359511007092035
+aF-0.1233097397950056
+aF-0.099342798002378746
+aF-0.071200194091729771
+aF-0.069633913320042803
+aF0.051661010490128022
+aF-0.055238623724216937
+aF-0.079874144305878664
+aF-0.21917630657339188
+aF-0.035799316878732682
+aF0.040232694075709688
+aF0.080978422593848368
+aF0.06510479448900991
+aF-0.059900216580945263
+aF-0.073524620206891031
+aF0.1215218442731168
+aF-0.24008788944347689
+aF0.11011887265232777
+aF0.01223121304774352
+aF-0.089306221120852292
+aF0.048795512493457108
+aF-0.074047411304813779
+aF0.10809436292091638
+aF0.16134931004364916
+aF0.15533788239422233
+aF-0.013830870051591202
+aF-0.07985662368756194
+aF-0.078791705788612401
+aF-0.096329533766666156
+aF-0.059158529230751621
+aF-0.20222684765650431
+aF0.037430191805560856
+aF0.054763129125730399
+aF-0.018620844957434483
+aF-0.077987529415600901
+aF0.0019992596411459677
+aF-0.05529912366532759
+aF-0.029129341704762411
+aF0.052871303728301872
+aF0.056265586293919367
+aF-0.11854910623057796
+aF0.087162520936002463
+aF-0.056621519772420068
+aF-0.11081584503649952
+aF-0.24049193003515856
+aF-0.12583845106754871
+aF0.0023451342816078356
+aF-0.064812191213504733
+aF-0.16890956781738725
+aF0.092515147088095967
+aF0.14921596030355722
+aF-0.014742319818963142
+aF0.033682604483814084
+aF0.12425160121451437
+aF-0.046185238920130371
+aF-0.064377741379582215
+aF0.056806202580856495
+aF-0.0091753928729996978
+aF-0.036943039398477616
+aF-0.035027065000936324
+aF0.01172725962279699
+aF0.10008614178984791
+aF0.043179312134217308
+aF0.11591003597298011
+aF0.10772505440764008
+aF0.019552296126425783
+aF-0.042744687104091489
+aF-0.063979800732527556
+aF0.042270474206796665
+aF0.086276894988110975
+aF0.038228292228884977
+aF0.051598418572029264
+aF-0.069975502367457226
+aF-0.078651998882348653
+aF-0.20765909943503544
+aF0.15157440176342074
+aF-0.091012133198523359
+aF0.03147085770447243
+aF0.11236183211433474
+aF0.0063486845668841276
+aF-0.14379668636598095
+aF-0.16496019959373359
+aF0.11772687969936144
+aF-0.086118941253464823
+aF0.026720733533377734
+aF0.085471747551329233
+aF0.12050779341873413
+aF0.030453195829649268
+aF0.046875154950436274
+aF0.0046587597737350311
+aF0.015443534139250195
+aF-0.040719502167033725
+aF-0.048652227065329366
+aF-0.014226920842525565
+aF-0.039533677503780673
+aF0.0088099468664679121
+aF0.051156333701157408
+aF0.0018645389882668906
+aF0.081208113666952797
+aF-0.023146825116148032
+aF0.11617443194952629
+aF-0.094090320134152791
+aF0.010684461111130585
+aF-0.1235586826793115
+aF-0.073432318081182668
+aF-0.088295145596297323
+aF0.042581756099878611
+aF-0.029788989389739961
+aF-0.071782509330200556
+aF0.0085472991432579692
+aF-0.0044144868911086431
+aF-0.036103901230470706
+aF-0.11150689459097783
+aF0.063386941535653427
+aF0.014017931749509408
+aF0.058170381331469151
+aF0.12211767786227606
+aF-0.11354097088743476
+aF0.024472115890565926
+aF-0.11180637414500229
+aF-0.026289395615343283
+aF0.0096431378808807672
+aF-0.12827700489590682
+aF-0.11993098892062856
+aF0.021410766662417414
+aF0.0080384617328952551
+aF0.083156770586368292
+aF-0.17064167670284544
+aF0.051547595657153465
+aF0.043914312895561324
+aF0.13310479969656669
+aF-0.0036998534149256168
+aF0.016395538372920047
+aF0.0011467704759317602
+aF-0.085352843039020965
+aF0.042479436140357853
+aF-0.13491053140260531
+aF-0.079253982699096059
+aF0.0065538594803589249
+aF0.05769840820742974
+aF0.064997719607653867
+aF0.019503860418133991
+aF0.17676206960240576
+aF0.1346850229343102
+aF-0.072160378166972267
+aF0.12257425820771946
+aF0.050233339138728378
+aF0.1761840863714334
+aF0.056146602432152387
+aF0.0042914391883953421
+aF0.040125503911374642
+aF0.19176283646512979
+aF0.0032538725206520407
+aF-0.21240349624260044
+aF-0.16756070125515354
+aF-0.091835353963488506
+aF-0.12500510063194875
+aF-0.069358084610301574
+aF-0.034786612564470493
+aF-0.063695763168122602
+aF-0.15094364807696381
+aF-0.033286174687399459
+aF0.077396125269460977
+aF-0.030244053445085836
+aF-0.10154325773246933
+aF0.012443758777270759
+aF-0.02685728148948913
+aF0.015202581616044764
+aF0.033811352422597959
+aF-0.20742738562223223
+aF0.059611919386579844
+aF0.029314793620553042
+aF-0.053042562221212307
+aF0.055360563432240287
+aF0.034445690355433031
+aF0.052925977560950653
+aF-0.12699388857431659
+aF-0.057788060160968935
+aF-0.058488746877789551
+aF-0.088835266516803582
+aF-0.010194685978115427
+aF0.061379126930147701
+aF0.10628921727689004
+aF0.0799499126816616
+aF0.0071407208307813358
+aF-0.10450485262403755
+aF-0.018717876024268582
+aF0.036290012997277521
+aF0.0026508606817946174
+aF0.0085048509956422141
+aF-0.077603908515031586
+aF-0.15701955443394924
+aF-0.017496364061716767
+aF0.068004411659852618
+aF0.0010938806266890552
+aF0.046252269845260402
+aF-0.005385596777490842
+aF0.054849019963044955
+aF0.11709782636063537
+aF-0.1043525292628899
+aF-0.10986654424012431
+aF-0.10136901884315185
+aF0.095983118768833309
+aF0.069890029991237015
+aF-0.068522458322577959
+aF0.032805239817532326
+aF-0.11879007648617979
+aF-0.014480764793735799
+aF0.19507489345612583
+aF-0.018018409975172251
+aF0.059850802815706913
+aF0.033454527254848355
+aF-0.021362709766800637
+aF-0.099361977511118443
+aF-0.17404795127674799
+aF-0.034681964502361363
+aF-0.072973346723094204
+aF-0.10891475677147996
+aF0.063046558718000509
+aF-0.070884820987525993
+aF0.019597000772303357
+aF0.038043501261174256
+aF-0.027365588653200604
+aF0.035294900908687261
+aF0.15027749823781078
+aF-0.13373718134667167
+aF-0.056185354136965758
+aF-0.049512171310170841
+aF-0.1369444557703017
+aF-0.0023723288375381924
+aF0.072089759275013293
+aF0.20160165746954786
+aF0.12695709886025536
+aF0.10434114176479499
+aF-0.097721782903832238
+aF0.070403216173654137
+aF0.10907763224810438
+aF-0.015406029028988003
+aF0.064594896436268881
+aF-0.14029873124724718
+aF0.079894346718532017
+aF-0.16463733676156195
+aF-0.14485942349207542
+aF-0.05885129854919343
+aF-0.0092074740632008909
+aF0.19156233637432854
+aF0.076023243615986016
+aF-0.014004328469303702
+aF0.084182008023716906
+aF0.010185320757573741
+aF-0.056793101767079836
+aF-0.035175096833726383
+aF-0.015142087371648813
+aF0.051404733282198689
+aF0.026177927705903201
+aF0.046522232676116902
+aF0.060840554247612935
+aF-0.19491388432482804
+aF0.092163938242887364
+aF-0.0074705865930164029
+aF0.03393784129401306
+aF0.10641811745639287
+aF0.047104046492291315
+aF-0.003466640874568507
+aF0.17419701778544236
+aF0.080292129236603338
+aF-0.041658588401389987
+aF0.043071865359607067
+aF-0.014600170016479707
+aF0.25767278129496635
+aF-0.071340820996881771
+aF0.1522728991685649
+aF-0.060750304629792792
+aF-0.062847231777321821
+aF-0.0470595236344774
+aF-0.091672523032918507
+aF0.032847694492830433
+aF-0.039580234965704349
+aF0.029537233543764363
+aF0.0750993948476993
+aF-0.17135631302778428
+aF-0.1499336206996055
+aF0.11848430853427927
+aF-0.049386713333446824
+aF-0.086627133187029207
+aF-0.036044210165912888
+aF0.015524993228403087
+aF-0.11084586091403006
+aF0.0052337011841395624
+aF0.040367561058598622
+aF-0.0027402794492594343
+aF-0.0048802757640931628
+aF-0.13314784335585331
+aF-0.065092817685368523
+aF-0.10533487385104119
+aF0.0097306019106171097
+aF-0.030242134029479995
+aF-0.043836532336292304
+aF-0.056997007768730873
+aF-0.028142797293627567
+aF-0.084407619677833154
+aF-0.033961894521222169
+aF-0.13410619572506033
+aF0.016711858272088265
+aF-0.088760956500893634
+aF-0.12040560080957897
+aF0.083990730559999061
+aF-0.090370052154332359
+aF0.040825177481693481
+aF-0.0040608988006757465
+aF0.19532525716272187
+aF-0.18573291087434221
+aF0.050286492977160188
+aF0.05417242691142634
+aF0.067479227233466901
+aF0.0039202440906208596
+aF-0.0088662660033878484
+aF0.10356758858610658
+aF-0.089891072987312443
+aF-0.06759663772839386
+aF0.0038027819206750083
+aF0.034066951953398331
+aF-0.16964413648618737
+aF0.016812764001769641
+aF0.01269202611335889
+aF-0.0056337056792934749
+aF-0.016084473719576123
+aF-0.046546559449240341
+aF0.14519627035611532
+aF0.15190980499116222
+aF-0.07777342973983295
+aF0.034866032603455617
+aF0.018363011662855363
+a(I50
+I20
+tp17
+g7
+tp18
+Rp19
+sS'b'
+p20
+g4
+((lp21
+F-0.17494482323471078
+aF0.010130086837419693
+aF1.3907158254129897
+aF0.37464418421812318
+aF0.23718600597427367
+aF0.34016090872354826
+aF-0.55201056728697639
+aF0.0098429496749409054
+aF0.75292121325671646
+aF-0.51870628663700846
+aF-0.65736287593121612
+aF-0.37620337387404923
+aF-0.24838703758738293
+aF-0.026058490448326192
+aF-0.53581320087497364
+aF-0.013763428549170446
+aF-0.64386495906274166
+aF-0.63616003623358797
+aF0.48130362205467414
+aF0.50392445528638474
+aF-0.50757353001414185
+aF-0.37687414611842035
+aF-1.0252370937233803
+aF0.70861811021923793
+aF-0.50244984236478107
+aF-0.27862255650801299
+aF-0.63395458332606547
+aF0.49636111640380809
+aF0.59720961963333297
+aF-0.24271422651405122
+aF-0.35107467913367585
+aF-1.2693851997695071
+aF-0.7021056349631144
+aF-0.24984839210936544
+aF-1.4665448318244334
+aF-0.30600624812549704
+aF-1.3920359660059674
+aF-0.67759063840720701
+aF0.041754150431754018
+aF-1.2792723419519247
+aF-0.072005469411446477
+aF0.34970320199098109
+aF-0.5568863827471715
+aF0.94591956778302877
+aF-0.13506237517641967
+aF-1.1810864887056822
+aF-0.094365674428022822
+aF0.073998408524320824
+aF0.42898056846646548
+aF-0.29027578779908775
+a(I50
+I1
+tp22
+g7
+tp23
+Rp24
+ssS'6.15'
+p25
+(dp26
+S'A'
+p27
+g4
+((lp28
+F0.25003786892612351
+aF-0.059178809368941487
+aF-0.23893546269585741
+aF0.8040982384692108
+aF0.72834087768969935
+aF2.259480041314939
+aF0.87784937292095555
+aF-1.1781235875351923
+aF1.1710997389319298
+aF0.28661532004049511
+aF-1.4218299880529588
+aF-0.21927421285446527
+aF-0.15292762220225695
+aF0.71754808267764503
+aF0.10592678760041113
+aF-0.23814046412136802
+aF-1.1080236744514922
+aF0.3968374365453794
+aF-1.1725308971226422
+aF0.28749556684309852
+aF-0.50788540647101621
+aF-0.20682368621171882
+aF-0.70924466217796689
+aF1.0676194771667535
+aF0.6061780816583493
+aF1.6657625388586141
+aF0.53493822500285182
+aF-1.1761399714418026
+aF-0.0073116050361567986
+aF-0.81914582091229393
+aF0.9671726592132065
+aF0.45028478327067722
+aF-0.50514111734975509
+aF-0.78287996597012754
+aF-0.45783088442576902
+aF0.25610096521534903
+aF-0.055630973574346765
+aF0.064597886078462841
+aF-1.18546001926358
+aF0.50803565677923179
+aF0.63414537417766026
+aF0.14602884511059472
+aF0.13729739931455973
+aF-0.44577386903833183
+aF-1.2222043565421912
+aF-0.56834380363492487
+aF-1.0983773329343263
+aF1.6653566688636419
+aF0.73258043398945261
+aF-0.87169609885764143
+aF-0.1984768527922223
+aF0.2834991082277834
+aF-0.77011755849317387
+aF0.4852839022277608
+aF0.58750812526043239
+aF-0.36741047292678397
+aF-0.61215769716140112
+aF0.1968585721871858
+aF0.46718984199461056
+aF-0.9085570245213993
+aF0.01242276114682081
+aF-0.11043147006685544
+aF0.24304333547244455
+aF-1.3283319269971927
+aF-1.36752640140215
+aF-2.2598206713738187
+aF-1.2640377985028335
+aF2.283052815269464
+aF-1.0557862202057837
+aF0.079432182176553123
+aF1.0562408793635381
+aF0.6333966102538291
+aF0.14171268191814351
+aF-0.27125339381618702
+aF0.31954097806615628
+aF0.47400091612796624
+aF0.49104886341471743
+aF-0.97220236579446462
+aF1.1647582542226096
+aF-0.35766948146152477
+aF-0.14129038813643882
+aF0.34629777676935619
+aF0.2728380774782162
+aF0.19385462511317461
+aF0.74489924106931782
+aF-0.80643974520986705
+aF0.46229319252446149
+aF-0.72185528204607852
+aF-0.60700378551548728
+aF0.39633882772925744
+aF-0.17306267930447911
+aF-0.85630984070369109
+aF1.0528134657514998
+aF-0.20078964091426316
+aF-0.027624055334616128
+aF-0.21735590066143673
+aF0.55858142828074853
+aF0.45636177042259124
+aF0.59690439001968731
+aF0.44997981230070444
+aF-0.32914405620430975
+aF0.63877354673037445
+aF-0.5497895663657002
+aF1.2772230925541375
+aF2.3263264245959441
+aF1.8695478346490835
+aF1.4368926766296901
+aF-3.0353406845280073
+aF-0.11956323005386738
+aF0.57975361681607707
+aF-0.69181718147751226
+aF-0.84664291566905225
+aF1.2030788383857915
+aF0.17007323610646807
+aF-0.49364611846537132
+aF-0.064552797091005809
+aF-0.22527474566659766
+aF0.68055920970193839
+aF-0.8221157921078055
+aF1.1839675057756698
+aF-0.015542966211810907
+aF-0.36476277266424911
+aF0.22764150044329121
+aF-0.33453182607716475
+aF-0.43262068989118102
+aF-0.42015688055241684
+aF0.095687891188762392
+aF0.46282388164921529
+aF0.0012939188673551649
+aF0.052697744521397943
+aF-0.054349221743711679
+aF0.14637680393589755
+aF-0.19314828759177663
+aF-0.043098093601348489
+aF0.18005659861412335
+aF0.075801297944294882
+aF0.078637553327431275
+aF-0.29762304957670394
+aF0.10745122983225297
+aF-0.059909109492088886
+aF-0.16819981839908613
+aF-0.87664730332226048
+aF0.45053146573490332
+aF-0.55942490969674263
+aF-0.24564446891847397
+aF-1.347678346984984
+aF0.0025483544526788693
+aF1.0895861546022101
+aF-0.41981826178634635
+aF1.2114864571427428
+aF-0.47824834776036768
+aF0.19427198975720733
+aF0.92158533631803974
+aF-0.030614869655718482
+aF0.092893881414845059
+aF0.17924769984076383
+aF0.14016240160280791
+aF-0.25336078119949618
+aF1.2268030036203061
+aF0.29405587003838152
+aF-0.30898884644941987
+aF-1.128976901562095
+aF0.59589299679666929
+aF0.18832573509477502
+aF0.60058916286136077
+aF0.16113351033858725
+aF1.648542205360084
+aF-0.94061950991812737
+aF0.76110120970872552
+aF1.1418429796637746
+aF-1.5985935916679974
+aF-0.34385834145024674
+aF0.47790224628531475
+aF0.062383787224935247
+aF0.26433977498802291
+aF-0.24273399707910578
+aF-0.35225750718632526
+aF0.54663129357503393
+aF-0.17146329731512616
+aF0.710021533328133
+aF0.34016765225765688
+aF1.0905802833841407
+aF-1.1163511782899787
+aF1.7083740772773495
+aF0.61271253928299041
+aF3.679149076624626
+aF0.06244669701249439
+aF-1.8808226976540339
+aF1.3903547169318622
+aF-2.1718223133725196
+aF0.36928192990289305
+aF-0.012675364423275159
+aF-1.7675282839522111
+aF0.33134577440020696
+aF-0.13910060537803384
+aF-0.36533787708139259
+aF-1.1716298369989993
+aF0.84284939693097127
+aF-2.4535530177841922
+aF-0.4231636179078207
+a(I20
+I10
+tp29
+g7
+tp30
+Rp31
+sS'B'
+p32
+g4
+((lp33
+F-0.093938931711387313
+aF0.047650608737320022
+aF0.087250063886046808
+aF0.028832813514696722
+aF-0.035279958109078753
+aF0.24096602913672696
+aF-0.085959767026266412
+aF0.014646280558452431
+aF-0.09612726965853495
+aF0.056233185489577731
+aF-0.2581708991108852
+aF0.088274670093458754
+aF-0.14739315874547268
+aF-0.013766019455205326
+aF-0.14168357045466881
+aF-0.16558236423992856
+aF-0.25256965636892853
+aF-0.13015732756336501
+aF0.028357506876190701
+aF0.065967655870973405
+aF0.2068401448938435
+aF0.086220269830623003
+aF-0.2872114847970883
+aF-0.1375449654712638
+aF-0.018927939751101793
+aF-0.33779224929697216
+aF-0.041842112730442409
+aF-0.079360012932377308
+aF0.044427743093070467
+aF0.074712066583139863
+aF0.12030433363980031
+aF-0.026857922136630887
+aF-0.031247742712063424
+aF0.19383623915751369
+aF0.24547024343911816
+aF-0.051191873439064617
+aF0.020732822319118504
+aF-0.12896264384766068
+aF0.0051812998677210134
+aF0.10233319497439021
+aF-0.079481187009714765
+aF0.017412425023895249
+aF0.0046809126504802796
+aF-0.083511921102900274
+aF-0.072161891340576545
+aF0.25132916562484875
+aF-0.13420340497169353
+aF-0.066502930595451606
+aF-0.20112101420637343
+aF-0.012760499960766095
+aF0.053037954284978983
+aF-0.070469346934467658
+aF0.04606528272383318
+aF-0.096695825289419557
+aF0.16954321866785454
+aF-0.0041767927517590312
+aF0.10403817474036575
+aF0.29150617764628844
+aF0.058530775273754554
+aF0.17825112004322385
+aF0.033566329139915779
+aF-0.041506475749662694
+aF-0.12339523823319276
+aF-0.05144019724694613
+aF0.15483574310236209
+aF0.11530659463253326
+aF-0.13832852868924445
+aF-0.025758201968683746
+aF-0.17375834779733651
+aF0.040988432791573506
+aF0.12954337814549641
+aF-0.099907912084635064
+aF-0.3737970832399844
+aF0.093145188715757637
+aF0.42872754479190567
+aF0.071658125829274735
+aF0.039899486866684299
+aF0.037973382571938948
+aF0.12829635533627493
+aF0.27908776828996129
+aF0.20383267432903876
+aF-0.026104176052743806
+aF0.0023075104956709154
+aF0.032932951757010887
+aF-0.11423501661555235
+aF0.15478255246577705
+aF0.021645245373229743
+aF0.20816194788420123
+aF-0.025874641130714547
+aF0.22076043309473167
+aF-0.25384533121579078
+aF0.24365110512152224
+aF-0.20299506100340059
+aF-0.14051634335505611
+aF0.0066751492342585683
+aF-0.19448359599694048
+aF0.062371943679208328
+aF0.072918783810003551
+aF0.17651184103014611
+aF-0.054076351660124054
+aF0.0559445428423406
+aF0.033067751624565968
+aF0.094131646353192364
+aF0.084483131915361359
+aF-0.13266767636353727
+aF0.23618907966749306
+aF-0.051082967341706725
+aF-0.12184734897111189
+aF-0.13316605092856204
+aF0.15977715556848729
+aF-0.021316378897339026
+aF0.36149793311295858
+aF-0.026537210834598337
+aF-0.01890420979350084
+aF0.054981905778027418
+aF-0.15762704252767767
+aF-0.037135467442436933
+aF-0.21136909594524519
+aF0.14024251411408523
+aF0.040466126804798518
+aF-0.16396959694154201
+aF0.0093047515346948908
+aF-0.05300976688431705
+aF0.18566787627956607
+aF0.18240794619002834
+aF0.087987620610470371
+aF0.065683123112646166
+aF0.10704910853367605
+aF-0.10257525315626044
+aF0.04871879750717404
+aF-0.05319661626353285
+aF0.11554447883599699
+aF-0.023745543509868891
+aF0.25058363785205195
+aF0.023047976386687919
+aF0.17001783136201642
+aF-0.0047251453017347787
+aF-0.20071081476484645
+aF0.048846324186016393
+aF-0.02655859302220747
+aF-0.18579019372064606
+aF0.030658554557631289
+aF0.036255090888476657
+aF-0.048978249485660652
+aF0.18408414957892838
+aF-0.10662117817764771
+aF-0.12523170597448163
+aF-0.00032532702304840605
+aF0.052952274725589277
+aF-0.068006567645814017
+aF-0.035866797423479826
+aF-0.1446700328849464
+aF0.26926707210159284
+aF0.25989514200800623
+aF-0.20341140557302756
+aF0.25926510700881922
+aF-0.11976380145691037
+aF-0.040662454998708748
+aF0.074231110500328365
+aF-0.043348164646155235
+aF0.17898445425805082
+aF0.16340759237636424
+aF-0.21336436737100381
+aF-0.14274355981617665
+aF-0.10159266947780948
+aF0.056281478049249649
+aF-0.057937113791074073
+aF0.094417964240449445
+aF0.030461911080015641
+aF-0.13596039596590107
+aF0.018697762042241526
+aF-0.10001108124764241
+aF-0.084086889050591557
+aF0.18647320311578539
+aF-0.22027781201374391
+aF-0.2693809914594773
+aF0.065737028012767873
+aF-0.2078827414961984
+aF-0.018797855914423962
+aF0.032746219310993682
+aF-0.035756199536202765
+aF-0.076235420322406891
+aF-0.025035467555755597
+aF0.1615704591946841
+aF-0.085407697696901319
+aF0.080953941428165893
+aF-0.083486039679039115
+aF0.076500477282197998
+aF-0.096845552646085534
+aF0.15938315808573472
+aF0.024965942731801929
+aF0.2132254272303416
+aF0.042955147049117182
+aF0.11588687675041494
+aF0.17270498668787082
+aF0.058062727113721561
+aF-0.051631531729916122
+aF-0.015048511289939285
+aF-0.12892050918179207
+aF-0.27503139425554307
+a(I20
+I10
+tp34
+g7
+tp35
+Rp36
+sS'b'
+p37
+g4
+((lp38
+F0.14999606832610834
+aF0.54203757081097381
+aF0.25440881648061237
+aF-0.30724069381998481
+aF-0.41711182958174531
+aF1.1368048328938969
+aF0.39131380909323454
+aF1.6051478186749
+aF0.82589230735685759
+aF1.4703903557201077
+aF-1.3789068923398957
+aF-0.26017206900968748
+aF0.99476817276398244
+aF1.8340336818640284
+aF-1.7159103187349525
+aF0.086931705874662257
+aF1.9556743528105947
+aF0.1614537696153415
+aF-0.6286883591253638
+aF-1.4388244653384346
+a(I20
+I1
+tp39
+g7
+tp40
+Rp41
+ss.
\ No newline at end of file
diff --git a/examples/book/chap6/smoothrec b/examples/book/chap6/smoothrec
new file mode 100755
index 0000000..ddca231
--- /dev/null
+++ b/examples/book/chap6/smoothrec
@@ -0,0 +1,84 @@
+#!/usr/bin/python
+
+# Figures 6.8-10, pages 313-314
+# Quadratic smoothing.
+
+from math import pi
+from cvxopt import random, blas, lapack 
+from cvxopt.base import matrix, spmatrix, sin, mul
+import pylab
+
+n = 4000
+t = matrix(range(n), tc='d')
+ex = 0.5 * mul( sin(2*pi/n * t), sin(0.01 * t))
+corr = ex + 0.05 * random.normal(n,1)
+
+pylab.figure(1, facecolor='w', figsize=(8,5))
+pylab.subplot(211)
+pylab.plot(t, ex)
+pylab.ylabel('x[i]')
+pylab.xlabel('i')
+pylab.title('Original and corrupted signal (fig. 6.8)')
+pylab.subplot(212)
+pylab.plot(t, corr)
+pylab.ylabel('xcor[i]')
+pylab.xlabel('i')
+
+
+# A = D'*D is an n by n tridiagonal matrix with -1.0 on the 
+# upper/lower diagonal and 1, 2, 2, ..., 2, 2, 1 on the diagonal.
+Ad = matrix([1.0] + (n-2)*[2.0] + [1.0])
+As = matrix(-1.0, (n-1,1))
+
+nopts = 50
+deltas = -10.0 + 20.0/(nopts-1) * matrix(range(nopts))
+cost1, cost2 = [], []
+for delta in deltas:
+    xr = +corr 
+    lapack.ptsv(1.0 + 10**delta * Ad, 10**delta *As, xr)
+    cost1 += [blas.nrm2(xr - corr)] 
+    cost2 += [blas.nrm2(xr[1:] - xr[:-1])] 
+
+# Find solutions with ||xhat - xcorr || roughly equal to 8.0, 3.1, 1.0.
+mv1, k1 = min(zip([abs(c - 8.0) for c in cost1], range(nopts)))
+xr1 = +corr 
+lapack.ptsv(1.0 + 10**deltas[k1] * Ad, 10**deltas[k1] *As, xr1)
+mv2, k2 = min(zip([abs(c - 3.1) for c in cost1], range(nopts)))
+xr2 = +corr 
+lapack.ptsv(1.0 + 10**deltas[k2] * Ad, 10**deltas[k2] *As, xr2)
+mv3, k3 = min(zip([abs(c - 1.0) for c in cost1], range(nopts)))
+xr3 = +corr 
+lapack.ptsv(1.0 + 10**deltas[k3] * Ad, 10**deltas[k3] *As, xr3)
+
+pylab.figure(2, facecolor='w')
+pylab.plot(cost1, cost2, [blas.nrm2(corr)], [0], 'o',
+    [0], [blas.nrm2(corr[1:] - corr[:-1])], 'o') 
+pylab.plot([cost1[k1]], [cost2[k1]], 'o', [cost1[k2]], [cost2[k2]], 'o',
+    [cost1[k3]], [cost2[k3]], 'o')
+pylab.text(cost1[k1], cost2[k1],'1')
+pylab.text(cost1[k2], cost2[k2],'2')
+pylab.text(cost1[k3], cost2[k3],'3')
+pylab.title('Optimal trade-off curve (fig. 6.9)')
+pylab.xlabel('|| xhat - xcor ||_2')
+pylab.ylabel('|| D*xhat ||_2')
+pylab.axis([-0.4, 20, -0.1, 5])
+pylab.grid()
+
+pylab.figure(3, facecolor='w', figsize=(8,7.5))
+pylab.subplot(311)
+pylab.plot(t, xr1)
+pylab.axis([0, 4000, -0.6, 0.6])
+pylab.ylabel('xhat1[i]')
+pylab.title('Three smoothed sigals (fig. 6.10).')
+
+pylab.subplot(312)
+pylab.plot(t, xr2)
+pylab.ylabel('xhat2[i]')
+pylab.axis([0, 4000, -0.6, 0.6])
+
+pylab.subplot(313)
+pylab.plot(t, xr3)
+pylab.axis([0, 4000, -0.6, 0.6])
+pylab.ylabel('xhat3[i]')
+pylab.xlabel('i')
+pylab.show()
diff --git a/examples/book/chap6/tv b/examples/book/chap6/tv
new file mode 100755
index 0000000..0b4948f
--- /dev/null
+++ b/examples/book/chap6/tv
@@ -0,0 +1,286 @@
+#!/usr/bin/python
+
+# Figures 6.11-14, pages 315-317.
+# Total variation reconstruction.
+
+from math import pi
+from cvxopt import random, blas, lapack, solvers
+from cvxopt.base import matrix, spmatrix, sin, mul, div
+solvers.options['show_progress'] = 0
+import pylab
+
+n = 2000
+t = matrix( range(n), tc='d' )
+ex = matrix( n/4*[1.0] + n/4*[-1.0] + n/4*[1.0] + n/4*[-1.0] ) + \
+    0.5 * sin( 2.0*pi/n * t )
+corr = ex + 0.1 * random.normal(n,1)
+
+pylab.figure(1, facecolor='w', figsize=(8,5))
+pylab.subplot(211)
+pylab.plot(t, ex)
+pylab.ylabel('x[i]')
+pylab.xlabel('i')
+pylab.axis([0, 2000, -2, 2])
+pylab.title('Original and corrupted signal (fig. 6.11)')
+pylab.subplot(212)
+pylab.plot(t, corr)
+pylab.ylabel('xcor[i]')
+pylab.xlabel('i')
+pylab.axis([0, 2000, -2, 2])
+
+
+# Quadratic smoothing.
+# A = D'*D is an n by n tridiagonal matrix with -1.0 on the 
+# upper/lower diagonal and 1, 2, 2, ..., 2, 2, 1 on the diagonal.
+Ad = matrix([1.0] + (n-2)*[2.0] + [1.0])
+As = matrix(-1.0, (n-1,1))
+
+nopts = 100
+deltas = -10.0 + 20.0/(nopts-1) * matrix(range(nopts))
+
+cost1, cost2 = [], []
+for delta in deltas:
+    xr = +corr 
+    lapack.ptsv(1.0 + 10**delta * Ad, 10**delta * As, xr)
+    cost1 += [blas.nrm2(xr - corr)] 
+    cost2 += [blas.nrm2(xr[1:] - xr[:-1])] 
+
+# Find solutions with ||xhat - xcorr || roughly equal to 4, 7, 10.
+mv1, k1 = min(zip([abs(c - 10.0) for c in cost1], range(nopts)))
+xr1 = +corr 
+lapack.ptsv(1.0 + 10**deltas[k1] * Ad, 10**deltas[k1] * As, xr1)
+mv2, k2 = min(zip([abs(c - 7.0) for c in cost1], range(nopts)))
+xr2 = +corr 
+lapack.ptsv(1.0 + 10**deltas[k2] * Ad, 10**deltas[k2] * As, xr2)
+mv3, k3 = min(zip([abs(c - 4.0) for c in cost1], range(nopts)))
+xr3 = +corr 
+lapack.ptsv(1.0 + 10**deltas[k3] * Ad, 10**deltas[k3] * As, xr3)
+
+pylab.figure(2, facecolor='w')
+pylab.plot(cost1, cost2, [blas.nrm2(corr)], [0], 'o',
+    [0], [blas.nrm2(corr[1:] - corr[:-1])], 'o') 
+pylab.plot([cost1[k1]], [cost2[k1]], 'o', 
+    [cost1[k2]], [cost2[k2]], 'o', [cost1[k3]], [cost2[k3]], 'o')
+pylab.text(cost1[k1], cost2[k1], '1')
+pylab.text(cost1[k2], cost2[k2], '2')
+pylab.text(cost1[k3], cost2[k3], '3')
+pylab.title('Optimal trade-off curve (quadratic smoothing)')
+pylab.xlabel('|| xhat - xcor ||_2')
+pylab.ylabel('|| D*xhat ||_2')
+pylab.axis([-0.4, 50, -0.1, 8.0])
+pylab.grid()
+
+pylab.figure(3, facecolor='w', figsize=(8,7.5))
+pylab.subplot(311)
+pylab.plot(t, xr1)
+pylab.axis([0, 2000, -2.0, 2.0])
+pylab.ylabel('xhat1[i]')
+pylab.title('Three quadratically smoothed sigals (fig. 6.12).')
+pylab.subplot(312)
+pylab.plot(t, xr2)
+pylab.ylabel('xhat2[i]')
+pylab.axis([0, 2000, -2.0, 2.0])
+pylab.subplot(313)
+pylab.plot(t, xr3)
+pylab.axis([0, 2000, -2.0, 2.0])
+pylab.ylabel('xhat3[i]')
+pylab.xlabel('i')
+print "Close figures to start total variation reconstruction."
+pylab.show()
+
+
+# Total variation smoothing.
+#
+# minimize (1/2) * ||x-corr||_2^2 + delta * || D*x ||_1
+#
+# minimize    (1/2) * ||x-corr||_2^2 + delta * 1'*y
+# subject to  -y <= D*x <= y
+#
+# Variables x (n), y (n-1).
+
+def tv(delta):
+    """
+        minimize    (1/2) * ||x-corr||_2^2 + delta * sum(y)
+        subject to  -y <= D*x <= y
+    
+    Variables x (n), y (n-1).
+    """
+
+    def F(x=None):
+        """
+        Function and gradient evaluation of 
+
+            f = 1/2 * || x[:n]-corr ||_2^2 + delta * sum(x[n:]).
+        """
+    
+        nvars = 2*n - 1
+        if x is None: return 0, matrix(0.0, (nvars,1))
+        f = 0.5 * blas.nrm2( x[:n]-corr )**2 + delta * sum(x[n:])
+        gradf = matrix(0.0, (1,nvars))
+        gradf[:n] = x[:n]-corr
+        gradf[n:] = delta
+        return f, gradf 
+
+
+    def G(u, v, alpha=1.0, beta=0.0, trans='N'):
+        """
+           v := alpha*[D, -I;  -D, -I] * u + beta * v  (trans = 'N')
+           v := alpha*[D, -I;  -D, -I]' * u + beta * v  (trans = 'T')
+
+        For an n-vector z, D*z = z[1:] - z[:-1].
+        For an (n-1)-vector z, D'*z = [-z;0] + [0; z].
+        """
+
+        v *= beta
+        if trans == 'N':
+            y = u[1:n] - u[:n-1]
+            v[:n-1] += alpha*(y - u[n:])
+            v[n-1:] += alpha*(-y - u[n:])
+        else:
+            y = u[:n-1] - u[n-1:]
+            v[:n-1] -= alpha * y
+            v[1:n] += alpha * y
+            v[n:] -= alpha * (u[:n-1] + u[n-1:])
+
+    h = matrix(0.0, (2*(n-1),1))
+
+
+    # Customized solver for KKT system with coefficient
+    #
+    #     [  z[0]*I  0    D'   -D' ] 
+    #     [  0       0   -I    -I  ] 
+    #     [  D      -I   -D1    0  ] 
+    #     [ -D      -I    0    -D2 ].
+     
+    # Diagonal and subdiagonal.
+    Sd = matrix(0.0, (n,1))
+    Se = matrix(0.0, (n-1,1))
+
+    def kktsolver(x, z, dnl, dl):
+        """
+        Factor the tridiagonal matrix
+
+             S = z[0]*I + 4.0 * D' * diag( d1.*d2./(d1+d2) ) * D 
+
+        with d1 = dl[:n-1]**2 = diag(D1^-1),  
+        d2 = dl[n-1:]**2 = diag(D2^-1).
+        """
+
+        d1 = dl[:n-1]**2
+        d2 = dl[n-1:]**2
+        d = 4.0*div( mul(d1,d2), d1+d2) 
+        Sd[:] = z[0]
+        Sd[:n-1] += d
+        Sd[1:] += d
+        Se[:] = -d
+        lapack.pttrf(Sd, Se)
+        def g(x, y, znl, zl):
+
+            """
+            Solve 
+
+                [  z[0]*I  0   D'  -D' ] [x[:n]   ]    [bx[:n]   ]
+                [  0       0  -I   -I  ] [x[n:]   ] =  [bx[n:]   ]
+                [  D      -I  -D1   0  ] [zl[:n-1]]    [bzl[:n-1]]
+                [ -D      -I   0   -D2 ] [zl[n-1:]]    [bzl[n-1:]].
+
+            First solve
+                 
+                S*x[:n] = bx[:n] + D' * ( (d1-d2) ./ (d1+d2) .* bx[n:] 
+                    + 2*d1.*d2./(d1+d2) .* (bzl[:n-1] - bzl[n-1:]) ).
+
+            Then take
+
+                x[n:] = (d1+d2)^-1 .* ( bx[n:] - d1.*bzl[:n-1] 
+                         - d2.*bzl[n-1:]  + (d1-d2) .* D*x[:n] ) 
+                zl[:n-1] = d1 .* (D*x[:n] - x[n:] - bzl[:n-1])
+                zl[n-1:] = d2 .* (-D*x[:n] - x[n:] - bzl[n-1:]).
+            """
+
+            # y = (d1-d2) ./ (d1+d2) .* bx[n:] + 
+            #     2*d1.*d2./(d1+d2) .* (bzl[:n-1] - bzl[n-1:])
+            y = mul( div(d1-d2, d1+d2), x[n:]) + \
+                mul( 0.5*d, zl[:n-1]-zl[n-1:] ) 
+
+            # x[:n] += D*y
+            x[:n-1] -= y
+            x[1:n] += y
+
+            # x[:n] := S^-1 * x[:n]
+            lapack.pttrs(Sd, Se, x) 
+
+            # u = D*x[:n]
+            u = x[1:n] - x[0:n-1]
+
+            # x[n:] = (d1+d2)^-1 .* ( bx[n:] - d1.*bzl[:n-1] 
+            #     - d2.*bzl[n-1:]  + (d1-d2) .* u) 
+            x[n:] = div( x[n:] - mul(d1, zl[:n-1]) - 
+                mul(d2, zl[n-1:]) + mul(d1-d2, u), d1+d2 )
+
+            # zl[:n-1] = d1 .* (D*x[:n] - x[n:] - bzl[:n-1])
+            # zl[n-1:] = d2 .* (-D*x[:n] - x[n:] - bzl[n-1:])
+            zl[:n-1] = mul(d1, u - x[n:] - zl[:n-1])
+            zl[n-1:] = mul(d2, -u - x[n:] - zl[n-1:])
+
+        return g
+
+    return solvers.nlcp(kktsolver, F, G, h)['x'][:n]
+
+
+nopts = 15
+deltas = -3.0 + (3.0-(-3.0))/(nopts-1) * matrix(range(nopts))
+cost1, cost2 = [], []
+for delta, k in zip(deltas, xrange(nopts)):
+    xtv = tv(10**delta)
+    cost1 += [blas.nrm2(xtv - corr)] 
+    cost2 += [blas.asum(xtv[1:] - xtv[:-1])] 
+mv1, k1 = min(zip([abs(c - 20.0) for c in cost2], range(nopts)))
+xtv1 = tv(10**deltas[k1])
+mv2, k2 = min(zip([abs(c - 8.0) for c in cost2], range(nopts)))
+xtv2 = tv(10**deltas[k2])
+mv3, k3 = min(zip([abs(c - 5.0) for c in cost2], range(nopts)))
+xtv3 = tv(10**deltas[k3])
+
+pylab.figure(1, facecolor='w', figsize=(8,5))
+pylab.subplot(211)
+pylab.plot(t, ex)
+pylab.ylabel('x[i]')
+pylab.xlabel('i')
+pylab.axis([0, 2000, -2, 2])
+pylab.title('Original and corrupted signal (fig. 6.11)')
+pylab.subplot(212)
+pylab.plot(t, corr)
+pylab.ylabel('xcor[i]')
+pylab.xlabel('i')
+pylab.axis([0, 2000, -2, 2])
+
+pylab.figure(2, facecolor='w') #figsize=(8,7.5))
+pylab.plot(cost1, cost2, [blas.nrm2(corr)], [0], 'o',
+        [0], [blas.asum(corr[1:] - corr[:-1])], 'o') 
+pylab.plot([cost1[k1]], [cost2[k1]], 'o', [cost1[k2]], [cost2[k2]], 'o',
+    [cost1[k3]], [cost2[k3]], 'o')
+pylab.text(cost1[k1], cost2[k1],'1')
+pylab.text(cost1[k2], cost2[k2],'2')
+pylab.text(cost1[k3], cost2[k3],'3')
+pylab.grid()
+pylab.axis([-1, 50, -5, 250])
+pylab.xlabel('||xhat-xcor||_2')
+pylab.ylabel('||D*xhat||_1')
+pylab.title('Optimal trade-off curve (fig. 6.13)')
+
+pylab.figure(3, facecolor='w', figsize=(8,7.5))
+pylab.subplot(311)
+pylab.plot(t, xtv1)
+pylab.axis([0, 2000, -2.0, 2.0])
+pylab.ylabel('xhat1[i]')
+pylab.title('Three reconstructed signals (fig. 6.14)')
+pylab.subplot(312)
+pylab.plot(t, xtv2)
+pylab.ylabel('xhat2[i]')
+pylab.axis([0, 2000, -2.0, 2.0])
+pylab.subplot(313)
+pylab.plot(t, xtv3)
+pylab.axis([0, 2000, -2.0, 2.0])
+pylab.ylabel('xhat3[i]')
+pylab.xlabel('i')
+pylab.show()
diff --git a/examples/book/chap7/chernoff b/examples/book/chap7/chernoff
new file mode 100755
index 0000000..53b8d72
--- /dev/null
+++ b/examples/book/chap7/chernoff
@@ -0,0 +1,104 @@
+#!/usr/bin/python
+
+# Figure 7.8, page 384.
+# Chernoff lower bound.
+
+import pylab
+from cvxopt.base import matrix, mul, exp
+from cvxopt import solvers, blas, random 
+solvers.options['show_progress'] = False
+
+# Extreme points and inequality description of Voronoi region around 
+# first symbol (at the origin).
+m = 6
+V = matrix([ 1.0,  1.0, 
+            -1.0,  2.0,
+            -2.0,  1.0,
+            -2.0, -1.0,
+             0.0, -2.0,
+             1.5, -1.0,
+             1.0,  1.0 ], (2,m+1))
+
+# A and b are lists with the inequality descriptions of the regions.
+A = [ matrix( [-(V[1,:m] - V[1,1:]), V[0,:m] - V[0,1:]] ).T ]
+b = [ mul(A[0], V[:,:m].T) * matrix(1.0, (2,1)) ]
+
+# List of symbols.
+C = [ matrix(0.0, (2,1)) ] + \
+    [ 2.0 * b[0][k] / blas.nrm2(A[0][k,:])**2 * A[0][k,:].T for k in 
+    xrange(m) ]
+
+# Voronoi set around C[1]
+A += [ matrix(0.0, (3,2)) ] 
+b += [ matrix(0.0, (3,1)) ]
+A[1][0,:] = -A[0][0,:]
+b[1][0] = -b[0][0]
+A[1][1,:] = (C[m] - C[1]).T
+b[1][1] = 0.5 * A[1][1,:] * ( C[m] + C[1] )
+A[1][2,:] = (C[2] - C[1]).T
+b[1][2] = 0.5 * A[1][2,:] * ( C[2] + C[1] )
+
+# Voronoi set around C[2], ..., C[5]
+for k in xrange(2, 6):
+    A += [ matrix(0.0, (3,2)) ] 
+    b += [ matrix(0.0, (3,1)) ]
+    A[k][0,:] = -A[0][k-1,:]
+    b[k][0] = -b[0][k-1]
+    A[k][1,:] = (C[k-1] - C[k]).T
+    b[k][1] = 0.5 * A[k][1,:] * ( C[k-1] + C[k] )
+    A[k][2,:] = (C[k+1] - C[k]).T
+    b[k][2] = 0.5 * A[k][2,:] * ( C[k+1] + C[k] )
+
+# Voronoi set around C[6]
+A += [ matrix(0.0, (3,2)) ] 
+b += [ matrix(0.0, (3,1)) ]
+A[6][0,:] = -A[0][5,:]
+b[6][0] = -b[0][5]
+A[6][1,:] = (C[1] - C[6]).T
+b[6][1] = 0.5 * A[6][1,:] * ( C[1] + C[6] )
+A[6][2,:] = (C[5] - C[6]).T
+b[6][2] = 0.5 * A[6][2,:] * ( C[5] + C[6] )
+
+
+# For regions k=1, ..., 6, let pk be the optimal value of 
+#
+#     minimize    x'*x 
+#     subject to  A*x <= b.
+#
+# The Chernoff upper bound is  1.0 - sum exp( - pk / (2 sigma^2)).
+
+P = matrix([1.0, 0.0, 0.0, 1.0], (2,2))
+q = matrix(0.0, (2,1))
+optvals = matrix([ blas.nrm2( solvers.qp(P, q, A[k], b[k] )['x'] )**2
+    for k in xrange(1,7) ])
+nopts = 200
+sigmas = 0.2 + (0.5 - 0.2)/nopts * matrix(range(nopts), tc='d')
+bnds = [ 1.0 - sum( exp( - optvals / (2*sigma**2) )) for sigma 
+    in sigmas]
+
+pylab.figure(facecolor='w')
+pylab.plot(sigmas, bnds, '-')
+pylab.axis([0.2, 0.5, 0.9, 1.0])
+pylab.title('Chernoff lower bound (fig. 7.8)')
+pylab.xlabel('sigma')
+pylab.ylabel('Probability of correct detection')
+pylab.show()
+
+if 0:  # uncomment out for the Monte Carlo estimation.
+    N = 100000
+    mcest = []
+    ones = matrix(1.0, (1,m))
+    for sigma in sigmas: 
+        X = sigma * random.normal(2, N)
+        S = b[0][:,N*[0]] - A[0]*X 
+        S = ones * (S - abs(S))
+        mcest += [ N - len(filter(lambda x: x < 0.0, S)) ]
+
+    pylab.figure(facecolor='w')
+    pylab.plot(sigmas, bnds, '-', sigmas, (1.0/N)*matrix(mcest), '--')
+    pylab.plot(sigmas, bnds, '-')
+    pylab.axis([0.2, 0.5, 0.9, 1.0])
+    pylab.title('Chernoff lower bound (fig. 7.8)')
+    pylab.xlabel('sigma')
+    pylab.ylabel('Probability of correct detection')
+    pylab.show()
diff --git a/examples/book/chap7/expdesign b/examples/book/chap7/expdesign
new file mode 100755
index 0000000..5887458
--- /dev/null
+++ b/examples/book/chap7/expdesign
@@ -0,0 +1,185 @@
+#!/usr/bin/python
+
+# Figures 7.9-12, pages 389-390.
+# Experiment design.
+
+from math import pi, log, sqrt
+import pylab
+from cvxopt import base, blas, lapack, solvers
+from cvxopt.base import matrix, spmatrix, mul, cos, sin
+solvers.options['show_progress'] = False
+
+V = matrix([-2.1213,    2.1213,
+            -2.2981,    1.9284,
+            -2.4575,    1.7207,
+            -2.5981,    1.5000,
+            -2.7189,    1.2679,
+            -2.8191,    1.0261,
+            -2.8978,    0.7765,
+            -2.9544,    0.5209,
+            -2.9886,    0.2615,
+            -3.0000,    0.0000,
+             1.5000,    0.0000,
+             1.4772,   -0.2605,
+             1.4095,   -0.5130,
+             1.2990,   -0.7500,
+             1.1491,   -0.9642,
+             0.9642,   -1.1491,
+             0.7500,   -1.2990,
+             0.5130,   -1.4095,
+             0.2605,   -1.4772,
+             0.0000,   -1.5000 ], (2,20))
+
+n = V.size[1]
+G = spmatrix(-1.0, range(n), range(n))
+h = matrix(0.0, (n,1))
+A = matrix(1.0, (1,n))
+b = matrix(1.0)
+
+
+# D-design
+#
+# minimize    f(x) = -log det V*diag(x)*V'
+# subject to  x >= 0
+#             sum(x) = 1
+#
+# The gradient and Hessian of f are 
+#
+#     gradf = -diag(V' * X^-1 * V) 
+#         H = (V' * X^-1 * V)**2.
+#
+# where X = V * diag(x) * V'.
+
+def F(x=None, z=None):
+    if x is None: return 0, matrix(1.0, (n,1))
+    X = V * spmatrix(x, range(n), range(n)) * V.T
+    L = +X
+    try: lapack.potrf(L)
+    except ArithmeticError: return None
+    f = - 2.0 * (log(L[0,0])  + log(L[1,1]))
+    W = +V
+    blas.trsm(L, W)    
+    gradf = matrix(-1.0, (1,2)) * W**2
+    if z is None: return f, gradf
+    H = matrix(0.0, (n,n))
+    blas.syrk(W, H, trans='T')
+    return f, gradf, z[0] * H**2
+xd = solvers.cp(F, G, h, A, b)['x']
+
+pylab.figure(1, facecolor='w', figsize=(5,5))
+pylab.plot(V[0,:], V[1,:],'ow', [0], [0], 'k+')
+I = [ k for k in xrange(n) if xd[k] > 1e-5 ]
+pylab.plot(V[0,I], V[1,I],'or')
+
+# Enclosing ellipse is  {x | x' * (V*diag(xe)*V')^-1 * x = sqrt(2)}
+nopts = 1000
+angles = matrix( [ a*2.0*pi/nopts for a in xrange(nopts) ], (1,nopts) )
+circle = matrix(0.0, (2,nopts))
+circle[0,:], circle[1,:] = cos(angles), sin(angles)
+
+W = V * spmatrix(xd, range(n), range(n)) * V.T
+lapack.potrf(W)
+ellipse = sqrt(2.0) * circle
+blas.trmm(W, ellipse)
+pylab.plot(ellipse[0,:], ellipse[1,:], 'k--')
+pylab.axis([-5, 5, -5, 5])
+pylab.title('D-optimal design (fig. 7.9)')
+pylab.axis('off')
+
+
+# E-design.
+#
+# maximize    w
+# subject to  w*I <= V*diag(x)*V' 
+#             x >= 0
+#             sum(x) = 1
+
+novars = n+1
+c = matrix(0.0, (novars,1))
+c[-1] = -1.0
+Gs = [matrix(0.0, (4,novars))]
+for k in xrange(n):  Gs[0][:,k] = -(V[:,k]*V[:,k].T)[:]
+Gs[0][[0,3],-1] = 1.0
+hs = [matrix(0.0, (2,2))]
+Ge = matrix(0.0, (n, novars))
+Ge[:,:n] = G
+Ae = matrix(n*[1.0] + [0.0], (1,novars))
+sol = solvers.sdp(c, Ge, h, Gs, hs, Ae, b)
+xe = sol['x'][:n]
+Z = sol['zs'][0]
+mu = sol['y'][0]
+
+pylab.figure(2, facecolor='w', figsize=(5,5))
+pylab.plot(V[0,:], V[1,:],'ow', [0], [0], 'k+')
+I = [ k for k in xrange(n) if xe[k] > 1e-5 ]
+pylab.plot(V[0,I], V[1,I],'or')
+
+# Enclosing ellipse follows from the solution of the dual problem:
+#
+# minimize    mu
+# subject to  diag(V'*Z*V) <= mu*1
+#             Z >= 0 
+
+lapack.potrf(Z)
+ellipse = sqrt(mu) * circle
+blas.trsm(Z, ellipse, transA='T')
+pylab.plot(ellipse[0,:], ellipse[1,:], 'k--')
+pylab.axis([-5, 5, -5, 5])
+pylab.title('E-optimal design (fig. 7.10)')
+pylab.axis('off')
+
+
+# A-design.
+#
+# minimize    tr (V*diag(x)*V')^{-1}
+# subject to  x >= 0
+#             sum(x) = 1
+# 
+# minimize    tr Y 
+# subject to  [ V*diag(x)*V', I ]
+#             [ I,            Y ] >= 0          
+#             x >= 0
+#             sum(x) = 1
+
+novars = 3 + n
+c = matrix(0.0, (novars,1))
+c[[-3, -1]] = 1.0
+Gs = [matrix(0.0, (16, novars))]
+for k in xrange(n):
+    Gk = matrix(0.0, (4,4))
+    Gk[:2,:2] = -V[:,k] * V[:,k].T
+    Gs[0][:,k] = Gk[:]
+Gs[0][10,-3] = -1.0    
+Gs[0][11,-2] = -1.0    
+Gs[0][15,-1] = -1.0    
+hs = [matrix(0.0, (4,4))]
+hs[0][2,0] = 1.0
+hs[0][3,1] = 1.0
+Ga = matrix(0.0, (n, novars))
+Ga[:,:n] = G
+Aa = matrix(n*[1.0] + 3*[0.0], (1,novars))
+sol = solvers.sdp(c, Ga, h, Gs, hs, Aa, b)
+xa = sol['x'][:n]
+Z = sol['zs'][0][:2,:2]
+mu = sol['y'][0]
+
+pylab.figure(3, facecolor='w', figsize=(5,5))
+pylab.plot(V[0,:], V[1,:],'ow', [0], [0], 'k+')
+I = [ k for k in xrange(n) if xa[k] > 1e-5 ]
+pylab.plot(V[0,I], V[1,I],'or')
+
+# Enclosing ellipse follows from the solution of the dual problem:
+#
+# maximize    -mu - 2 * tr Z12
+# subject to  diag(V'*Z11*V) <= mu*1
+#             [ Z11, Z12 ]
+#             [ Z21, I   ] >= 0  
+
+lapack.potrf(Z)
+ellipse = sqrt(mu) * circle
+blas.trsm(Z, ellipse, transA='T')
+pylab.plot(ellipse[0,:], ellipse[1,:], 'k--')
+pylab.axis([-5, 5, -5, 5])
+pylab.title('A-optimal design (fig. 7.11)')
+pylab.axis('off')
+pylab.show()
diff --git a/examples/book/chap7/logreg b/examples/book/chap7/logreg
new file mode 100755
index 0000000..17c2d43
--- /dev/null
+++ b/examples/book/chap7/logreg
@@ -0,0 +1,47 @@
+#!/usr/bin/python
+
+# Figures 7.1, page 355.
+# Logistic regression.
+
+import pylab, pickle
+from cvxopt import solvers
+from cvxopt.base import matrix, spmatrix, log, exp, div
+solvers.options['show_progress'] = False
+
+data = pickle.load(open("logreg.pic"))
+u, y = data['u'], data['y']
+
+# minimize   sum_{y_k = 1} (a*uk + b) + sum log (1 + exp(a*u + b))
+#
+# two variables a, b. 
+
+m = u.size[0]
+A = matrix(1.0, (m,2))
+A[:,0] = u
+c = -matrix([sum( uk for uk, yk in zip(u,y) if yk ), sum(y) ])
+
+# minimize  c'*x + sum log (1 + exp(A*x)) 
+#
+# variable x (2).
+
+def F(x=None, z=None):
+   if x is None: return 0, matrix(0.0, (2,1))
+   w = exp(A*x)
+   f = c.T*x + sum(log(1+w))
+   grad = c + A.T * div(w, 1+w)  
+   if z is None: return f, grad.T
+   H = A.T * spmatrix(div(w,(1+w)**2), range(m), range(m)) * A
+   return f, grad.T, z[0]*H 
+sol = solvers.cp(F)
+a, b = sol['x'][0], sol['x'][1]
+
+pylab.figure(facecolor='w')
+nopts = 200
+pts = -1.0 + 12.0/nopts * matrix(range(nopts)) 
+w = exp(a*pts + b)
+pylab.plot(u, y, 'o', pts, div(w, 1+w), '-')
+pylab.title('Logistic regression (fig. 7.1)')
+pylab.axis([-1, 11, -0.1, 1.1])
+pylab.xlabel('u')
+pylab.ylabel('Prob(y=1)')
+pylab.show()
diff --git a/examples/book/chap7/logreg.pic b/examples/book/chap7/logreg.pic
new file mode 100644
index 0000000..cb1da1a
--- /dev/null
+++ b/examples/book/chap7/logreg.pic
@@ -0,0 +1,226 @@
+(dp0
+S'y'
+p1
+ccvxopt.base
+matrix
+p2
+((lp3
+I1
+aI0
+aI1
+aI1
+aI1
+aI1
+aI0
+aI0
+aI1
+aI0
+aI1
+aI1
+aI1
+aI1
+aI0
+aI0
+aI1
+aI1
+aI0
+aI1
+aI0
+aI0
+aI1
+aI0
+aI0
+aI0
+aI0
+aI0
+aI0
+aI0
+aI0
+aI1
+aI1
+aI1
+aI0
+aI0
+aI1
+aI1
+aI0
+aI0
+aI1
+aI0
+aI1
+aI0
+aI1
+aI1
+aI1
+aI0
+aI0
+aI0
+aI0
+aI1
+aI1
+aI1
+aI1
+aI1
+aI0
+aI1
+aI1
+aI1
+aI0
+aI1
+aI1
+aI1
+aI1
+aI1
+aI0
+aI0
+aI0
+aI0
+aI1
+aI0
+aI1
+aI1
+aI1
+aI1
+aI0
+aI0
+aI1
+aI1
+aI1
+aI1
+aI0
+aI1
+aI0
+aI1
+aI0
+aI0
+aI1
+aI1
+aI0
+aI0
+aI1
+aI0
+aI0
+aI1
+aI0
+aI1
+aI0
+aI0
+a(I100
+I1
+tp4
+S'i'
+p5
+tp6
+Rp7
+sS'u'
+p8
+g2
+((lp9
+F9.5012928514717547
+aF2.3113851357428783
+aF6.068425835417866
+aF4.8598246870929973
+aF8.9129896614890161
+aF7.6209683302739473
+aF4.5646766516834134
+aF0.185036432482244
+aF8.2140716429525327
+aF4.4470336435319417
+aF6.1543234810009473
+aF7.9193703742703541
+aF9.2181297074480248
+aF7.382072458106653
+aF1.7626614449461799
+aF4.0570621306209551
+aF9.3546969910760538
+aF9.1690443991340764
+aF4.1027020699094532
+aF8.9364953091353367
+aF0.5789130478426856
+aF3.5286813221700037
+aF8.1316649730375783
+aF0.098613006609235609
+aF1.3889088195694987
+aF2.0276521856027316
+aF1.9872174266148965
+aF6.0379247919381926
+aF2.7218792496996036
+aF1.9881426776106215
+aF0.15273927029036269
+aF7.4678567656442931
+aF4.450964322879468
+aF9.3181457846166467
+aF4.6599434167542402
+aF4.1864946772750624
+aF8.4622141782432454
+aF5.2515249630517236
+aF2.0264735765038728
+aF6.7213746847428846
+aF8.3811844505238682
+aF0.19639513864817498
+aF6.8127716128213534
+aF3.7948101802799803
+aF8.3179601760960651
+aF5.028128839962509
+aF7.0947139270338679
+aF4.2889236534099675
+aF3.0461736686939433
+aF1.8965374754717499
+aF1.9343115640521509
+aF6.8222322359138357
+aF3.02764400776609
+aF5.4167385389808764
+aF1.5087297614976465
+aF6.9789848185986338
+aF3.7837300051267109
+aF8.6001160488681965
+aF8.5365513066276772
+aF5.9356291253968161
+aF4.9655244970310282
+aF8.9976917516960988
+aF8.216291607353428
+aF6.4491038419384434
+aF8.1797434083924507
+aF6.6022755644160238
+aF3.4197061827021575
+aF2.8972589585623814
+aF3.411935694148835
+aF5.3407901762660046
+aF7.2711321692967692
+aF3.0929015979095773
+aF8.3849604493808059
+aF5.6807246100777578
+aF3.704135566321165
+aF7.0273991324037688
+aF5.4657115182910623
+aF4.4488020467291216
+aF6.9456724042554754
+aF6.2131013079541342
+aF7.9482108020092648
+aF9.5684344844487708
+aF5.2259034908070774
+aF8.8014220741132725
+aF1.729561412752366
+aF9.7974689678884097
+aF2.7144725864179984
+aF2.5232934687399036
+aF8.7574189981807429
+aF7.373059884652557
+aF1.3651874225970972
+aF0.11756687353117969
+aF8.9389796644525337
+aF1.991380672057383
+aF2.9872301210221446
+aF6.6144257638232498
+aF2.8440858974994461
+aF4.6922428521100104
+aF0.64781122963272486
+aF9.8833493827763075
+a(I100
+I1
+tp10
+S'd'
+p11
+tp12
+Rp13
+s.
\ No newline at end of file
diff --git a/examples/book/chap7/maxent b/examples/book/chap7/maxent
new file mode 100755
index 0000000..9b77c93
--- /dev/null
+++ b/examples/book/chap7/maxent
@@ -0,0 +1,95 @@
+#!/usr/bin/python
+
+# Figures 7.2 and 7.3, pages 363 and 364.
+# Maximum entropy distribution.
+
+import pylab
+from cvxopt import solvers, blas
+from cvxopt.base import matrix, spmatrix, log, div
+solvers.options['show_progress'] = False
+
+# minimize     p'*log p  
+# subject to  -0.1 <= a'*p <= 0.1
+#              0.5 <= (a**2)'*p <= 0.6
+#             -0.3 <= (3*a**3 - 2*a)'*p <= -0.2 
+#              0.3 <= sum_{k:ak < 0} pk <= 0.4
+#              sum(p) = 1
+#
+# a in R^100 is made of 100 equidistant points in [-1,1].
+# The variable is p (100).
+
+n = 100 
+a = -1.0 + (2.0/(n-1)) * matrix(range(n), (1,n))
+I = [k for k in xrange(n) if a[k] < 0]
+G = matrix([-a, a, -a**2, a**2, -(3 * a**3 - 2*a), (3 * a**3 - 2*a),
+    matrix(0.0, (2,n))])
+G[6,I] = -1.0
+G[7,I] =  1.0
+h = matrix([0.1, 0.1, -0.5, 0.6, 0.3, -0.2, -0.3, 0.4 ])
+
+A, b = matrix(1.0, (1,n)), matrix(1.0)
+
+# minimize    x'*log x
+# subject to  G*x <= h
+#             A*x = b
+#
+# variable x (n).
+
+def F(x=None, z=None):
+   if x is None: return 0, matrix(1.0, (n,1))
+   if min(x) <= 0: return None
+   f = x.T*log(x)
+   grad = 1.0 + log(x)
+   if z is None: return f, grad.T
+   H = spmatrix(x**-1, range(n), range(n))
+   return f, grad.T, z[0]*H 
+sol = solvers.cp(F, G, h, A, b)
+p = sol['x']
+
+
+# Upper/lower bounds on cumulative distribution.
+# 
+# minimize/maximize  ck'*p = sum_{i<=alphak} pi 
+# subject to         G*x <= h
+#                    A*x = b
+#                    x >= 0
+#
+# Solve via dual:
+#
+# maximize    -h'*z - b'*w 
+# subject to   +/- c + G'*z + A'*w >= 0
+#              z >= 0
+#
+# with variables z (8), w (1).
+
+cc = matrix(0.0, (9,1))
+cc[:8], cc[8] = h, b
+GG = spmatrix([], [], [], (n+8, 9))
+GG[:n,:8] = -G.T
+GG[:n,8] = -A.T
+GG[n::n+9] = -1.0
+hh = matrix(0.0, (n+8,n))
+hh[:n,:] = matrix([i>=j for i in xrange(n) for j in xrange(n)], 
+    (n,n), 'd')  # upper triangular matrix of ones
+l = [-blas.dot(cc, solvers.lp(cc, GG, hh[:,k])['x']) for k in xrange(n)]
+u = [blas.dot(cc, solvers.lp(cc, GG, -hh[:,k])['x']) for k in xrange(n)]
+
+def f(x,y): return x+2*[y]
+def stepl(x): return reduce(f, x[1:], [x[0]])
+def stepr(x): return reduce(f, x[:-1], []) + [x[-1]]
+
+pylab.figure(1, facecolor='w')
+pylab.plot(stepl(a), stepr(p), '-')
+pylab.title('Maximum entropy distribution (fig. 7.2)')
+pylab.xlabel('a')
+pylab.ylabel('p = Prob(X = a)')
+
+pylab.figure(2, facecolor='w')
+pylab.plot([-1.0] + stepl(a), [0.0] + stepr(hh[:n,:].T*p), '-', 
+    [-1.0] + stepl(a), [0.0] + stepr(l), 'r-', 
+    [-1.0] + stepl(a), [0.0] + stepr(u), 'r-')
+pylab.title('Cumulative distribution (fig. 7.3)')
+pylab.xlabel('a')
+pylab.ylabel('Prob(X <= a)')
+pylab.axis([-1.1, 1.1, -0.1, 1.1])
+pylab.show()
diff --git a/examples/book/chap7/probbounds b/examples/book/chap7/probbounds
new file mode 100755
index 0000000..959ef62
--- /dev/null
+++ b/examples/book/chap7/probbounds
@@ -0,0 +1,204 @@
+#!/usr/bin/python
+
+# Figures 7.6 and 7.7, page 383.
+# Chebyshev bounds.
+
+import pylab
+from math import pi, sqrt
+from cvxopt.base import matrix, spmatrix, mul, cos, sin
+from cvxopt import solvers, blas, lapack
+solvers.options['show_progress'] = False
+
+# Extreme points and inequality description of Voronoi region around 
+# first symbol (0,0).
+m = 6
+V = matrix([ 1.0,  1.0, 
+            -1.0,  2.0,
+            -2.0,  1.0,
+            -2.0, -1.0,
+             0.0, -2.0,
+             1.5, -1.0,
+             1.0,  1.0 ], (2,m+1))
+
+A0 = matrix([-(V[1,:m] - V[1,1:]), V[0,:m] - V[0,1:]]).T
+b0 = mul(A0, V[:,:m].T) * matrix(1.0, (2,1))
+
+# List of symbols.
+C = [ matrix(0.0, (2,1)) ] + \
+    [ 2.0 * b0[k] / blas.nrm2(A0[k,:])**2 * A0[k,:].T for k in 
+    xrange(m) ]
+
+# Voronoi set around C[1]
+A1, b1 = matrix(0.0, (3,2)), matrix(0.0, (3,1))
+A1[0,:] = -A0[0,:]
+b1[0] = -b0[0]
+A1[1,:] = (C[m] - C[1]).T
+b1[1] = 0.5 * A1[1,:] * ( C[m] + C[1] )
+A1[2,:] = (C[2] - C[1]).T
+b1[2] = 0.5 * A1[2,:] * ( C[2] + C[1] )
+
+# Voronoi set around C[2]
+A2, b2 = matrix(0.0, (3,2)), matrix(0.0, (3,1))
+A2[0,:] = -A0[1,:]
+b2[0] = -b0[1]
+A2[1,:] = (C[1] - C[2]).T
+b2[1] = 0.5 * A2[1,:] * ( C[1] + C[2] )
+A2[2,:] = (C[3] - C[2]).T
+b2[2] = 0.5 * A2[2,:] * ( C[3] + C[2] )
+
+
+def cheb(A, b, Sigma):
+
+    # Calculates Chebyshev lower bound on Prob(A*x <= b) where
+    # x in R^2 has mean zero and covariance Sigma.
+    #
+    # maximize    1 - tr(Sigma*P) - r
+    # subject to  [ P,                    q - (tauk/2)*ak ]
+    #             [ (q - (tauk/2)*ak)',   r - 1 + tauk*bk ] >= 0,
+    #                                                 k = 0,...,m-1
+    #             [ P,   q ]
+    #             [ q',  r ] >= 0
+    #             tauk >= 0, k=0,...,m-1.
+    #
+    # variables P[0,0], P[1,0], P[1,1], q[0], q[1], r, tau[0], ..., 
+    #     tau[m-1].
+
+    m = A.size[0]
+    novars = 3 + 2 + 1 + m
+
+    # Cost function.
+    c = matrix(0.0, (novars,1))
+    c[0], c[1], c[2] = Sigma[0,0], 2*Sigma[1,0], Sigma[1,1]
+    c[5] = 1.0
+
+    Gs = [ spmatrix([],[],[], (9,novars)) for k in xrange(m+1) ]
+
+    # Coefficients of P, q, r in LMI constraints.
+    for k in xrange(m+1):
+        Gs[k][0,0] = -1.0   # P[0,0]
+        Gs[k][1,1] = -1.0   # P[1,0]
+        Gs[k][4,2] = -1.0   # P[1,1]
+        Gs[k][2,3] = -1.0   # q[0]
+        Gs[k][5,4] = -1.0   # q[1]
+        Gs[k][8,5] = -1.0   # r
+    # Coefficients of tau.
+    for k in xrange(m):
+        Gs[k][2, 6+k] = 0.5 * A[k,0]   
+        Gs[k][5, 6+k] = 0.5 * A[k,1]   
+        Gs[k][8, 6+k] = -b[k]   
+    
+    hs = [ matrix(8*[0.0] + [-1.0], (3,3)) for k in xrange(m) ] + \
+        [ matrix(0.0, (3,3)) ]
+
+    # Constraints tau >= 0.
+    Gl, hl = spmatrix(-1.0, range(m), range(6,6+m)), matrix(0.0, (m,1)) 
+
+    sol = solvers.sdp(c, Gl, hl, Gs, hs)
+    P = matrix(sol['x'][[0,1,1,2]], (2,2))  
+    q = matrix(sol['x'][[3,4]], (2,1))  
+    r = sol['x'][5]
+    bound = 1.0 - Sigma[0]*P[0] - 2*Sigma[1]*P[1] - Sigma[3]*P[3] - r
+
+    # Worst-case distribution from dual solution.
+    X = [ Z[2,:2].T / Z[2,2] for Z in sol['zs'] if Z[2,2] > 1e-5 ]
+
+    return bound, P, q, r, X
+
+
+# Compute bound for s0 with sigma = 1.0.
+# Write ellipse {x | x'*P*x + 2*q'*x + r = 1} in the form 
+# {xc + L^{-T}*u | ||u||_2 = 1}
+
+Sigma = matrix([1.0, 0.0, 0.0, 1.0], (2,2))
+bnd, P, q, r, X = cheb(A0, b0, Sigma)
+xc = -q
+L = +P
+lapack.posv(L, xc)
+L /= sqrt(1 - r - blas.dot(q, xc))
+
+def makefig1():
+    pylab.figure(1, facecolor='w', figsize=(6,6))
+    pylab.plot(V[0,:], V[1,:], '-')
+    nopts = 1000
+    angles = matrix( [a*2.0*pi/nopts for a in xrange(nopts) ], 
+        (1,nopts) )
+    circle = matrix(0.0, (2,nopts))
+    circle[0,:], circle[1,:] = cos(angles), sin(angles)
+    for k in xrange(len(C)):
+        c = C[k]
+        pylab.plot([c[0]], [c[1]], 'ow')
+        pylab.text(c[0], c[1], "s%d" %k)
+        pylab.plot(c[0] + circle[0,:], c[1]+circle[1,:], ':')
+        if k >= 1:
+            v = V[:,k-1]
+            if k==1: 
+                dir = 0.5 * (C[k] + C[-1]) - v
+            else: 
+                dir = 0.5 * (C[k] + C[k-1]) - v
+            pylab.plot([v[0], v[0] + 5*dir[0]], 
+                [v[1], v[1] + 5*dir[1]], 'b-')
+    ellipse = +circle
+    blas.trsm(L, ellipse, transA='T')
+    pylab.plot(xc[0] + ellipse[0,:], xc[1]+ellipse[1,:], 'r-')
+    for Xk in X: 
+        pylab.plot([Xk[0]], [Xk[1]], 'ro')
+
+    pylab.axis([-5, 5, -5, 5])
+    pylab.title('Geometrical interpretation of Chebyshev bound (fig. 7.7)')
+    pylab.axis('off')
+makefig1()
+print "Close figure to continue." 
+pylab.show()
+
+
+# Compute bounds for s0 with sigma in [0,2.5]
+nosigmas = 150
+sigmas = 0.001 + (2.5 - 0.001) / nosigmas * matrix(range(nosigmas), 
+    tc='d')
+I = matrix([1.0, 0.0, 0.0, 1.0], (2,2))
+print "Computing lower bounds for symbol 0 ..."  
+bnds0 = [ cheb(A0, b0, sigma**2*I)[0] for sigma in sigmas ]
+
+pylab.figure(2,facecolor='w')
+pylab.plot(sigmas, bnds0)
+pylab.axis([0, 2.5, 0.0, 1.0])
+pylab.title('Chebyshev lower bounds (fig 7.6)')
+pylab.text(sigmas[nosigmas/2], bnds0[nosigmas/2], 's0')
+pylab.xlabel('sigma')
+pylab.ylabel('Probability of correct detection')
+print "Close figure to continue."
+pylab.show()
+
+# Bounds for s1.
+b1 -= A1*C[1]  # put s1 at the origin
+print "Computing lower bounds for symbol 1 ..." 
+bnds1 = [ cheb(A1, b1, sigma**2*I)[0] for sigma in sigmas ]
+
+pylab.figure(2,facecolor='w')
+pylab.plot(sigmas,bnds0, '-b', sigmas, bnds1, 'r')
+pylab.axis([0, 2.5, 0.0, 1.0])
+pylab.title('Chebyshev lower bounds (fig 7.6)')
+pylab.text(sigmas[nosigmas/2], bnds0[nosigmas/2], 's0')
+pylab.text(sigmas[nosigmas/2], bnds1[nosigmas/2], 's1')
+pylab.xlabel('sigma')
+pylab.ylabel('Probability of correct detection')
+print "Close figure to continue."
+pylab.show()
+
+# Bounds for s2.
+b2 -= A2*C[2]  # put s2 at the origin
+print "Computing lower bounds for symbol 2 ..." 
+bnds2 = [ cheb(A2, b2, sigma**2*I)[0] for sigma in sigmas ]
+
+makefig1()
+pylab.figure(2,facecolor='w')
+pylab.plot(sigmas,bnds0, '-b', sigmas, bnds1, 'r', sigmas, bnds2, 'g')
+pylab.axis([0, 2.5, 0.0, 1.0])
+pylab.title('Chebyshev lower bounds (fig 7.6)')
+pylab.text(sigmas[nosigmas/2], bnds0[nosigmas/2], 's0')
+pylab.text(sigmas[nosigmas/2], bnds1[nosigmas/2], 's1')
+pylab.text(sigmas[nosigmas/2], bnds2[nosigmas/2], 's2')
+pylab.xlabel('sigma')
+pylab.ylabel('Probability of correct detection')
+
+pylab.show()
diff --git a/examples/book/chap8/centers b/examples/book/chap8/centers
new file mode 100755
index 0000000..39bde8c
--- /dev/null
+++ b/examples/book/chap8/centers
@@ -0,0 +1,206 @@
+#!/usr/bin/python
+
+# Figures 8.5-7, pages 417-421.
+# Centers of polyhedra.
+ 
+import pylab
+from math import log, pi
+from cvxopt import blas, lapack, solvers
+from cvxopt.base import matrix, spmatrix, sqrt, mul, cos, sin, log
+from cvxopt.modeling import variable, op 
+solvers.options['show_progress'] = False
+
+# Extreme points (with first one appended at the end)
+X = matrix([ 0.55,  0.25, -0.20, -0.25,  0.00,  0.40,  0.55,  
+             0.00,  0.35,  0.20, -0.10, -0.30, -0.20,  0.00 ], (7,2))
+m = X.size[0] - 1
+
+# Inequality description G*x <= h with h = 1
+G, h = matrix(0.0, (m,2)), matrix(0.0, (m,1))
+G = (X[:m,:] - X[1:,:]) * matrix([0., -1., 1., 0.], (2,2))
+h = (G * X.T)[::m+1]
+G = mul(h[:,[0,0]]**-1, G)
+h = matrix(1.0, (m,1))
+
+
+# Chebyshev center
+#
+# maximizse   R 
+# subject to  gk'*xc + R*||gk||_2 <= hk,  k=1,...,m
+#             R >= 0
+
+R = variable()
+xc = variable(2)
+op(-R, [ G[k,:]*xc + R*blas.nrm2(G[k,:]) <= h[k] for k in xrange(m) ] + 
+    [ R >= 0] ).solve()
+R = R.value    
+xc = xc.value    
+
+pylab.figure(1, facecolor='w')
+
+# polyhedron
+for k in xrange(m):
+    edge = X[[k,k+1],:] + 0.1 * matrix([1., 0., 0., -1.], (2,2)) * \
+        (X[2*[k],:] - X[2*[k+1],:])
+    pylab.plot(edge[:,0], edge[:,1], 'k')
+
+
+# 1000 points on the unit circle
+nopts = 1000
+angles = matrix( [ a*2.0*pi/nopts for a in xrange(nopts) ], (1,nopts) )
+circle = matrix(0.0, (2,nopts))
+circle[0,:], circle[1,:] = R*cos(angles), R*sin(angles)
+circle += xc[:,nopts*[0]]
+
+# plot maximum inscribed disk
+pylab.fill(circle[0,:], circle[1,:], '#F0F0F0')
+pylab.plot([xc[0]], [xc[1]], 'ko')
+pylab.title('Chebyshev center (fig 8.5)')
+pylab.axis('equal')
+pylab.axis('off')
+
+
+# Maximum volume enclosed ellipsoid center
+#
+# minimize    -log det B
+# subject to  ||B * gk||_2 + gk'*c <= hk,  k=1,...,m
+#
+# with variables  B and c.
+#
+# minimize    -log det L
+# subject to  ||L' * gk||_2^2 / (hk - gk'*c) <= hk - gk'*c,  k=1,...,m
+#
+# L lower triangular with positive diagonal and B*B = L*L'.
+#
+# minimize    -log x[0] - log x[2]
+# subject to   g( Dk*x + dk ) <= 0,  k=1,...,m
+#
+# g(u,t) = u'*u/t - t 
+# Dk = [ G[k,0]   G[k,1]  0       0        0 
+#        0        0       G[k,1]  0        0 
+#        0        0       0      -G[k,0]  -G[k,1] ] 
+# dk = [0; 0; h[k]] 
+#
+# 5 variables x = (L[0,0], L[1,0], L[1,1], c[0], c[1])
+
+D = [ matrix(0.0, (3,5)) for k in xrange(m) ]
+for k in xrange(m):
+    D[k][ [0, 3, 7, 11, 14] ] = matrix( [G[k,0], G[k,1], G[k,1], 
+        -G[k,0], -G[k,1]] )
+d = [matrix([0.0, 0.0, hk]) for hk in h]
+
+def F(x=None, z=None):
+    if x is None:  
+        return m, matrix([ 1.0, 0.0, 1.0, 0.0, 0.0 ])
+    if min(x[0], x[2], min(h-G*x[3:])) <= 0.0:  
+        return None
+
+    y = [ Dk*x + dk for Dk, dk in zip(D, d) ]
+
+    f = matrix(0.0, (m+1,1))
+    f[0] = -log(x[0]) - log(x[2])
+    for k in xrange(m):  
+        f[k+1] = y[k][:2].T * y[k][:2] / y[k][2] - y[k][2]
+       
+    Df = matrix(0.0, (m+1,5))
+    Df[0,0], Df[0,2] = -1.0/x[0], -1.0/x[2]
+
+    # gradient of g is ( 2.0*(u/t);  -(u/t)'*(u/t) -1) 
+    for k in xrange(m):
+        a = y[k][:2] / y[k][2]
+        gradg = matrix(0.0, (3,1))
+        gradg[:2], gradg[2] = 2.0 * a, -a.T*a - 1
+        Df[k+1,:] =  gradg.T * D[k]
+    if z is None: return f, Df
+    
+    H = matrix(0.0, (5,5))
+    H[0,0] = z[0] / x[0]**2
+    H[2,2] = z[0] / x[2]**2
+
+    # Hessian of g is (2.0/t) * [ I, -u/t;  -(u/t)',  (u/t)*(u/t)' ]
+    for k in xrange(m):
+        a = y[k][:2] / y[k][2]
+        hessg = matrix(0.0, (3,3))
+        hessg[0,0], hessg[1,1] = 1.0, 1.0
+        hessg[:2,2], hessg[2,:2] = -a,  -a.T
+        hessg[2, 2] = a.T*a
+        H += (z[k] * 2.0 / y[k][2]) *  D[k].T * hessg * D[k]
+
+    return f, Df, H 
+    
+sol = solvers.cp(F)
+L = matrix([sol['x'][0], sol['x'][1], 0.0, sol['x'][2]], (2,2))
+c = matrix([sol['x'][3], sol['x'][4]])
+
+
+pylab.figure(2, facecolor='w')
+
+# polyhedron
+for k in xrange(m):
+    edge = X[[k,k+1],:] + 0.1 * matrix([1., 0., 0., -1.], (2,2)) * \
+        (X[2*[k],:] - X[2*[k+1],:])
+    pylab.plot(edge[:,0], edge[:,1], 'k')
+
+
+# 1000 points on the unit circle
+nopts = 1000
+angles = matrix( [ a*2.0*pi/nopts for a in xrange(nopts) ], (1,nopts) )
+circle = matrix(0.0, (2,nopts))
+circle[0,:], circle[1,:] = cos(angles), sin(angles)
+
+# ellipse = L * circle + c
+ellipse = L * circle + c[:, nopts*[0]]
+
+pylab.fill(ellipse[0,:], ellipse[1,:], '#F0F0F0')
+pylab.plot([c[0]], [c[1]], 'ko')
+pylab.title('Maximum volume inscribed ellipsoid center (fig 8.6)')
+pylab.axis('equal')
+pylab.axis('off')
+
+
+# Analytic center.
+#
+# minimize  -sum log (h-G*x)
+#
+
+def F(x=None, z=None):
+    if x is None: return 0, matrix(0.0, (2,1))
+    y = h-G*x
+    if min(y) <= 0: return None
+    f = -sum(log(y))
+    Df = (y**-1).T * G
+    if z is None: return matrix(f), Df
+    H =  G.T * spmatrix(y**-1, range(m), range(m)) * G
+    return matrix(f), Df, z[0]*H
+
+sol = solvers.cp(F)
+xac = sol['x']
+Hac = G.T * spmatrix( (h-G*xac)**-1, range(m), range(m)) * G
+
+pylab.figure(3, facecolor='w')
+
+# polyhedron
+for k in xrange(m):
+    edge = X[[k,k+1],:] + 0.1 * matrix([1., 0., 0., -1.], (2,2)) * \
+        (X[2*[k],:] - X[2*[k+1],:])
+    pylab.plot(edge[:,0], edge[:,1], 'k')
+
+
+# 1000 points on the unit circle
+nopts = 1000
+angles = matrix( [ a*2.0*pi/nopts for a in xrange(nopts) ], (1,nopts) )
+circle = matrix(0.0, (2,nopts))
+circle[0,:], circle[1,:] = cos(angles), sin(angles)
+
+# ellipse = L^-T * circle + xc  where Hac = L*L'
+lapack.potrf(Hac)
+ellipse = +circle
+blas.trsm(Hac, ellipse, transA='T')
+ellipse += xac[:, nopts*[0]]
+pylab.fill(ellipse[0,:], ellipse[1,:], '#F0F0F0')
+pylab.plot([xac[0]], [xac[1]], 'ko')
+
+pylab.title('Analytic center (fig 8.7)')
+pylab.axis('equal')
+pylab.axis('off')
+pylab.show()
diff --git a/examples/book/chap8/ellipsoids b/examples/book/chap8/ellipsoids
new file mode 100755
index 0000000..062a781
--- /dev/null
+++ b/examples/book/chap8/ellipsoids
@@ -0,0 +1,228 @@
+#!/usr/bin/python
+
+# Figures 8.3 and 8.4, pages 412 and 416.
+# Ellipsoidal approximations.
+ 
+import pylab
+from math import log, pi
+from cvxopt import blas, lapack, solvers
+from cvxopt.base import matrix, sqrt, mul, cos, sin
+solvers.options['show_progress'] = False
+
+# Extreme points (with first one appended at the end)
+X = matrix([ 0.55,  0.25, -0.20, -0.25,  0.00,  0.40,  0.55,  
+             0.00,  0.35,  0.20, -0.10, -0.30, -0.20,  0.00 ], (7,2))
+m = X.size[0] - 1
+
+# Inequality description G*x <= h with h = 1
+G, h = matrix(0.0, (m,2)), matrix(0.0, (m,1))
+G = (X[:m,:] - X[1:,:]) * matrix([0., -1., 1., 0.], (2,2))
+h = (G * X.T)[::m+1]
+G = mul(h[:,[0,0]]**-1, G)
+h = matrix(1.0, (m,1))
+
+
+# Loewner-John ellipsoid 
+#
+# minimize     log det A^-1
+# subject to   xk'*A*xk - 2*xk'*b + b'*A^1*b <= 1,  k=1,...,m
+#
+# 5 variables x = (A[0,0], A[1,0], A[1,1], b[0], b[1])
+
+def F(x=None, z=None):
+    if x is None:  
+        return m, matrix([ 1.0, 0.0, 1.0, 0.0, 0.0 ])
+
+    # Factor A as A = L*L'.  Compute inverse B = A^-1.
+    A = matrix( [x[0], x[1], x[1], x[2]], (2,2))
+    L = +A
+    try: lapack.potrf(L)
+    except: return None
+    B = +L
+    lapack.potri(B)
+    B[0,1] = B[1,0]
+
+    # f0 = -log det A    
+    f = matrix(0.0, (m+1,1))
+    f[0] = -2.0 * (log(L[0,0]) + log(L[1,1]))
+
+    # fk = xk'*A*xk - 2*xk'*b + b*A^-1*b - 1 
+    #    = (xk - c)' * A * (xk - c) - 1  where c = A^-1*b  
+    c = x[3:]
+    lapack.potrs(L, c)  
+    for k in xrange(m):
+        f[k+1] = (X[k,:].T - c).T * A * (X[k,:].T - c) - 1.0 
+
+    # gradf0 = (-A^-1, 0) = (-B, 0)
+    Df = matrix(0.0, (m+1,5))
+    Df[0,0], Df[0,1], Df[0,2] = -B[0,0], -2.0*B[1,0], -B[1,1]
+
+    # gradfk = (xk*xk' - A^-1*b*b'*A^-1,  2*(-xk + A^-1*b))
+    #        = (xk*xk' - c*c', 2*(-xk+c))
+    Df[1:,0] = X[:m,0]**2 - c[0]**2
+    Df[1:,1] = 2.0 * (mul(X[:m,0], X[:m,1]) - c[0]*c[1])
+    Df[1:,2] = X[:m,1]**2 - c[1]**2
+    Df[1:,3] = 2.0 * (-X[:m,0] + c[0])
+    Df[1:,4] = 2.0 * (-X[:m,1] + c[1])
+
+    if z is None: return f, Df
+    
+    # hessf0(Y, y) = (A^-1*Y*A^-1, 0) = (B*YB, 0)
+    H0 = matrix(0.0, (5,5))
+    H0[0,0] = B[0,0]**2
+    H0[1,0] = 2.0 * B[0,0] * B[1,0]
+    H0[2,0] = B[1,0]**2
+    H0[1,1] = 2.0 * ( B[0,0] * B[1,1] + B[1,0]**2 )
+    H0[2,1] = 2.0 * B[1,0] * B[1,1]
+    H0[2,2] = B[1,1]**2
+ 
+    # hessfi(Y, y) 
+    #     = ( A^-1*Y*A^-1*b*b'*A^-1 + A^-1*b*b'*A^-1*Y*A^-1 
+    #             - A^-1*y*b'*A^-1 - A^-1*b*y'*A^-1, 
+    #         -2*A^-1*Y*A^-1*b + 2*A^-1*y ) 
+    #     = ( B*Y*c*c' + c*c'*Y*B - B*y*c' - c*y'*B,  -2*B*Y*c + 2*B*y )
+    #     = ( B*(Y*c-y)*c' + c*(Y*c-y)'*B, -2*B*(Y*c - y) ) 
+    H1 = matrix(0.0, (5,5))
+    H1[0,0] = 2.0 * c[0]**2 * B[0,0] 
+    H1[1,0] = 2.0 * ( c[0] * c[1] * B[0,0] + c[0]**2 * B[1,0] )
+    H1[2,0] = 2.0 * c[0] * c[1] * B[1,0] 
+    H1[3:,0] = -2.0 * c[0] * B[:,0] 
+    H1[1,1] = 2.0 * c[0]**2 * B[1,1] + 4.0 * c[0]*c[1]*B[1,0]  + \
+              2.0 * c[1]**2 + B[0,0]
+    H1[2,1] = 2.0 * (c[1]**2 * B[1,0] + c[0]*c[1]*B[1,1])
+    H1[3:,1] = -2.0 * B * c[[1,0]]
+    H1[2,2] = 2.0 * c[1]**2 * B[1,1]
+    H1[3:,2] = -2.0 * c[1] * B[:,1] 
+    H1[3:,3:] = 2*B
+
+    return f, Df, z[0]*H0 + sum(z[1:])*H1
+    
+sol = solvers.cp(F)
+A = matrix( sol['x'][[0, 1, 1, 2]], (2,2)) 
+b = sol['x'][3:]
+
+pylab.figure(1, facecolor='w')
+pylab.plot(X[:,0], X[:,1], 'ko', X[:,0], X[:,1], '-k')
+
+# Ellipsoid in the form { x | || L' * (x-c) ||_2 <= 1 }
+L = +A
+lapack.potrf(L)
+c = +b
+lapack.potrs(L, c)    
+
+# 1000 points on the unit circle
+nopts = 1000
+angles = matrix( [ a*2.0*pi/nopts for a in xrange(nopts) ], (1,nopts) )
+circle = matrix(0.0, (2,nopts))
+circle[0,:], circle[1,:] = cos(angles), sin(angles)
+
+# ellipse = L^-T * circle + c
+blas.trsm(L, circle, transA='T')
+ellipse = circle + c[:, nopts*[0]]
+ellipse2 = 0.5 * circle + c[:, nopts*[0]]
+
+pylab.plot(ellipse[0,:], ellipse[1,:], 'k-')
+pylab.fill(ellipse2[0,:], ellipse2[1,:], '#F0F0F0')
+pylab.title('Loewner-John ellipsoid (fig 8.3)')
+pylab.axis('equal')
+pylab.axis('off')
+
+
+# Maximum volume enclosed ellipsoid
+#
+# minimize    -log det B
+# subject to  ||B * gk||_2 + gk'*c <= hk,  k=1,...,m
+#
+# with variables  B and c.
+#
+# minimize    -log det L
+# subject to  ||L' * gk||_2^2 / (hk - gk'*c) <= hk - gk'*c,  k=1,...,m
+#
+# L lower triangular with positive diagonal and B*B = L*L'.
+#
+# minimize    -log x[0] - log x[2]
+# subject to   g( Dk*x + dk ) <= 0,  k=1,...,m
+#
+# g(u,t) = u'*u/t - t 
+# Dk = [ G[k,0]   G[k,1]  0       0        0 
+#        0        0       G[k,1]  0        0 
+#        0        0       0      -G[k,0]  -G[k,1] ] 
+# dk = [0; 0; h[k]] 
+#
+# 5 variables x = (L[0,0], L[1,0], L[1,1], c[0], c[1])
+
+D = [ matrix(0.0, (3,5)) for k in xrange(m) ]
+for k in xrange(m):
+    D[k][ [0, 3, 7, 11, 14] ] = matrix( [G[k,0], G[k,1], G[k,1], 
+        -G[k,0], -G[k,1]] )
+d = [matrix([0.0, 0.0, hk]) for hk in h]
+
+def F(x=None, z=None):
+    if x is None:  
+        return m, matrix([ 1.0, 0.0, 1.0, 0.0, 0.0 ])
+    if min(x[0], x[2], min(h-G*x[3:])) <= 0.0:  
+        return None
+
+    y = [ Dk*x + dk for Dk, dk in zip(D, d) ]
+
+    f = matrix(0.0, (m+1,1))
+    f[0] = -log(x[0]) - log(x[2])
+    for k in xrange(m):  
+        f[k+1] = y[k][:2].T * y[k][:2] / y[k][2] - y[k][2]
+       
+    Df = matrix(0.0, (m+1,5))
+    Df[0,0], Df[0,2] = -1.0/x[0], -1.0/x[2]
+
+    # gradient of g is ( 2.0*(u/t);  -(u/t)'*(u/t) -1) 
+    for k in xrange(m):
+        a = y[k][:2] / y[k][2]
+        gradg = matrix(0.0, (3,1))
+        gradg[:2], gradg[2] = 2.0 * a, -a.T*a - 1
+        Df[k+1,:] =  gradg.T * D[k]
+    if z is None: return f, Df
+    
+    H = matrix(0.0, (5,5))
+    H[0,0] = z[0] / x[0]**2
+    H[2,2] = z[0] / x[2]**2
+
+    # Hessian of g is (2.0/t) * [ I, -u/t;  -(u/t)',  (u/t)*(u/t)' ]
+    for k in xrange(m):
+        a = y[k][:2] / y[k][2]
+        hessg = matrix(0.0, (3,3))
+        hessg[0,0], hessg[1,1] = 1.0, 1.0
+        hessg[:2,2], hessg[2,:2] = -a,  -a.T
+        hessg[2, 2] = a.T*a
+        H += (z[k] * 2.0 / y[k][2]) *  D[k].T * hessg * D[k]
+
+    return f, Df, H 
+    
+sol = solvers.cp(F)
+L = matrix([sol['x'][0], sol['x'][1], 0.0, sol['x'][2]], (2,2))
+c = matrix([sol['x'][3], sol['x'][4]])
+
+pylab.figure(2, facecolor='w')
+
+# polyhedron
+for k in xrange(m):
+    edge = X[[k,k+1],:] + 0.1 * matrix([1., 0., 0., -1.], (2,2)) * \
+        (X[2*[k],:] - X[2*[k+1],:])
+    pylab.plot(edge[:,0], edge[:,1], 'k')
+
+
+# 1000 points on the unit circle
+nopts = 1000
+angles = matrix( [ a*2.0*pi/nopts for a in xrange(nopts) ], (1,nopts) )
+circle = matrix(0.0, (2,nopts))
+circle[0,:], circle[1,:] = cos(angles), sin(angles)
+
+# ellipse = L * circle + c
+ellipse = L * circle + c[:, nopts*[0]]
+ellipse2 = 2.0 * L * circle + c[:, nopts*[0]]
+
+pylab.plot(ellipse2[0,:], ellipse2[1,:], 'k-')
+pylab.fill(ellipse[0,:], ellipse[1,:], '#F0F0F0')
+pylab.title('Maximum volume inscribed ellipsoid (fig 8.4)')
+pylab.axis('equal')
+pylab.axis('off')
+
+pylab.show()
diff --git a/examples/book/chap8/floorplan b/examples/book/chap8/floorplan
new file mode 100755
index 0000000..2cd5903
--- /dev/null
+++ b/examples/book/chap8/floorplan
@@ -0,0 +1,210 @@
+#!/usr/bin/python
+#
+# Figure 8.20, page 444.
+# Floor planning example.
+
+import pylab
+from cvxopt import solvers
+from cvxopt.base import matrix, spmatrix, mul, div
+
+def floorplan(Amin):
+
+    #     minimize    W+H
+    #     subject to  Amin1 / h1 <= w1 
+    #                 Amin2 / h2 <= w2 
+    #                 Amin3 / h3 <= w3 
+    #                 Amin4 / h4 <= w4 
+    #                 Amin5 / h5 <= w5 
+    #                 x1 >= 0
+    #                 x2 >= 0
+    #                 x4 >= 0
+    #                 x1 + w1 + rho <= x3  
+    #                 x2 + w2 + rho <= x3 
+    #                 x3 + w3 + rho <= x5  
+    #                 x4 + w4 + rho <= x5
+    #                 x5 + w5 <= W
+    #                 y2 >= 0  
+    #                 y3 >= 0  
+    #                 y5 >= 0 
+    #                 y2 + h2 + rho <= y1 
+    #                 y1 + h1 + rho <= y4 
+    #                 y3 + h3 + rho <= y4
+    #                 y4 + h4 <= H  
+    #                 y5 + h5 <= H
+    #                 h1/gamma <= w1 <= gamma*h1
+    #                 h2/gamma <= w2 <= gamma*h2
+    #                 h3/gamma <= w3 <= gamma*h3
+    #                 h4/gamma <= w4 <= gamma*h4
+    #                 h5/gamma <= w5 <= gamma*h5
+    #
+    # 22 Variables W, H, x (5), y (5), w (5), h (5).
+    #
+    # W, H:  scalars; bounding box width and height
+    # x, y:  5-vectors; coordinates of bottom left corners of blocks
+    # w, h:  5-vectors; widths and heigths of the 5 blocks
+
+    rho, gamma = 1.0, 5.0   # min spacing, min aspect ratio
+
+    # The objective is to minimize W + H.  There are five nonlinear 
+    # constraints 
+    #
+    #     -w1 + Amin1 / h1 <= 0 
+    #     -w2 + Amin2 / h2 <= 0 
+    #     -w3 + Amin3 / h3 <= 0 
+    #     -w4 + Amin4 / h4 <= 0 
+    #     -w5 + Amin5 / h5 <= 0.
+
+    def F(x=None, z=None):
+        if x is None:  
+            return 5, matrix(17*[0.0] + 5*[1.0])
+        if min(x[17:]) <= 0.0:  
+            return None 
+        f = matrix(0.0, (6,1))
+        f[0] = x[0] + x[1]  
+        f[1:] = -x[12:17] + div(Amin, x[17:]) 
+        Df = matrix(0.0, (6,22))
+        Df[0, [0,1]] = 1.0
+        Df[1:,12:17] = spmatrix(-1.0, range(5), range(5))
+        Df[1:,17:] = spmatrix(-div(Amin, x[17:]**2), range(5), range(5))
+        if z is None: 
+            return f, Df
+        H = spmatrix( 2.0* mul(z[1:], div(Amin, x[17::]**3)), 
+            range(17,22), range(17,22) )
+        return f, Df, H
+
+    # linear inequalities
+    G = matrix(0.0, (26,22)) 
+    h = matrix(0.0, (26,1))
+
+    # -x1 <= 0
+    G[0,2] = -1.0   
+
+    # -x2 <= 0
+    G[1,3] = -1.0   
+
+    # -x4 <= 0
+    G[2,5] = -1.0   
+
+    # x1 - x3 + w1 <= -rho 
+    G[3, [2, 4, 12]], h[3] = [1.0, -1.0, 1.0], -rho
+
+    # x2 - x3 + w2 <= -rho 
+    G[4, [3, 4, 13]], h[4] = [1.0, -1.0, 1.0], -rho
+ 
+    # x3 - x5 + w3 <= -rho 
+    G[5, [4, 6, 14]], h[5] = [1.0, -1.0, 1.0], -rho 
+
+    # x4 - x5 + w4 <= -rho 
+    G[6, [5, 6, 15]], h[6] = [1.0, -1.0, 1.0], -rho 
+
+    # -W + x5 + w5 <= 0
+    G[7, [0, 6, 16]] = -1.0, 1.0, 1.0
+
+    # -y2 <= 0  
+    G[8,8] = -1.0
+
+    # -y3 <= 0  
+    G[9,9] = -1.0
+
+    # -y5 <= 0 
+    G[10,11] = -1.0
+
+    # -y1 + y2 + h2 <= -rho 
+    G[11, [7, 8, 18]], h[11] = [-1.0, 1.0, 1.0], -rho 
+
+    # y1 - y4 + h1 <= -rho 
+    G[12, [7, 10, 17]], h[12] = [1.0, -1.0, 1.0], -rho 
+
+    # y3 - y4 + h3 <= -rho 
+    G[13, [9, 10, 19]], h[13] = [1.0, -1.0, 1.0], -rho 
+
+    # -H + y4 + h4 <= 0  
+    G[14, [1, 10, 20]] = -1.0, 1.0, 1.0
+
+    # -H + y5 + h5 <= 0
+    G[15, [1, 11, 21]] = -1.0, 1.0, 1.0
+
+    # -w1 + h1/gamma <= 0 
+    G[16, [12, 17]] = -1.0, 1.0/gamma
+
+    # w1 - gamma * h1 <= 0
+    G[17, [12, 17]] = 1.0, -gamma
+
+    # -w2 + h2/gamma <= 0 
+    G[18, [13, 18]] = -1.0, 1.0/gamma 
+
+    # w2 - gamma * h2 <= 0
+    G[19, [13, 18]] = 1.0, -gamma
+
+    # -w3 + h3/gamma <= 0  
+    G[20, [14, 18]] = -1.0, 1.0/gamma
+
+    # w3 - gamma * h3 <= 0
+    G[21, [14, 19]] = 1.0, -gamma
+
+    # -w4  + h4/gamma <= 0 
+    G[22, [15, 19]] = -1.0, 1.0/gamma
+
+    # w4 - gamma * h4 <= 0
+    G[23, [15, 20]] = 1.0, -gamma
+
+    # -w5 + h5/gamma <= 0 
+    G[24, [16, 21]] = -1.0, 1.0/gamma
+
+    # w5 - gamma * h5 <= 0.0
+    G[25, [16, 21]] = 1.0, -gamma
+
+    # solve and return W, H, x, y, w, h 
+    sol = solvers.cp(F, G, h)
+    return  sol['x'][0], sol['x'][1], sol['x'][2:7], sol['x'][7:12], \
+        sol['x'][12:17], sol['x'][17:] 
+
+solvers.options['show_progress'] = False
+
+pylab.figure(facecolor='w')
+
+pylab.subplot(221)
+Amin = matrix([100., 100., 100., 100., 100.])
+W, H, x, y, w, h =  floorplan(Amin)
+for k in xrange(5):
+    pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], 
+               [y[k], y[k]+h[k], y[k]+h[k], y[k]], '#D0D0D0')
+    pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1))
+pylab.axis([-1.0, 26, -1.0, 26])
+pylab.xticks([])
+pylab.yticks([])
+
+pylab.subplot(222)
+Amin = matrix([20., 50., 80., 150., 200.])
+W, H, x, y, w, h =  floorplan(Amin)
+for k in xrange(5):
+    pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], 
+               [y[k], y[k]+h[k], y[k]+h[k], y[k]], '#D0D0D0')
+    pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1))
+pylab.axis([-1.0, 26, -1.0, 26])
+pylab.xticks([])
+pylab.yticks([])
+
+pylab.subplot(223)
+Amin = matrix([180., 80., 80., 80., 80.])
+W, H, x, y, w, h =  floorplan(Amin)
+for k in xrange(5):
+    pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], 
+               [y[k], y[k]+h[k], y[k]+h[k], y[k]],'#D0D0D0')
+    pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1))
+pylab.axis([-1.0, 26, -1.0, 26])
+pylab.xticks([])
+pylab.yticks([])
+
+pylab.subplot(224)
+Amin = matrix([20., 150., 20., 200., 110.])
+W, H, x, y, w, h =  floorplan(Amin)
+for k in xrange(5):
+    pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], 
+               [y[k], y[k]+h[k], y[k]+h[k], y[k]],'#D0D0D0')
+    pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1))
+pylab.axis([-1.0, 26, -1.0, 26])
+pylab.xticks([])
+pylab.yticks([])
+
+pylab.show()
diff --git a/examples/book/chap8/linsep b/examples/book/chap8/linsep
new file mode 100755
index 0000000..15f1c89
--- /dev/null
+++ b/examples/book/chap8/linsep
@@ -0,0 +1,134 @@
+#!/usr/bin/python
+
+# Figures 8.10-12, page 426-429.
+# Approximate linear discrimination.
+
+import pylab, pickle
+from cvxopt import solvers 
+from cvxopt.blas import dot
+from cvxopt.base import matrix, spmatrix, log, exp, div
+from cvxopt.modeling import variable, op
+solvers.options['show_progress'] = False
+
+data = pickle.load(open("linsep.pic"))
+X, Y = data['X'], data['Y']
+n, N, M = X.size[0], X.size[1], Y.size[1]
+
+# Via linear programming.
+#
+# minimize    sum(u) + sum(v)
+# subject to  a'*X - b >= 1 - u
+#             a'*Y - b <= -1 + v 
+#             u >= 0, v >= 0
+
+a, b = variable(2), variable()
+u, v = variable(N), variable(M)
+op( sum(u)+sum(v), [X.T*a-b >= 1-u,  Y.T*a-b <= -1+v,  
+    u>=0,  v>=0] ).solve()
+a = a.value
+b = b.value
+
+pylab.figure(1, facecolor='w', figsize=(5,5))
+pts = matrix([-10.0, 10.0], (1,2))
+pylab.plot(X[0,:], X[1,:], 'ow', Y[0,:], Y[1,:], 'ok',
+    pts, (b - a[0]*pts)/a[1], '-r', 
+    pts, (b+1.0 - a[0]*pts)/a[1], '--r',
+    pts, (b-1.0 - a[0]*pts)/a[1], '--r' )
+pylab.title('Separation via linear programming (fig. 8.10)')
+pylab.axis([-10, 10, -10, 10])
+pylab.axis('off')
+pylab.xticks([])
+pylab.yticks([])
+
+# Support vector classifier.
+#
+# minimize    t  + gamma*(1'*u + 1'*v)
+# subject to  a'*X - b >= 1 - u
+#             a'*Y - b <= -1 + v 
+#             u >= 0, v >= 0
+#             [t*I a; a' t] >= 0
+
+gamma = 0.1
+nv = n + 2 + N + M   # variables (a, b, t, u, v)
+ni = 2 * (N + M)
+
+c = matrix(0.0, (nv,1))
+c[3], c[4:] = 1.0, gamma
+
+IN = spmatrix(1.0, range(N), range(N))
+IM = spmatrix(1.0, range(M), range(M))
+Gl = matrix(0.0, (ni, nv))
+hl = matrix(0.0, (ni, 1))
+Gl[:N, :n] = -X.T
+Gl[:N, n] = 1.0
+Gl[:N, n+2:n+2+N] = -IN
+hl[:N] = -1.0
+Gl[N:N+M, :n] = Y.T
+Gl[N:N+M, n] = -1.0
+Gl[N:N+M, -M:] = -IM
+hl[N:N+M] = -1.0
+Gl[N+M:N+M+N, n+2:n+2+N] = -IN
+Gl[N+M+N:, -M:] = -IM
+
+Gs = [spmatrix(0.0, [], [], (9, nv))]
+Gs[0][2,0] = -1.0 
+Gs[0][6,0] = -1.0 
+Gs[0][5,1] = -1.0 
+Gs[0][7,1] = -1.0 
+Gs[0][0,3] = -1.0 
+Gs[0][4,3] = -1.0 
+Gs[0][8,3] = -1.0 
+hs = [matrix(0.0, (3,3))]
+
+sol = solvers.sdp(c, Gl, hl, Gs, hs)
+a = sol['x'][:2]
+b = sol['x'][2]
+
+pylab.figure(2, facecolor='w', figsize=(5,5))
+pts = matrix([-10.0, 10.0], (1,2))
+pylab.plot(X[0,:], X[1,:], 'ow', Y[0,:], Y[1,:], 'ok',
+    pts, (b - a[0]*pts)/a[1], '-r', 
+    pts, (b+1.0 - a[0]*pts)/a[1], '--r',
+    pts, (b-1.0 - a[0]*pts)/a[1], '--r' )
+pylab.title('Support vector classifier (fig. 8.11)')
+pylab.axis([-10, 10, -10, 10])
+pylab.xticks([])
+pylab.yticks([])
+pylab.axis('off')
+
+
+# Via logistic modeling.
+#
+# minimize -sum(X'*a - b) + sum log (1 + exp([X';Y']*a - b))
+
+A = matrix(0.0, (N+M,n+1)) 
+A[:N,:n], A[N:,:n], A[:,n] = X.T, Y.T, -1.0
+c = -(matrix(1.0, (1,N)) * A[:N,:]).T
+
+# minimize c'*x + sum log (1 + exp(A*x)) 
+
+def F(x=None, z=None):
+   if x is None: return 0, matrix(0.0, (n+1,1))
+   w = exp(A*x)
+   f = dot(c,x) + sum(log(1+w)) 
+   grad = c + A.T * div(w, 1+w)  
+   if z is None: return matrix(f), grad.T
+   H = A.T * spmatrix(div(w,(1+w)**2), range(len(w)), range(len(w))) * A
+   return matrix(f), grad.T, z[0]*H 
+
+sol = solvers.cp(F)
+a, b = sol['x'][:2],  sol['x'][2]
+
+pylab.figure(3, facecolor='w', figsize=(5,5))
+pts = matrix([-10.0, 10.0], (1,2))
+pylab.plot(X[0,:], X[1,:], 'ow', Y[0,:], Y[1,:], 'ok',
+    pts, (b - a[0]*pts)/a[1], '-r', 
+    pts, (b+1.0 - a[0]*pts)/a[1], '--r',
+    pts, (b-1.0 - a[0]*pts)/a[1], '--r' )
+pylab.title('Separation via logistic modeling (fig. 8.12)')
+pylab.axis([-10, 10, -10, 10])
+pylab.xticks([])
+pylab.yticks([])
+pylab.axis('off')
+
+pylab.show()
diff --git a/examples/book/chap8/linsep.pic b/examples/book/chap8/linsep.pic
new file mode 100644
index 0000000..f8031f7
--- /dev/null
+++ b/examples/book/chap8/linsep.pic
@@ -0,0 +1,225 @@
+(dp0
+S'Y'
+p1
+ccvxopt.base
+matrix
+p2
+((lp3
+F-3.3259124319899862
+aF2.8225398072811516
+aF-0.085583482542882061
+aF3.1530933114417081
+aF-1.3247761851520539
+aF2.2606345410061248
+aF4.1832161373082064
+aF5.7543596834452719
+aF0.75502644379389472
+aF4.3218889499026991
+aF1.5867204004149711
+aF3.6376335205696551
+aF-3.7537950975207721
+aF0.92428488418482946
+aF-4.1800929390295156
+aF0.91630289899980921
+aF4.2629206573744911
+aF3.5807156730501672
+aF2.573748910847383
+aF4.4138777646398388
+aF0.13453652761961798
+aF6.2684549569682044
+aF3.4378865234397504
+aF7.3140696878676845
+aF-1.7591406875563949
+aF3.12875120530243
+aF2.6282388968157653
+aF8.3076743912936379
+aF1.1486751015240078
+aF6.4355777960311435
+aF3.0470243371220431
+aF2.7060007913042123
+aF-0.5171185991922278
+aF6.3246590293256251
+aF-3.1507825952040975
+aF2.4337415612517659
+aF2.3579117888673511
+aF3.7067675889497793
+aF-1.4175554889396924
+aF-0.40849422934491386
+aF-1.7717823012505192
+aF2.6872451500321142
+aF0.931122926878857
+aF5.1885004522252878
+aF-1.6371106533789872
+aF0.64004041011870338
+aF1.2351587354330928
+aF6.5189109009536264
+aF0.39904790672760693
+aF1.98855295706613
+aF-0.92488907487814354
+aF2.4589906199856588
+aF-1.9759356663570427
+aF2.4422815951389691
+aF-1.6901883178447037
+aF2.9238391663761094
+aF1.6863365498640297
+aF4.3498854200260988
+aF-0.054069207143000675
+aF4.7696578032384611
+aF-3.763470227580636
+aF-0.41566113012203587
+aF-4.6912529063267048
+aF-1.6078012334153884
+aF-3.6342230231157275
+aF1.2930152609673407
+aF-3.3015329081859432
+aF-1.817701136997784
+aF-6.0700828799319808
+aF-1.6205068273178593
+aF-6.0922564178915257
+aF-0.87265141093362164
+aF-3.046827042693721
+aF1.235109483262729
+aF-4.6075121063136342
+aF-2.3866354834632082
+aF-3.2776708818532097
+aF0.044761524054909962
+aF-1.3836061813809617
+aF2.2811212122200692
+aF0.89365751897667056
+aF2.1812349207644646
+aF-1.9504864207015848
+aF3.3866795568055132
+aF2.5555324747844974
+aF4.629692916135788
+aF-6.9008879666136647
+aF-4.0252986202193295
+aF-3.7027690950618588
+aF-0.26702581794135005
+aF-4.9641892055436436
+aF-3.1956203424905927
+aF-5.4535810893929106
+aF-1.7786517352517941
+aF-5.7927828700513126
+aF-0.66709383907920383
+aF-4.9928597973428914
+aF-2.104980529891062
+aF-2.6695985995034452
+aF-0.30423711825838984
+a(I2
+I50
+tp4
+S'd'
+p5
+tp6
+Rp7
+sS'X'
+p8
+g2
+((lp9
+F-2.2988730425412962
+aF-6.8886127538282613
+aF0.11206447589345725
+aF-3.3240576614930459
+aF-0.74372051739217349
+aF-2.1470371556379169
+aF-1.0829466884697956
+aF-5.2923651188100989
+aF0.12976840441848125
+aF-4.2049779282934852
+aF-4.0222415940723328
+aF-5.044396125337884
+aF3.4598318341371579
+aF-0.92970676505898897
+aF1.3952691136349913
+aF-2.559228827847134
+aF1.8011678836395115
+aF-1.7619157225981017
+aF-0.98362919545773275
+aF-3.6273804334157735
+aF-2.3656826672527456
+aF-4.5278749522154893
+aF-5.7199620621032308
+aF-3.749201369226534
+aF1.572658516501757
+aF-2.1537197033803914
+aF0.23314811759215015
+aF-4.7095822287706097
+aF4.4922671955365825
+aF2.7367666036134843
+aF-1.1776750048123226
+aF-3.3663465468972991
+aF-2.3038884777014044
+aF-6.5438609147713596
+aF0.52318914850250631
+aF-0.56843868120988461
+aF-2.6652661202159162
+aF-4.560160151307489
+aF0.025142514973025221
+aF-1.2938685960527376
+aF-5.5306699466330507
+aF-2.9482496744854205
+aF-0.24365598231452346
+aF-6.433884777987851
+aF-1.2587526414888468
+aF-5.8634676835104891
+aF2.9082964700370413
+aF-2.04119192292415
+aF1.3692304592723086
+aF-5.0646827172416486
+aF0.38444927208825685
+aF-3.8547764797604556
+aF-1.5000663120577835
+aF-4.3107025534659931
+aF4.3069464239149244
+aF1.6142135661793393
+aF1.0320292288276742
+aF-1.6989736371650852
+aF-3.5977156960777501
+aF-4.6287278188825374
+aF7.8452137354493381
+aF4.3299787523984534
+aF3.9147900464905931
+aF0.27707044522956314
+aF2.5487116241206644
+aF-1.1377492790435122
+aF0.83364231666949484
+aF-0.82955309110512321
+aF2.5364592833901565
+aF-0.56945672762463717
+aF-0.46843548774939214
+aF-0.42212397750498121
+aF3.1121398420558943
+aF0.11136088696540258
+aF5.9088501740048818
+aF2.5339351757838608
+aF7.920056421946466
+aF3.5443936333542574
+aF7.5875426443774714
+aF0.67263456075981409
+aF2.8803338222063486
+aF-1.0726633535600105
+aF2.3493280656232298
+aF1.8713377957720971
+aF6.3375235850156715
+aF2.4011775105257085
+aF0.72189465458660751
+aF-1.1792894527679461
+aF5.64036424092766
+aF3.5213766242958182
+aF8.738328157638346
+aF3.1098075267940533
+aF2.5791206203432999
+aF0.52790175355367319
+aF3.611168317023135
+aF-0.21097517368754937
+aF6.1573596252569232
+aF2.4297655543463108
+aF2.5780511922520906
+aF-2.0378512504695636
+a(I2
+I50
+tp10
+g5
+tp11
+Rp12
+s.
\ No newline at end of file
diff --git a/examples/book/chap8/placement b/examples/book/chap8/placement
new file mode 100755
index 0000000..7f95fc2
--- /dev/null
+++ b/examples/book/chap8/placement
@@ -0,0 +1,176 @@
+#!/usr/bin/python
+
+# Figures 8.15-17, pages 435 and 436.
+# Linear, quadratic and fourth-order placement.
+#
+# The problem data are different from the example in the book.
+
+import pylab, pickle
+from cvxopt import lapack, solvers
+from cvxopt.base import matrix, spmatrix, sqrt, mul
+from cvxopt.modeling import variable, op
+solvers.options['show_progress'] = False
+
+data = pickle.load(open("placement.pic", "r"))
+Xf = data['X']  # M by n matrix with coordinates of M fixed nodes
+M = Xf.size[0]  
+E = data['E']   # list of edges 
+L = len(E)      # number of edges
+N = max(max(e) for e in E) + 1 - M  # number of free nodes; fixed nodes
+                                    # have the highest M indices.
+# arc-node incidence matrix
+A = matrix(0.0, (L,M+N))
+for k in xrange(L):  A[k, E[k]] = matrix([1.0, -1.0], (1,2))
+
+
+# minimize sum h( sqrt( (A1*X[:,0] + B[:,0])**2 + 
+#                       (A1*X[:,1] + B[:,1])**2 ) for different h
+
+
+A1 = A[:,:N]
+B = A[:,N:]*Xf
+
+
+# Linear placement: h(u) = u.
+#
+# minimize    1'*t
+# subject to  [ ti*I               (A[i,:]*[x,y] + B)'  ]
+#             [ A[i,:]*[x,y] + B   ti                   ] >= 0, 
+#             i = 1, ..., L
+#
+# variables t (L), x (N), y (N).
+
+novars = L + 2*N
+c = matrix(0.0, (novars,1))
+c[:L] = 1.0
+G = [ spmatrix([], [], [], (9, novars)) for k in xrange(L) ]
+h = [ matrix(0.0, (3,3)) for k in xrange(L) ]
+for k in xrange(L):
+
+    # coefficient of tk
+    C = spmatrix(-1.0, [0,1,2], [0,1,2])
+    G[k][C.I + 3*C.J, k] = C.V
+
+    for j in xrange(N):
+        # coefficient of x[j]
+        C = spmatrix(-A[k,j], [2, 0], [0, 2])
+        G[k][C.I + 3*C.J, L+j] = C.V
+
+        # coefficient of y[j]
+        C = spmatrix(-A[k,j], [2, 1], [1, 2])
+        G[k][C.I + 3*C.J, L+N+j] = C.V
+
+    # constant
+    h[k][2,:2] = B[k,:]
+    h[k][:2,2] = B[k,:].T
+
+sol = solvers.sdp(c, Gs=G, hs=h)
+X1 = matrix(sol['x'][L:], (N,2))
+
+
+# Quadratic placement: h(u) = u^2.
+#
+# minimize  sum (A*X[:,0] + B[:,0])**2 + (A*X[:,1] + B[:,1])**2 
+# 
+# with variable X (Nx2).
+
+Bc = -B
+lapack.gels(+A1, Bc)
+X2 = Bc[:N,:]
+
+
+# Fourth order placement: h(u) = u^4
+#
+# minimize  g(AA*x + BB)            
+#
+# where AA = [A1, 0; 0, A1] 
+#       BB = [B[:,0]; B[:,1]] 
+#       x = [X[:,0]; X[:,1]]
+#       g(u,v) = sum((uk.^2 + vk.^2).^2)
+#
+# with variables x (2*N).
+
+AA = matrix(0.0, (2*L, 2*N))
+AA[:L, :N], AA[L:,N:] = A1, A1
+BB = matrix(B, (2*L,1))
+def F(x=None, z=None):
+    if x is None: 
+        return 0, matrix(0.0, (2*N,1))
+    y = AA*x + BB
+    d = y[:L]**2 + y[L:]**2
+    f = sum(d**2)
+    gradg = matrix(0.0, (2*L,1))
+    gradg[:L], gradg[L:] = 4*mul(d,y[:L]), 4*mul(d,y[L:])
+    g = gradg.T * AA
+    if z is None: return f, g
+    H = matrix(0.0, (2*L, 2*L))
+    for k in xrange(L):
+        H[k,k], H[k+L,k+L] = 4*d[k], 4*d[k]
+        H[[k,k+L], [k,k+L]] += 8 * y[[k,k+L]] * y[[k,k+L]].T 
+    return f, g, AA.T*H*AA
+
+sol = solvers.cp(F)
+X4 = matrix(sol['x'], (N,2))
+
+
+# Figures for linear placement.
+
+pylab.figure(1, figsize=(10,4), facecolor='w')
+pylab.subplot(121) 
+X = matrix(0.0, (N+M,2))
+X[:N,:], X[N:,:] = X1, Xf
+pylab.plot(Xf[:,0], Xf[:,1], 'sw', X1[:,0], X1[:,1], 'or', ms=10)
+for s, t in E:  pylab.plot([X[s,0], X[t,0]], [X[s,1],X[t,1]], ':')
+pylab.axis([-1.1, 1.1, -1.1, 1.1])
+pylab.axis('equal')
+pylab.title('Linear placement')
+
+pylab.subplot(122) 
+lngths = sqrt((A1*X1 + B)**2 * matrix(1.0, (2,1)))
+pylab.hist(lngths, [.1*k for k in xrange(15)])
+x = pylab.arange(0, 1.6, 1.6/500)
+pylab.plot( x, 5.0/1.6*x, '--k')
+pylab.axis([0, 1.6, 0, 5.5])
+pylab.title('Length distribution')
+
+
+# Figures for quadratic placement.
+
+pylab.figure(2, figsize=(10,4), facecolor='w')
+pylab.subplot(121) 
+X[:N,:], X[N:,:] = X2, Xf
+pylab.plot(Xf[:,0], Xf[:,1], 'sw', X2[:,0], X2[:,1], 'or', ms=10)
+for s, t in E:  pylab.plot([X[s,0], X[t,0]], [X[s,1],X[t,1]], ':')
+pylab.axis([-1.1, 1.1, -1.1, 1.1])
+pylab.axis('equal')
+pylab.title('Quadratic placement')
+
+pylab.subplot(122) 
+lngths = sqrt((A1*X2 + B)**2 * matrix(1.0, (2,1)))
+pylab.hist(lngths, [.1*k for k in xrange(15)])
+x = pylab.arange(0, 1.5, 1.5/500)
+pylab.plot( x, 5.0/1.5**2 * x**2, '--k')
+pylab.axis([0, 1.5, 0, 5.5])
+pylab.title('Length distribution')
+
+
+# Figures for fourth order placement.
+
+pylab.figure(3, figsize=(10,4), facecolor='w')
+pylab.subplot(121) 
+X[:N,:], X[N:,:] = X4, Xf
+pylab.plot(Xf[:,0], Xf[:,1], 'sw', X4[:,0], X4[:,1], 'or', ms=10)
+for s, t in E:  pylab.plot([X[s,0], X[t,0]], [X[s,1],X[t,1]], ':')
+pylab.axis([-1.1, 1.1, -1.1, 1.1])
+pylab.axis('equal')
+pylab.title('Fourth order placement')
+
+pylab.subplot(122) 
+lngths = sqrt((A1*X4 + B)**2 * matrix(1.0, (2,1)))
+pylab.hist(lngths, [.1*k for k in xrange(15)])
+x = pylab.arange(0, 1.5, 1.5/500)
+pylab.plot( x, 6.0/1.4**4 * x**4, '--k')
+pylab.axis([0, 1.4, 0, 6.5])
+pylab.title('Length distribution')
+
+pylab.show()
diff --git a/examples/book/chap8/placement.pic b/examples/book/chap8/placement.pic
new file mode 100644
index 0000000..e4ed24e
--- /dev/null
+++ b/examples/book/chap8/placement.pic
@@ -0,0 +1,118 @@
+(dp0
+S'X'
+p1
+ccvxopt.base
+matrix
+p2
+((lp3
+F1.0
+aF1.0
+aF-1.0
+aF-1.0
+aF1.0
+aF-1.0
+aF-0.20000000000000001
+aF0.10000000000000001
+aF1.0
+aF-1.0
+aF-1.0
+aF1.0
+aF-0.5
+aF-0.20000000000000001
+aF-1.0
+aF1.0
+a(I8
+I2
+tp4
+S'd'
+p5
+tp6
+Rp7
+sS'E'
+p8
+(lp9
+(lp10
+I0
+aI3
+aa(lp11
+I0
+aI2
+aa(lp12
+I0
+aI4
+aa(lp13
+I0
+aI6
+aa(lp14
+I0
+aI7
+aa(lp15
+I0
+aI10
+aa(lp16
+I0
+aI13
+aa(lp17
+I1
+aI2
+aa(lp18
+I1
+aI3
+aa(lp19
+I1
+aI5
+aa(lp20
+I1
+aI7
+aa(lp21
+I1
+aI8
+aa(lp22
+I1
+aI12
+aa(lp23
+I2
+aI3
+aa(lp24
+I2
+aI7
+aa(lp25
+I2
+aI10
+aa(lp26
+I3
+aI4
+aa(lp27
+I3
+aI8
+aa(lp28
+I3
+aI9
+aa(lp29
+I3
+aI11
+aa(lp30
+I3
+aI5
+aa(lp31
+I4
+aI5
+aa(lp32
+I4
+aI6
+aa(lp33
+I4
+aI9
+aa(lp34
+I4
+aI13
+aa(lp35
+I5
+aI8
+aa(lp36
+I5
+aI10
+aa(lp37
+I1
+aI11
+aas.
\ No newline at end of file
diff --git a/examples/doc/README b/examples/doc/README
new file mode 100644
index 0000000..2a24119
--- /dev/null
+++ b/examples/doc/README
@@ -0,0 +1 @@
+This directory contains some examples from the CVXOPT documentation.
diff --git a/examples/doc/acent b/examples/doc/acent
new file mode 100755
index 0000000..336ec1f
--- /dev/null
+++ b/examples/doc/acent
@@ -0,0 +1,77 @@
+#!/usr/bin/python
+
+# The analytic centering example of section 4.8.
+
+from cvxopt.base import matrix, log, mul, div
+from cvxopt import blas, lapack, random
+from math import sqrt
+
+def acent(A,b):
+    """  
+    Computes analytic center of A*x <= b with A m by n of rank n. 
+    We assume that b > 0 and the feasible set is bounded.
+    """
+
+    MAXITERS = 100
+    ALPHA = 0.01
+    BETA = 0.5
+    TOL = 1e-8
+
+    ntdecrs = []
+    m, n = A.size
+    x = matrix(0.0, (n,1))
+    H = matrix(0.0, (n,n))
+    g = matrix(0.0, (n,1))
+
+    for iter in xrange(MAXITERS):
+        
+        # Gradient is g = A^T * (1./(b-A*x)).
+        d = (b-A*x)**-1
+        g = A.T * d
+
+        # Hessian is H = A^T * diag(1./(b-A*x))^2 * A.
+        Asc = mul( d[:,n*[0]], A)
+        blas.syrk(Asc, H, trans='T')
+
+        # Newton step is v = H^-1 * g.
+        v = -g
+        lapack.posv(H, v)
+
+        # Directional derivative and Newton decrement.
+	lam = blas.dot(g, v)
+        ntdecrs += [ sqrt(-lam) ]
+        print "%2d.  Newton decr. = %3.3e" %(iter,ntdecrs[-1])
+        if ntdecrs[-1] < TOL: return x, ntdecrs
+
+        # Backtracking line search.
+        y = mul(A*v, d)
+	step = 1.0
+        while 1-step*max(y) < 0: step *= BETA 
+	while True:
+            if -sum(log(1-step*y)) < ALPHA*step*lam: break
+	    step *= BETA
+        x += step*v
+
+
+# Generate an analytic centering problem  
+#
+#    -b1 <=  Ar*x <= b2 
+#
+# with random mxn Ar and random b1, b2.
+
+m, n  = 500, 500
+Ar = random.normal(m,n);
+A = matrix([Ar, -Ar])
+b = random.uniform(2*m,1)
+
+x, ntdecrs = acent(A, b)  
+try: 
+    import pylab
+except ImportError: 
+    pass
+else:
+    pylab.semilogy(range(len(ntdecrs)), ntdecrs, 'o', 
+             range(len(ntdecrs)), ntdecrs, '-')
+    pylab.xlabel('Iteration number')
+    pylab.ylabel('Newton decrement')
+    pylab.show()
diff --git a/examples/doc/covsel b/examples/doc/covsel
new file mode 100755
index 0000000..ff45f43
--- /dev/null
+++ b/examples/doc/covsel
@@ -0,0 +1,90 @@
+#! /usr/bin/python
+
+# The covariance selection example of section 7.4.
+
+from cvxopt.base import matrix, spmatrix, log, mul
+from cvxopt import blas, lapack, amd, cholmod
+from pickle import load
+
+def covsel(Y):
+    """
+    Returns the solution of
+ 
+        minimize    -logdet K + tr(KY)
+        subject to  K_ij = 0  if (i,j) not in zip(I, J).
+
+    Y is a symmetric sparse matrix with nonzero diagonal elements.
+    I = Y.I,  J = Y.J.
+    """
+
+    cholmod.options['supernodal'] = 2
+
+    I, J = Y.I, Y.J
+    n, m = Y.size[0], len(I) 
+    # non-zero positions for one-argument indexing 
+    N = I + J*n         
+    # position of diagonal elements
+    D = [ k for k in xrange(m) if I[k]==J[k] ]  
+
+    # starting point: symmetric identity with nonzero pattern I,J
+    K = spmatrix(0.0, I, J) 
+    K[::n+1] = 1.0
+
+    # Kn is used in the line search
+    Kn = spmatrix(0.0, I, J)
+
+    # symbolic factorization of K 
+    F = cholmod.symbolic(K)
+
+    # Kinv will be the inverse of K
+    Kinv = matrix(0.0, (n,n))
+
+    for iters in xrange(100):
+
+        # numeric factorization of K
+        cholmod.numeric(K, F)
+        d = cholmod.diag(F)
+
+        # compute Kinv by solving K*X = I 
+        Kinv[:] = 0.0
+        Kinv[::n+1] = 1.0
+        cholmod.solve(F, Kinv)
+        
+        # solve Newton system
+        grad = 2 * (Y.V - Kinv[N])
+        hess = 2 * ( mul(Kinv[I,J], Kinv[J,I]) + 
+               mul(Kinv[I,I], Kinv[J,J]) )
+        v = -grad
+        lapack.posv(hess,v) 
+                                                  
+        # stopping criterion
+        sqntdecr = -blas.dot(grad,v) 
+        print "Newton decrement squared:%- 7.5e" %sqntdecr
+        if (sqntdecr < 1e-12):
+            print "number of iterations: ", iters+1 
+            break
+
+        # line search
+        dx = +v
+        dx[D] *= 2      
+        f = -2.0*sum(log(d))      # f = -log det K
+        s = 1
+        for lsiter in xrange(50):
+            Kn.V = K.V + s*dx
+            try: 
+                cholmod.numeric(Kn, F)
+            except ArithmeticError: 
+                s *= 0.5
+            else:
+                d = cholmod.diag(F)
+                fn = -2.0 * sum(log(d)) + 2*s*blas.dot(v,Y.V)
+                if (fn < f - 0.01*s*sqntdecr): break
+                else: s *= 0.5
+
+        K.V = Kn.V
+
+    return K
+
+Y = load(open("covsel.pic","r"))
+print "%d rows/columns, %d nonzeros\n" %(Y.size[0], len(Y))
+covsel(Y)
diff --git a/examples/doc/covsel.pic b/examples/doc/covsel.pic
new file mode 100644
index 0000000..c1a9588
--- /dev/null
+++ b/examples/doc/covsel.pic
@@ -0,0 +1,5261 @@
+ccvxopt.base
+spmatrix
+p0
+(ccvxopt.base
+matrix
+p1
+((lp2
+F996.97909104636949
+aF-23.899785763250076
+aF26.492011082544277
+aF6.3509700389619157
+aF27.477696307918759
+aF-20.10640486870755
+aF-14.851814216051114
+aF-39.697185237027547
+aF947.38157898332565
+aF-4.2503539341531873
+aF-28.731726153288296
+aF25.951573115917355
+aF912.79246253755866
+aF-13.786277258261793
+aF-3.3396074735661352
+aF22.900426085981067
+aF978.76440922035999
+aF29.399302044217663
+aF29.493675458377876
+aF-9.8056680822397801
+aF38.431393241910094
+aF6.6172107423274227
+aF7.0193511209072703
+aF922.22675939152157
+aF-8.8777874529557934
+aF4.9296560159837606
+aF-30.101427193113
+aF-42.311444619096605
+aF-32.096792771239414
+aF18.08157424957227
+aF12.193794230496929
+aF-28.008728552794793
+aF-23.317097036200213
+aF913.96913055908465
+aF-24.845831724585306
+aF10.001968526688348
+aF-15.928081845683554
+aF32.134996939691057
+aF953.23023703606907
+aF-31.408813001264047
+aF-21.955758549991032
+aF-2.6022523785110319
+aF-24.409891669365642
+aF-46.51328294593565
+aF-44.116017388700271
+aF1047.0946975616821
+aF-57.51406393738516
+aF22.728277462104138
+aF7.9737432521521878
+aF-33.082296788521418
+aF949.77361988281746
+aF8.4350733450998465
+aF32.682251604762506
+aF-29.480929352123582
+aF15.844238681521945
+aF19.775029611324165
+aF-5.0947662446639193
+aF-0.010269200096147485
+aF25.839862079998419
+aF-0.53768144547513474
+aF13.728102825219038
+aF936.80804613048372
+aF-9.2282887491194838
+aF930.34719524342438
+aF4.5440998141051496
+aF-9.6553236811682304
+aF14.957827712488848
+aF-17.772161782765689
+aF60.971088332972244
+aF-7.2789998145743278
+aF1.4970964152603377
+aF1018.8447349499803
+aF10.983621609183592
+aF49.840242715255179
+aF-14.10310178560856
+aF-30.919625902218471
+aF-5.7599582459395755
+aF19.647643056574967
+aF1134.6711873207071
+aF-29.786221437844866
+aF46.925579827039364
+aF0.26189711511288483
+aF19.875802071318404
+aF1079.0353644586974
+aF23.864347083036272
+aF-25.868571048536605
+aF1026.8823934566585
+aF-7.2148710028710292
+aF-2.6049232502276154
+aF-0.48592393316242866
+aF28.012666242657978
+aF1.1148049429081099
+aF-29.37521222391932
+aF-14.572743019440765
+aF20.13160412481874
+aF-9.2583971209111322
+aF-33.345663083499836
+aF34.695361038279906
+aF888.60799648751174
+aF-4.4075247942034945
+aF2.5932154444147235
+aF1080.670303921205
+aF-16.282864156980011
+aF31.309379807682205
+aF-21.954211030193544
+aF-2.8603119891005853
+aF18.247977543227993
+aF991.71279680172734
+aF-4.8485196053621094
+aF-5.0414818836610902
+aF-34.90572009172373
+aF975.70285310346287
+aF-27.599258403475741
+aF-19.554081005222098
+aF-8.4018748398906382
+aF23.194823652370179
+aF933.75953922039957
+aF-6.2430607181068556
+aF-5.9586117210145542
+aF-43.032268527051862
+aF-1.3812138155781659
+aF32.113618418246595
+aF1018.2708462985455
+aF-8.5235052900855326
+aF-35.664545920199821
+aF6.9328650233786639
+aF31.856762014760918
+aF-40.504040625099428
+aF938.17126479725312
+aF-5.7229700303609707
+aF22.891261221872782
+aF-11.645128742304806
+aF12.999683036644514
+aF-19.628499827095307
+aF986.78052223527141
+aF-23.573385777900366
+aF7.4680279152300253
+aF5.1275578653598348
+aF-1.042737735489033
+aF-4.2674437851554483
+aF7.3323248320460674
+aF25.626888311650887
+aF22.80125702608931
+aF-7.0929101723473753
+aF1006.3374409062694
+aF-33.532331109901136
+aF33.655649116864673
+aF20.598909487118235
+aF6.4286632720213177
+aF-12.60913185908931
+aF1090.9574377004108
+aF-33.926302763271558
+aF21.256562156107488
+aF3.7370158811410956
+aF1053.3609691435686
+aF30.744153525385499
+aF29.109422450014989
+aF21.014174788884503
+aF1007.0584482857449
+aF-1.5984603405285771
+aF-14.656323249191676
+aF-14.431719681436043
+aF-18.271260473117763
+aF-24.38795987203671
+aF-56.856177163127157
+aF1052.7732207215265
+aF16.404203703933042
+aF25.114131414464595
+aF43.133027375829762
+aF-14.703733280794587
+aF12.381973661705503
+aF-8.9376590885897382
+aF-16.582927679703612
+aF901.18993301223213
+aF-7.5820865223780309
+aF-22.465964144743388
+aF961.23344219977866
+aF4.3139958368775391
+aF4.719391490830203
+aF14.133862869025142
+aF-7.0983741979460708
+aF1087.2808790903955
+aF-14.135427208865305
+aF1054.4748258881555
+aF13.737369734368269
+aF-15.347220908753725
+aF-6.4321258683569837
+aF36.216082201781745
+aF-26.965083293110879
+aF960.10855261010522
+aF-21.914454026182778
+aF-21.827743043101556
+aF1008.5701804044542
+aF-25.993860159652677
+aF85.778194350390905
+aF-6.6487449866476691
+aF-7.0668184483549874
+aF46.461350622533871
+aF17.297997152422933
+aF22.805276284461865
+aF1032.0095447438723
+aF-28.641108711765913
+aF5.9399886197386076
+aF22.255065673589328
+aF-3.5282149200877768
+aF26.949329521067011
+aF1041.6709435362741
+aF-5.8457038568418431
+aF-19.394448816940876
+aF-9.2550734558361949
+aF-31.611246970898662
+aF-25.985863560140764
+aF-0.57462882128036252
+aF18.864377008466146
+aF1013.3491173265605
+aF-66.863711615746723
+aF949.11778431555842
+aF19.063907832744778
+aF7.3797451308862891
+aF-49.391427131873691
+aF1041.6901639915379
+aF23.119632520877254
+aF-26.314137094746943
+aF-14.435128309283789
+aF1103.8106946503312
+aF8.0832360649960648
+aF14.197651570310311
+aF-27.496153186411568
+aF39.459897343147475
+aF22.124776203268652
+aF-23.53779700269606
+aF990.02001217446423
+aF8.0394128461011025
+aF-4.580004486298054
+aF-11.701232366733938
+aF-15.517650888909165
+aF11.260868174999487
+aF1125.5105685637313
+aF4.2307417866318442
+aF-18.811122017069376
+aF-49.166763753463947
+aF-26.514217249254244
+aF1013.0784977065847
+aF23.740469837673491
+aF-6.9238624602975936
+aF-18.843063615748449
+aF-11.123058027239367
+aF13.709049567101383
+aF4.8061662338869713
+aF911.39063888213821
+aF30.639006236842935
+aF-0.021747565629815252
+aF17.198727471641135
+aF921.03696800405214
+aF8.9522118988766852
+aF24.559371916829303
+aF12.932954764470599
+aF-17.862368579528425
+aF3.2581867346836741
+aF24.263041799814406
+aF0.34139103729579945
+aF-1.520341874100088
+aF-54.577702864673071
+aF959.12473603431908
+aF33.549573383678258
+aF26.330997861825583
+aF1020.9158970042796
+aF38.420919342586295
+aF-30.575114960947744
+aF-38.522949644282029
+aF-6.4801590504904771
+aF45.165711036976923
+aF-32.513122824771081
+aF981.28052425351871
+aF15.793285693426757
+aF21.574299701890954
+aF-30.343103155018674
+aF28.371611701865337
+aF-7.0184647466242422
+aF849.66955580056037
+aF-23.979181842500758
+aF2.2871064797447076
+aF-9.1828674356218212
+aF3.2444600514822808
+aF0.88520801809984306
+aF-8.0220996082277569
+aF-9.8464906550347102
+aF1.0072931682897124
+aF1113.6735624030134
+aF10.804331377034174
+aF-22.097135878587959
+aF9.0655932227405636
+aF1076.1844627846301
+aF-31.100256263310126
+aF-0.78639288985198375
+aF53.059431630329676
+aF19.477550749954521
+aF-0.3826662495765199
+aF9.6945653910461882
+aF9.8505431522987958
+aF971.94270834392728
+aF-4.0344149756277154
+aF-4.9201586782246132
+aF6.7313325590936808
+aF-14.495111443520264
+aF1014.0009690725504
+aF-6.619427100713871
+aF-1.8259780647314727
+aF31.650817134456236
+aF977.30778603252725
+aF11.959060583725442
+aF13.668415163062924
+aF-14.272952682797696
+aF0.82816229449399392
+aF892.67161757111035
+aF-15.388540215810602
+aF-19.852898468643751
+aF-37.932623711393028
+aF7.3614409924374371
+aF-23.143487814306138
+aF-20.806535758751799
+aF925.26375242625215
+aF13.344536737030985
+aF4.2522225932815099
+aF26.885612171187148
+aF1077.2879274467157
+aF52.15050215627641
+aF-30.226756669657068
+aF-6.4380544094973979
+aF-28.982072345780633
+aF-48.120758203276559
+aF-30.281662458765187
+aF999.84673918724889
+aF-23.518683701514437
+aF-9.2419948216726358
+aF-27.438359166235458
+aF936.47768527933579
+aF-20.582899958385791
+aF-23.537182437014597
+aF988.23103074703317
+aF-28.998617923082069
+aF-12.078155195404895
+aF19.25665241106865
+aF-4.1099889849555238
+aF-14.936505807695358
+aF-39.598183889818408
+aF972.94890387750684
+aF-24.196169328949043
+aF5.7677076851447193
+aF1012.5648842676636
+aF12.957654862031266
+aF-15.472932456386102
+aF13.842590808859299
+aF26.678461221430695
+aF9.6047202281871211
+aF-14.16174880616726
+aF19.040103169315316
+aF30.591039143354898
+aF-11.361246706625865
+aF11.864708678940017
+aF8.0503791145424515
+aF32.596981761299347
+aF900.79255703062927
+aF-15.354325213770883
+aF-26.270810710786609
+aF-3.8707954077725923
+aF-22.438403031173699
+aF-18.011636544558115
+aF-6.6582438290461647
+aF1094.8219953058203
+aF7.398624298056065
+aF-44.582754735006624
+aF4.2281391277265081
+aF1134.6529637723695
+aF39.24556319852524
+aF-2.977945087145295
+aF17.008299420676956
+aF7.8496400060045977
+aF-31.201097633100112
+aF-6.1170257923647799
+aF-2.3387994558943466
+aF13.132685477001628
+aF6.3718428136022842
+aF39.049743685277633
+aF969.37520985338426
+aF10.546857547725025
+aF-0.57545883560222955
+aF0.86008774637314589
+aF0.30067153225729298
+aF-4.4472034653756438
+aF975.41455974105622
+aF-38.195275733532654
+aF-12.02436581887414
+aF23.58432513783886
+aF-5.3242633833109938
+aF-20.825119054173413
+aF918.75128197974425
+aF-29.722700733593467
+aF8.6243893591408174
+aF929.95202309010733
+aF-11.295440035213476
+aF-1.1179207192235838
+aF-10.354913806751139
+aF-6.6253088069908292
+aF973.38113123859966
+aF-38.267940654994547
+aF16.750357165266838
+aF-9.8139331127157341
+aF950.45077464160636
+aF26.441691642553554
+aF2.2956260079994126
+aF14.512140450419707
+aF-27.171992256251436
+aF1062.4893287119701
+aF-1.217693535488708
+aF9.7779485751468496
+aF7.3963156251352249
+aF48.050547699593373
+aF-29.845428287043386
+aF2.5228808932107616
+aF976.82200012005626
+aF-38.67074388666515
+aF18.763585988988229
+aF985.16522410123071
+aF-6.3203686815117974
+aF19.920540122599444
+aF9.211874436274794
+aF-25.488973067721716
+aF-1.5394340988510185
+aF-19.736036540870781
+aF-29.482083648037243
+aF-31.600174660431303
+aF997.47509814723696
+aF44.767248594881814
+aF21.380693018896356
+aF915.72994752936518
+aF29.524207112551998
+aF-7.1189585506651047
+aF10.129794131677576
+aF-13.755517278622316
+aF36.546611617912895
+aF1082.9853923512619
+aF-14.639195139804945
+aF91.215090903308365
+aF10.802159371636852
+aF45.870551534479745
+aF3.4166552312576117
+aF-28.897224258101772
+aF47.088508956929481
+aF929.00054452676727
+aF23.791661469381662
+aF-2.868962217178268
+aF-42.75056506451557
+aF965.20234904468873
+aF15.616555773420478
+aF996.77078853869205
+aF8.985429539837785
+aF-44.283100598935007
+aF15.271861194244881
+aF38.926856224741563
+aF-2.8823526596194515
+aF1062.5887993753693
+aF-36.035798686900542
+aF45.851311182426933
+aF20.94683708207695
+aF29.854527434845895
+aF968.61499685452327
+aF-4.6751894657062341
+aF-17.515650154579198
+aF3.8148691793079674
+aF949.74187830913331
+aF43.516266277561122
+aF-3.7364772531718558
+aF58.879958188684917
+aF990.52088554920647
+aF49.44521495647534
+aF0.85799963670139845
+aF-13.781671082551123
+aF29.834743853696214
+aF988.21958032416353
+aF11.894845749015804
+aF-26.84587645106037
+aF1038.5621852545107
+aF-22.387152764567098
+aF21.923875285433486
+aF35.005604407147011
+aF1007.9812225895364
+aF9.0973077722126057
+aF24.093345355166914
+aF-0.67057040703503723
+aF39.611893715767785
+aF-14.46663769098736
+aF-0.20062715808099191
+aF-4.2744627422786481
+aF1005.5851962727806
+aF1.8504674828965959
+aF-41.25983683691846
+aF-13.710216406501571
+aF-16.303794457336465
+aF-54.03312808273779
+aF1004.8065453788909
+aF6.9983168162326583
+aF-40.057710409860363
+aF42.779489697955128
+aF1.7332844880624727
+aF1038.0797697191394
+aF-33.168165561438087
+aF-6.9327933949906893
+aF1.430662134835005
+aF1094.8945947785323
+aF-37.243987292832131
+aF-11.197691834606399
+aF27.381174573947252
+aF-28.252922210902209
+aF18.737618837615397
+aF-5.7831802021351457
+aF16.964448208683656
+aF16.275657558233878
+aF-18.719750404254576
+aF1068.4179631910599
+aF-9.8198917335797642
+aF36.710032425130073
+aF1031.2836526872818
+aF24.264059442944379
+aF-11.727968212515853
+aF-18.151293655059753
+aF-24.976172833095269
+aF8.3667909344237614
+aF-4.4027812298738107
+aF1054.3948452057666
+aF-50.233686556757249
+aF4.6638860661300994
+aF19.98484850322081
+aF11.212676332857964
+aF-7.2815878645996515
+aF10.565828529712272
+aF987.13682955214369
+aF2.4302981844950278
+aF936.96450077602799
+aF-27.114012164333719
+aF-2.8138847985580897
+aF-9.1287015698329466
+aF57.29093169564895
+aF-29.53431342140323
+aF-33.278679663689758
+aF939.29199645795825
+aF-12.419627542773917
+aF887.07987341233002
+aF29.756103704007913
+aF2.4618525611882416
+aF957.25992971071935
+aF-20.489353133724816
+aF11.515863543184533
+aF-0.80449734677080986
+aF-2.7284743869198489
+aF22.229240705888756
+aF17.90116513975228
+aF21.72211693735008
+aF959.94709648027799
+aF34.995273758518863
+aF27.134387200012014
+aF-13.540189765604676
+aF1008.3249906000322
+aF-27.527424161063873
+aF35.384114149189564
+aF29.830611110003879
+aF1140.27562979709
+aF4.5363497360224887
+aF937.30782908739877
+aF-21.019776840796247
+aF23.718961413043186
+aF1081.3801927663999
+aF-10.874492381232081
+aF-16.78244226343773
+aF3.9580343961792464
+aF1017.2558843909964
+aF-5.2974886623784085
+aF19.717334827021709
+aF12.725210028812757
+aF10.573580776229626
+aF7.0077864958226712
+aF981.26394725566024
+aF2.3980900683046502
+aF-11.083431325927501
+aF994.49342592893572
+aF-25.482713356790338
+aF1055.5519883462389
+aF15.692942677531224
+aF-1.0735847177568509
+aF9.5716744111900738
+aF38.044645125443772
+aF1014.2620152503325
+aF5.272922152362578
+aF-31.121812465026423
+aF11.475405850078996
+aF6.4940372367327832
+aF1034.8872819188484
+aF-6.2508460631289662
+aF0.26188270833388227
+aF26.519785811843121
+aF43.57089398457493
+aF1004.116273921304
+aF28.704065287909565
+aF30.427557981129272
+aF-11.326465061106145
+aF14.069455348079217
+aF933.60658849461709
+aF15.676874577427034
+aF3.4084531694784346
+aF18.173465882323715
+aF45.013906240699093
+aF4.5319108153049346
+aF11.885075058291193
+aF992.64788528761187
+aF14.18959996401418
+aF3.7769693527975239
+aF-25.980421919719532
+aF10.938509729705492
+aF994.513735429446
+aF6.1197875649908644
+aF919.76287575430251
+aF18.742518559670419
+aF6.5867800823202103
+aF6.4771363562967323
+aF-62.45016616494982
+aF1110.7757959588073
+aF7.725509489390177
+aF-17.893776294187496
+aF-11.069031616989474
+aF-12.00684811208982
+aF1049.0632719788891
+aF-47.582662848842126
+aF-20.238606857455949
+aF14.129689818693368
+aF1049.3586290282979
+aF39.554447989074859
+aF-13.516310850214932
+aF921.11145940005633
+aF6.8214590647956586
+aF34.078692056032722
+aF-18.90239181389882
+aF6.5658112888807789
+aF-18.53692030669146
+aF988.12241478553949
+aF-18.044846992594707
+aF16.370358177846555
+aF5.6769283570573323
+aF4.0252910266531039
+aF-20.071459215447749
+aF1092.6347297868579
+aF-23.334143249427662
+aF2.1597939530351002
+aF-27.987812677839283
+aF942.5282200812286
+aF13.857525561174864
+aF-23.994012273363303
+aF882.17315406181706
+aF24.583870087304529
+aF1.026884690639823
+aF17.834431109537359
+aF1032.9956875586195
+aF39.018910399607357
+aF-28.497374264658632
+aF31.22736612426257
+aF-12.171225572720768
+aF10.164992053560601
+aF1076.6470432120457
+aF-5.2672822581787608
+aF1057.1455550686983
+aF13.179716530232717
+aF-5.3428894527137469
+aF7.2874129869206765
+aF22.842223576470332
+aF-14.710067883564854
+aF42.289407851641968
+aF975.84247946784501
+aF-14.023467851648695
+aF24.229909789557059
+aF11.047698002925632
+aF-8.398349859307098
+aF-47.737302476602771
+aF-12.222399410493942
+aF29.924836183159623
+aF-27.569583619433335
+aF12.770587324899454
+aF1011.0679190716759
+aF1032.3413399546473
+aF1.0387597682992924
+aF-0.91377003635400444
+aF11.457770746909334
+aF928.27273798487136
+aF-3.8668667143785065
+aF-26.800143894417431
+aF980.56202340494872
+aF-3.9512316927659463
+aF-3.1617150619105154
+aF998.88354816553306
+aF38.517681536164325
+aF2.9203953964333933
+aF9.5761883172002502
+aF-16.175462931073753
+aF-4.3248265065054357
+aF1116.3448423596058
+aF11.774687341176623
+aF5.3199036328884404
+aF-9.9795719318183238
+aF7.8566636930425036
+aF30.3367700810978
+aF954.44449445688542
+aF8.0265790854975343
+aF30.754542408670797
+aF-28.164624762465621
+aF1000.0628032213147
+aF-27.494312468544834
+aF-2.6021471753383776
+aF8.7581693881982901
+aF22.431023844326432
+aF962.1463604946772
+aF-23.551611772685607
+aF7.3746320850423022
+aF1013.3465262998698
+aF12.493368987203331
+aF36.509309951825344
+aF-23.711073590863279
+aF52.730079549213912
+aF46.100384322751111
+aF-4.9065936527229486
+aF962.36936009293674
+aF20.215352623151198
+aF29.848570313773834
+aF5.4755866112082101
+aF3.8220384611879292
+aF1006.0068763722406
+aF-20.367203213511527
+aF-0.42045513517412436
+aF993.82372076550655
+aF-8.6880764634740562
+aF44.203842622387775
+aF-14.241290998893584
+aF-26.225894835652635
+aF-10.269201095552537
+aF19.633669806612005
+aF1043.8579294866754
+aF15.007029627523357
+aF17.186354706126608
+aF25.659546891593109
+aF31.860361951425794
+aF992.07992771387035
+aF-13.027965586523621
+aF-3.7261819344015157
+aF-2.8846061326574799
+aF1014.4091678600224
+aF13.760142036001628
+aF9.1624223284910133
+aF-10.337483218210073
+aF1032.7995635309576
+aF-28.817042577007591
+aF6.226865529298812
+aF-21.9417763910762
+aF-24.24139759003009
+aF53.842854869350795
+aF8.1280170174491602
+aF978.52914499772362
+aF8.3241149896082334
+aF-7.4669602996361393
+aF997.04558743852147
+aF-2.4859489080113
+aF-21.847666936301977
+aF-0.52144893192605135
+aF949.8994980544112
+aF-16.909903785338692
+aF18.539701926532178
+aF944.41326783890531
+aF8.1659096876066677
+aF16.310477734763122
+aF1113.8988696385118
+aF-33.958016089052528
+aF35.272948568283248
+aF-13.534255517263681
+aF0.70271285423549901
+aF1002.7457241696035
+aF-16.480026534436487
+aF-19.229461976581153
+aF25.828947433523179
+aF907.83851651473435
+aF-6.5226624352274056
+aF966.31430559772741
+aF-31.261644297897224
+aF-15.763682697269594
+aF7.4337743999308259
+aF1054.7064765026309
+aF28.073531561104041
+aF8.2529009925065235
+aF-24.401260507710667
+aF990.31828208353966
+aF-16.941317689731754
+aF1002.9542840643745
+aF-0.20877765764089851
+aF-28.685492670197856
+aF28.051702686275132
+aF10.279726273699406
+aF-21.097934707750436
+aF1112.6168482264152
+aF17.92809104975856
+aF16.895332074163214
+aF998.83210342895165
+aF33.72095713353616
+aF-16.419105890554142
+aF-2.0926743729112021
+aF-9.9857304056984031
+aF1010.3628621834437
+aF0.23621362811159408
+aF-8.4231733795926189
+aF8.7295690899221849
+aF25.892471008496319
+aF-23.431441779738066
+aF24.833173156257082
+aF1020.6533198616248
+aF26.164357763872164
+aF958.78939823174119
+aF-7.6422366645427982
+aF-13.11394145360636
+aF-2.6753300179342001
+aF25.247458461348916
+aF1039.2055829452127
+aF-7.2872759774750611
+aF7.0528882516125604
+aF3.7080961723917261
+aF973.79589640868289
+aF-16.86881908205179
+aF10.659872977309448
+aF4.430660601918734
+aF1037.1729140350162
+aF29.89355938656152
+aF-50.189857566834895
+aF-5.9636923789074094
+aF17.826068259796294
+aF953.92372527061502
+aF-2.0454784830086687
+aF6.4625250006392605
+aF989.64607184204749
+aF-9.182833176252025
+aF17.644501542694162
+aF20.222933139883466
+aF11.696837507359968
+aF-6.0295871163723538
+aF903.51849980515908
+aF-0.8349072738825507
+aF13.081763637251349
+aF5.5823785824615308
+aF2.7279389271868797
+aF-4.2057616210887945
+aF965.10829682890244
+aF-14.716828140390311
+aF-3.4227041275294057
+aF19.081184392250034
+aF31.602308063382814
+aF-7.5721483503993117
+aF954.06001071077765
+aF17.958634708939744
+aF-7.9726690157125155
+aF4.264877245808858
+aF-10.351933782805398
+aF-22.447819727267706
+aF-6.3797954849566114
+aF8.5297158949405976
+aF1109.990294416541
+aF-42.898936696936097
+aF3.0954216394606271
+aF-11.300425546825728
+aF919.10549497839702
+aF33.591358147857235
+aF935.56184410429842
+aF2.4792243365005695
+aF47.290613566030274
+aF-24.723451850020865
+aF18.189449295176459
+aF-9.354433646338757
+aF1009.176919166517
+aF26.265855914888188
+aF12.241139956354482
+aF1007.5162553425275
+aF-35.083016459819333
+aF2.8223796343765208
+aF24.30865232386504
+aF940.49192387351047
+aF26.765120022454042
+aF-29.991980589880797
+aF-6.5726652531282781
+aF-35.138197763678562
+aF898.02294601185963
+aF-11.80030385171745
+aF6.3959385613508735
+aF5.2095056251171412
+aF-11.267639136207618
+aF8.9834269096049191
+aF-15.601450911359493
+aF12.002934352490424
+aF1061.9088314574196
+aF1021.5286307963414
+aF974.27096227826451
+aF29.231106974629462
+aF-12.372457679181895
+aF16.839782914040239
+aF-10.784906960159148
+aF1110.9133558869853
+aF-5.2464051847499347
+aF30.421024568712987
+aF929.45612487422636
+aF0.15988306104624417
+aF-23.588118640476875
+aF-16.733021339712685
+aF1.2551095486065418
+aF978.84550675877881
+aF2.0201676799620762
+aF-6.2871676715210647
+aF13.741736823981698
+aF-11.700604477132963
+aF912.73065437846151
+aF-34.706466001545323
+aF30.381298303545133
+aF1009.3731061378852
+aF1008.3238318628544
+aF-5.188124346961434
+aF0.9410066436597293
+aF13.664028186614686
+aF31.955663189822026
+aF36.298825292433868
+aF35.176273581571088
+aF-2.8977416727142895
+aF963.93010211866283
+aF-29.79958993383384
+aF994.77502674420896
+aF15.935386715699183
+aF923.05426690660636
+aF10.813258829419137
+aF-5.0352645809704404
+aF-33.739262545004195
+aF9.2116967596217449
+aF946.32432870467312
+aF-8.5126420806973595
+aF1081.0704440762224
+aF-37.94791662819712
+aF37.652164163556137
+aF12.207073541807159
+aF921.1930928641782
+aF9.6812477407748254
+aF-14.504560064472656
+aF-4.4435393555856164
+aF1079.7871664885888
+aF-4.2068315640642764
+aF-8.6579170353384622
+aF987.87888532003547
+aF-18.620256480458224
+aF22.673599291714876
+aF0.7976252139129526
+aF19.045514512488833
+aF-6.7236942771881969
+aF1020.8978670132979
+aF-15.665420619434165
+aF945.76290267502304
+aF1.5002038650554304
+aF-12.140751228062987
+aF-8.1605631695879008
+aF36.38551674207541
+aF954.2048524912725
+aF18.096363537958595
+aF6.0562064745208684
+aF1068.2886355623439
+aF3.7385075441161346
+aF1043.5461446148433
+aF27.167655521117048
+aF-1.7205580132454539
+aF1021.3718384285742
+aF1.4106247755596306
+aF-13.751870029269391
+aF994.82426288387512
+aF-12.597355438002541
+aF-1.8773847569154434
+aF-7.5209177992746694
+aF-1.6775361606032031
+aF3.5860267753881669
+aF993.30830163951464
+aF1023.7684322108034
+aF7.3827281845142592
+aF-6.2365289844226357
+aF-19.581305627993292
+aF21.894835215302475
+aF982.303314742054
+aF42.020832311455976
+aF-14.223923349187423
+aF15.473580458743308
+aF0.89564973651898327
+aF1012.4385069146476
+aF-7.2487238491036035
+aF1026.5110056674478
+aF62.970107595120894
+aF-32.575454655734426
+aF-5.7355057597276309
+aF13.588454572583924
+aF7.8487505645684745
+aF982.13309030362689
+aF63.488587900901173
+aF-37.193347878489483
+aF979.96862484579469
+aF990.17460576284623
+aF6.3290285485479219
+aF-31.241455279740322
+aF14.860911033605705
+aF1124.0924276728445
+aF18.350218398281889
+aF-28.656127294058741
+aF968.25647178214444
+aF49.613549770982445
+aF-3.3406091757118856
+aF1064.8492682682361
+aF-5.8492167950322704
+aF0.29639565205010271
+aF-35.755746541632156
+aF935.43814194014988
+aF-30.387506374733036
+aF5.6872214491917221
+aF991.88747302311162
+aF12.259443441354779
+aF0.181752200689414
+aF16.774813957070222
+aF-71.796419982668723
+aF41.56387470064346
+aF-16.257927337035415
+aF986.15091307304851
+aF1115.3974609551856
+aF1051.793615857719
+aF25.486172028493307
+aF-1.6049595921194972
+aF1059.8939545017458
+aF22.26305700865467
+aF-0.73933252451773435
+aF33.678645064785698
+aF12.144505068647897
+aF1014.2947204119002
+aF-14.265739115479134
+aF19.337207481655788
+aF-8.6131796268442606
+aF940.39212528740211
+aF-29.596684220709747
+aF1122.0343586091929
+aF-14.356302062808773
+aF21.163932957048655
+aF1038.3909029991755
+aF39.044908091569226
+aF-11.630458257577232
+aF-17.138505408734574
+aF1040.082081491717
+aF986.20675504822998
+aF1073.0478251789652
+aF-25.571873318266967
+aF-25.733135530201718
+aF1.1874720864945678
+aF-20.316559061832148
+aF-1.0994577450697369
+aF-1.5295198320725041
+aF1035.9342679890772
+aF35.422212819916567
+aF3.7260719482504827
+aF22.090112190960102
+aF29.924784730321939
+aF1042.7415438674823
+aF1117.4125977172403
+aF27.991226802966825
+aF53.299664091488509
+aF-16.868980357007661
+aF5.6904830265721369
+aF25.065404373823458
+aF-19.684108774384359
+aF1038.6668477350022
+aF27.74060789188448
+aF11.729918308461404
+aF1008.0403256317013
+aF-7.198024472953171
+aF11.550463076420227
+aF904.53619512376258
+aF31.259542543394222
+aF19.522792433471572
+aF-1.7081953140500363
+aF26.361472695929937
+aF42.169357609930557
+aF36.954953151121451
+aF1004.3887145255586
+aF-3.0567176590418392
+aF-28.932663385700138
+aF2.8463172759176762
+aF-41.480817393903472
+aF-0.68495314097315418
+aF21.208653848364019
+aF19.876255515102429
+aF998.12874980374295
+aF1.3961086816912429
+aF23.821668920901342
+aF21.441174552653806
+aF-44.665288201485076
+aF12.633140606795406
+aF988.38432905112916
+aF18.71811669630037
+aF24.913145241742193
+aF4.8273734459764572
+aF-21.359128252832029
+aF1065.3762097654769
+aF24.918183253589213
+aF-27.897058417766164
+aF12.561904979061016
+aF1089.7539174243775
+aF14.699878990740451
+aF5.0699757690162865
+aF-55.839834801834542
+aF984.98626773133446
+aF892.9497079083751
+aF-22.650241838469928
+aF-12.441283303937622
+aF881.06274521697583
+aF-9.399730594999296
+aF31.227087359930721
+aF2.4612959698168853
+aF1053.8605901273861
+aF-6.0066185359336677
+aF11.865775216869102
+aF40.152389574564538
+aF869.1604587083126
+aF959.64234290126842
+aF44.706151674854247
+aF3.4962543700800031
+aF986.8188443638802
+aF-10.502807678052365
+aF-6.1711187034702828
+aF-20.63589248183213
+aF7.8996595892496178
+aF1036.4526079439877
+aF-37.585419309157089
+aF1.8542119127221615
+aF11.17639906818914
+aF-13.310845893051535
+aF49.80080106133682
+aF22.217313576784736
+aF-5.1966403433892667
+aF1029.3305958673775
+aF26.108870350830433
+aF-2.2237912026804105
+aF22.044642806617869
+aF996.90680772704093
+aF-0.61622767913287646
+aF-14.016484663587772
+aF954.02738078624384
+aF28.518877124687648
+aF-0.52675077970567385
+aF989.09821783581117
+aF-9.6785742503752914
+aF-15.566186467510502
+aF-4.1923485158047118
+aF0.47988670677906098
+aF20.338575090204959
+aF995.46484752607512
+aF3.2491500593837461
+aF-14.090077037761237
+aF890.6364469937937
+aF20.468092222026829
+aF26.222243827677108
+aF952.93565485434056
+aF-14.247537927605798
+aF12.031538779218243
+aF1075.0278864196378
+aF-9.0683180187256625
+aF-1.3173814606159042
+aF20.351359463761465
+aF-5.7249534947634393
+aF20.95643328024418
+aF1078.3569908140601
+aF29.153198423325712
+aF44.631955652940036
+aF17.672876412345737
+aF7.9498981094329411
+aF-37.993369063165886
+aF973.76818102942673
+aF24.093330458313645
+aF-21.383690393991195
+aF942.32575201335362
+aF43.917484208170215
+aF1041.4431633288777
+aF17.528531982715048
+aF1097.1674463245085
+aF6.1199204015642081
+aF-39.180665949999771
+aF38.463774914761672
+aF-9.2703971202383144
+aF985.15913015727836
+aF2.9683966801746893
+aF5.2893991353821059
+aF-2.5889710667866952
+aF31.124961594345585
+aF930.66965419763653
+aF-9.7478464098365709
+aF17.546913210897511
+aF880.63523601875465
+aF-1.3146259309146979
+aF12.689126566426291
+aF994.38622297713937
+aF-7.8134192093558745
+aF-9.3952889452393329
+aF26.651688979252885
+aF13.453806672476007
+aF928.41139317250713
+aF-31.988649613129311
+aF991.57609530813193
+aF2.5393815526079515
+aF-16.972908002764807
+aF1.4846009214004348
+aF-26.042299178951076
+aF945.54557673218176
+aF19.488128200930728
+aF-1.849008087892962
+aF5.51190192752148
+aF-11.515577789711328
+aF-9.5639555992494927
+aF1094.9177538581603
+aF8.1024844191992873
+aF-25.855057493164132
+aF-3.229587151702018
+aF-1.0377722247306955
+aF1033.8433841240162
+aF2.890273219319742
+aF-39.000392988349212
+aF58.316975034515771
+aF1027.122258371923
+aF17.752403838655663
+aF9.8199946666143685
+aF1053.4288870389064
+aF-5.40502329884493
+aF21.007796646011563
+aF2.150905627670832
+aF969.2460169792904
+aF56.045494254328204
+aF1037.746950512076
+aF0.24332250043871628
+aF8.4542032980737787
+aF-15.852582989449385
+aF-31.093548106104357
+aF845.25214591528243
+aF18.822705535329607
+aF1037.6688377619087
+aF14.099455252562741
+aF-11.92605334630179
+aF-10.56113567926128
+aF874.50805199618765
+aF1.196678136954834
+aF0.70470221711887693
+aF-0.20806098944469181
+aF1095.2559846523645
+aF860.78536001686632
+aF-12.797069836169143
+aF-6.2274215684928294
+aF985.36032569452755
+aF1018.5176809725897
+aF14.258103397746838
+aF1142.8546968002693
+aF24.576361342147866
+aF1027.9333668285065
+aF23.37255889290406
+aF36.716482522820854
+aF914.07006274048194
+aF1069.982698286032
+aF-24.58754150894681
+aF-35.167338791626172
+aF4.8587288213400228
+aF1074.8431308260019
+aF20.751120169182563
+aF1056.7832693106482
+aF-9.8124652020303191
+aF1036.0045977289219
+aF17.905178428610338
+aF-13.048210549286546
+aF884.72968635915527
+aF15.399121995606359
+aF35.895017097770577
+aF-23.341495476676403
+aF963.65890337824419
+aF22.484448482758129
+aF10.904932456284781
+aF1001.8703297958077
+aF-43.221184817162396
+aF3.8710014167748614
+aF34.457107600168627
+aF1020.9619479343471
+aF-23.129131179532354
+aF1058.5907629595138
+aF-13.3685670710124
+aF-16.845929132808557
+aF-12.161931765514332
+aF1031.6664400398736
+aF7.220741488892048
+aF-17.933143005178746
+aF941.05724984507799
+aF-14.874306018602075
+aF-14.591792091451611
+aF1045.2438710868398
+aF0.27301241405562382
+aF26.333662896490534
+aF5.7101051104655438
+aF7.9745010847051745
+aF973.48560626466599
+aF-7.2155368654098302
+aF980.93130564350122
+aF3.3226128119453353
+aF-26.134141028751909
+aF-6.88979382182242
+aF-21.570137984224818
+aF949.18843783724299
+aF2.9123065753508346
+aF946.2190659424208
+aF5.0246998616493821
+aF1060.2297489473428
+aF2.2579504344955397
+aF36.431019185289209
+aF39.163261277266919
+aF0.29119685754385904
+aF1130.4653674161852
+aF41.263367726066292
+aF961.92303817120467
+aF4.2441858477579597
+aF-21.721232874125565
+aF962.81486162665954
+aF33.090755972740929
+aF-9.419895650959198
+aF1072.3701007222294
+aF-7.5446176173667325
+aF24.367840463798203
+aF-7.9482872551822537
+aF-30.078032175900017
+aF1058.590797698771
+aF22.219462604678778
+aF-3.1221810681913449
+aF1030.2954465560813
+aF973.44287898903872
+aF19.070422894893159
+aF-20.602423395747593
+aF1052.6446075369067
+aF-24.972376245461938
+aF15.86630462956346
+aF8.4119910789460643
+aF-5.8166121590676125
+aF992.34080681946023
+aF-48.026914381512078
+aF1102.50042272269
+aF-40.974133403946382
+aF-24.778237077313729
+aF1119.3619835852157
+aF1001.8715736102101
+aF-22.424055041406888
+aF1100.3127279430839
+aF9.8551286851660649
+aF1.5542250669072661
+aF-1.6387055046079277
+aF0.058188311049613639
+aF-5.7970879163450055
+aF926.53484785132218
+aF10.937116140506209
+aF961.80175491873672
+aF4.0987684089706811
+aF943.83622286389163
+aF18.72811324906888
+aF-23.334282235668393
+aF919.90348509748162
+aF-11.824265890167711
+aF-16.024023045230184
+aF-6.8172077271259317
+aF42.581953551651942
+aF868.04659905310757
+aF8.8222034549754849
+aF-14.802741048883513
+aF1048.8008769723617
+aF11.866490457418777
+aF962.30668386268746
+aF-10.798600875780245
+aF0.049648873582764486
+aF1164.6723608986147
+aF948.08224712533661
+aF-21.861378589742827
+aF1022.5393005597326
+aF27.391385725380363
+aF34.987962527246275
+aF947.60052859086602
+aF12.20367669050575
+aF10.134490427507579
+aF1080.3929607252189
+aF30.369547551456343
+aF-31.042478397057547
+aF890.06171429438177
+aF-8.528837594248964
+aF0.49299278460067036
+aF-15.025645146000203
+aF-5.2267993584695596
+aF894.26347001313684
+aF20.892000568179263
+aF992.57451357195839
+aF-4.6347168639342042
+aF1078.3450181206704
+aF1012.5901973092599
+aF-23.794667180651647
+aF-7.6153326612137331
+aF8.4029780733473416
+aF-17.396674871072385
+aF34.063227713663309
+aF1040.6216780137013
+aF12.92394217124675
+aF1.1176512938483714
+aF997.57531107561965
+aF10.956467531790262
+aF1012.6047576585988
+aF-14.115861508554012
+aF1079.2460363014945
+aF1.8388919522855594
+aF984.25058468817645
+aF35.284751721373318
+aF1154.2438296290475
+aF32.292059665412793
+aF-12.51204320110017
+aF1048.4143436956451
+aF41.525824654444548
+aF15.816075416153463
+aF1038.3599067838497
+aF-37.189056192851531
+aF7.9524081361040162
+aF1005.8286010408865
+aF-24.021984764595079
+aF3.0284471123144368
+aF982.31115518576803
+aF-20.223385367054817
+aF986.62025061368115
+aF-35.363607813007349
+aF1043.4879215084611
+aF-11.001392841554651
+aF937.99393396710968
+aF13.102924948310127
+aF23.996638111433885
+aF-11.453656280105179
+aF9.612866110733675
+aF1053.8512892805804
+aF-38.569530052983552
+aF-2.8506035976923503
+aF51.167696065134137
+aF-15.262377715627675
+aF1024.0504723597667
+aF-9.7126020168417355
+aF7.5396868035090678
+aF19.757287237002707
+aF969.10047352986612
+aF-22.519440649244434
+aF1008.639534783092
+aF-13.656048137721186
+aF17.52161899914616
+aF1012.6602643199868
+aF14.170828278223663
+aF1067.6727006394742
+aF-55.08763015568703
+aF5.7816666740873996
+aF7.7956599752965126
+aF1028.116423646366
+aF1016.6730692943916
+aF1035.5641382640888
+aF1031.5770300131906
+aF902.9755036007233
+aF-1.6266503890861388
+aF34.828424513659414
+aF-5.1322544201335329
+aF22.298025788808712
+aF944.90613724033199
+aF1083.066953429895
+aF-37.145935482450305
+aF914.83968021758108
+aF13.450714635283198
+aF1085.150628757217
+aF1064.6913348870519
+aF1.4845313668293347
+aF28.699482151607306
+aF962.77695606781299
+aF21.606881063496761
+aF31.900194025609075
+aF968.3873931216566
+aF-14.581533717781955
+aF990.63754331208384
+aF949.32033881652762
+aF-10.164453921095163
+aF927.78881334431424
+aF-34.879023681702066
+aF-42.411340964874896
+aF1015.0254286716503
+aF-17.51391259196031
+aF-1.192211149272236
+aF910.60996636908112
+aF-41.119147920753122
+aF997.94539888372083
+aF5.2030150807425128
+aF-12.364252341458542
+aF1057.8320736368826
+aF-11.385501356635903
+aF-3.4371146477551435
+aF-26.183440640331504
+aF-11.207579747827953
+aF964.85387844413162
+aF-15.750916769393649
+aF12.86135575095007
+aF987.99364283168984
+aF-9.1887750696343726
+aF-68.361901712757955
+aF1000.5306627855193
+aF961.16810507729178
+aF1015.8794408458266
+aF-48.165554189084503
+aF1004.5613771108118
+aF30.245288304632414
+aF-11.848015635387574
+aF1131.7841986312073
+aF950.6151615140991
+aF-39.187096352484502
+aF919.85797568755595
+aF-16.370606082533385
+aF-11.023760543202551
+aF930.31457724392965
+aF-20.223865960920197
+aF998.72932245736808
+aF-23.643069651849167
+aF-52.032647345224525
+aF-18.621798467787276
+aF864.24780043477608
+aF40.648586362092338
+aF12.485635719738591
+aF952.23439650522516
+aF-7.371859311419855
+aF995.18363948349895
+aF-13.254059968734097
+aF14.337265201938701
+aF-3.3261839967506139
+aF16.211839828317693
+aF1074.139174661495
+aF-10.087982425771164
+aF904.48930096073479
+aF9.0842068994247516
+aF-0.4220891199209208
+aF946.92140709184116
+aF-27.378548896563728
+aF3.814940602605347
+aF5.3956601271397435
+aF940.23063254604722
+aF-15.922400477895781
+aF6.274879494548907
+aF974.41202259981242
+aF14.363341858558419
+aF-23.51470777818486
+aF-22.367266066999168
+aF951.53245999452179
+aF1056.8821961344183
+aF974.2797783339729
+aF5.0956087710680453
+aF973.1342393195049
+aF-0.48487549782106809
+aF5.3911196018824006
+aF35.40333353489487
+aF1011.7838219109634
+aF-21.303413004827721
+aF939.32748124646128
+aF9.5240512336702583
+aF0.36220236398636069
+aF1050.4081052988722
+aF42.507341543793771
+aF1055.8226636867626
+aF-15.315517028556171
+aF-16.967342302016135
+aF-6.5409236400023083
+aF-28.404566524894278
+aF41.336057845888099
+aF909.51985771002228
+aF-20.464344284853819
+aF7.5154546862177085
+aF929.47379834671563
+aF966.89872590184143
+aF1043.8363313205539
+aF967.74388162008802
+aF943.55151897067867
+aF1013.35891218988
+aF-48.289777667663273
+aF1013.4766696460173
+aF-8.3019251704998034
+aF933.02130189564059
+aF979.82454256921528
+aF10.826500158875172
+aF22.23609977106408
+aF-9.9065238589767102
+aF895.42629386976046
+aF1033.7650085054131
+aF-26.419340364393445
+aF-2.8419668453944009
+aF1045.3304269590642
+aF1037.5565575658654
+aF26.958064399787073
+aF917.55386570862493
+aF-1.9728745470291336
+aF1069.0994429015495
+aF-28.893692649280052
+aF-22.473997814268785
+aF1026.9972040539328
+aF6.2716951855902057
+aF1013.7031728491301
+aF-19.135459133406375
+aF-13.405773291252935
+aF1024.747144283941
+aF31.239715856179213
+aF-2.2878756503907827
+aF1063.5916560044479
+aF994.00118061524631
+aF1085.0476371930081
+aF1018.9346955919999
+aF981.02630476923832
+aF-12.315961623885986
+aF1033.3195592051256
+aF-19.884832176672305
+aF1086.3422997247997
+aF1089.948013267651
+aF-13.820654131725412
+aF1010.0176711914314
+aF1134.0133980707567
+aF-48.292789736819884
+aF1039.5433667005323
+aF-6.0658259213090426
+aF35.599445050683187
+aF893.95788310940941
+aF912.97805803559447
+aF27.184908324890884
+aF1024.9079250586999
+aF1.472525225721192
+aF1005.4274975899647
+aF17.484545693171139
+aF925.78394689545382
+aF-34.416632014764573
+aF965.53055305106489
+aF914.19651933299031
+aF28.735865458125126
+aF1031.8596967361379
+aF25.813138890047036
+aF24.563692965820579
+aF1055.1906070264945
+aF1086.5947819427661
+aF13.468114187807418
+aF-12.813392736986273
+aF1056.1012294652878
+aF-26.752094420026225
+aF1027.9653495103669
+aF7.5200870390244505
+aF1022.887871087179
+aF984.73350227425601
+aF3.2119742965560669
+aF978.67299769512749
+aF-33.196767950035316
+aF1014.1868246033498
+aF1057.2764997292174
+aF-15.216392866795037
+aF998.6369174062296
+aF954.90106260473101
+aF1078.9809922782297
+aF991.60916989484087
+aF980.139645841723
+aF1020.2784569576114
+aF-5.7754331748898489
+aF2.0404211376002506
+aF-8.2752009625003176
+aF934.21201651093918
+aF1019.147716604636
+aF1034.7989964933827
+aF1.1638870936243366
+aF-23.449642607352398
+aF1092.635886078124
+aF1005.0625569318283
+aF1083.803931047164
+aF984.36707052852069
+aF1057.3355470860913
+aF929.76356924498668
+aF21.396148357435539
+aF1052.943770437791
+aF1043.3610400096018
+aF1019.5749436920019
+aF959.5331478112048
+aF930.41539085051556
+aF1032.6286330130063
+aF4.9165441773389817
+aF1024.1518881303691
+aF1107.6072629997207
+aF971.39933430058716
+aF1007.6514067614387
+aF22.692355989800468
+aF1097.1836298545143
+aF1008.1598110487311
+aF1005.1692930610582
+aF1038.5089238765574
+aF949.68407053315957
+aF1043.2951673187827
+aF1004.8650127406853
+aF24.578040280957357
+aF977.34335829467489
+aF5.1942821518718931
+aF936.90665990233072
+aF-32.9237508225727
+aF951.24434240502751
+aF12.976620825879872
+aF1019.9827337001312
+aF1.2256141352438643
+aF1001.6049118767753
+aF971.0729403287537
+aF957.72738871108663
+aF975.52626578186107
+aF998.89766790206545
+aF973.56130719300143
+aF952.69278806347302
+aF949.7715416137188
+aF974.28989659037643
+aF898.4280248875865
+aF949.09480919694738
+aF1022.6988429363347
+aF948.35892041370619
+aF973.04990543830502
+aF-0.28996713733898249
+aF977.07780990786443
+aF5.1628957467225183
+aF-16.201618129462801
+aF1011.9107287308251
+aF1026.9203268242227
+aF918.24347258308478
+aF1217.0982332180433
+aF1011.7445525360112
+aF961.72715842890295
+aF925.73220480416978
+aF1001.7653601153918
+aF950.75346555742806
+aF1039.0521363974576
+aF960.7958892640188
+aF1084.7239842867043
+a(I1741
+I1
+tp3
+S'd'
+p4
+tp5
+Rp6
+g1
+((lp7
+I0
+aI22
+aI47
+aI120
+aI255
+aI348
+aI357
+aI485
+aI1
+aI34
+aI39
+aI83
+aI2
+aI329
+aI360
+aI395
+aI3
+aI8
+aI23
+aI59
+aI257
+aI338
+aI412
+aI4
+aI88
+aI227
+aI244
+aI310
+aI341
+aI365
+aI432
+aI463
+aI469
+aI5
+aI389
+aI398
+aI399
+aI491
+aI6
+aI7
+aI126
+aI346
+aI347
+aI363
+aI439
+aI7
+aI107
+aI257
+aI296
+aI322
+aI8
+aI11
+aI20
+aI23
+aI158
+aI187
+aI215
+aI317
+aI352
+aI464
+aI489
+aI9
+aI488
+aI10
+aI48
+aI119
+aI145
+aI343
+aI347
+aI357
+aI422
+aI11
+aI97
+aI196
+aI314
+aI380
+aI458
+aI465
+aI12
+aI40
+aI239
+aI261
+aI274
+aI13
+aI100
+aI191
+aI14
+aI78
+aI92
+aI124
+aI143
+aI197
+aI226
+aI234
+aI241
+aI282
+aI479
+aI492
+aI15
+aI217
+aI436
+aI16
+aI55
+aI87
+aI344
+aI428
+aI479
+aI17
+aI266
+aI355
+aI429
+aI18
+aI289
+aI294
+aI296
+aI424
+aI19
+aI28
+aI110
+aI256
+aI381
+aI396
+aI20
+aI103
+aI166
+aI349
+aI425
+aI445
+aI21
+aI24
+aI77
+aI321
+aI395
+aI399
+aI22
+aI42
+aI181
+aI193
+aI245
+aI311
+aI369
+aI415
+aI468
+aI489
+aI23
+aI32
+aI134
+aI333
+aI350
+aI465
+aI24
+aI190
+aI343
+aI399
+aI25
+aI240
+aI298
+aI336
+aI26
+aI87
+aI199
+aI202
+aI236
+aI246
+aI316
+aI27
+aI47
+aI122
+aI174
+aI235
+aI262
+aI344
+aI440
+aI28
+aI137
+aI476
+aI29
+aI45
+aI387
+aI477
+aI487
+aI30
+aI44
+aI31
+aI124
+aI190
+aI274
+aI299
+aI399
+aI32
+aI451
+aI494
+aI33
+aI108
+aI224
+aI346
+aI366
+aI415
+aI460
+aI486
+aI34
+aI43
+aI121
+aI122
+aI336
+aI427
+aI35
+aI143
+aI160
+aI165
+aI207
+aI225
+aI296
+aI488
+aI36
+aI202
+aI37
+aI202
+aI388
+aI414
+aI38
+aI49
+aI276
+aI399
+aI39
+aI57
+aI110
+aI142
+aI162
+aI182
+aI442
+aI40
+aI50
+aI94
+aI201
+aI399
+aI407
+aI41
+aI68
+aI122
+aI188
+aI215
+aI42
+aI61
+aI152
+aI171
+aI386
+aI466
+aI499
+aI43
+aI59
+aI72
+aI302
+aI44
+aI116
+aI121
+aI131
+aI132
+aI169
+aI307
+aI366
+aI478
+aI484
+aI45
+aI327
+aI390
+aI46
+aI66
+aI259
+aI296
+aI344
+aI370
+aI413
+aI47
+aI282
+aI296
+aI339
+aI374
+aI440
+aI48
+aI78
+aI113
+aI186
+aI216
+aI400
+aI407
+aI489
+aI492
+aI49
+aI395
+aI470
+aI492
+aI50
+aI75
+aI144
+aI196
+aI217
+aI239
+aI276
+aI496
+aI51
+aI174
+aI252
+aI258
+aI411
+aI52
+aI53
+aI151
+aI154
+aI53
+aI102
+aI177
+aI274
+aI423
+aI54
+aI66
+aI107
+aI155
+aI250
+aI314
+aI335
+aI55
+aI344
+aI421
+aI461
+aI56
+aI65
+aI271
+aI279
+aI362
+aI406
+aI478
+aI57
+aI125
+aI403
+aI406
+aI58
+aI274
+aI375
+aI59
+aI183
+aI316
+aI415
+aI442
+aI459
+aI463
+aI60
+aI315
+aI450
+aI61
+aI160
+aI176
+aI193
+aI196
+aI303
+aI378
+aI385
+aI400
+aI430
+aI435
+aI465
+aI495
+aI62
+aI142
+aI196
+aI228
+aI264
+aI274
+aI471
+aI63
+aI276
+aI319
+aI378
+aI64
+aI92
+aI108
+aI152
+aI159
+aI254
+aI267
+aI277
+aI308
+aI439
+aI446
+aI65
+aI212
+aI313
+aI344
+aI389
+aI432
+aI66
+aI153
+aI372
+aI399
+aI420
+aI440
+aI67
+aI130
+aI355
+aI68
+aI250
+aI282
+aI306
+aI414
+aI69
+aI132
+aI301
+aI340
+aI70
+aI73
+aI151
+aI434
+aI497
+aI71
+aI156
+aI269
+aI319
+aI352
+aI443
+aI494
+aI72
+aI221
+aI295
+aI73
+aI226
+aI299
+aI302
+aI307
+aI376
+aI396
+aI427
+aI477
+aI74
+aI119
+aI476
+aI75
+aI261
+aI285
+aI338
+aI346
+aI456
+aI76
+aI123
+aI154
+aI239
+aI276
+aI281
+aI487
+aI494
+aI77
+aI114
+aI147
+aI407
+aI78
+aI390
+aI79
+aI287
+aI346
+aI378
+aI447
+aI495
+aI80
+aI85
+aI216
+aI218
+aI256
+aI81
+aI247
+aI445
+aI474
+aI82
+aI370
+aI430
+aI453
+aI83
+aI289
+aI331
+aI361
+aI378
+aI84
+aI288
+aI352
+aI85
+aI282
+aI367
+aI450
+aI86
+aI110
+aI135
+aI160
+aI376
+aI383
+aI489
+aI493
+aI87
+aI212
+aI313
+aI416
+aI425
+aI481
+aI88
+aI154
+aI207
+aI352
+aI485
+aI89
+aI180
+aI339
+aI457
+aI90
+aI152
+aI173
+aI182
+aI273
+aI295
+aI364
+aI373
+aI387
+aI474
+aI91
+aI134
+aI164
+aI92
+aI129
+aI220
+aI221
+aI242
+aI287
+aI431
+aI93
+aI155
+aI306
+aI310
+aI350
+aI376
+aI498
+aI94
+aI475
+aI95
+aI118
+aI133
+aI165
+aI203
+aI360
+aI414
+aI96
+aI181
+aI97
+aI205
+aI290
+aI98
+aI112
+aI139
+aI188
+aI294
+aI301
+aI379
+aI486
+aI99
+aI149
+aI376
+aI397
+aI100
+aI298
+aI389
+aI402
+aI101
+aI420
+aI102
+aI164
+aI360
+aI103
+aI156
+aI368
+aI473
+aI104
+aI107
+aI116
+aI263
+aI326
+aI477
+aI105
+aI270
+aI493
+aI106
+aI174
+aI107
+aI110
+aI124
+aI304
+aI369
+aI108
+aI210
+aI283
+aI314
+aI322
+aI109
+aI163
+aI288
+aI405
+aI480
+aI110
+aI139
+aI176
+aI212
+aI369
+aI111
+aI134
+aI230
+aI239
+aI305
+aI309
+aI459
+aI112
+aI155
+aI309
+aI383
+aI443
+aI113
+aI160
+aI114
+aI176
+aI189
+aI393
+aI423
+aI115
+aI204
+aI205
+aI208
+aI336
+aI116
+aI298
+aI357
+aI395
+aI117
+aI137
+aI484
+aI118
+aI122
+aI141
+aI161
+aI280
+aI433
+aI119
+aI177
+aI230
+aI315
+aI343
+aI498
+aI120
+aI136
+aI242
+aI484
+aI121
+aI151
+aI290
+aI122
+aI151
+aI397
+aI482
+aI123
+aI127
+aI318
+aI353
+aI379
+aI458
+aI124
+aI458
+aI125
+aI281
+aI301
+aI314
+aI386
+aI434
+aI479
+aI126
+aI216
+aI238
+aI284
+aI298
+aI301
+aI326
+aI372
+aI381
+aI496
+aI127
+aI128
+aI219
+aI231
+aI464
+aI129
+aI274
+aI349
+aI130
+aI327
+aI466
+aI131
+aI141
+aI162
+aI215
+aI341
+aI462
+aI132
+aI202
+aI243
+aI256
+aI326
+aI339
+aI133
+aI327
+aI419
+aI425
+aI134
+aI280
+aI296
+aI358
+aI477
+aI135
+aI147
+aI324
+aI136
+aI172
+aI197
+aI262
+aI289
+aI352
+aI433
+aI137
+aI176
+aI245
+aI412
+aI413
+aI138
+aI286
+aI490
+aI139
+aI274
+aI301
+aI312
+aI370
+aI380
+aI416
+aI140
+aI285
+aI395
+aI420
+aI467
+aI141
+aI253
+aI271
+aI374
+aI142
+aI177
+aI199
+aI338
+aI143
+aI144
+aI215
+aI268
+aI314
+aI352
+aI491
+aI144
+aI240
+aI259
+aI145
+aI187
+aI354
+aI439
+aI146
+aI262
+aI409
+aI147
+aI188
+aI434
+aI148
+aI375
+aI404
+aI411
+aI443
+aI149
+aI198
+aI284
+aI494
+aI150
+aI274
+aI151
+aI227
+aI322
+aI354
+aI152
+aI329
+aI470
+aI473
+aI153
+aI491
+aI154
+aI173
+aI263
+aI276
+aI396
+aI455
+aI155
+aI295
+aI371
+aI156
+aI255
+aI310
+aI448
+aI477
+aI157
+aI274
+aI301
+aI413
+aI423
+aI444
+aI457
+aI158
+aI370
+aI159
+aI188
+aI228
+aI277
+aI339
+aI160
+aI220
+aI283
+aI310
+aI161
+aI276
+aI299
+aI444
+aI162
+aI213
+aI244
+aI305
+aI347
+aI163
+aI355
+aI464
+aI164
+aI165
+aI210
+aI218
+aI357
+aI456
+aI165
+aI228
+aI324
+aI326
+aI328
+aI414
+aI166
+aI188
+aI216
+aI265
+aI409
+aI422
+aI167
+aI210
+aI211
+aI253
+aI349
+aI352
+aI368
+aI444
+aI168
+aI172
+aI439
+aI479
+aI169
+aI491
+aI170
+aI283
+aI329
+aI394
+aI417
+aI465
+aI171
+aI228
+aI376
+aI172
+aI255
+aI277
+aI302
+aI173
+aI203
+aI243
+aI290
+aI472
+aI174
+aI236
+aI319
+aI324
+aI367
+aI423
+aI435
+aI496
+aI175
+aI176
+aI177
+aI268
+aI318
+aI329
+aI337
+aI178
+aI319
+aI386
+aI179
+aI200
+aI241
+aI481
+aI485
+aI180
+aI244
+aI291
+aI315
+aI448
+aI181
+aI212
+aI375
+aI182
+aI183
+aI204
+aI288
+aI303
+aI386
+aI416
+aI464
+aI469
+aI184
+aI478
+aI185
+aI321
+aI186
+aI271
+aI368
+aI386
+aI396
+aI187
+aI429
+aI188
+aI231
+aI292
+aI416
+aI189
+aI281
+aI454
+aI486
+aI190
+aI202
+aI343
+aI191
+aI205
+aI446
+aI471
+aI474
+aI484
+aI192
+aI469
+aI193
+aI239
+aI284
+aI334
+aI387
+aI194
+aI265
+aI438
+aI195
+aI435
+aI196
+aI337
+aI442
+aI197
+aI381
+aI450
+aI198
+aI210
+aI407
+aI421
+aI427
+aI443
+aI199
+aI200
+aI201
+aI211
+aI220
+aI230
+aI201
+aI244
+aI310
+aI361
+aI478
+aI202
+aI220
+aI203
+aI244
+aI370
+aI441
+aI468
+aI471
+aI204
+aI207
+aI383
+aI205
+aI206
+aI304
+aI453
+aI486
+aI207
+aI228
+aI269
+aI208
+aI296
+aI421
+aI209
+aI228
+aI286
+aI380
+aI210
+aI317
+aI370
+aI211
+aI243
+aI251
+aI289
+aI339
+aI361
+aI415
+aI212
+aI213
+aI214
+aI348
+aI498
+aI215
+aI328
+aI352
+aI357
+aI421
+aI216
+aI232
+aI240
+aI488
+aI217
+aI381
+aI218
+aI228
+aI274
+aI219
+aI345
+aI372
+aI490
+aI220
+aI221
+aI222
+aI249
+aI266
+aI331
+aI364
+aI474
+aI479
+aI223
+aI239
+aI312
+aI315
+aI369
+aI224
+aI225
+aI308
+aI313
+aI347
+aI403
+aI421
+aI469
+aI226
+aI267
+aI294
+aI227
+aI341
+aI379
+aI228
+aI235
+aI237
+aI360
+aI413
+aI475
+aI494
+aI229
+aI257
+aI277
+aI291
+aI361
+aI389
+aI455
+aI477
+aI230
+aI311
+aI355
+aI376
+aI380
+aI471
+aI231
+aI358
+aI453
+aI471
+aI478
+aI232
+aI261
+aI467
+aI496
+aI233
+aI308
+aI392
+aI428
+aI234
+aI235
+aI388
+aI463
+aI236
+aI331
+aI468
+aI471
+aI237
+aI257
+aI271
+aI317
+aI238
+aI239
+aI300
+aI374
+aI240
+aI328
+aI330
+aI395
+aI423
+aI241
+aI256
+aI264
+aI266
+aI353
+aI358
+aI393
+aI488
+aI242
+aI244
+aI251
+aI423
+aI243
+aI351
+aI459
+aI244
+aI264
+aI468
+aI245
+aI327
+aI341
+aI372
+aI376
+aI379
+aI246
+aI276
+aI287
+aI247
+aI329
+aI493
+aI248
+aI313
+aI442
+aI249
+aI269
+aI294
+aI325
+aI326
+aI370
+aI250
+aI258
+aI264
+aI320
+aI403
+aI460
+aI251
+aI390
+aI486
+aI252
+aI451
+aI253
+aI390
+aI254
+aI293
+aI339
+aI357
+aI491
+aI255
+aI402
+aI423
+aI466
+aI489
+aI256
+aI330
+aI392
+aI257
+aI304
+aI324
+aI258
+aI320
+aI438
+aI464
+aI488
+aI259
+aI409
+aI260
+aI302
+aI388
+aI407
+aI421
+aI261
+aI394
+aI400
+aI424
+aI455
+aI479
+aI262
+aI285
+aI330
+aI402
+aI452
+aI263
+aI347
+aI441
+aI498
+aI264
+aI443
+aI458
+aI265
+aI342
+aI488
+aI490
+aI266
+aI280
+aI267
+aI274
+aI321
+aI357
+aI460
+aI268
+aI372
+aI269
+aI320
+aI356
+aI378
+aI270
+aI421
+aI453
+aI492
+aI271
+aI272
+aI314
+aI397
+aI273
+aI274
+aI317
+aI275
+aI356
+aI276
+aI400
+aI469
+aI277
+aI278
+aI287
+aI409
+aI483
+aI279
+aI409
+aI280
+aI405
+aI281
+aI390
+aI447
+aI282
+aI303
+aI379
+aI484
+aI283
+aI303
+aI427
+aI284
+aI335
+aI372
+aI444
+aI285
+aI455
+aI286
+aI322
+aI400
+aI450
+aI287
+aI361
+aI391
+aI288
+aI292
+aI373
+aI289
+aI349
+aI357
+aI368
+aI450
+aI290
+aI374
+aI291
+aI351
+aI388
+aI479
+aI480
+aI292
+aI382
+aI293
+aI353
+aI294
+aI295
+aI420
+aI469
+aI493
+aI295
+aI359
+aI296
+aI313
+aI490
+aI297
+aI315
+aI397
+aI298
+aI410
+aI426
+aI429
+aI437
+aI299
+aI424
+aI439
+aI300
+aI301
+aI321
+aI385
+aI302
+aI363
+aI373
+aI471
+aI496
+aI303
+aI388
+aI304
+aI336
+aI443
+aI305
+aI306
+aI405
+aI307
+aI309
+aI381
+aI407
+aI446
+aI494
+aI308
+aI441
+aI309
+aI498
+aI310
+aI322
+aI379
+aI311
+aI330
+aI333
+aI398
+aI496
+aI312
+aI469
+aI474
+aI313
+aI349
+aI314
+aI349
+aI410
+aI315
+aI316
+aI492
+aI317
+aI344
+aI476
+aI318
+aI467
+aI481
+aI319
+aI377
+aI448
+aI320
+aI382
+aI447
+aI449
+aI480
+aI321
+aI465
+aI322
+aI405
+aI323
+aI324
+aI336
+aI345
+aI404
+aI405
+aI428
+aI325
+aI332
+aI417
+aI326
+aI334
+aI327
+aI434
+aI328
+aI399
+aI329
+aI330
+aI330
+aI368
+aI409
+aI331
+aI458
+aI467
+aI332
+aI364
+aI478
+aI333
+aI369
+aI489
+aI334
+aI494
+aI335
+aI464
+aI336
+aI393
+aI337
+aI368
+aI441
+aI461
+aI481
+aI338
+aI398
+aI406
+aI459
+aI465
+aI339
+aI355
+aI385
+aI434
+aI340
+aI457
+aI341
+aI361
+aI478
+aI342
+aI453
+aI343
+aI407
+aI449
+aI495
+aI344
+aI345
+aI346
+aI347
+aI348
+aI351
+aI364
+aI471
+aI485
+aI349
+aI350
+aI359
+aI351
+aI449
+aI352
+aI353
+aI358
+aI370
+aI354
+aI395
+aI489
+aI355
+aI382
+aI356
+aI357
+aI360
+aI358
+aI424
+aI472
+aI359
+aI375
+aI399
+aI360
+aI412
+aI361
+aI384
+aI439
+aI362
+aI434
+aI441
+aI458
+aI469
+aI363
+aI374
+aI421
+aI364
+aI432
+aI462
+aI365
+aI366
+aI367
+aI487
+aI368
+aI415
+aI434
+aI369
+aI370
+aI422
+aI371
+aI399
+aI475
+aI372
+aI487
+aI373
+aI432
+aI444
+aI493
+aI374
+aI383
+aI413
+aI375
+aI396
+aI376
+aI418
+aI432
+aI449
+aI451
+aI377
+aI381
+aI378
+aI380
+aI478
+aI379
+aI402
+aI417
+aI418
+aI380
+aI441
+aI458
+aI381
+aI384
+aI410
+aI464
+aI382
+aI383
+aI384
+aI445
+aI385
+aI388
+aI406
+aI430
+aI386
+aI460
+aI387
+aI463
+aI496
+aI388
+aI392
+aI389
+aI414
+aI415
+aI421
+aI448
+aI496
+aI390
+aI413
+aI438
+aI391
+aI392
+aI393
+aI394
+aI395
+aI396
+aI461
+aI397
+aI417
+aI398
+aI399
+aI442
+aI467
+aI485
+aI400
+aI401
+aI417
+aI479
+aI402
+aI403
+aI444
+aI404
+aI468
+aI405
+aI430
+aI471
+aI406
+aI414
+aI407
+aI469
+aI483
+aI408
+aI423
+aI496
+aI409
+aI410
+aI411
+aI412
+aI413
+aI442
+aI414
+aI424
+aI415
+aI416
+aI424
+aI417
+aI418
+aI430
+aI419
+aI464
+aI478
+aI420
+aI421
+aI480
+aI422
+aI472
+aI423
+aI437
+aI424
+aI492
+aI425
+aI426
+aI457
+aI427
+aI476
+aI484
+aI428
+aI429
+aI446
+aI488
+aI430
+aI474
+aI431
+aI496
+aI432
+aI433
+aI466
+aI434
+aI460
+aI435
+aI436
+aI461
+aI437
+aI438
+aI439
+aI440
+aI441
+aI442
+aI465
+aI466
+aI491
+aI443
+aI444
+aI445
+aI449
+aI451
+aI446
+aI447
+aI448
+aI449
+aI450
+aI451
+aI497
+aI452
+aI453
+aI454
+aI455
+aI456
+aI457
+aI470
+aI458
+aI459
+aI460
+aI461
+aI486
+aI462
+aI463
+aI464
+aI465
+aI466
+aI467
+aI468
+aI489
+aI469
+aI475
+aI470
+aI486
+aI471
+aI478
+aI472
+aI477
+aI473
+aI474
+aI475
+aI476
+aI477
+aI478
+aI479
+aI480
+aI481
+aI482
+aI483
+aI484
+aI485
+aI486
+aI493
+aI487
+aI488
+aI497
+aI488
+aI489
+aI490
+aI491
+aI492
+aI493
+aI494
+aI495
+aI496
+aI497
+aI498
+aI499
+a(I1741
+I1
+tp8
+S'i'
+p9
+tp10
+Rp11
+g1
+((lp12
+I0
+aI0
+aI0
+aI0
+aI0
+aI0
+aI0
+aI0
+aI1
+aI1
+aI1
+aI1
+aI2
+aI2
+aI2
+aI2
+aI3
+aI3
+aI3
+aI3
+aI3
+aI3
+aI3
+aI4
+aI4
+aI4
+aI4
+aI4
+aI4
+aI4
+aI4
+aI4
+aI4
+aI5
+aI5
+aI5
+aI5
+aI5
+aI6
+aI6
+aI6
+aI6
+aI6
+aI6
+aI6
+aI7
+aI7
+aI7
+aI7
+aI7
+aI8
+aI8
+aI8
+aI8
+aI8
+aI8
+aI8
+aI8
+aI8
+aI8
+aI8
+aI9
+aI9
+aI10
+aI10
+aI10
+aI10
+aI10
+aI10
+aI10
+aI10
+aI11
+aI11
+aI11
+aI11
+aI11
+aI11
+aI11
+aI12
+aI12
+aI12
+aI12
+aI12
+aI13
+aI13
+aI13
+aI14
+aI14
+aI14
+aI14
+aI14
+aI14
+aI14
+aI14
+aI14
+aI14
+aI14
+aI14
+aI15
+aI15
+aI15
+aI16
+aI16
+aI16
+aI16
+aI16
+aI16
+aI17
+aI17
+aI17
+aI17
+aI18
+aI18
+aI18
+aI18
+aI18
+aI19
+aI19
+aI19
+aI19
+aI19
+aI19
+aI20
+aI20
+aI20
+aI20
+aI20
+aI20
+aI21
+aI21
+aI21
+aI21
+aI21
+aI21
+aI22
+aI22
+aI22
+aI22
+aI22
+aI22
+aI22
+aI22
+aI22
+aI22
+aI23
+aI23
+aI23
+aI23
+aI23
+aI23
+aI24
+aI24
+aI24
+aI24
+aI25
+aI25
+aI25
+aI25
+aI26
+aI26
+aI26
+aI26
+aI26
+aI26
+aI26
+aI27
+aI27
+aI27
+aI27
+aI27
+aI27
+aI27
+aI27
+aI28
+aI28
+aI28
+aI29
+aI29
+aI29
+aI29
+aI29
+aI30
+aI30
+aI31
+aI31
+aI31
+aI31
+aI31
+aI31
+aI32
+aI32
+aI32
+aI33
+aI33
+aI33
+aI33
+aI33
+aI33
+aI33
+aI33
+aI34
+aI34
+aI34
+aI34
+aI34
+aI34
+aI35
+aI35
+aI35
+aI35
+aI35
+aI35
+aI35
+aI35
+aI36
+aI36
+aI37
+aI37
+aI37
+aI37
+aI38
+aI38
+aI38
+aI38
+aI39
+aI39
+aI39
+aI39
+aI39
+aI39
+aI39
+aI40
+aI40
+aI40
+aI40
+aI40
+aI40
+aI41
+aI41
+aI41
+aI41
+aI41
+aI42
+aI42
+aI42
+aI42
+aI42
+aI42
+aI42
+aI43
+aI43
+aI43
+aI43
+aI44
+aI44
+aI44
+aI44
+aI44
+aI44
+aI44
+aI44
+aI44
+aI44
+aI45
+aI45
+aI45
+aI46
+aI46
+aI46
+aI46
+aI46
+aI46
+aI46
+aI47
+aI47
+aI47
+aI47
+aI47
+aI47
+aI48
+aI48
+aI48
+aI48
+aI48
+aI48
+aI48
+aI48
+aI48
+aI49
+aI49
+aI49
+aI49
+aI50
+aI50
+aI50
+aI50
+aI50
+aI50
+aI50
+aI50
+aI51
+aI51
+aI51
+aI51
+aI51
+aI52
+aI52
+aI52
+aI52
+aI53
+aI53
+aI53
+aI53
+aI53
+aI54
+aI54
+aI54
+aI54
+aI54
+aI54
+aI54
+aI55
+aI55
+aI55
+aI55
+aI56
+aI56
+aI56
+aI56
+aI56
+aI56
+aI56
+aI57
+aI57
+aI57
+aI57
+aI58
+aI58
+aI58
+aI59
+aI59
+aI59
+aI59
+aI59
+aI59
+aI59
+aI60
+aI60
+aI60
+aI61
+aI61
+aI61
+aI61
+aI61
+aI61
+aI61
+aI61
+aI61
+aI61
+aI61
+aI61
+aI61
+aI62
+aI62
+aI62
+aI62
+aI62
+aI62
+aI62
+aI63
+aI63
+aI63
+aI63
+aI64
+aI64
+aI64
+aI64
+aI64
+aI64
+aI64
+aI64
+aI64
+aI64
+aI64
+aI65
+aI65
+aI65
+aI65
+aI65
+aI65
+aI66
+aI66
+aI66
+aI66
+aI66
+aI66
+aI67
+aI67
+aI67
+aI68
+aI68
+aI68
+aI68
+aI68
+aI69
+aI69
+aI69
+aI69
+aI70
+aI70
+aI70
+aI70
+aI70
+aI71
+aI71
+aI71
+aI71
+aI71
+aI71
+aI71
+aI72
+aI72
+aI72
+aI73
+aI73
+aI73
+aI73
+aI73
+aI73
+aI73
+aI73
+aI73
+aI74
+aI74
+aI74
+aI75
+aI75
+aI75
+aI75
+aI75
+aI75
+aI76
+aI76
+aI76
+aI76
+aI76
+aI76
+aI76
+aI76
+aI77
+aI77
+aI77
+aI77
+aI78
+aI78
+aI79
+aI79
+aI79
+aI79
+aI79
+aI79
+aI80
+aI80
+aI80
+aI80
+aI80
+aI81
+aI81
+aI81
+aI81
+aI82
+aI82
+aI82
+aI82
+aI83
+aI83
+aI83
+aI83
+aI83
+aI84
+aI84
+aI84
+aI85
+aI85
+aI85
+aI85
+aI86
+aI86
+aI86
+aI86
+aI86
+aI86
+aI86
+aI86
+aI87
+aI87
+aI87
+aI87
+aI87
+aI87
+aI88
+aI88
+aI88
+aI88
+aI88
+aI89
+aI89
+aI89
+aI89
+aI90
+aI90
+aI90
+aI90
+aI90
+aI90
+aI90
+aI90
+aI90
+aI90
+aI91
+aI91
+aI91
+aI92
+aI92
+aI92
+aI92
+aI92
+aI92
+aI92
+aI93
+aI93
+aI93
+aI93
+aI93
+aI93
+aI93
+aI94
+aI94
+aI95
+aI95
+aI95
+aI95
+aI95
+aI95
+aI95
+aI96
+aI96
+aI97
+aI97
+aI97
+aI98
+aI98
+aI98
+aI98
+aI98
+aI98
+aI98
+aI98
+aI99
+aI99
+aI99
+aI99
+aI100
+aI100
+aI100
+aI100
+aI101
+aI101
+aI102
+aI102
+aI102
+aI103
+aI103
+aI103
+aI103
+aI104
+aI104
+aI104
+aI104
+aI104
+aI104
+aI105
+aI105
+aI105
+aI106
+aI106
+aI107
+aI107
+aI107
+aI107
+aI107
+aI108
+aI108
+aI108
+aI108
+aI108
+aI109
+aI109
+aI109
+aI109
+aI109
+aI110
+aI110
+aI110
+aI110
+aI110
+aI111
+aI111
+aI111
+aI111
+aI111
+aI111
+aI111
+aI112
+aI112
+aI112
+aI112
+aI112
+aI113
+aI113
+aI114
+aI114
+aI114
+aI114
+aI114
+aI115
+aI115
+aI115
+aI115
+aI115
+aI116
+aI116
+aI116
+aI116
+aI117
+aI117
+aI117
+aI118
+aI118
+aI118
+aI118
+aI118
+aI118
+aI119
+aI119
+aI119
+aI119
+aI119
+aI119
+aI120
+aI120
+aI120
+aI120
+aI121
+aI121
+aI121
+aI122
+aI122
+aI122
+aI122
+aI123
+aI123
+aI123
+aI123
+aI123
+aI123
+aI124
+aI124
+aI125
+aI125
+aI125
+aI125
+aI125
+aI125
+aI125
+aI126
+aI126
+aI126
+aI126
+aI126
+aI126
+aI126
+aI126
+aI126
+aI126
+aI127
+aI128
+aI128
+aI128
+aI128
+aI129
+aI129
+aI129
+aI130
+aI130
+aI130
+aI131
+aI131
+aI131
+aI131
+aI131
+aI131
+aI132
+aI132
+aI132
+aI132
+aI132
+aI132
+aI133
+aI133
+aI133
+aI133
+aI134
+aI134
+aI134
+aI134
+aI134
+aI135
+aI135
+aI135
+aI136
+aI136
+aI136
+aI136
+aI136
+aI136
+aI136
+aI137
+aI137
+aI137
+aI137
+aI137
+aI138
+aI138
+aI138
+aI139
+aI139
+aI139
+aI139
+aI139
+aI139
+aI139
+aI140
+aI140
+aI140
+aI140
+aI140
+aI141
+aI141
+aI141
+aI141
+aI142
+aI142
+aI142
+aI142
+aI143
+aI143
+aI143
+aI143
+aI143
+aI143
+aI143
+aI144
+aI144
+aI144
+aI145
+aI145
+aI145
+aI145
+aI146
+aI146
+aI146
+aI147
+aI147
+aI147
+aI148
+aI148
+aI148
+aI148
+aI148
+aI149
+aI149
+aI149
+aI149
+aI150
+aI150
+aI151
+aI151
+aI151
+aI151
+aI152
+aI152
+aI152
+aI152
+aI153
+aI153
+aI154
+aI154
+aI154
+aI154
+aI154
+aI154
+aI155
+aI155
+aI155
+aI156
+aI156
+aI156
+aI156
+aI156
+aI157
+aI157
+aI157
+aI157
+aI157
+aI157
+aI157
+aI158
+aI158
+aI159
+aI159
+aI159
+aI159
+aI159
+aI160
+aI160
+aI160
+aI160
+aI161
+aI161
+aI161
+aI161
+aI162
+aI162
+aI162
+aI162
+aI162
+aI163
+aI163
+aI163
+aI164
+aI164
+aI164
+aI164
+aI164
+aI164
+aI165
+aI165
+aI165
+aI165
+aI165
+aI165
+aI166
+aI166
+aI166
+aI166
+aI166
+aI166
+aI167
+aI167
+aI167
+aI167
+aI167
+aI167
+aI167
+aI167
+aI168
+aI168
+aI168
+aI168
+aI169
+aI169
+aI170
+aI170
+aI170
+aI170
+aI170
+aI170
+aI171
+aI171
+aI171
+aI172
+aI172
+aI172
+aI172
+aI173
+aI173
+aI173
+aI173
+aI173
+aI174
+aI174
+aI174
+aI174
+aI174
+aI174
+aI174
+aI174
+aI175
+aI176
+aI177
+aI177
+aI177
+aI177
+aI177
+aI178
+aI178
+aI178
+aI179
+aI179
+aI179
+aI179
+aI179
+aI180
+aI180
+aI180
+aI180
+aI180
+aI181
+aI181
+aI181
+aI182
+aI183
+aI183
+aI183
+aI183
+aI183
+aI183
+aI183
+aI183
+aI184
+aI184
+aI185
+aI185
+aI186
+aI186
+aI186
+aI186
+aI186
+aI187
+aI187
+aI188
+aI188
+aI188
+aI188
+aI189
+aI189
+aI189
+aI189
+aI190
+aI190
+aI190
+aI191
+aI191
+aI191
+aI191
+aI191
+aI191
+aI192
+aI192
+aI193
+aI193
+aI193
+aI193
+aI193
+aI194
+aI194
+aI194
+aI195
+aI195
+aI196
+aI196
+aI196
+aI197
+aI197
+aI197
+aI198
+aI198
+aI198
+aI198
+aI198
+aI198
+aI199
+aI200
+aI200
+aI200
+aI200
+aI200
+aI201
+aI201
+aI201
+aI201
+aI201
+aI202
+aI202
+aI203
+aI203
+aI203
+aI203
+aI203
+aI203
+aI204
+aI204
+aI204
+aI205
+aI206
+aI206
+aI206
+aI206
+aI207
+aI207
+aI207
+aI208
+aI208
+aI208
+aI209
+aI209
+aI209
+aI209
+aI210
+aI210
+aI210
+aI211
+aI211
+aI211
+aI211
+aI211
+aI211
+aI211
+aI212
+aI213
+aI214
+aI214
+aI214
+aI215
+aI215
+aI215
+aI215
+aI215
+aI216
+aI216
+aI216
+aI216
+aI217
+aI217
+aI218
+aI218
+aI218
+aI219
+aI219
+aI219
+aI219
+aI220
+aI221
+aI222
+aI222
+aI222
+aI222
+aI222
+aI222
+aI222
+aI223
+aI223
+aI223
+aI223
+aI223
+aI224
+aI225
+aI225
+aI225
+aI225
+aI225
+aI225
+aI225
+aI226
+aI226
+aI226
+aI227
+aI227
+aI227
+aI228
+aI228
+aI228
+aI228
+aI228
+aI228
+aI228
+aI229
+aI229
+aI229
+aI229
+aI229
+aI229
+aI229
+aI229
+aI230
+aI230
+aI230
+aI230
+aI230
+aI230
+aI231
+aI231
+aI231
+aI231
+aI231
+aI232
+aI232
+aI232
+aI232
+aI233
+aI233
+aI233
+aI233
+aI234
+aI235
+aI235
+aI235
+aI236
+aI236
+aI236
+aI236
+aI237
+aI237
+aI237
+aI237
+aI238
+aI239
+aI239
+aI239
+aI240
+aI240
+aI240
+aI240
+aI240
+aI241
+aI241
+aI241
+aI241
+aI241
+aI241
+aI241
+aI241
+aI242
+aI242
+aI242
+aI242
+aI243
+aI243
+aI243
+aI244
+aI244
+aI244
+aI245
+aI245
+aI245
+aI245
+aI245
+aI245
+aI246
+aI246
+aI246
+aI247
+aI247
+aI247
+aI248
+aI248
+aI248
+aI249
+aI249
+aI249
+aI249
+aI249
+aI249
+aI250
+aI250
+aI250
+aI250
+aI250
+aI250
+aI251
+aI251
+aI251
+aI252
+aI252
+aI253
+aI253
+aI254
+aI254
+aI254
+aI254
+aI254
+aI255
+aI255
+aI255
+aI255
+aI255
+aI256
+aI256
+aI256
+aI257
+aI257
+aI257
+aI258
+aI258
+aI258
+aI258
+aI258
+aI259
+aI259
+aI260
+aI260
+aI260
+aI260
+aI260
+aI261
+aI261
+aI261
+aI261
+aI261
+aI261
+aI262
+aI262
+aI262
+aI262
+aI262
+aI263
+aI263
+aI263
+aI263
+aI264
+aI264
+aI264
+aI265
+aI265
+aI265
+aI265
+aI266
+aI266
+aI267
+aI267
+aI267
+aI267
+aI267
+aI268
+aI268
+aI269
+aI269
+aI269
+aI269
+aI270
+aI270
+aI270
+aI270
+aI271
+aI272
+aI272
+aI272
+aI273
+aI274
+aI274
+aI275
+aI275
+aI276
+aI276
+aI276
+aI277
+aI278
+aI278
+aI278
+aI278
+aI279
+aI279
+aI280
+aI280
+aI281
+aI281
+aI281
+aI282
+aI282
+aI282
+aI282
+aI283
+aI283
+aI283
+aI284
+aI284
+aI284
+aI284
+aI285
+aI285
+aI286
+aI286
+aI286
+aI286
+aI287
+aI287
+aI287
+aI288
+aI288
+aI288
+aI289
+aI289
+aI289
+aI289
+aI289
+aI290
+aI290
+aI291
+aI291
+aI291
+aI291
+aI291
+aI292
+aI292
+aI293
+aI293
+aI294
+aI294
+aI294
+aI294
+aI294
+aI295
+aI295
+aI296
+aI296
+aI296
+aI297
+aI297
+aI297
+aI298
+aI298
+aI298
+aI298
+aI298
+aI299
+aI299
+aI299
+aI300
+aI301
+aI301
+aI301
+aI302
+aI302
+aI302
+aI302
+aI302
+aI303
+aI303
+aI304
+aI304
+aI304
+aI305
+aI306
+aI306
+aI307
+aI307
+aI307
+aI307
+aI307
+aI307
+aI308
+aI308
+aI309
+aI309
+aI310
+aI310
+aI310
+aI311
+aI311
+aI311
+aI311
+aI311
+aI312
+aI312
+aI312
+aI313
+aI313
+aI314
+aI314
+aI314
+aI315
+aI316
+aI316
+aI317
+aI317
+aI317
+aI318
+aI318
+aI318
+aI319
+aI319
+aI319
+aI320
+aI320
+aI320
+aI320
+aI320
+aI321
+aI321
+aI322
+aI322
+aI323
+aI324
+aI324
+aI324
+aI324
+aI324
+aI324
+aI325
+aI325
+aI325
+aI326
+aI326
+aI327
+aI327
+aI328
+aI328
+aI329
+aI329
+aI330
+aI330
+aI330
+aI331
+aI331
+aI331
+aI332
+aI332
+aI332
+aI333
+aI333
+aI333
+aI334
+aI334
+aI335
+aI335
+aI336
+aI336
+aI337
+aI337
+aI337
+aI337
+aI337
+aI338
+aI338
+aI338
+aI338
+aI338
+aI339
+aI339
+aI339
+aI339
+aI340
+aI340
+aI341
+aI341
+aI341
+aI342
+aI342
+aI343
+aI343
+aI343
+aI343
+aI344
+aI345
+aI346
+aI347
+aI348
+aI348
+aI348
+aI348
+aI348
+aI349
+aI350
+aI350
+aI351
+aI351
+aI352
+aI353
+aI353
+aI353
+aI354
+aI354
+aI354
+aI355
+aI355
+aI356
+aI357
+aI357
+aI358
+aI358
+aI358
+aI359
+aI359
+aI359
+aI360
+aI360
+aI361
+aI361
+aI361
+aI362
+aI362
+aI362
+aI362
+aI362
+aI363
+aI363
+aI363
+aI364
+aI364
+aI364
+aI365
+aI366
+aI367
+aI367
+aI368
+aI368
+aI368
+aI369
+aI370
+aI370
+aI371
+aI371
+aI371
+aI372
+aI372
+aI373
+aI373
+aI373
+aI373
+aI374
+aI374
+aI374
+aI375
+aI375
+aI376
+aI376
+aI376
+aI376
+aI376
+aI377
+aI377
+aI378
+aI378
+aI378
+aI379
+aI379
+aI379
+aI379
+aI380
+aI380
+aI380
+aI381
+aI381
+aI381
+aI381
+aI382
+aI383
+aI384
+aI384
+aI385
+aI385
+aI385
+aI385
+aI386
+aI386
+aI387
+aI387
+aI387
+aI388
+aI388
+aI389
+aI389
+aI389
+aI389
+aI389
+aI389
+aI390
+aI390
+aI390
+aI391
+aI392
+aI393
+aI394
+aI395
+aI396
+aI396
+aI397
+aI397
+aI398
+aI399
+aI399
+aI399
+aI399
+aI400
+aI401
+aI401
+aI401
+aI402
+aI403
+aI403
+aI404
+aI404
+aI405
+aI405
+aI405
+aI406
+aI406
+aI407
+aI407
+aI407
+aI408
+aI408
+aI408
+aI409
+aI410
+aI411
+aI412
+aI413
+aI413
+aI414
+aI414
+aI415
+aI416
+aI416
+aI417
+aI418
+aI418
+aI419
+aI419
+aI419
+aI420
+aI421
+aI421
+aI422
+aI422
+aI423
+aI423
+aI424
+aI424
+aI425
+aI426
+aI426
+aI427
+aI427
+aI427
+aI428
+aI429
+aI429
+aI429
+aI430
+aI430
+aI431
+aI431
+aI432
+aI433
+aI433
+aI434
+aI434
+aI435
+aI436
+aI436
+aI437
+aI438
+aI439
+aI440
+aI441
+aI442
+aI442
+aI442
+aI442
+aI443
+aI444
+aI445
+aI445
+aI445
+aI446
+aI447
+aI448
+aI449
+aI450
+aI451
+aI451
+aI452
+aI453
+aI454
+aI455
+aI456
+aI457
+aI457
+aI458
+aI459
+aI460
+aI461
+aI461
+aI462
+aI463
+aI464
+aI465
+aI466
+aI467
+aI468
+aI468
+aI469
+aI469
+aI470
+aI470
+aI471
+aI471
+aI472
+aI472
+aI473
+aI474
+aI475
+aI476
+aI477
+aI478
+aI479
+aI480
+aI481
+aI482
+aI483
+aI484
+aI485
+aI486
+aI486
+aI487
+aI487
+aI487
+aI488
+aI489
+aI490
+aI491
+aI492
+aI493
+aI494
+aI495
+aI496
+aI497
+aI498
+aI499
+a(I1741
+I1
+tp13
+g9
+tp14
+Rp15
+(I500
+I500
+tp16
+g4
+tp17
+Rp18
+.
\ No newline at end of file
diff --git a/examples/doc/l1 b/examples/doc/l1
new file mode 100755
index 0000000..92ab0f3
--- /dev/null
+++ b/examples/doc/l1
@@ -0,0 +1,127 @@
+#!/usr/bin/python
+
+# The 1-norm approximation example of section 8.6.  
+
+from cvxopt import base, random, blas, lapack, solvers
+from cvxopt.base import matrix, spmatrix, mul, div
+from math import sqrt
+solvers.options['refinement'] = False
+
+def l1(P, q):
+
+    """
+    Returns the solution u, w of the ell-1 approximation problem
+
+        (primal) minimize ||P*u - q||_1       
+    
+        (dual)   maximize    q'*w
+                 subject to  P'*w = 0
+                             ||w||_infty <= 1.
+    """
+
+    m, n = P.size
+
+    # Solve equivalent LP 
+    #
+    #     minimize    [0; 1]' * [u; v]
+    #     subject to  [P, -I; -P, -I] * [u; v] <= [q; -q]
+    #
+    #     maximize    -[q; -q]' * z 
+    #     subject to  [P', -P']*z  = 0
+    #                 [-I, -I]*z + 1 = 0 
+    #                 z >= 0 
+    
+    c = matrix(n*[0.0] + m*[1.0])
+    h = matrix([q, -q])
+
+    def Fi(x, y, alpha=1.0, beta=0.0, trans='N'):    
+        if trans=='N':
+            # y := alpha * [P, -I; -P, -I] * x + beta*y
+            u = P*x[:n]
+            y[:m] = alpha * ( u - x[n:]) + beta*y[:m]
+            y[m:] = alpha * (-u - x[n:]) + beta*y[m:]
+
+        else:
+            # y := alpha * [P', -P'; -I, -I] * x + beta*y
+            y[:n] =  alpha * P.T * (x[:m] - x[m:]) + beta*y[:n]
+            y[n:] = -alpha * (x[:m] + x[m:]) + beta*y[n:]
+
+
+    def kktsolver(d, R): 
+
+        # Returns a function f(x,y,zl,zs) that solves
+        #
+        # [ 0  0  P'      -P'      ] [ x[:n] ]   [ bx[:n]  ]
+        # [ 0  0 -I       -I       ] [ x[n:] ]   [ bx[n:]  ]
+        # [ P -I -D1^{-1}  0       ] [ zl[:m]] = [ bzl[:m] ]
+        # [-P -I  0       -D2^{-1} ] [ zl[m:]]   [ bzl[m:] ]
+        #
+        # where D1 = diag(d[:m])^2, D2 = diag(d[m:])^2.
+        #
+        # On entry bx, bzl are stored in x, zl.
+        # On exit x, zl contain the solution, with zl scaled (d.*zl is
+        # returned instead of zl). 
+
+        # Factor A = 4*P'*D*P where D = d1.*d2 ./(d1+d2) and
+        # d1 = d[:m].^2, d2 = d[m:].^2.
+
+        d1, d2 = d[:m]**2, d[m:]**2
+        D = div( mul(d1,d2), d1+d2 )  
+        A = P.T * spmatrix(4*D, range(m), range(m)) * P
+        lapack.potrf(A)
+
+        def f(x, y, zl, zs):
+
+            # Solve for x[:n]:
+            #
+            #    A*x[:n] = bx[:n] + P' * ( ((D1-D2)*(D1+D2)^{-1})*bx[n:]
+            #        + (2*D1*D2*(D1+D2)^{-1}) * (bzl[:m] - bzl[m:]) ).
+
+            x[:n] += P.T * ( mul( div(d1-d2, d1+d2), x[n:]) + 
+                mul( 2*D, zl[:m]-zl[m:] ) )
+            lapack.potrs(A, x)
+
+            # x[n:] := (D1+D2)^{-1} * (bx[n:] - D1*bzl[:m] - D2*bzl[m:]
+            #     + (D1-D2)*P*x[:n])
+
+            u = P*x[:n]
+            x[n:] =  div( x[n:] - mul(d1, zl[:m]) - mul(d2, zl[m:]) + 
+                mul(d1-d2, u), d1+d2 )
+
+            # z[:m] := d1[:m] .* ( P*x[:n] - x[n:] - bzl[:m])
+            # z[m:] := d2[m:] .* (-P*x[:n] - x[n:] - bzl[m:]) 
+
+            zl[:m] = mul(d[:m],  u-x[n:]-zl[:m])
+            zl[m:] = mul(d[m:], -u-x[n:]-zl[m:])
+
+        return f
+
+
+    # Initial primal and dual points from least-squares solution.
+
+    # uls minimizes ||P*u-q||_2; rls is the LS residual.
+    uls =  +q
+    lapack.gels(+P, uls)
+    rls = P*uls[:n] - q 
+
+    # x0 = [ uls;  1.1*abs(rls) ];   s0 = [q;-q] - [P,-I; -P,-I] * x0
+    x0 = matrix( [uls[:n],  1.1*abs(rls)] ) 
+    s0 = +h
+    Fi(x0, s0, alpha=-1, beta=1) 
+
+    # z0 = [ (1+w)/2; (1-w)/2 ] where w = (.9/||rls||_inf) * rls  
+    # if rls is nonzero and w = 0 otherwise.
+    if max(abs(rls)) > 1e-10:  
+        w = .9/max(abs(rls)) * rls
+    else: 
+        w = matrix(0.0, (m,1))
+    z0 = matrix([.5*(1+w), .5*(1-w)])
+
+    sol = solvers.conelp(c, kktsolver, Gl=Fi, hl=h, 
+        primalstart={'x': x0, 'sl':s0}, dualstart={'zl': z0})
+    return sol['x'][:n],  sol['zl'][m:] - sol['zl'][:m]    
+
+random.setseed()
+m, n = 500, 100
+P, q = random.normal(m,n), random.normal(m,1)
+x, y = l1(P,q)
diff --git a/examples/doc/mcsdp b/examples/doc/mcsdp
new file mode 100755
index 0000000..43b4c06
--- /dev/null
+++ b/examples/doc/mcsdp
@@ -0,0 +1,121 @@
+#!/usr/bin/python
+
+# The SDP example of section 8.6.
+
+from cvxopt import base, blas, lapack, random, solvers
+from cvxopt.base import matrix
+
+def mcsdp(w):
+    """
+    Returns solution x, z to 
+
+        (primal)  minimize    sum(x)
+                  subject to  w + diag(x) >= 0
+
+        (dual)    maximize    -tr(w*z)
+                  subject to  diag(z) = 1
+                              z >= 0.
+    """
+
+    n = w.size[0]
+
+    def Fs(x, y, alpha=1.0, beta=0.0, trans='N'):
+        """
+            y := alpha*(-diag(x)) + beta*y.   
+        """
+	if trans=='N':
+            # x is a vector; y[0] is a matrix.
+	    blas.scal(beta, y[0])
+	    blas.axpy(x, y[0], alpha=-alpha, incy=n+1)
+
+	else:   
+            # x[0] is a matrix; y is a vector.
+	    blas.scal(beta, y)
+	    blas.axpy(x[0], y, alpha=-alpha, incx=n+1)
+	 
+
+    def cngrnc(r, x, alpha=1.0):
+        """
+        Congruence transformation
+
+	    x := alpha * r'*x*r.
+
+        r and x are square matrices.  
+        """
+
+        # Scale diagonal of x by 1/2.  
+        x[::n+1] *= 0.5 
+    
+        # a := tril(x)*r 
+        a = +r
+        blas.trmm(x, a, side='L')
+
+        # x := alpha*(a*r' + r*a') 
+        blas.syr2k(r, a, x, trans='T', alpha=alpha)
+
+
+    def kktsolver(d, r):
+
+        # t = r*r' as a nonsymmetric matrix.
+        t = matrix(0.0, (n,n))
+	blas.gemm(r[0], r[0], t, transB='T') 
+
+	# Cholesky factorization of tsq = t.*t.
+        tsq = t**2
+	lapack.potrf(tsq)
+
+	def f(x, y, zl, zs):
+            """
+            Solve
+                          -diag(zs)               = bx
+                -diag(x) - inv(r*r')*zs*inv(r*r') = bs
+
+            On entry, x and zs contain bx and bs.  
+            On exit, they contain the solution, with zs scaled
+            (inv(r)'*zs*inv(r) is returned instead of zs).
+
+            We first solve 
+
+                ((r*r') .* (r*r')) * x = bx - diag(t*bs*t) 
+
+            and take zs  = -r' * (diag(x) + bs) * r.
+            """
+
+            # tbst := t * zs * t = t * bs * t
+            tbst = +zs[0]
+            cngrnc(t, tbst) 
+
+            # x := x - diag(tbst) = bx - diag(r*r' * bs * r*r')
+            x -= tbst[::n+1]
+
+            # x := (t.*t)^{-1} * x = (t.*t)^{-1} * (bx - diag(t*bs*t))
+            lapack.potrs(tsq, x)
+
+            # zs := zs + diag(x) = bs + diag(x)
+            zs[0][::n+1] += x
+
+            # zs := -r' * zs * r = -r' * (diag(x) + bs) * r 
+            cngrnc(r[0], zs[0], alpha=-1.0)
+
+	return f
+
+    c = matrix(1.0, (n,1))
+
+    # Initial feasible x:  x = 1.0 - min(lambda(w)).
+    lmbda = matrix(0.0, (n,1))
+    lapack.syevx(+w, lmbda, range='I', il=1, iu=1)
+    x0 = matrix(-lmbda[0]+1.0, (n,1)) 
+    s0 = +w
+    s0[::n+1] += x0
+
+    # Initial feasible z is identity.
+    z0 = matrix(0.0, (n,n))
+    z0[::n+1] = 1.0
+
+    sol = solvers.conelp(c, kktsolver, Gs=Fs, hs=[w], 
+        primalstart={'x': x0, 'ss': [s0]}, dualstart={'zs': [z0]})
+    return sol['x'], sol['zs'][0]
+
+n = 100
+w = random.normal(n,n)
+x, z = mcsdp(w)
diff --git a/examples/doc/normappr b/examples/doc/normappr
new file mode 100755
index 0000000..254a8f4
--- /dev/null
+++ b/examples/doc/normappr
@@ -0,0 +1,34 @@
+#!/usr/bin/python
+
+# The norm and penalty approximation problems of section 9.5.
+
+from cvxopt.random import normal, setseed
+from cvxopt.modeling import variable, op, max, sum
+
+setseed(1)
+m, n = 500, 100
+A = normal(m,n)
+b = normal(m)
+
+x1 = variable(n)
+prob1=op(max(abs(A*x1+b)))
+prob1.solve()
+
+x2 = variable(n)
+prob2=op(sum(abs(A*x2+b)))
+prob2.solve()
+
+x3 = variable(n)
+prob3=op(sum(max(0, abs(A*x3+b)-0.75, 2*abs(A*x3+b)-2.25)))
+prob3.solve()
+
+try: import pylab
+except ImportError: pass
+else:
+    pylab.subplot(311)
+    pylab.hist(A*x1.value + b, m/5)
+    pylab.subplot(312)
+    pylab.hist(A*x2.value + b, m/5)
+    pylab.subplot(313)
+    pylab.hist(A*x3.value + b, m/5)
+    pylab.show()
diff --git a/examples/filterdemo/README b/examples/filterdemo/README
new file mode 100644
index 0000000..81eb297
--- /dev/null
+++ b/examples/filterdemo/README
@@ -0,0 +1,12 @@
+The filterdemo computes a FIR lowpass filter by solving a linear 
+program.  It solves a discretization of the  problem
+
+minimize     d2
+subject to   -1/d1 <= H(wk) <= d1,   0 <= w <=  wc
+	     max(abs(H(wk))) <= d2,  ws <= w <= pi
+
+where H(w) = h_0 + sum_{i=1}^{n-1} h_i*cos(2*pi/n*i*w).
+The variables are h and d2.
+
+'filterdemo_cli' uses a simple a simple command-line interface. 
+'filterdemo_gui' uses a graphical user interface based on GTK.
diff --git a/examples/filterdemo/filterdemo_cli b/examples/filterdemo/filterdemo_cli
new file mode 100755
index 0000000..15ac64a
--- /dev/null
+++ b/examples/filterdemo/filterdemo_cli
@@ -0,0 +1,136 @@
+#!/usr/bin/python
+import getopt, sys
+
+from cvxopt.base import matrix
+from cvxopt.solvers import options
+from cvxopt.modeling import op, variable, max
+
+from math import cos, log10, pi
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+
+import matplotlib
+matplotlib.use('GTKAgg')  # or 'GTK'
+from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas
+import pylab 
+
+def frange(a,b,N):    
+    return [ a+k*float((b-a))/N  for k in xrange(N) ]
+
+def design_lowpass(N, d1, wc, ws, solver=None, Q=50):
+
+    h = variable(N+1)
+    d1 = 10**(d1/20.0)     # convert from dB
+    
+    n1 = int(round(N*Q*wc/pi));
+    w1 = matrix(frange(0,wc,n1))
+    G1 = matrix([cos(wi*j) for j in xrange(N+1) for wi in w1], (n1,N+1))
+
+    n2 = int(round(N*Q*(pi-ws)/pi));
+    w2 = matrix(frange(ws,pi,n2))
+    G2 = matrix([cos(wi*j) for j in xrange(N+1) for wi in w2], (n2,N+1))
+    
+    options['show_progress'] = 0    
+    options['LPX_K_MSGLEV'] = 0
+    options['MSK_IPAR_LOG']= 0
+    op(max(abs(G2*h)), [G1*h <= d1, G1*h >= 1.0/d1]).solve(solver=solver)
+
+    return (h.value, max(abs(G2*h.value)))
+
+def make_plot(h, d2, co, sb, pr, N, output=None):
+    w = matrix(frange(0,pi,N*50));        
+    C = w*matrix(range(N+1), (1,N+1), 'd');
+    for i in xrange(len(C)): C[i] = cos(C[i])
+    
+    fig = pylab.figure()
+    ax = fig.add_subplot(111)
+    ylim = [round((20*log10(d2)-40)/10)*10,10]
+    ax.plot(list(w/pi),[20*log10(abs(x)) for x in C*h])
+    ax.plot(2*[co],[-pr,ylim[0]],'g--')
+    ax.plot(2*[co],[10,pr],'g--')
+    ax.plot(2*[sb],[10,20*log10(d2)],'g--')
+    ax.plot([sb, 1],2*[20*log10(d2)],'g--')
+    ax.plot([0, co],2*[-pr],'g--')
+    ax.plot([0, co],2*[pr],'g--')
+
+    pylab.setp(ax,ylim=ylim)
+    pylab.setp(ax,xlabel="Normalized frequency")
+    pylab.setp(ax,ylabel="Attenuation [dB]")
+    ax.grid()
+
+def usage():
+    print """
+Usage:
+filterdemo_cli --cutoff=CO --stopband=SB --ripple=RP --order=N [options]
+
+Arguments:
+ CO: normalized cutoff frequency
+ SB: normalized stopband frequency, 0.1 <= co < sb-0.1 <= 0.5,
+ RP: maximum passband ripple in dB, 0.01 <= rp <= 3,
+ N : filterorder, 5 <= or <= 50.
+
+Options:
+--solver = SOLVER      One of default, mosek, glpk
+--output = FILENAME    Output filename.
+"""
+    sys.exit(2)
+    
+def main():
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], "",
+             ['cutoff=', 'stopband=', 'ripple=', 'order=',
+              'solver=', 'output='])
+    except getopt.GetoptError:
+        usage()
+
+    if opts==[]: usage()
+        
+    co, sb, pr, N, output = [None]*5
+    solver = "default"
+    
+    try:
+        for o, a in opts:
+            if o == "--cutoff":   co = float(a);
+            if o == "--stopband": sb = float(a);
+            if o == "--ripple":   pr = float(a);
+            if o == "--order":    N  = int(a);
+            if o == "--solver":   solver = a;
+            if o == "--output":   output = a;            
+    except: usage()
+
+    if None in [co, sb, pr, N]: usage()
+    
+    if not (0.1 <= co < sb-0.01+1E-8 <= 0.5):
+        print "invalid cutoff and stopband frequencies"
+        usage()
+
+    if not (0.01 <= pr <= 3):
+        print "invalid value of passband ripple"
+        usage()
+
+    if not (5 <= N <= 50):
+        print "invalid filterorder"
+        usage()
+    
+    if not solver in ['default','mosek','glpk']:
+        print "invalid solver"
+        usage()
+
+
+    try:
+        [h, d2] = design_lowpass(N, pr, co*pi, sb*pi, solver)
+    except:
+        print "Please tighten filter specifications."
+        sys.exit(2)
+        
+        
+    make_plot(h, d2, co, sb, pr, N, output);
+
+    if (output != None): savefig(output)
+
+    pylab.show()
+        
+if __name__ == "__main__":
+    main()
diff --git a/examples/filterdemo/filterdemo_gui b/examples/filterdemo/filterdemo_gui
new file mode 100755
index 0000000..196f612
--- /dev/null
+++ b/examples/filterdemo/filterdemo_gui
@@ -0,0 +1,213 @@
+#!/usr/bin/python
+from cvxopt.base import matrix, cos
+from cvxopt.solvers import options
+from cvxopt.modeling import op, variable, max
+
+from math import log10, pi, floor
+
+import gtk
+
+import matplotlib
+matplotlib.use('GTK')  # or 'GTK'
+from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas
+import pylab 
+
+
+def frange(a,b,N):    
+    return [ a+k*float((b-a))/N  for k in xrange(N) ]
+
+
+def design_lowpass(N, d1, wc, ws, solver=None, Q=50):
+
+    h = variable(N+1)
+    d1 = 10**(d1/20.0)     # convert from dB
+    
+    n  = matrix(range(N+1), (1,N+1), 'd')
+    n1 = int(round(N*Q*wc/pi));
+    G1 = cos(matrix(frange(0,wc,n1))*n)
+
+    n2 = int(round(N*Q*(pi-ws)/pi));
+    G2 = cos(matrix(frange(ws,pi,n2))*n)
+
+    op(max(abs(G2*h)), [G1*h <= d1, G1*h >= 1.0/d1]).solve(solver=solver)
+
+    return (h.value, max(abs(G2*h.value)))
+
+
+
+class MainGUI:
+
+    def check_values(self, param=None):
+        page = self.nb.get_current_page()
+        if page>=0:
+            N  = self.fo_spinner.get_value_as_int()
+            co = self.co_spinner.get_value()
+            sb = self.sb_spinner.get_value()
+            pr = self.pr_spinner.get_value()
+            if (co == self.tabs[page][1] and sb == self.tabs[page][2] and
+                pr == self.tabs[page][3] and N  == self.tabs[page][4]):
+                self.compute_filter.set_sensitive(False)
+            else:
+                self.compute_filter.set_sensitive(True)
+            
+    def change_co(self, param1):
+        self.sb_spinner.set_range(param1.get_value()+0.01,
+                                  self.sb_spinner.get_range()[1]);        
+        self.check_values()
+        
+    def change_sb(self, param1):
+        self.co_spinner.set_range(0.1, param1.get_value()-0.01);
+        self.check_values()
+        
+    def switch_page(self, page, page_num, page_int, notebook):
+        if len(self.tabs)>page_int:
+            self.tabs[page_int][0].draw()
+            self.co_spinner.set_value(self.tabs[page_int][1])
+            self.sb_spinner.set_value(self.tabs[page_int][2])
+            self.pr_spinner.set_value(self.tabs[page_int][3])
+            self.fo_spinner.set_value(self.tabs[page_int][4])
+            self.compute_filter.set_sensitive(False)
+            
+    def new_tab(self, button, notebook):
+        
+        N  = self.fo_spinner.get_value_as_int()
+        co = self.co_spinner.get_value()
+        sb = self.sb_spinner.get_value()
+        pr = self.pr_spinner.get_value()
+        
+        try: 
+            h, d2 = design_lowpass(N, pr, pi*co, pi*sb)
+        except:
+            x = gtk.MessageDialog(flags=gtk.DIALOG_MODAL, \
+                type=gtk.MESSAGE_WARNING, message_format= \
+                "KKT matrix is nearly singular.\n"\
+                "Please tighten the filter specifications.");
+            x.run()
+            return
+
+        w  = matrix(frange(0,pi,N*50));        
+        C = cos(w*matrix(range(N+1),(1,N+1)));
+        
+        fig = pylab.figure()
+        canvas = FigureCanvas(fig)  # a gtk.DrawingArea
+        ax = fig.add_subplot(111)
+        
+        ylim = [floor((20*log10(d2)-30)/100)*100,10]
+        
+        ax.plot(list(w/pi),[20*log10(abs(x)) for x in C*h])
+        ax.plot(2*[co],[-pr,ylim[0]],'g--')
+        ax.plot(2*[co],[10,pr],'g--')
+        ax.plot(2*[sb],[10,20*log10(d2)],'g--')
+        ax.plot([sb, 1],2*[20*log10(d2)],'g--')
+        ax.plot([0, co],2*[-pr],'g--')
+        ax.plot([0, co],2*[pr],'g--')
+
+        pylab.setp(ax,ylim=ylim)
+        pylab.setp(ax,xlabel="Normalized frequency")
+        pylab.setp(ax,ylabel="Attenuation [dB]")
+        ax.grid()        
+        canvas.show()               
+        notebook.append_page(canvas)
+        notebook.set_current_page(notebook.get_n_pages()-1)
+        
+        self.tabs.append([canvas,co,sb,pr,N])
+        self.compute_filter.set_sensitive(False)
+        
+    def close_tab(self, button, notebook):
+        page = notebook.get_current_page()
+        notebook.remove_page(page)
+        if page>=0: del(self.tabs[page])
+        # Need to refresh the widget -- 
+        # This forces the widget to redraw itself.
+        notebook.queue_draw_area(0,0,-1,-1)
+
+        if notebook.get_n_pages() == 0:
+            self.compute_filter.set_sensitive(True)
+
+    def delete(self, widget, event=None):
+        gtk.main_quit()
+        return gtk.FALSE
+    
+    def __init__(self):
+        window = gtk.Window (gtk.WINDOW_TOPLEVEL)
+        window.connect("delete_event", self.delete)
+        window.set_default_size(600, 400)
+        window.set_border_width(10)
+        table = gtk.Table(4,6,False)
+        window.add(table)
+        
+        # Create a new notebook, place the position of the tabs
+        notebook = gtk.Notebook()
+        notebook.connect("switch-page", self.switch_page, notebook)
+        notebook.set_tab_pos(gtk.POS_BOTTOM)
+        table.attach(notebook, 0,6,0,1)
+        notebook.show()
+        self.nb = notebook
+        self.tabs = []
+
+        # Stopband frequency 
+        co_label = gtk.Label("Cutoff")
+        co_label.show()
+        table.attach(co_label, 0,1,1,2, gtk.SHRINK, gtk.SHRINK)
+
+        co_adj = gtk.Adjustment(0.25, 0.1, 0.34, 0.01, 0, 0)
+        self.co_spinner = gtk.SpinButton(co_adj, 0.0, 2)
+        self.co_spinner.set_numeric(True)
+        self.co_spinner.connect("value-changed", self.change_co);
+        self.co_spinner.show()
+        table.attach(self.co_spinner, 0,1,2,3, gtk.SHRINK, gtk.SHRINK)
+
+        # Stopband frequency 
+        sb_label = gtk.Label("Stopband")
+        sb_label.show()
+        table.attach(sb_label, 1,2,1,2, gtk.SHRINK, gtk.SHRINK)
+
+        sb_adj = gtk.Adjustment(0.35, 0.26, 0.5, 0.01, 0, 0)
+        self.sb_spinner = gtk.SpinButton(sb_adj, 0.0, 2)
+        self.sb_spinner.set_numeric(True)
+        self.sb_spinner.connect("value-changed", self.change_sb);
+        self.sb_spinner.show()
+        table.attach(self.sb_spinner, 1,2,2,3, gtk.SHRINK, gtk.SHRINK)
+
+        # Passband ripple
+        pr_label = gtk.Label("Passband ripple")
+        pr_label.show()
+        table.attach(pr_label, 2,3,1,2, gtk.SHRINK, gtk.SHRINK)
+
+        pr_adj = gtk.Adjustment(1, 0.3, 3, 0.01, 0, 0)
+        self.pr_spinner = gtk.SpinButton(pr_adj, 0.0, 2)
+        self.pr_spinner.connect("value-changed", self.check_values);
+        self.pr_spinner.set_numeric(True)
+        self.pr_spinner.show()
+        table.attach(self.pr_spinner, 2,3,2,3, gtk.SHRINK, gtk.SHRINK)
+        
+        # Filter order
+        fo_label = gtk.Label("Filter order")
+        fo_label.show()
+        table.attach(fo_label, 3,4,1,2, gtk.SHRINK, gtk.SHRINK)
+
+        fo_adj = gtk.Adjustment(10, 5, 50, 1, 0, 0)
+        self.fo_spinner = gtk.SpinButton(fo_adj, 0.0, 0)
+        self.fo_spinner.connect("value-changed", self.check_values);
+        self.fo_spinner.set_numeric(True)
+        self.fo_spinner.show()
+        table.attach(self.fo_spinner, 3,4,2,3, gtk.SHRINK, gtk.SHRINK)
+
+        # Buttons
+        button = gtk.Button("compute filter")        
+        button.connect("clicked", self.new_tab, notebook)
+        table.attach(button, 4,5,2,3, gtk.FILL, gtk.SHRINK)
+        button.show()
+        self.compute_filter = button
+
+        button = gtk.Button("close tab")
+        button.connect("clicked", self.close_tab, notebook)
+        table.attach(button, 5,6,2,3, gtk.FILL, gtk.SHRINK)
+        button.show()
+        
+        table.show()
+        window.show()
+
+options['show_progress']=False
+gui = MainGUI()
+gtk.main()
diff --git a/src/C/SuiteSparse/AMD/Doc/AMD_UserGuide.bib b/src/C/SuiteSparse/AMD/Doc/AMD_UserGuide.bib
new file mode 100644
index 0000000..03fbfa8
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Doc/AMD_UserGuide.bib
@@ -0,0 +1,98 @@
+ at string{SIREV       = "{SIAM} Review"}
+ at string{SIMAX       = "{SIAM} J. Matrix Anal. Applic."}
+ at string{SIAMJSC     = "{SIAM} J. Sci. Comput."}
+ at string{TOMS        = "{ACM} Trans. Math. Softw."}
+
+ at article{schu:01,
+	author    = {J. Schulze},
+	title     = {Towards a tighter coupling of bottom-up and top-down sparse matrix ordering methods},
+	journal   = {BIT},
+	volume    = {41},
+	number    = {4},
+	pages     = "800--841",
+	year      = {2001}
+	}
+
+ at article{GeorgeLiu89,
+	author={George, A. and Liu, J. W. H.},
+	year={1989},
+	title={The Evolution of the Minimum Degree Ordering Algorithm},
+	journal=SIREV,
+	volume={31},
+	number={1},
+	pages={1--19}}
+
+ at article{AmestoyDavisDuff96,
+	author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.},
+	title={An approximate minimum degree ordering algorithm},
+	journal=SIMAX,
+	year={1996}
+	,volume={17}
+	,number={4}
+	,pages={886-905}
+	}
+
+ at article{AmestoyDavisDuff04,
+	author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.},
+	title={Algorithm 837: An approximate minimum degree ordering algorithm},
+	journal=TOMS,
+	year={2004}
+	,volume={30}
+	,number={3}
+	,pages={381-388}
+	}
+
+ at misc{hsl:2002,
+ author = {HSL},
+  title = "{HSL} 2002: {A} collection of {F}ortran codes for large
+           scale scientific computation",
+  note = {{\tt www.cse.clrc.ac.uk/nag/hsl}},
+  year = 2002}
+
+
+ at article{RothbergEisenstat98,
+	author={Rothberg, E. and Eisenstat, S. C.},
+	title={Node selection strategies for bottom-up sparse matrix orderings},
+	journal=SIMAX,
+	year={1998}
+	,volume={19}
+	,number={3}
+	,pages={682-695}
+	}
+
+ at article{KarypisKumar98e,
+	author={Karypis, G. and Kumar, V.},
+	title={A fast and high quality multilevel scheme for partitioning irregular graphs},
+	journal=SIAMJSC,
+	year={1998}
+	,volume={20}
+	,pages={359-392}
+	}
+
+ at article{Chaco,
+	author={B. Hendrickson and E. Rothberg},
+	title={Improving the runtime and quality of nested dissection ordering},
+	journal=SIAMJSC,
+	year={1999}
+	,volume={20}
+	,pages={468--489}
+	}
+
+ at article{PellegriniRomanAmestoy00,
+	author={Pellegrini, F. and Roman, J. and Amestoy, P.},
+	title={Hybridizing nested dissection and halo approximate minimum degree for efficient sparse matrix ordering},
+	journal={Concurrency: Practice and Experience},
+	year={2000}
+	,volume={12}
+	,pages={68-84}
+	}
+
+ at article{DavisGilbertLarimoreNg04,
+	author={Davis, T. A. and Gilbert, J. R. and Larimore, S. I. and Ng, E. G.},
+	title={A column approximate minimum degree ordering algorithm},
+	journal=TOMS,
+	year={2004}
+	,volume={30}
+	,pages={353-376}
+	}
+
diff --git a/src/C/SuiteSparse/AMD/Doc/AMD_UserGuide.pdf b/src/C/SuiteSparse/AMD/Doc/AMD_UserGuide.pdf
new file mode 100644
index 0000000..0fcffe6
Binary files /dev/null and b/src/C/SuiteSparse/AMD/Doc/AMD_UserGuide.pdf differ
diff --git a/src/C/SuiteSparse/AMD/Doc/AMD_UserGuide.tex b/src/C/SuiteSparse/AMD/Doc/AMD_UserGuide.tex
new file mode 100644
index 0000000..2ea79e0
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Doc/AMD_UserGuide.tex
@@ -0,0 +1,1203 @@
+\documentclass[11pt]{article}
+
+\newcommand{\m}[1]{{\bf{#1}}}       % for matrices and vectors
+\newcommand{\tr}{^{\sf T}}          % transpose
+
+\topmargin 0in
+\textheight 9in
+\oddsidemargin 0pt
+\evensidemargin 0pt
+\textwidth 6.5in
+
+%------------------------------------------------------------------------------
+\begin{document}
+%------------------------------------------------------------------------------
+
+\title{AMD Version 2.0 User Guide}
+\author{Patrick R. Amestoy\thanks{ENSEEIHT-IRIT,
+2 rue Camichel 31017 Toulouse, France.
+email: amestoy at enseeiht.fr.  http://www.enseeiht.fr/$\sim$amestoy.}
+\and Timothy A. Davis\thanks{
+Dept.~of Computer and Information Science and Engineering,
+Univ.~of Florida, Gainesville, FL, USA.
+email: davis at cise.ufl.edu.
+http://www.cise.ufl.edu/$\sim$davis.
+This work was supported by the National
+Science Foundation, under grants ASC-9111263, DMS-9223088, and CCR-0203270.
+Portions of the work were done while on sabbatical at Stanford University
+and Lawrence Berkeley National Laboratory (with funding from Stanford
+University and the SciDAC program).
+}
+\and Iain S. Duff\thanks{Rutherford Appleton Laboratory, Chilton, Didcot, 
+Oxon OX11 0QX, England. email: i.s.duff at rl.ac.uk.  
+http://www.numerical.rl.ac.uk/people/isd/isd.html.
+This work was supported by the EPSRC under grant GR/R46441.
+}}
+
+\date{Dec 12, 2006}
+\maketitle
+
+%------------------------------------------------------------------------------
+\begin{abstract}
+AMD is a set of routines that implements the approximate minimum degree ordering
+algorithm to permute sparse matrices prior to
+numerical factorization.
+There are versions written in both C and Fortran 77.
+A MATLAB interface is included.
+\end{abstract}
+%------------------------------------------------------------------------------
+
+Technical report TR-04-002 (revised), CISE Department, University of Florida,
+Gainesville, FL, 2006.
+
+AMD Version 2.0, Copyright\copyright 2006 by Timothy A.
+Davis, Patrick R. Amestoy, and Iain S. Duff.  All Rights Reserved.
+AMD is available under alternate licences; contact T. Davis for details.
+
+{\bf AMD License:}
+    Your use or distribution of AMD or any modified version of
+    AMD implies that you agree to this License.
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+    USA
+
+    Permission is hereby granted to use or copy this program under the
+    terms of the GNU LGPL, provided that the Copyright, this License,
+    and the Availability of the original version is retained on all copies.
+    User documentation of any code that uses this code or any modified
+    version of this code must cite the Copyright, this License, the
+    Availability note, and "Used by permission." Permission to modify
+    the code and to distribute modified code is granted, provided the
+    Copyright, this License, and the Availability note are retained,
+    and a notice that the code was modified is included.
+
+{\bf Availability:}
+    http://www.cise.ufl.edu/research/sparse/amd
+
+{\bf Acknowledgments:}
+
+    This work was supported by the National Science Foundation, under
+    grants ASC-9111263 and DMS-9223088 and CCR-0203270.
+    The conversion to C, the addition of the elimination tree
+    post-ordering, and the handling of dense rows and columns
+    were done while Davis was on sabbatical at
+    Stanford University and Lawrence Berkeley National Laboratory.
+
+%------------------------------------------------------------------------------
+\newpage
+\section{Overview}
+%------------------------------------------------------------------------------
+
+AMD is a set of routines for preordering a sparse matrix prior to
+numerical factorization.  It uses an approximate minimum degree ordering
+algorithm \cite{AmestoyDavisDuff96,AmestoyDavisDuff04}
+to find a permutation matrix $\m{P}$
+so that the Cholesky factorization $\m{PAP}\tr=\m{LL}\tr$ has fewer
+(often much fewer) nonzero entries than the Cholesky factorization of $\m{A}$.
+The algorithm is typically much faster than other ordering methods
+and  minimum degree ordering
+algorithms that compute an exact degree \cite{GeorgeLiu89}.
+Some methods, such as approximate deficiency
+\cite{RothbergEisenstat98} and graph-partitioning based methods
+\cite{Chaco,KarypisKumar98e,PellegriniRomanAmestoy00,schu:01}
+can produce better orderings, depending on the matrix.
+
+The algorithm starts with an undirected graph representation of a
+symmetric sparse matrix $\m{A}$.  Node $i$ in the graph corresponds to row
+and column $i$ of the matrix, and there is an edge $(i,j)$ in the graph if
+$a_{ij}$ is nonzero.
+The degree of a node is initialized to the number of off-diagonal nonzeros
+in row $i$, which is the size of the set of nodes
+adjacent to $i$ in the graph.
+
+The selection of a pivot $a_{ii}$ from the diagonal of $\m{A}$ and the first
+step of Gaussian elimination corresponds to one step of graph elimination.
+Numerical fill-in causes new nonzero entries in the matrix
+(fill-in refers to
+nonzeros in $\m{L}$ that are not in $\m{A}$).
+Node $i$ is eliminated and edges are added to its neighbors
+so that they form a clique (or {\em element}).  To reduce fill-in,
+node $i$ is selected as the node of least degree in the graph.
+This process repeats until the graph is eliminated.
+
+The clique is represented implicitly.  Rather than listing all the
+new edges in the graph, a single list of nodes is kept which represents
+the clique.  This list corresponds to the nonzero pattern of the first
+column of $\m{L}$.  As the elimination proceeds, some of these cliques
+become subsets of subsequent cliques, and are removed.   This graph
+can be stored in place, that is
+using the same amount of memory as the original graph.
+
+The most costly part of the minimum degree algorithm is the recomputation
+of the degrees of nodes adjacent to the current pivot element.
+Rather than keep track of the exact degree, the approximate minimum degree
+algorithm finds an upper bound on the degree that is easier to compute.
+For nodes of least degree, this bound tends to be tight.  Using the
+approximate degree instead of the exact degree leads to a substantial savings
+in run time, particularly for very irregularly structured matrices.
+It has no effect on the quality of the ordering.
+
+In the C version of AMD, the elimination phase is followed by an
+elimination tree post-ordering.  This has no effect on fill-in, but
+reorganizes the ordering so that the subsequent numerical factorization is
+more efficient.  It also includes a pre-processing phase in which nodes of
+very high degree are removed (without causing fill-in), and placed last in the
+permutation $\m{P}$.  This reduces the run time substantially if the matrix
+has a few rows with many nonzero entries, and has little effect on the quality
+of the ordering.
+The C version operates on the
+symmetric nonzero pattern of $\m{A}+\m{A}\tr$, so it can be given
+an unsymmetric matrix, or either the lower or upper triangular part of
+a symmetric matrix.
+
+The two Fortran versions of AMD are essentially identical to two versions of
+the AMD algorithm discussed in an earlier paper \cite{AmestoyDavisDuff96}
+(approximate minimum external degree, both with and without aggressive
+absorption).
+For a discussion of the long history of the minimum degree algorithm,
+see \cite{GeorgeLiu89}.
+
+%------------------------------------------------------------------------------
+\section{Availability}
+%------------------------------------------------------------------------------
+
+In addition to appearing as a Collected Algorithm of the ACM,
+AMD Version 2.0 is available at http://www.cise.ufl.edu/research/sparse.
+The Fortran version is available as the routine {\tt MC47} in HSL
+(formerly the Harwell Subroutine Library) \cite{hsl:2002}.
+
+%------------------------------------------------------------------------------
+\section{Using AMD in MATLAB}
+%------------------------------------------------------------------------------
+
+The MATLAB function {\tt amd} is now a built-in function in MATLAB 7.3
+(R2006b).  Compiling the AMD mexFunction, here, causes a name conflict
+(it is MATLAB that is conflict with AMD, not the other way around ...).
+
+To avoid this issue, either use the built-in {\tt amd}, or use the
+{\tt amd2} function provided here.  {\tt amd}
+and {\tt amd2} differ in how the optional parameters are passed
+(the 2nd input parameter).
+
+To use AMD2 in MATLAB, you must first compile the AMD2 mexFunction.
+Just type {\tt make} in the Unix system shell, while in the {\tt AMD/MATLAB}
+directory.  You can also type {\tt amd\_make} in MATLAB, while in the
+{\tt AMD/MATLAB} directory.  Place the {\tt AMD/MATLAB} directory in your
+MATLAB path.  This can be done on any system with MATLAB, including Windows.
+See Section~\ref{Install} for more details on how to install AMD.
+
+The MATLAB statement {\tt p=amd(A)} finds a permutation vector {\tt p} such
+that the Cholesky factorization {\tt chol(A(p,p))} is typically sparser than
+{\tt chol(A)}.
+If {\tt A} is unsymmetric, {\tt amd(A)} is identical to {\tt amd(A+A')}
+(ignoring numerical cancellation).
+If {\tt A} is not symmetric positive definite,
+but has substantial diagonal entries and a mostly symmetric nonzero pattern,
+then this ordering is also suitable for LU factorization.  A partial pivoting
+threshold may be required to prevent pivots from being selected off the
+diagonal, such as the statement {\tt [L,U,P] = lu (A (p,p), 0.1)}.
+Type {\tt help lu} for more details.
+The statement {\tt [L,U,P,Q] = lu (A (p,p))} in MATLAB 6.5 is
+not suitable, however, because it uses UMFPACK Version 4.0 and thus
+does not attempt to select pivots from the diagonal.
+UMFPACK Version 4.1 in MATLAB 7.0 and later
+uses several strategies, including a symmetric pivoting strategy, and
+will give you better results if you want to factorize an unsymmetric matrix
+of this type.  Refer to the UMFPACK User Guide for more details, at
+http://www.cise.ufl.edu/research/sparse/umfpack.
+
+The AMD mexFunction is much faster than the built-in MATLAB symmetric minimum
+degree ordering methods, SYMAMD and SYMMMD.  Its ordering quality is
+comparable to SYMAMD, and better than SYMMMD
+\cite{DavisGilbertLarimoreNg04}.
+
+An optional input argument can be used to modify the control parameters for
+AMD (aggressive absorption, dense row/column handling, and printing of
+statistics).  An optional output
+argument provides statistics on the ordering, including an analysis of the
+fill-in and the floating-point operation count for a subsequent factorization.
+For more details (once AMD is installed),
+type {\tt help amd} in the MATLAB command window.
+
+%------------------------------------------------------------------------------
+\section{Using AMD in a C program}
+\label{Cversion}
+%------------------------------------------------------------------------------
+
+The C-callable AMD library consists of seven user-callable routines and one
+include file.  There are two versions of each of the routines, with
+{\tt int} and {\tt long} integers.
+The routines with prefix
+{\tt amd\_l\_} use {\tt long} integer arguments; the others use
+{\tt int} integer arguments.  If you compile AMD in the standard
+ILP32 mode (32-bit {\tt int}'s, {\tt long}'s, and pointers) then the versions
+are essentially identical.  You will be able to solve problems using up to 2GB
+of memory.  If you compile AMD in the standard LP64 mode, the size of an
+{\tt int} remains 32-bits, but the size of a {\tt long} and a pointer both get
+promoted to 64-bits.
+
+The following routines are fully described in Section~\ref{Primary}:
+
+\begin{itemize}
+\item {\tt amd\_order}
+({\tt long} version: {\tt amd\_l\_order})
+    {\footnotesize
+    \begin{verbatim}
+    #include "amd.h"
+    int n, Ap [n+1], Ai [nz], P [n] ;
+    double Control [AMD_CONTROL], Info [AMD_INFO] ;
+    int result = amd_order (n, Ap, Ai, P, Control, Info) ;
+    \end{verbatim}
+    }
+    Computes the approximate minimum degree ordering of an $n$-by-$n$ matrix
+    $\m{A}$.  Returns a permutation vector {\tt P} of size {\tt n}, where
+    {\tt P[k] = i} if row and column {\tt i} are the {\tt k}th row and
+    column in the permuted matrix.
+    This routine allocates its own memory of size $1.2e+9n$ integers,
+    where $e$ is the number of nonzeros in $\m{A}+\m{A}\tr$.
+    It computes statistics about the matrix $\m{A}$, such as the symmetry of
+    its nonzero pattern, the number of nonzeros in $\m{L}$,
+    and the number of floating-point operations required for Cholesky and LU
+    factorizations (which are returned in the {\tt Info} array).
+    The user's input matrix is not modified.
+    It returns {\tt AMD\_OK} if successful,
+    {\tt AMD\_OK\_BUT\_JUMBLED} if successful (but the matrix had unsorted
+    and/or duplicate row indices),
+    {\tt AMD\_INVALID} if the matrix is invalid,
+    {\tt AMD\_OUT\_OF\_MEMORY} if out of memory.
+
+\item {\tt amd\_defaults}
+({\tt long} version: {\tt amd\_l\_defaults})
+    {\footnotesize
+    \begin{verbatim}
+    #include "amd.h"
+    double Control [AMD_CONTROL] ;
+    amd_defaults (Control) ;
+    \end{verbatim}
+    }
+    Sets the default control parameters in the {\tt Control} array.  These can
+    then be modified as desired before passing the array to the other AMD
+    routines.
+
+\item {\tt amd\_control}
+({\tt long} version: {\tt amd\_l\_control})
+    {\footnotesize
+    \begin{verbatim}
+    #include "amd.h"
+    double Control [AMD_CONTROL] ;
+    amd_control (Control) ;
+    \end{verbatim}
+    }
+    Prints a description of the control parameters, and their values.
+
+\item {\tt amd\_info}
+({\tt long} version: {\tt amd\_l\_info})
+    {\footnotesize
+    \begin{verbatim}
+    #include "amd.h"
+    double Info [AMD_INFO] ;
+    amd_info (Info) ;
+    \end{verbatim}
+    }
+    Prints a description of the statistics computed by AMD, and their values.
+
+\item {\tt amd\_valid}
+({\tt long} version: {\tt amd\_valid})
+    {\footnotesize
+    \begin{verbatim}
+    #include "amd.h"
+    int n, Ap [n+1], Ai [nz] ;
+    int result = amd_valid (n, n, Ap, Ai) ;
+    \end{verbatim}
+    }
+    Returns {\tt AMD\_OK} or {\tt AMD\_OK\_BUT\_JUMBLED}
+    if the matrix is valid as input to {\tt amd\_order};
+    the latter is returned if the matrix has unsorted and/or duplicate
+    row indices in one or more columns. 
+    Returns {\tt AMD\_INVALID} if the matrix cannot be passed to
+    {\tt amd\_order}.
+    For {\tt amd\_order}, the matrix must
+    also be square.  The first two arguments are the number of rows and the
+    number of columns of the matrix.  For its use in AMD, these must both
+    equal {\tt n}.
+
+\item {\tt amd\_2}
+({\tt long} version: {\tt amd\_l2})
+    AMD ordering kernel.  It is faster than {\tt amd\_order}, and
+    can be called by the user, but it is difficult to use.
+    It does not check its inputs for errors.
+    It does not require the columns of its input matrix to be sorted,
+    but it destroys the matrix on output.  Additional workspace must be passed.
+    Refer to the source file {\tt AMD/Source/amd\_2.c} for a description.
+
+\end{itemize}
+
+The nonzero pattern of the matrix $\m{A}$ is represented in compressed column
+form.
+For an $n$-by-$n$ matrix $\m{A}$ with {\tt nz} nonzero entries, the
+representation consists of two arrays: {\tt Ap} of size {\tt n+1} and {\tt Ai}
+of size {\tt nz}.  The row indices of entries in column {\tt j} are stored in
+    {\tt Ai[Ap[j]} $\ldots$ {\tt Ap[j+1]-1]}.
+For {\tt amd\_order},
+if duplicate row indices are present, or if the row indices in any given
+column are not sorted in ascending order, then {\tt amd\_order} creates
+an internal copy of the matrix with sorted rows and no duplicate entries,
+and orders the copy.  This adds slightly to the time and memory usage of
+{\tt amd\_order}, but is not an error condition.
+
+The matrix is 0-based, and thus
+row indices must be in the range {\tt 0} to {\tt n-1}.
+The first entry {\tt Ap[0]} must be zero.
+The total number of entries in the matrix is thus {\tt nz = Ap[n]}.
+
+The matrix must be square, but it does not need to be symmetric.
+The {\tt amd\_order} routine constructs the nonzero pattern of
+$\m{B} = \m{A}+\m{A}\tr$ (without forming $\m{A}\tr$ explicitly if
+$\m{A}$ has sorted columns and no duplicate entries),
+and then orders the matrix $\m{B}$.  Thus, either the
+lower triangular part of $\m{A}$, the upper triangular part,
+or any combination may be passed.  The transpose $\m{A}\tr$ may also be
+passed to {\tt amd\_order}.
+The diagonal entries may be present, but are ignored.
+
+%------------------------------------------------------------------------------
+\subsection{Control parameters}
+\label{control_param}
+%------------------------------------------------------------------------------
+
+Control parameters are set in an optional {\tt Control} array.
+It is optional in the sense that if
+a {\tt NULL} pointer is passed for the {\tt Control} input argument,
+then default control parameters are used.
+%
+\begin{itemize}
+\item {\tt Control[AMD\_DENSE]} (or {\tt Control(1)} in MATLAB):
+controls the threshold for ``dense''
+rows/columns.  A dense row/column in $\m{A}+\m{A}\tr$
+can cause AMD to spend significant time
+in ordering the matrix.  If {\tt Control[AMD\_DENSE]} $\ge 0$,
+rows/columns with
+more than {\tt Control[AMD\_DENSE]} $\sqrt{n}$ entries are ignored during
+the ordering, and placed last in the output order.  The default
+value of {\tt Control[AMD\_DENSE]} is 10.  If negative, no rows/columns
+are treated as ``dense.''  Rows/columns with 16 or fewer off-diagonal
+entries are never considered ``dense.''
+%
+\item {\tt Control[AMD\_AGGRESSIVE]} (or {\tt Control(2)} in MATLAB):
+controls whether or not to use
+aggressive absorption, in which a prior element is absorbed into the current
+element if it is a subset of the current element, even if it is not
+adjacent to the current pivot element (refer
+to \cite{AmestoyDavisDuff96,AmestoyDavisDuff04}
+for more details).  The default value is nonzero,
+which means that aggressive absorption will be performed.  This nearly always
+leads to a better ordering (because the approximate degrees are more
+accurate) and a lower execution time.  There are cases where it can
+lead to a slightly worse ordering, however.  To turn it off, set
+{\tt Control[AMD\_AGGRESSIVE]} to 0.
+%
+\end{itemize}
+
+Statistics are returned in the {\tt Info} array
+(if {\tt Info} is {\tt NULL}, then no statistics are returned).
+Refer to {\tt amd.h} file, for more details
+(14 different statistics are returned, so the list is not included here).
+
+%------------------------------------------------------------------------------
+\subsection{Sample C program}
+%------------------------------------------------------------------------------
+
+The following program, {\tt amd\_demo.c}, illustrates the basic use of AMD.
+See Section~\ref{Synopsis} for a short description
+of each calling sequence.
+
+{\footnotesize
+\begin{verbatim}
+#include <stdio.h>
+#include "amd.h"
+
+int n = 5 ;
+int Ap [ ] = { 0,   2,       6,       10,  12, 14} ;
+int Ai [ ] = { 0,1, 0,1,2,4, 1,2,3,4, 2,3, 1,4   } ;
+int P [5] ;
+
+int main (void)
+{
+    int k ;
+    (void) amd_order (n, Ap, Ai, P, (double *) NULL, (double *) NULL) ;
+    for (k = 0 ; k < n ; k++) printf ("P [%d] = %d\n", k, P [k]) ;
+    return (0) ;
+}
+\end{verbatim}
+}
+
+The {\tt Ap} and {\tt Ai} arrays represent the binary matrix
+\[
+\m{A} = \left[
+\begin{array}{rrrrr}
+ 1 &  1 &  0 &  0 &  0 \\
+ 1 &  1 &  1 &  0 &  1 \\
+ 0 &  1 &  1 &  1 &  0 \\
+ 0 &  0 &  1 &  1 &  0 \\
+ 0 &  1 &  1 &  0 &  1 \\
+\end{array}
+\right].
+\]
+The diagonal entries are ignored.
+%
+AMD constructs the pattern of $\m{A}+\m{A}\tr$,
+and returns a permutation vector of $(0, 3, 1, 4, 2)$.
+%
+Since the matrix is unsymmetric but with a mostly symmetric nonzero
+pattern, this would be a suitable permutation for an LU factorization of a
+matrix with this nonzero pattern and whose diagonal entries are not too small.
+The program uses default control settings and does not return any statistics
+about the ordering, factorization, or solution ({\tt Control} and {\tt Info}
+are both {\tt (double *) NULL}).  It also ignores the status value returned by
+{\tt amd\_order}.
+
+More example programs are included with the AMD package.
+The {\tt amd\_demo.c} program provides a more detailed demo of AMD.
+Another example is the AMD mexFunction, {\tt amd\_mex.c}.
+
+%------------------------------------------------------------------------------
+\subsection{A note about zero-sized arrays}
+%------------------------------------------------------------------------------
+
+AMD uses several user-provided arrays of size {\tt n} or {\tt nz}.
+Either {\tt n} or {\tt nz} can be zero.
+If you attempt to {\tt malloc} an array of size zero,
+however, {\tt malloc} will return a null pointer which AMD will report
+as invalid.  If you {\tt malloc} an array of
+size {\tt n} or {\tt nz} to pass to AMD, make sure that you handle the
+{\tt n} = 0 and {\tt nz = 0} cases correctly.
+
+%------------------------------------------------------------------------------
+\section{Synopsis of C-callable routines}
+\label{Synopsis}
+%------------------------------------------------------------------------------
+
+The matrix $\m{A}$ is {\tt n}-by-{\tt n} with {\tt nz} entries.
+
+{\footnotesize
+\begin{verbatim}
+#include "amd.h"
+int n, status, Ap [n+1], Ai [nz], P [n] ;
+double Control [AMD_CONTROL], Info [AMD_INFO] ;
+amd_defaults (Control) ;
+status = amd_order (n, Ap, Ai, P, Control, Info) ;
+amd_control (Control) ;
+amd_info (Info) ;
+status = amd_valid (n, n, Ap, Ai) ;
+\end{verbatim}
+}
+
+The {\tt amd\_l\_*} routines are identical, except that all {\tt int}
+arguments become {\tt long}:
+
+{\footnotesize
+\begin{verbatim}
+#include "amd.h"
+long n, status, Ap [n+1], Ai [nz], P [n] ;
+double Control [AMD_CONTROL], Info [AMD_INFO] ;
+amd_l_defaults (Control) ;
+status = amd_l_order (n, Ap, Ai, P, Control, Info) ;
+amd_l_control (Control) ;
+amd_l_info (Info) ;
+status = amd_l_valid (n, n, Ap, Ai) ;
+\end{verbatim}
+}
+
+%------------------------------------------------------------------------------
+\section{Using AMD in a Fortran program}
+%------------------------------------------------------------------------------
+
+Two Fortran versions of AMD are provided.  The {\tt AMD} routine computes the
+approximate minimum degree ordering, using aggressive absorption.  The
+{\tt AMDBAR} routine is identical, except that it does not perform aggressive
+absorption.  The {\tt AMD} routine is essentially identical to the HSL
+routine {\tt MC47B/BD}.
+Note that earlier versions of the Fortran
+{\tt AMD} and {\tt AMDBAR} routines included an {\tt IOVFLO} argument,
+which is no longer present.
+
+In contrast to the C version, the Fortran routines require a symmetric
+nonzero pattern, with no diagonal entries present although the {\tt MC47A/AD}
+wrapper in HSL allows duplicates, ignores out-of-range entries, and only
+uses entries from the upper triangular part of the matrix.  Although we
+have an experimental Fortran code for treating ``dense'' rows, the Fortran
+codes in this release do not treat
+``dense'' rows and columns of $\m{A}$ differently, and thus their run time
+can be high if there are a few dense rows and columns in the matrix.
+They do not perform a post-ordering of the elimination tree,
+compute statistics on the ordering, or check the validity of their input
+arguments. These facilities are provided by {\tt MC47A/AD} and other
+subroutines from HSL.
+Only one {\tt integer}
+version of each Fortran routine is provided.  
+Both Fortran routines overwrite the user's input
+matrix, in contrast to the C version.  
+%
+The C version does not return the elimination or assembly tree.
+The Fortran version returns an assembly tree;
+refer to the User Guide for details.
+The following is the syntax of the {\tt AMD} Fortran routine.
+The {\tt AMDBAR} routine is identical except for the routine name.
+
+{\footnotesize
+\begin{verbatim}
+        INTEGER N, IWLEN, PFREE, NCMPA, IW (IWLEN), PE (N), DEGREE (N), NV (N),
+     $          NEXT (N), LAST (N), HEAD (N), ELEN (N), W (N), LEN (N)
+        CALL AMD (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT,
+     $          LAST, HEAD, ELEN, DEGREE, NCMPA, W)
+        CALL AMDBAR (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT,
+     $          LAST, HEAD, ELEN, DEGREE, NCMPA, W)
+\end{verbatim}
+}
+
+The input matrix is provided to {\tt AMD} and {\tt AMDBAR}
+in three arrays, {\tt PE}, of size {\tt N},
+{\tt LEN}, of size {\tt N}, and {\tt IW}, of size {\tt IWLEN}.  The size of
+{\tt IW} must be at least {\tt NZ+N}.  The recommended size is
+{\tt 1.2*NZ + N}.
+On input, the indices of nonzero entries in row {\tt I} are stored in {\tt IW}.
+{\tt PE(I)} is the index in {\tt IW} of the start of row {\tt I}.
+{\tt LEN(I)} is the number of entries in row {\tt I}.
+The matrix is 1-based, with row and column indices in the range 1 to {\tt N}.
+Row {\tt I} is contained in
+{\tt IW (PE(I)} $\ldots \:$ {\tt PE(I) + LEN(I) - 1)}.
+The diagonal entries must not be present.  The indices within each row must
+not contain any duplicates, but they need not be sorted.  The rows
+themselves need not be in any particular order, and there may be empty space
+between the rows.  If {\tt LEN(I)} is zero, then there are no off-diagonal
+entries in row {\tt I}, and {\tt PE(I)} is ignored.  The integer
+{\tt PFREE} defines what part of {\tt IW} contains the user's input matrix,
+which is held in {\tt IW(1}~$\ldots~\:${\tt PFREE-1)}.
+The contents of {\tt IW} and {\tt LEN} are undefined on output,
+and {\tt PE} is modified to contain information about the ordering.
+
+As the algorithm proceeds, it modifies the {\tt IW} array, placing the
+pattern of the partially eliminated matrix in
+{\tt IW(PFREE} $\ldots \:${\tt IWLEN)}.
+If this space is exhausted, the space is compressed.
+The number of compressions performed on the {\tt IW} array is
+returned in the scalar {\tt NCMPA}.  The value of {\tt PFREE} on output is the
+length of {\tt IW} required for no compressions to be needed.
+
+The output permutation is returned in the array {\tt LAST}, of size {\tt N}.
+If {\tt I=LAST(K)}, then {\tt I} is the {\tt K}th row in the permuted
+matrix.  The inverse permutation is returned in the array {\tt ELEN}, where
+{\tt K=ELEN(I)} if {\tt I} is the {\tt K}th row in the permuted matrix.
+On output, the {\tt PE} and {\tt NV} arrays hold the assembly tree,
+a supernodal elimination tree that represents the relationship between
+columns of the Cholesky factor $\m{L}$.
+If {\tt NV(I)} $> 0$, then {\tt I} is a node in the assembly
+tree, and the parent of {\tt I} is {\tt -PE(I)}.  If {\tt I} is a root of
+the tree, then {\tt PE(I)} is zero.  The value of {\tt NV(I)} is the
+number of entries in the corresponding column of $\m{L}$, including the
+diagonal.
+If {\tt NV(I)} is zero, then {\tt I} is a non-principal node that is
+not in the assembly tree.  Node {\tt -PE(I)} is the parent of node {\tt I}
+in a subtree, the root of which is a node in the assembly tree.  All nodes
+in one subtree belong to the same supernode in the assembly tree.
+The other size {\tt N} arrays
+({\tt DEGREE}, {\tt HEAD}, {\tt NEXT}, and {\tt W}) are used as workspace,
+and are not defined on input or output.
+
+If you want to use a simpler user-interface and compute the elimination
+tree post-ordering, you should be able to call the C routines {\tt amd\_order}
+or {\tt amd\_l\_order} from a Fortran program.   Just be sure to take into
+account the 0-based indexing in the {\tt P}, {\tt Ap}, and {\tt Ai} arguments
+to {\tt amd\_order} and {\tt amd\_l\_order}.  A sample interface is provided
+in the files {\tt AMD/Demo/amd\_f77cross.f} and
+{\tt AMD/Demo/amd\_f77wrapper.c}.  To compile the {\tt amd\_f77cross} program,
+type {\tt make cross} in the {\tt AMD/Demo} directory.  The
+Fortran-to-C calling conventions are highly non-portable, so this example
+is not guaranteed to work with your compiler C and Fortran compilers.
+The output of {\tt amd\_f77cross} is in {\tt amd\_f77cross.out}.
+
+%------------------------------------------------------------------------------
+\section{Sample Fortran main program}
+%------------------------------------------------------------------------------
+
+The following program illustrates the basic usage of the Fortran version of AMD.
+The {\tt AP} and {\tt AI} arrays represent the binary matrix
+\[
+\m{A} = \left[
+\begin{array}{rrrrr}
+ 1 &  1 &  0 &  0 &  0 \\
+ 1 &  1 &  1 &  0 &  1 \\
+ 0 &  1 &  1 &  1 &  1 \\
+ 0 &  0 &  1 &  1 &  0 \\
+ 0 &  1 &  1 &  0 &  1 \\
+\end{array}
+\right]
+\]
+in a conventional 1-based column-oriented form,
+except that the diagonal entries are not present.
+The matrix has the same as nonzero pattern of $\m{A}+\m{A}\tr$ in the C
+program, in Section~\ref{Cversion}.
+The output permutation is $(4, 1, 3, 5, 2)$.
+It differs from the permutation returned by the C routine {\tt amd\_order}
+because a post-order of the elimination tree has not yet been performed.
+
+{\footnotesize
+\begin{verbatim}
+        INTEGER N, NZ, J, K, P, IWLEN, PFREE, NCMPA
+        PARAMETER (N = 5, NZ = 10, IWLEN = 17)
+        INTEGER AP (N+1), AI (NZ), LAST (N), PE (N), LEN (N), ELEN (N),
+     $      IW (IWLEN), DEGREE (N), NV (N), NEXT (N), HEAD (N), W (N)
+        DATA AP / 1, 2,     5,     8,  9,  11/
+        DATA AI / 2, 1,3,5, 2,4,5, 3,  2,3   /
+C       load the matrix into the AMD workspace
+        DO 10 J = 1,N
+            PE (J) = AP (J)
+            LEN (J) = AP (J+1) - AP (J)
+10      CONTINUE
+        DO 20 P = 1,NZ
+            IW (P) = AI (P)
+20      CONTINUE
+        PFREE = NZ + 1
+C       order the matrix (destroys the copy of A in IW, PE, and LEN)
+        CALL AMD (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT, LAST, HEAD,
+     $      ELEN, DEGREE, NCMPA, W)
+        DO 60 K = 1, N
+            PRINT 50, K, LAST (K)
+50          FORMAT ('P (',I2,') = ', I2)
+60      CONTINUE
+        END
+\end{verbatim}
+}
+
+The {\tt Demo} directory contains an example of how the C version
+may be called from a Fortran program, but this is highly non-portable.
+For this reason, it is placed in the {\tt Demo} directory, not in the
+primary {\tt Source} directory.
+
+%------------------------------------------------------------------------------
+\section{Installation}
+\label{Install}
+%------------------------------------------------------------------------------
+
+The following discussion assumes you have the {\tt make} program, either in
+Unix, or in Windows with Cygwin.
+
+System-dependent configurations are in the {\tt ../UFconfig/UFconfig.mk}
+file.  You can edit that file to customize the compilation.  The default
+settings will work on most systems.
+Sample configuration files are provided
+for Linux, Sun Solaris, SGI IRIX, IBM AIX, and the DEC/Compaq Alpha.
+
+To compile and install the C-callable AMD library,
+go to the {\tt AMD} directory and type {\tt make}.
+The library will be placed in {\tt AMD/Lib/libamd.a}.
+Three demo programs of the AMD ordering routine will be compiled and tested in
+the {\tt AMD/Demo} directory.
+The outputs of these demo programs will then be compared with output
+files in the distribution.
+
+To compile and install the Fortran-callable AMD library,
+go to the {\tt AMD} directory and type {\tt make fortran}.
+The library will be placed in {\tt AMD/Lib/libamdf77.a}.
+A demo program will be compiled and tested in the {\tt AMD/Demo} directory.
+The output will be compared with an output file in the distribution.
+
+Typing {\tt make clean} will remove all but the final compiled libraries
+and demo programs.  Typing {\tt make purge} or {\tt make distclean}
+removes all files not in the original distribution.
+If you compile AMD and then later change the {\tt ../UFconfig/UFconfig.mk} file
+then you should type {\tt make purge} and then {\tt make} to recompile.
+
+When you compile your program that uses the C-callable AMD library,
+you need to add the {\tt AMD/Lib/libamd.a} library
+and you need to tell your compiler to look in the
+{\tt AMD/Include} directory for include
+files.   To compile a Fortran program that calls the Fortran AMD library,
+you need to add the {\tt AMD/Lib/libamdf77.a} library.
+See {\tt AMD/Demo/Makefile} for an example.
+
+If all you want to use is the AMD2 mexFunction in MATLAB, you can skip
+the use of the {\tt make} command entirely.  Simply type
+{\tt amd\_make} in MATLAB while in the {\tt AMD/MATLAB} directory.
+This works on any system with MATLAB, including Windows.
+Alternately, type {\tt make} in the {\tt AMD/MATLAB} directory,
+or just use the built-in {\tt amd} in MATLAB 7.3 or later.
+
+If you are including AMD as a subset of a larger library and do not want
+to link the C standard I/O library, or if you simply do not need to use
+them, you can safely remove the {\tt amd\_control.c} and {\tt amd\_info.c}
+files.  Similarly, if you use default parameters (or define your
+own {\tt Control} array), then you can exclude the {\tt amd\_defaults.c}
+file.
+Each of these files contains the user-callable routines of the same
+name.  None of these auxiliary routines are directly called by
+{\tt amd\_order}.
+The {\tt amd\_dump.c} file contains debugging routines
+that are neither used nor compiled unless debugging is enabled.
+The {\tt amd\_internal.h} file must be edited to enable debugging;
+refer to the instructions in that file.
+The bare minimum files required to use just {\tt amd\_order} are
+{\tt amd.h} and {\tt amd\_internal.h}
+in the {\tt Include} directory,
+and
+{\tt amd\_1.c},
+{\tt amd\_2.c},
+{\tt amd\_aat.c},
+{\tt amd\_global.c},
+{\tt and\_order.c},
+{\tt amd\_postorder.c},
+{\tt amd\_post\_tree.c},
+{\tt amd\_preprocess.c},
+and
+{\tt amd\_valid.c}
+in the {\tt Source} directory.
+
+%------------------------------------------------------------------------------
+\newpage
+\section{The AMD routines}
+\label{Primary}
+%------------------------------------------------------------------------------
+
+The file {\tt AMD/Include/amd.h} listed below
+describes each user-callable routine in the C version of AMD,
+and gives details on their use.
+
+{\footnotesize
+\begin{verbatim}
+/* ========================================================================= */
+/* === AMD:  approximate minimum degree ordering =========================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 2.0, Copyright (c) 2006 by Timothy A. Davis,                  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* AMD finds a symmetric ordering P of a matrix A so that the Cholesky
+ * factorization of P*A*P' has fewer nonzeros and takes less work than the
+ * Cholesky factorization of A.  If A is not symmetric, then it performs its
+ * ordering on the matrix A+A'.  Two sets of user-callable routines are
+ * provided, one for int integers and the other for UF_long integers.
+ *
+ * The method is based on the approximate minimum degree algorithm, discussed
+ * in Amestoy, Davis, and Duff, "An approximate degree ordering algorithm",
+ * SIAM Journal of Matrix Analysis and Applications, vol. 17, no. 4, pp.
+ * 886-905, 1996.  This package can perform both the AMD ordering (with
+ * aggressive absorption), and the AMDBAR ordering (without aggressive
+ * absorption) discussed in the above paper.  This package differs from the
+ * Fortran codes discussed in the paper:
+ *
+ *      (1) it can ignore "dense" rows and columns, leading to faster run times
+ *      (2) it computes the ordering of A+A' if A is not symmetric
+ *      (3) it is followed by a depth-first post-ordering of the assembly tree
+ *          (or supernodal elimination tree)
+ *
+ * For historical reasons, the Fortran versions, amd.f and amdbar.f, have
+ * been left (nearly) unchanged.  They compute the identical ordering as
+ * described in the above paper.
+ */
+
+#ifndef AMD_H
+#define AMD_H
+
+/* make it easy for C++ programs to include AMD */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* get the definition of size_t: */
+#include <stddef.h>
+
+/* define UF_long */
+#include "UFconfig.h"
+
+int amd_order               /* returns AMD_OK, AMD_OK_BUT_JUMBLED,
+                             * AMD_INVALID, or AMD_OUT_OF_MEMORY */
+(
+    int n,                  /* A is n-by-n.  n must be >= 0. */
+    const int Ap [ ],       /* column pointers for A, of size n+1 */
+    const int Ai [ ],       /* row indices of A, of size nz = Ap [n] */
+    int P [ ],              /* output permutation, of size n */
+    double Control [ ],     /* input Control settings, of size AMD_CONTROL */
+    double Info [ ]         /* output Info statistics, of size AMD_INFO */
+) ;
+
+UF_long amd_l_order         /* see above for description of arguments */
+(
+    UF_long n,
+    const UF_long Ap [ ],
+    const UF_long Ai [ ],
+    UF_long P [ ],
+    double Control [ ],
+    double Info [ ]
+) ;
+
+/* Input arguments (not modified):
+ *
+ *      n: the matrix A is n-by-n.
+ *      Ap: an int/UF_long array of size n+1, containing column pointers of A.
+ *      Ai: an int/UF_long array of size nz, containing the row indices of A,
+ *          where nz = Ap [n].
+ *      Control:  a double array of size AMD_CONTROL, containing control
+ *          parameters.  Defaults are used if Control is NULL.
+ *
+ * Output arguments (not defined on input):
+ *
+ *      P: an int/UF_long array of size n, containing the output permutation. If
+ *          row i is the kth pivot row, then P [k] = i.  In MATLAB notation,
+ *          the reordered matrix is A (P,P).
+ *      Info: a double array of size AMD_INFO, containing statistical
+ *          information.  Ignored if Info is NULL.
+ *
+ * On input, the matrix A is stored in column-oriented form.  The row indices
+ * of nonzero entries in column j are stored in Ai [Ap [j] ... Ap [j+1]-1].
+ *
+ * If the row indices appear in ascending order in each column, and there
+ * are no duplicate entries, then amd_order is slightly more efficient in
+ * terms of time and memory usage.  If this condition does not hold, a copy
+ * of the matrix is created (where these conditions do hold), and the copy is
+ * ordered.  This feature is new to v2.0 (v1.2 and earlier required this
+ * condition to hold for the input matrix).
+ * 
+ * Row indices must be in the range 0 to
+ * n-1.  Ap [0] must be zero, and thus nz = Ap [n] is the number of nonzeros
+ * in A.  The array Ap is of size n+1, and the array Ai is of size nz = Ap [n].
+ * The matrix does not need to be symmetric, and the diagonal does not need to
+ * be present (if diagonal entries are present, they are ignored except for
+ * the output statistic Info [AMD_NZDIAG]).  The arrays Ai and Ap are not
+ * modified.  This form of the Ap and Ai arrays to represent the nonzero
+ * pattern of the matrix A is the same as that used internally by MATLAB.
+ * If you wish to use a more flexible input structure, please see the
+ * umfpack_*_triplet_to_col routines in the UMFPACK package, at
+ * http://www.cise.ufl.edu/research/sparse/umfpack.
+ *
+ * Restrictions:  n >= 0.  Ap [0] = 0.  Ap [j] <= Ap [j+1] for all j in the
+ *      range 0 to n-1.  nz = Ap [n] >= 0.  Ai [0..nz-1] must be in the range 0
+ *      to n-1.  Finally, Ai, Ap, and P must not be NULL.  If any of these
+ *      restrictions are not met, AMD returns AMD_INVALID.
+ *
+ * AMD returns:
+ *
+ *      AMD_OK if the matrix is valid and sufficient memory can be allocated to
+ *          perform the ordering.
+ *
+ *      AMD_OUT_OF_MEMORY if not enough memory can be allocated.
+ *
+ *      AMD_INVALID if the input arguments n, Ap, Ai are invalid, or if P is
+ *          NULL.
+ *
+ *      AMD_OK_BUT_JUMBLED if the matrix had unsorted columns, and/or duplicate
+ *          entries, but was otherwise valid.
+ *
+ * The AMD routine first forms the pattern of the matrix A+A', and then
+ * computes a fill-reducing ordering, P.  If P [k] = i, then row/column i of
+ * the original is the kth pivotal row.  In MATLAB notation, the permuted
+ * matrix is A (P,P), except that 0-based indexing is used instead of the
+ * 1-based indexing in MATLAB.
+ *
+ * The Control array is used to set various parameters for AMD.  If a NULL
+ * pointer is passed, default values are used.  The Control array is not
+ * modified.
+ *
+ *      Control [AMD_DENSE]:  controls the threshold for "dense" rows/columns.
+ *          A dense row/column in A+A' can cause AMD to spend a lot of time in
+ *          ordering the matrix.  If Control [AMD_DENSE] >= 0, rows/columns
+ *          with more than Control [AMD_DENSE] * sqrt (n) entries are ignored
+ *          during the ordering, and placed last in the output order.  The
+ *          default value of Control [AMD_DENSE] is 10.  If negative, no
+ *          rows/columns are treated as "dense".  Rows/columns with 16 or
+ *          fewer off-diagonal entries are never considered "dense".
+ *
+ *      Control [AMD_AGGRESSIVE]: controls whether or not to use aggressive
+ *          absorption, in which a prior element is absorbed into the current
+ *          element if is a subset of the current element, even if it is not
+ *          adjacent to the current pivot element (refer to Amestoy, Davis,
+ *          & Duff, 1996, for more details).  The default value is nonzero,
+ *          which means to perform aggressive absorption.  This nearly always
+ *          leads to a better ordering (because the approximate degrees are
+ *          more accurate) and a lower execution time.  There are cases where
+ *          it can lead to a slightly worse ordering, however.  To turn it off,
+ *          set Control [AMD_AGGRESSIVE] to 0.
+ *
+ *      Control [2..4] are not used in the current version, but may be used in
+ *          future versions.
+ *
+ * The Info array provides statistics about the ordering on output.  If it is
+ * not present, the statistics are not returned.  This is not an error
+ * condition.
+ * 
+ *      Info [AMD_STATUS]:  the return value of AMD, either AMD_OK,
+ *          AMD_OK_BUT_JUMBLED, AMD_OUT_OF_MEMORY, or AMD_INVALID.
+ *
+ *      Info [AMD_N]: n, the size of the input matrix
+ *
+ *      Info [AMD_NZ]: the number of nonzeros in A, nz = Ap [n]
+ *
+ *      Info [AMD_SYMMETRY]:  the symmetry of the matrix A.  It is the number
+ *          of "matched" off-diagonal entries divided by the total number of
+ *          off-diagonal entries.  An entry A(i,j) is matched if A(j,i) is also
+ *          an entry, for any pair (i,j) for which i != j.  In MATLAB notation,
+ *              S = spones (A) ;
+ *              B = tril (S, -1) + triu (S, 1) ;
+ *              symmetry = nnz (B & B') / nnz (B) ;
+ *
+ *      Info [AMD_NZDIAG]: the number of entries on the diagonal of A.
+ *
+ *      Info [AMD_NZ_A_PLUS_AT]:  the number of nonzeros in A+A', excluding the
+ *          diagonal.  If A is perfectly symmetric (Info [AMD_SYMMETRY] = 1)
+ *          with a fully nonzero diagonal, then Info [AMD_NZ_A_PLUS_AT] = nz-n
+ *          (the smallest possible value).  If A is perfectly unsymmetric
+ *          (Info [AMD_SYMMETRY] = 0, for an upper triangular matrix, for
+ *          example) with no diagonal, then Info [AMD_NZ_A_PLUS_AT] = 2*nz
+ *          (the largest possible value).
+ *
+ *      Info [AMD_NDENSE]: the number of "dense" rows/columns of A+A' that were
+ *          removed from A prior to ordering.  These are placed last in the
+ *          output order P.
+ *
+ *      Info [AMD_MEMORY]: the amount of memory used by AMD, in bytes.  In the
+ *          current version, this is 1.2 * Info  [AMD_NZ_A_PLUS_AT] + 9*n
+ *          times the size of an integer.  This is at most 2.4nz + 9n.  This
+ *          excludes the size of the input arguments Ai, Ap, and P, which have
+ *          a total size of nz + 2*n + 1 integers.
+ *
+ *      Info [AMD_NCMPA]: the number of garbage collections performed.
+ *
+ *      Info [AMD_LNZ]: the number of nonzeros in L (excluding the diagonal).
+ *          This is a slight upper bound because mass elimination is combined
+ *          with the approximate degree update.  It is a rough upper bound if
+ *          there are many "dense" rows/columns.  The rest of the statistics,
+ *          below, are also slight or rough upper bounds, for the same reasons.
+ *          The post-ordering of the assembly tree might also not exactly
+ *          correspond to a true elimination tree postordering.
+ *
+ *      Info [AMD_NDIV]: the number of divide operations for a subsequent LDL'
+ *          or LU factorization of the permuted matrix A (P,P).
+ *
+ *      Info [AMD_NMULTSUBS_LDL]:  the number of multiply-subtract pairs for a
+ *          subsequent LDL' factorization of A (P,P).
+ *
+ *      Info [AMD_NMULTSUBS_LU]:  the number of multiply-subtract pairs for a
+ *          subsequent LU factorization of A (P,P), assuming that no numerical
+ *          pivoting is required.
+ *
+ *      Info [AMD_DMAX]:  the maximum number of nonzeros in any column of L,
+ *          including the diagonal.
+ *
+ *      Info [14..19] are not used in the current version, but may be used in
+ *          future versions.
+ */    
+
+/* ------------------------------------------------------------------------- */
+/* direct interface to AMD */
+/* ------------------------------------------------------------------------- */
+
+/* amd_2 is the primary AMD ordering routine.  It is not meant to be
+ * user-callable because of its restrictive inputs and because it destroys
+ * the user's input matrix.  It does not check its inputs for errors, either.
+ * However, if you can work with these restrictions it can be faster than
+ * amd_order and use less memory (assuming that you can create your own copy
+ * of the matrix for AMD to destroy).  Refer to AMD/Source/amd_2.c for a
+ * description of each parameter. */
+
+void amd_2
+(
+    int n,
+    int Pe [ ],
+    int Iw [ ],
+    int Len [ ],
+    int iwlen,
+    int pfree,
+    int Nv [ ],
+    int Next [ ], 
+    int Last [ ],
+    int Head [ ],
+    int Elen [ ],
+    int Degree [ ],
+    int W [ ],
+    double Control [ ],
+    double Info [ ]
+) ;
+
+void amd_l2
+(
+    UF_long n,
+    UF_long Pe [ ],
+    UF_long Iw [ ],
+    UF_long Len [ ],
+    UF_long iwlen,
+    UF_long pfree,
+    UF_long Nv [ ],
+    UF_long Next [ ], 
+    UF_long Last [ ],
+    UF_long Head [ ],
+    UF_long Elen [ ],
+    UF_long Degree [ ],
+    UF_long W [ ],
+    double Control [ ],
+    double Info [ ]
+) ;
+
+/* ------------------------------------------------------------------------- */
+/* amd_valid */
+/* ------------------------------------------------------------------------- */
+
+/* Returns AMD_OK or AMD_OK_BUT_JUMBLED if the matrix is valid as input to
+ * amd_order; the latter is returned if the matrix has unsorted and/or
+ * duplicate row indices in one or more columns.  Returns AMD_INVALID if the
+ * matrix cannot be passed to amd_order.  For amd_order, the matrix must also
+ * be square.  The first two arguments are the number of rows and the number
+ * of columns of the matrix.  For its use in AMD, these must both equal n.
+ *
+ * NOTE: this routine returned TRUE/FALSE in v1.2 and earlier.
+ */
+
+int amd_valid
+(
+    int n_row,              /* # of rows */
+    int n_col,              /* # of columns */
+    const int Ap [ ],       /* column pointers, of size n_col+1 */
+    const int Ai [ ]        /* row indices, of size Ap [n_col] */
+) ;
+
+UF_long amd_l_valid
+(
+    UF_long n_row,
+    UF_long n_col,
+    const UF_long Ap [ ],
+    const UF_long Ai [ ]
+) ;
+
+/* ------------------------------------------------------------------------- */
+/* AMD memory manager and printf routines */
+/* ------------------------------------------------------------------------- */
+
+/* The user can redefine these to change the malloc, free, and printf routines
+ * that AMD uses. */
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+EXTERN void *(*amd_malloc) (size_t) ;               /* pointer to malloc */
+EXTERN void (*amd_free) (void *) ;                  /* pointer to free */
+EXTERN void *(*amd_realloc) (void *, size_t) ;      /* pointer to realloc */
+EXTERN void *(*amd_calloc) (size_t, size_t) ;       /* pointer to calloc */
+EXTERN int (*amd_printf) (const char *, ...) ;      /* pointer to printf */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Control and Info arrays */
+/* ------------------------------------------------------------------------- */
+
+/* amd_defaults:  sets the default control settings */
+void amd_defaults   (double Control [ ]) ;
+void amd_l_defaults (double Control [ ]) ;
+
+/* amd_control: prints the control settings */
+void amd_control    (double Control [ ]) ;
+void amd_l_control  (double Control [ ]) ;
+
+/* amd_info: prints the statistics */
+void amd_info       (double Info [ ]) ;
+void amd_l_info     (double Info [ ]) ;
+
+#define AMD_CONTROL 5       /* size of Control array */
+#define AMD_INFO 20         /* size of Info array */
+
+/* contents of Control */
+#define AMD_DENSE 0         /* "dense" if degree > Control [0] * sqrt (n) */
+#define AMD_AGGRESSIVE 1    /* do aggressive absorption if Control [1] != 0 */
+
+/* default Control settings */
+#define AMD_DEFAULT_DENSE 10.0      /* default "dense" degree 10*sqrt(n) */
+#define AMD_DEFAULT_AGGRESSIVE 1    /* do aggressive absorption by default */
+
+/* contents of Info */
+#define AMD_STATUS 0        /* return value of amd_order and amd_l_order */
+#define AMD_N 1             /* A is n-by-n */
+#define AMD_NZ 2            /* number of nonzeros in A */ 
+#define AMD_SYMMETRY 3      /* symmetry of pattern (1 is sym., 0 is unsym.) */
+#define AMD_NZDIAG 4        /* # of entries on diagonal */
+#define AMD_NZ_A_PLUS_AT 5  /* nz in A+A' */
+#define AMD_NDENSE 6        /* number of "dense" rows/columns in A */
+#define AMD_MEMORY 7        /* amount of memory used by AMD */
+#define AMD_NCMPA 8         /* number of garbage collections in AMD */
+#define AMD_LNZ 9           /* approx. nz in L, excluding the diagonal */
+#define AMD_NDIV 10         /* number of fl. point divides for LU and LDL' */
+#define AMD_NMULTSUBS_LDL 11 /* number of fl. point (*,-) pairs for LDL' */
+#define AMD_NMULTSUBS_LU 12  /* number of fl. point (*,-) pairs for LU */
+#define AMD_DMAX 13          /* max nz. in any column of L, incl. diagonal */
+
+/* ------------------------------------------------------------------------- */
+/* return values of AMD */
+/* ------------------------------------------------------------------------- */
+
+#define AMD_OK 0                /* success */
+#define AMD_OUT_OF_MEMORY -1    /* malloc failed, or problem too large */
+#define AMD_INVALID -2          /* input arguments are not valid */
+#define AMD_OK_BUT_JUMBLED 1    /* input matrix is OK for amd_order, but
+    * columns were not sorted, and/or duplicate entries were present.  AMD had
+    * to do extra work before ordering the matrix.  This is a warning, not an
+    * error.  */
+
+/* ========================================================================== */
+/* === AMD version ========================================================== */
+/* ========================================================================== */
+
+/* AMD Version 1.2 and later include the following definitions.
+ * As an example, to test if the version you are using is 1.2 or later:
+ *
+ * #ifdef AMD_VERSION
+ *      if (AMD_VERSION >= AMD_VERSION_CODE (1,2)) ...
+ * #endif
+ *
+ * This also works during compile-time:
+ *
+ *      #if defined(AMD_VERSION) && (AMD_VERSION >= AMD_VERSION_CODE (1,2))
+ *          printf ("This is version 1.2 or later\n") ;
+ *      #else
+ *          printf ("This is an early version\n") ;
+ *      #endif
+ *
+ * Versions 1.1 and earlier of AMD do not include a #define'd version number.
+ */
+
+#define AMD_DATE "Dec 12, 2006"
+#define AMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub))
+#define AMD_MAIN_VERSION 2
+#define AMD_SUB_VERSION 0
+#define AMD_SUBSUB_VERSION 4
+#define AMD_VERSION AMD_VERSION_CODE(AMD_MAIN_VERSION,AMD_SUB_VERSION)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+\end{verbatim}
+}
+
+
+%------------------------------------------------------------------------------
+\newpage
+% References
+%------------------------------------------------------------------------------
+
+\bibliographystyle{plain}
+\bibliography{AMD_UserGuide}
+
+\end{document}
diff --git a/src/C/SuiteSparse/AMD/Doc/ChangeLog b/src/C/SuiteSparse/AMD/Doc/ChangeLog
new file mode 100644
index 0000000..da57054
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Doc/ChangeLog
@@ -0,0 +1,121 @@
+Dec 12, 2006, version 2.0.4
+
+    * minor MATLAB code cleanup
+
+Nov 29, 2006, version 2.0.3
+
+    * changed MATLAB function name to amd2, so as not to conflict with
+	the now built-in version of AMD in MATLAB (which is the same thing
+	as the AMD here...).
+
+Sept 28, 2006, version 2.0.2
+
+    * #define SIZE_T_MAX not done if already defined (Mac OSX).
+
+Aug 31, 2006:
+
+    * trivial change to comments in amd.m
+
+Apr 30, 2006: AMD Version 2.0:
+
+    * long integer redefined as UF_long, controlled by UFconfig.h.
+
+    * amd_order no longer requires its input to have sorted columns.  It can
+	also tolerate duplicate entries in each column.  If these conditions
+	hold, but the matrix is otherwise valid, amd_order returns
+	AMD_OK_BUT_JUMBLED (a warning, not an error).
+
+    * amd_preprocess no longer deemed user-callable, since it is no longer
+	needed (it was used to ensure the input matrix had sorted columns with
+	no duplicate entries).  It still exists, with additional parameters,
+	and is called by amd_order if necessary.  amd_wpreprocess and
+	amd_preprocess_valid removed.  Fortran interface routine amdpreproc
+	removed.
+
+    * Integer overflow computations modified, to extend the size of problem
+	that the "int" version can solve when used in an LP64 compilation.
+
+    * amd_demo2.c simplified (it tests AMD with a jumbled matrix).
+
+    * amd_valid returned TRUE/FALSE in v1.2.  It now returns AMD_OK,
+	AMD_OK_BUT_JUMBLED, or AMD_INVALID.  Only in the latter case is the
+	matrix unsuitable as input to amd_order.
+
+    * amd_internal.h include file moved from AMD/Source to AMD/Include.
+
+Nov 15, 2005:
+
+    * minor editting of comments; version number (1.2) unchanged.
+
+Aug. 30, 2005: AMD Version 1.2
+
+    * AMD v1.2 is upward compatible with v1.1 and v1.0, except that v1.2 no
+	longer includes the compile-time redefinition of malloc and free.
+
+    * Makefile modified to use UFconfig.mk.  "Make" directory removed.
+
+    * License changed to GNU LGPL.
+
+    * Easier inclusion in C++ programs.
+
+    * option to allow compile-time redefinition of malloc and free
+	(added to v1.1) removed for v1.2.  Replaced with a run-time
+	redefinition.  AMD includes function pointers for malloc, free,
+	calloc, realloc, and printf, so that all those routines can be
+	redefined at compile time.  These function pointers are global
+	variables, and so are not technically thread-safe, unless you
+	use defaults and don't need to change them (the common case)
+	or if you change them in one thread before using them in other
+	threads.
+
+    * added #define'd version number
+
+    * minor modification to AMD_2 to ensure all lines can be tested, without
+	conditional compilation.
+
+    * moved the prototype for AMD_2 from amd_internal.h to amd.h
+
+    * moved the prototype for AMD_valid from amd_internal.h to amd.h
+
+    * MATLAB mexFunction uses libamd.a (compiled with cc) instead of compiling
+	each AMD source file with the mex command
+
+    * long demo (amd_l_demo.c) added.
+
+Jan. 21, 2004: AMD Version 1.1
+
+    * No bugs found or fixed - new features added, only
+    * amd_preprocess added, to allow for more general input of the matrix A.
+    * ME=0 added to amd*.f, unused DEXT variable removed from amdbar.f,
+	to avoid spurious compiler warnings (this was not a bug).
+    * amd_demo2.c and amd_demo2.out added, to test/demo amd_preprocess.
+    * option to allow compile-time redefinition of malloc, free, printf added
+    * amd_demo.c shortened slightly (removed printing of PAP')
+    * User Guide modified (more details added)
+    * linewidth reduced from 80 to 79 columns
+
+Oct. 7, 2003:  AMD version 1.0.1.
+
+    * MATLAB mexFunction modified, to remove call to mexCallMATLAB function.
+      This function can take a long time to call, particularly if you are
+      ordering many small matrices.
+
+May 6, 2003:  AMD Version 1.0 released.
+
+    * converted to C (compare amd.f and amdbar.f with amd_2.c)
+    * dense rows/column removed prior to ordering
+    * elimination tree post-ordering added
+    * demos, user guide written
+    * statistics added (nz in L, flop count, symmetry of A)
+    * computes the pattern of A+A' if A is unsymmetric
+    * user's input matrix no longer overwritten
+    * degree lists initialized differently
+    * IOVFLO argument removed from Fortran versions (amd.f and amdbar.f)
+    * parameters added (dense row/column detection, aggressive absorption)
+    * MATLAB mexFunction added
+
+Jan, 1996:
+
+    * amdbar.f posted at http://www.netlib.org (with a restricted License)
+    * amd.f appears as MC47B/BD in the Harwell Subroutine Library
+	(without the IOVFLO argument)
diff --git a/src/C/SuiteSparse/AMD/Doc/License b/src/C/SuiteSparse/AMD/Doc/License
new file mode 100644
index 0000000..52e5087
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Doc/License
@@ -0,0 +1,39 @@
+AMD Version 2.0, Copyright (c) 2006 by Timothy A. Davis,
+Patrick R. Amestoy, and Iain S. Duff.  All Rights Reserved.
+AMD is available under alternate licenses, contact T. Davis for details.
+
+AMD License:
+
+    Your use or distribution of AMD or any modified version of
+    AMD implies that you agree to this License.
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+    USA
+
+    Permission is hereby granted to use or copy this program under the
+    terms of the GNU LGPL, provided that the Copyright, this License,
+    and the Availability of the original version is retained on all copies.
+    User documentation of any code that uses this code or any modified
+    version of this code must cite the Copyright, this License, the
+    Availability note, and "Used by permission." Permission to modify
+    the code and to distribute modified code is granted, provided the
+    Copyright, this License, and the Availability note are retained,
+    and a notice that the code was modified is included.
+
+Availability:
+
+    http://www.cise.ufl.edu/research/sparse/amd
+
+-------------------------------------------------------------------------------
diff --git a/src/C/SuiteSparse/AMD/Doc/Makefile b/src/C/SuiteSparse/AMD/Doc/Makefile
new file mode 100644
index 0000000..8b593fa
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Doc/Makefile
@@ -0,0 +1,33 @@
+#------------------------------------------------------------------------------
+# AMD Makefile for compiling on Unix systems (for GNU or original make)
+#------------------------------------------------------------------------------
+
+default: dist
+
+include ../../UFconfig/UFconfig.mk
+
+#------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#------------------------------------------------------------------------------
+
+clean:
+	- $(RM) $(CLEAN)
+
+purge: distclean
+
+distclean: clean
+	- $(RM) *.aux *.bbl *.blg *.log *.toc
+
+#------------------------------------------------------------------------------
+# Create the User Guide and Quick Start Guide
+#------------------------------------------------------------------------------
+
+AMD_UserGuide.pdf: AMD_UserGuide.tex AMD_UserGuide.bib
+	pdflatex AMD_UserGuide
+	bibtex AMD_UserGuide
+	pdflatex AMD_UserGuide
+	pdflatex AMD_UserGuide
+
+dist:  AMD_UserGuide.pdf
+	- $(RM) *.aux *.bbl *.blg *.log *.toc
+
diff --git a/src/C/SuiteSparse/AMD/Doc/lesser.txt b/src/C/SuiteSparse/AMD/Doc/lesser.txt
new file mode 100644
index 0000000..8add30a
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Doc/lesser.txt
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+

+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+

+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+

+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+

+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+

+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+

+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+

+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+

+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/C/SuiteSparse/AMD/Include/amd.h b/src/C/SuiteSparse/AMD/Include/amd.h
new file mode 100644
index 0000000..4c73b42
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Include/amd.h
@@ -0,0 +1,412 @@
+/* ========================================================================= */
+/* === AMD:  approximate minimum degree ordering =========================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 2.0, Copyright (c) 2006 by Timothy A. Davis,		     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* AMD finds a symmetric ordering P of a matrix A so that the Cholesky
+ * factorization of P*A*P' has fewer nonzeros and takes less work than the
+ * Cholesky factorization of A.  If A is not symmetric, then it performs its
+ * ordering on the matrix A+A'.  Two sets of user-callable routines are
+ * provided, one for int integers and the other for UF_long integers.
+ *
+ * The method is based on the approximate minimum degree algorithm, discussed
+ * in Amestoy, Davis, and Duff, "An approximate degree ordering algorithm",
+ * SIAM Journal of Matrix Analysis and Applications, vol. 17, no. 4, pp.
+ * 886-905, 1996.  This package can perform both the AMD ordering (with
+ * aggressive absorption), and the AMDBAR ordering (without aggressive
+ * absorption) discussed in the above paper.  This package differs from the
+ * Fortran codes discussed in the paper:
+ *
+ *	(1) it can ignore "dense" rows and columns, leading to faster run times
+ *	(2) it computes the ordering of A+A' if A is not symmetric
+ *	(3) it is followed by a depth-first post-ordering of the assembly tree
+ *	    (or supernodal elimination tree)
+ *
+ * For historical reasons, the Fortran versions, amd.f and amdbar.f, have
+ * been left (nearly) unchanged.  They compute the identical ordering as
+ * described in the above paper.
+ */
+
+#ifndef AMD_H
+#define AMD_H
+
+/* make it easy for C++ programs to include AMD */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* get the definition of size_t: */
+#include <stddef.h>
+
+/* define UF_long */
+#include "UFconfig.h"
+
+int amd_order		    /* returns AMD_OK, AMD_OK_BUT_JUMBLED,
+			     * AMD_INVALID, or AMD_OUT_OF_MEMORY */
+(
+    int n,		    /* A is n-by-n.  n must be >= 0. */
+    const int Ap [ ],	    /* column pointers for A, of size n+1 */
+    const int Ai [ ],	    /* row indices of A, of size nz = Ap [n] */
+    int P [ ],		    /* output permutation, of size n */
+    double Control [ ],	    /* input Control settings, of size AMD_CONTROL */
+    double Info [ ]	    /* output Info statistics, of size AMD_INFO */
+) ;
+
+UF_long amd_l_order	    /* see above for description of arguments */
+(
+    UF_long n,
+    const UF_long Ap [ ],
+    const UF_long Ai [ ],
+    UF_long P [ ],
+    double Control [ ],
+    double Info [ ]
+) ;
+
+/* Input arguments (not modified):
+ *
+ *	n: the matrix A is n-by-n.
+ *	Ap: an int/UF_long array of size n+1, containing column pointers of A.
+ *	Ai: an int/UF_long array of size nz, containing the row indices of A,
+ *	    where nz = Ap [n].
+ *	Control:  a double array of size AMD_CONTROL, containing control
+ *	    parameters.  Defaults are used if Control is NULL.
+ *
+ * Output arguments (not defined on input):
+ *
+ *	P: an int/UF_long array of size n, containing the output permutation. If
+ *	    row i is the kth pivot row, then P [k] = i.  In MATLAB notation,
+ *	    the reordered matrix is A (P,P).
+ *	Info: a double array of size AMD_INFO, containing statistical
+ *	    information.  Ignored if Info is NULL.
+ *
+ * On input, the matrix A is stored in column-oriented form.  The row indices
+ * of nonzero entries in column j are stored in Ai [Ap [j] ... Ap [j+1]-1].
+ *
+ * If the row indices appear in ascending order in each column, and there
+ * are no duplicate entries, then amd_order is slightly more efficient in
+ * terms of time and memory usage.  If this condition does not hold, a copy
+ * of the matrix is created (where these conditions do hold), and the copy is
+ * ordered.  This feature is new to v2.0 (v1.2 and earlier required this
+ * condition to hold for the input matrix).
+ * 
+ * Row indices must be in the range 0 to
+ * n-1.  Ap [0] must be zero, and thus nz = Ap [n] is the number of nonzeros
+ * in A.  The array Ap is of size n+1, and the array Ai is of size nz = Ap [n].
+ * The matrix does not need to be symmetric, and the diagonal does not need to
+ * be present (if diagonal entries are present, they are ignored except for
+ * the output statistic Info [AMD_NZDIAG]).  The arrays Ai and Ap are not
+ * modified.  This form of the Ap and Ai arrays to represent the nonzero
+ * pattern of the matrix A is the same as that used internally by MATLAB.
+ * If you wish to use a more flexible input structure, please see the
+ * umfpack_*_triplet_to_col routines in the UMFPACK package, at
+ * http://www.cise.ufl.edu/research/sparse/umfpack.
+ *
+ * Restrictions:  n >= 0.  Ap [0] = 0.  Ap [j] <= Ap [j+1] for all j in the
+ *	range 0 to n-1.  nz = Ap [n] >= 0.  Ai [0..nz-1] must be in the range 0
+ *	to n-1.  Finally, Ai, Ap, and P must not be NULL.  If any of these
+ *	restrictions are not met, AMD returns AMD_INVALID.
+ *
+ * AMD returns:
+ *
+ *	AMD_OK if the matrix is valid and sufficient memory can be allocated to
+ *	    perform the ordering.
+ *
+ *	AMD_OUT_OF_MEMORY if not enough memory can be allocated.
+ *
+ *	AMD_INVALID if the input arguments n, Ap, Ai are invalid, or if P is
+ *	    NULL.
+ *
+ *	AMD_OK_BUT_JUMBLED if the matrix had unsorted columns, and/or duplicate
+ *	    entries, but was otherwise valid.
+ *
+ * The AMD routine first forms the pattern of the matrix A+A', and then
+ * computes a fill-reducing ordering, P.  If P [k] = i, then row/column i of
+ * the original is the kth pivotal row.  In MATLAB notation, the permuted
+ * matrix is A (P,P), except that 0-based indexing is used instead of the
+ * 1-based indexing in MATLAB.
+ *
+ * The Control array is used to set various parameters for AMD.  If a NULL
+ * pointer is passed, default values are used.  The Control array is not
+ * modified.
+ *
+ *	Control [AMD_DENSE]:  controls the threshold for "dense" rows/columns.
+ *	    A dense row/column in A+A' can cause AMD to spend a lot of time in
+ *	    ordering the matrix.  If Control [AMD_DENSE] >= 0, rows/columns
+ *	    with more than Control [AMD_DENSE] * sqrt (n) entries are ignored
+ *	    during the ordering, and placed last in the output order.  The
+ *	    default value of Control [AMD_DENSE] is 10.  If negative, no
+ *	    rows/columns are treated as "dense".  Rows/columns with 16 or
+ *	    fewer off-diagonal entries are never considered "dense".
+ *
+ *	Control [AMD_AGGRESSIVE]: controls whether or not to use aggressive
+ *	    absorption, in which a prior element is absorbed into the current
+ *	    element if is a subset of the current element, even if it is not
+ *	    adjacent to the current pivot element (refer to Amestoy, Davis,
+ *	    & Duff, 1996, for more details).  The default value is nonzero,
+ *	    which means to perform aggressive absorption.  This nearly always
+ *	    leads to a better ordering (because the approximate degrees are
+ *	    more accurate) and a lower execution time.  There are cases where
+ *	    it can lead to a slightly worse ordering, however.  To turn it off,
+ *	    set Control [AMD_AGGRESSIVE] to 0.
+ *
+ *	Control [2..4] are not used in the current version, but may be used in
+ *	    future versions.
+ *
+ * The Info array provides statistics about the ordering on output.  If it is
+ * not present, the statistics are not returned.  This is not an error
+ * condition.
+ * 
+ *	Info [AMD_STATUS]:  the return value of AMD, either AMD_OK,
+ *	    AMD_OK_BUT_JUMBLED, AMD_OUT_OF_MEMORY, or AMD_INVALID.
+ *
+ *	Info [AMD_N]: n, the size of the input matrix
+ *
+ *	Info [AMD_NZ]: the number of nonzeros in A, nz = Ap [n]
+ *
+ *	Info [AMD_SYMMETRY]:  the symmetry of the matrix A.  It is the number
+ *	    of "matched" off-diagonal entries divided by the total number of
+ *	    off-diagonal entries.  An entry A(i,j) is matched if A(j,i) is also
+ *	    an entry, for any pair (i,j) for which i != j.  In MATLAB notation,
+ *		S = spones (A) ;
+ *		B = tril (S, -1) + triu (S, 1) ;
+ *		symmetry = nnz (B & B') / nnz (B) ;
+ *
+ *	Info [AMD_NZDIAG]: the number of entries on the diagonal of A.
+ *
+ *	Info [AMD_NZ_A_PLUS_AT]:  the number of nonzeros in A+A', excluding the
+ *	    diagonal.  If A is perfectly symmetric (Info [AMD_SYMMETRY] = 1)
+ *	    with a fully nonzero diagonal, then Info [AMD_NZ_A_PLUS_AT] = nz-n
+ *	    (the smallest possible value).  If A is perfectly unsymmetric
+ *	    (Info [AMD_SYMMETRY] = 0, for an upper triangular matrix, for
+ *	    example) with no diagonal, then Info [AMD_NZ_A_PLUS_AT] = 2*nz
+ *	    (the largest possible value).
+ *
+ *	Info [AMD_NDENSE]: the number of "dense" rows/columns of A+A' that were
+ *	    removed from A prior to ordering.  These are placed last in the
+ *	    output order P.
+ *
+ *	Info [AMD_MEMORY]: the amount of memory used by AMD, in bytes.  In the
+ *	    current version, this is 1.2 * Info  [AMD_NZ_A_PLUS_AT] + 9*n
+ *	    times the size of an integer.  This is at most 2.4nz + 9n.  This
+ *	    excludes the size of the input arguments Ai, Ap, and P, which have
+ *	    a total size of nz + 2*n + 1 integers.
+ *
+ *	Info [AMD_NCMPA]: the number of garbage collections performed.
+ *
+ *	Info [AMD_LNZ]: the number of nonzeros in L (excluding the diagonal).
+ *	    This is a slight upper bound because mass elimination is combined
+ *	    with the approximate degree update.  It is a rough upper bound if
+ *	    there are many "dense" rows/columns.  The rest of the statistics,
+ *	    below, are also slight or rough upper bounds, for the same reasons.
+ *	    The post-ordering of the assembly tree might also not exactly
+ *	    correspond to a true elimination tree postordering.
+ *
+ *	Info [AMD_NDIV]: the number of divide operations for a subsequent LDL'
+ *	    or LU factorization of the permuted matrix A (P,P).
+ *
+ *	Info [AMD_NMULTSUBS_LDL]:  the number of multiply-subtract pairs for a
+ *	    subsequent LDL' factorization of A (P,P).
+ *
+ *	Info [AMD_NMULTSUBS_LU]:  the number of multiply-subtract pairs for a
+ *	    subsequent LU factorization of A (P,P), assuming that no numerical
+ *	    pivoting is required.
+ *
+ *	Info [AMD_DMAX]:  the maximum number of nonzeros in any column of L,
+ *	    including the diagonal.
+ *
+ *	Info [14..19] are not used in the current version, but may be used in
+ *	    future versions.
+ */    
+
+/* ------------------------------------------------------------------------- */
+/* direct interface to AMD */
+/* ------------------------------------------------------------------------- */
+
+/* amd_2 is the primary AMD ordering routine.  It is not meant to be
+ * user-callable because of its restrictive inputs and because it destroys
+ * the user's input matrix.  It does not check its inputs for errors, either.
+ * However, if you can work with these restrictions it can be faster than
+ * amd_order and use less memory (assuming that you can create your own copy
+ * of the matrix for AMD to destroy).  Refer to AMD/Source/amd_2.c for a
+ * description of each parameter. */
+
+void amd_2
+(
+    int n,
+    int Pe [ ],
+    int Iw [ ],
+    int Len [ ],
+    int iwlen,
+    int pfree,
+    int Nv [ ],
+    int Next [ ], 
+    int Last [ ],
+    int Head [ ],
+    int Elen [ ],
+    int Degree [ ],
+    int W [ ],
+    double Control [ ],
+    double Info [ ]
+) ;
+
+void amd_l2
+(
+    UF_long n,
+    UF_long Pe [ ],
+    UF_long Iw [ ],
+    UF_long Len [ ],
+    UF_long iwlen,
+    UF_long pfree,
+    UF_long Nv [ ],
+    UF_long Next [ ], 
+    UF_long Last [ ],
+    UF_long Head [ ],
+    UF_long Elen [ ],
+    UF_long Degree [ ],
+    UF_long W [ ],
+    double Control [ ],
+    double Info [ ]
+) ;
+
+/* ------------------------------------------------------------------------- */
+/* amd_valid */
+/* ------------------------------------------------------------------------- */
+
+/* Returns AMD_OK or AMD_OK_BUT_JUMBLED if the matrix is valid as input to
+ * amd_order; the latter is returned if the matrix has unsorted and/or
+ * duplicate row indices in one or more columns.  Returns AMD_INVALID if the
+ * matrix cannot be passed to amd_order.  For amd_order, the matrix must also
+ * be square.  The first two arguments are the number of rows and the number
+ * of columns of the matrix.  For its use in AMD, these must both equal n.
+ *
+ * NOTE: this routine returned TRUE/FALSE in v1.2 and earlier.
+ */
+
+int amd_valid
+(
+    int n_row,		    /* # of rows */
+    int n_col,		    /* # of columns */
+    const int Ap [ ],	    /* column pointers, of size n_col+1 */
+    const int Ai [ ]	    /* row indices, of size Ap [n_col] */
+) ;
+
+UF_long amd_l_valid
+(
+    UF_long n_row,
+    UF_long n_col,
+    const UF_long Ap [ ],
+    const UF_long Ai [ ]
+) ;
+
+/* ------------------------------------------------------------------------- */
+/* AMD memory manager and printf routines */
+/* ------------------------------------------------------------------------- */
+
+/* The user can redefine these to change the malloc, free, and printf routines
+ * that AMD uses. */
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+EXTERN void *(*amd_malloc) (size_t) ;		    /* pointer to malloc */
+EXTERN void (*amd_free) (void *) ;		    /* pointer to free */
+EXTERN void *(*amd_realloc) (void *, size_t) ;	    /* pointer to realloc */
+EXTERN void *(*amd_calloc) (size_t, size_t) ;	    /* pointer to calloc */
+EXTERN int (*amd_printf) (const char *, ...) ;	    /* pointer to printf */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Control and Info arrays */
+/* ------------------------------------------------------------------------- */
+
+/* amd_defaults:  sets the default control settings */
+void amd_defaults   (double Control [ ]) ;
+void amd_l_defaults (double Control [ ]) ;
+
+/* amd_control: prints the control settings */
+void amd_control    (double Control [ ]) ;
+void amd_l_control  (double Control [ ]) ;
+
+/* amd_info: prints the statistics */
+void amd_info       (double Info [ ]) ;
+void amd_l_info     (double Info [ ]) ;
+
+#define AMD_CONTROL 5	    /* size of Control array */
+#define AMD_INFO 20	    /* size of Info array */
+
+/* contents of Control */
+#define AMD_DENSE 0	    /* "dense" if degree > Control [0] * sqrt (n) */
+#define AMD_AGGRESSIVE 1    /* do aggressive absorption if Control [1] != 0 */
+
+/* default Control settings */
+#define AMD_DEFAULT_DENSE 10.0	    /* default "dense" degree 10*sqrt(n) */
+#define AMD_DEFAULT_AGGRESSIVE 1    /* do aggressive absorption by default */
+
+/* contents of Info */
+#define AMD_STATUS 0	    /* return value of amd_order and amd_l_order */
+#define AMD_N 1		    /* A is n-by-n */
+#define AMD_NZ 2	    /* number of nonzeros in A */ 
+#define AMD_SYMMETRY 3	    /* symmetry of pattern (1 is sym., 0 is unsym.) */
+#define AMD_NZDIAG 4	    /* # of entries on diagonal */
+#define AMD_NZ_A_PLUS_AT 5  /* nz in A+A' */
+#define AMD_NDENSE 6	    /* number of "dense" rows/columns in A */
+#define AMD_MEMORY 7	    /* amount of memory used by AMD */
+#define AMD_NCMPA 8	    /* number of garbage collections in AMD */
+#define AMD_LNZ 9	    /* approx. nz in L, excluding the diagonal */
+#define AMD_NDIV 10	    /* number of fl. point divides for LU and LDL' */
+#define AMD_NMULTSUBS_LDL 11 /* number of fl. point (*,-) pairs for LDL' */
+#define AMD_NMULTSUBS_LU 12  /* number of fl. point (*,-) pairs for LU */
+#define AMD_DMAX 13	     /* max nz. in any column of L, incl. diagonal */
+
+/* ------------------------------------------------------------------------- */
+/* return values of AMD */
+/* ------------------------------------------------------------------------- */
+
+#define AMD_OK 0		/* success */
+#define AMD_OUT_OF_MEMORY -1	/* malloc failed, or problem too large */
+#define AMD_INVALID -2		/* input arguments are not valid */
+#define AMD_OK_BUT_JUMBLED 1	/* input matrix is OK for amd_order, but
+    * columns were not sorted, and/or duplicate entries were present.  AMD had
+    * to do extra work before ordering the matrix.  This is a warning, not an
+    * error.  */
+
+/* ========================================================================== */
+/* === AMD version ========================================================== */
+/* ========================================================================== */
+
+/* AMD Version 1.2 and later include the following definitions.
+ * As an example, to test if the version you are using is 1.2 or later:
+ *
+ * #ifdef AMD_VERSION
+ *	if (AMD_VERSION >= AMD_VERSION_CODE (1,2)) ...
+ * #endif
+ *
+ * This also works during compile-time:
+ *
+ *	#if defined(AMD_VERSION) && (AMD_VERSION >= AMD_VERSION_CODE (1,2))
+ *	    printf ("This is version 1.2 or later\n") ;
+ *	#else
+ *	    printf ("This is an early version\n") ;
+ *	#endif
+ *
+ * Versions 1.1 and earlier of AMD do not include a #define'd version number.
+ */
+
+#define AMD_DATE "Dec 12, 2006"
+#define AMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub))
+#define AMD_MAIN_VERSION 2
+#define AMD_SUB_VERSION 0
+#define AMD_SUBSUB_VERSION 4
+#define AMD_VERSION AMD_VERSION_CODE(AMD_MAIN_VERSION,AMD_SUB_VERSION)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/C/SuiteSparse/AMD/Include/amd_internal.h b/src/C/SuiteSparse/AMD/Include/amd_internal.h
new file mode 100644
index 0000000..68b6e4f
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Include/amd_internal.h
@@ -0,0 +1,350 @@
+/* ========================================================================= */
+/* === amd_internal.h ====================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 2.0, Copyright (c) 2006 by Timothy A. Davis,		     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* This file is for internal use in AMD itself, and does not normally need to
+ * be included in user code (it is included in UMFPACK, however).   All others
+ * should use amd.h instead.
+ *
+ * The following compile-time definitions affect how AMD is compiled.
+ *
+ *	-DNPRINT
+ *
+ *	    Disable all printing.  stdio.h will not be included.  Printing can
+ *	    be re-enabled at run-time by setting the global pointer amd_printf
+ *	    to printf (or mexPrintf for a MATLAB mexFunction).
+ *
+ *	-DNMALLOC
+ *
+ *	    No memory manager is defined at compile-time.  You MUST define the
+ *	    function pointers amd_malloc, amd_free, amd_realloc, and
+ *	    amd_calloc at run-time for AMD to work properly.
+ */
+
+/* ========================================================================= */
+/* === NDEBUG ============================================================== */
+/* ========================================================================= */
+
+/*
+ * Turning on debugging takes some work (see below).   If you do not edit this
+ * file, then debugging is always turned off, regardless of whether or not
+ * -DNDEBUG is specified in your compiler options.
+ *
+ * If AMD is being compiled as a mexFunction, then MATLAB_MEX_FILE is defined,
+ * and mxAssert is used instead of assert.  If debugging is not enabled, no
+ * MATLAB include files or functions are used.  Thus, the AMD library libamd.a
+ * can be safely used in either a stand-alone C program or in another
+ * mexFunction, without any change.
+ */
+
+/*
+    AMD will be exceedingly slow when running in debug mode.  The next three
+    lines ensure that debugging is turned off.
+*/
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+
+/*
+    To enable debugging, uncomment the following line:
+#undef NDEBUG
+*/
+
+/* ------------------------------------------------------------------------- */
+/* ANSI include files */
+/* ------------------------------------------------------------------------- */
+
+/* from stdlib.h:  size_t, malloc, free, realloc, and calloc */
+#include <stdlib.h>
+
+#if !defined(NPRINT) || !defined(NDEBUG)
+/* from stdio.h:  printf.  Not included if NPRINT is defined at compile time.
+ * fopen and fscanf are used when debugging. */
+#include <stdio.h>
+#endif
+
+/* from limits.h:  INT_MAX and LONG_MAX */
+#include <limits.h>
+
+/* from math.h: sqrt */
+#include <math.h>
+
+/* ------------------------------------------------------------------------- */
+/* MATLAB include files (only if being used in or via MATLAB) */
+/* ------------------------------------------------------------------------- */
+
+#ifdef MATLAB_MEX_FILE
+#include "matrix.h"
+#include "mex.h"
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* basic definitions */
+/* ------------------------------------------------------------------------- */
+
+#ifdef FLIP
+#undef FLIP
+#endif
+
+#ifdef MAX
+#undef MAX
+#endif
+
+#ifdef MIN
+#undef MIN
+#endif
+
+#ifdef EMPTY
+#undef EMPTY
+#endif
+
+#ifdef GLOBAL
+#undef GLOBAL
+#endif
+
+#ifdef PRIVATE
+#undef PRIVATE
+#endif
+
+/* FLIP is a "negation about -1", and is used to mark an integer i that is
+ * normally non-negative.  FLIP (EMPTY) is EMPTY.  FLIP of a number > EMPTY
+ * is negative, and FLIP of a number < EMTPY is positive.  FLIP (FLIP (i)) = i
+ * for all integers i.  UNFLIP (i) is >= EMPTY. */
+#define EMPTY (-1)
+#define FLIP(i) (-(i)-2)
+#define UNFLIP(i) ((i < EMPTY) ? FLIP (i) : (i))
+
+/* for integer MAX/MIN, or for doubles when we don't care how NaN's behave: */
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+/* logical expression of p implies q: */
+#define IMPLIES(p,q) (!(p) || (q))
+
+/* Note that the IBM RS 6000 xlc predefines TRUE and FALSE in <types.h>. */
+/* The Compaq Alpha also predefines TRUE and FALSE. */
+#ifdef TRUE
+#undef TRUE
+#endif
+#ifdef FALSE
+#undef FALSE
+#endif
+
+#define TRUE (1)
+#define FALSE (0)
+#define PRIVATE static
+#define GLOBAL
+#define EMPTY (-1)
+
+/* Note that Linux's gcc 2.96 defines NULL as ((void *) 0), but other */
+/* compilers (even gcc 2.95.2 on Solaris) define NULL as 0 or (0).  We */
+/* need to use the ANSI standard value of 0. */
+#ifdef NULL
+#undef NULL
+#endif
+
+#define NULL 0
+
+/* largest value of size_t */
+#ifndef SIZE_T_MAX
+#define SIZE_T_MAX ((size_t) (-1))
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* integer type for AMD: int or UF_long */
+/* ------------------------------------------------------------------------- */
+
+/* define UF_long */
+#include "UFconfig.h"
+
+#if defined (DLONG) || defined (ZLONG)
+
+#define Int UF_long
+#define ID  UF_long_id
+#define Int_MAX UF_long_max
+
+#define AMD_order amd_l_order
+#define AMD_defaults amd_l_defaults
+#define AMD_control amd_l_control
+#define AMD_info amd_l_info
+#define AMD_1 amd_l1
+#define AMD_2 amd_l2
+#define AMD_valid amd_l_valid
+#define AMD_aat amd_l_aat
+#define AMD_postorder amd_l_postorder
+#define AMD_post_tree amd_l_post_tree
+#define AMD_dump amd_l_dump
+#define AMD_debug amd_l_debug
+#define AMD_debug_init amd_l_debug_init
+#define AMD_preprocess amd_l_preprocess
+
+#else
+
+#define Int int
+#define ID "%d"
+#define Int_MAX INT_MAX
+
+#define AMD_order amd_order
+#define AMD_defaults amd_defaults
+#define AMD_control amd_control
+#define AMD_info amd_info
+#define AMD_1 amd_1
+#define AMD_2 amd_2
+#define AMD_valid amd_valid
+#define AMD_aat amd_aat
+#define AMD_postorder amd_postorder
+#define AMD_post_tree amd_post_tree
+#define AMD_dump amd_dump
+#define AMD_debug amd_debug
+#define AMD_debug_init amd_debug_init
+#define AMD_preprocess amd_preprocess
+
+#endif
+
+/* ========================================================================= */
+/* === PRINTF macro ======================================================== */
+/* ========================================================================= */
+
+/* All output goes through the PRINTF macro.  */
+#define PRINTF(params) { if (amd_printf != NULL) (void) amd_printf params ; }
+
+/* ------------------------------------------------------------------------- */
+/* AMD routine definitions (user-callable) */
+/* ------------------------------------------------------------------------- */
+
+#include "amd.h"
+
+/* ------------------------------------------------------------------------- */
+/* AMD routine definitions (not user-callable) */
+/* ------------------------------------------------------------------------- */
+
+GLOBAL size_t AMD_aat
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    Int Len [ ],
+    Int Tp [ ],
+    double Info [ ]
+) ;
+
+GLOBAL void AMD_1
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    Int P [ ],
+    Int Pinv [ ],
+    Int Len [ ],
+    Int slen,
+    Int S [ ],
+    double Control [ ],
+    double Info [ ]
+) ;
+
+GLOBAL void AMD_postorder
+(
+    Int nn,
+    Int Parent [ ],
+    Int Npiv [ ],
+    Int Fsize [ ],
+    Int Order [ ],
+    Int Child [ ],
+    Int Sibling [ ],
+    Int Stack [ ]
+) ;
+
+GLOBAL Int AMD_post_tree
+(
+    Int root,
+    Int k,
+    Int Child [ ],
+    const Int Sibling [ ],
+    Int Order [ ],
+    Int Stack [ ]
+#ifndef NDEBUG
+    , Int nn
+#endif
+) ;
+
+GLOBAL void AMD_preprocess
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    Int Rp [ ],
+    Int Ri [ ],
+    Int W [ ],
+    Int Flag [ ]
+) ;
+
+/* ------------------------------------------------------------------------- */
+/* debugging definitions */
+/* ------------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+
+/* from assert.h:  assert macro */
+#include <assert.h>
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+EXTERN Int AMD_debug ;
+
+GLOBAL void AMD_debug_init ( char *s ) ;
+
+GLOBAL void AMD_dump
+(
+    Int n,
+    Int Pe [ ],
+    Int Iw [ ],
+    Int Len [ ],
+    Int iwlen,
+    Int pfree,
+    Int Nv [ ],
+    Int Next [ ],
+    Int Last [ ],
+    Int Head [ ],
+    Int Elen [ ],
+    Int Degree [ ],
+    Int W [ ],
+    Int nel
+) ;
+
+#ifdef ASSERT
+#undef ASSERT
+#endif
+
+/* Use mxAssert if AMD is compiled into a mexFunction */
+#ifdef MATLAB_MEX_FILE
+#define ASSERT(expression) (mxAssert ((expression), ""))
+#else
+#define ASSERT(expression) (assert (expression))
+#endif
+
+#define AMD_DEBUG0(params) { PRINTF (params) ; }
+#define AMD_DEBUG1(params) { if (AMD_debug >= 1) PRINTF (params) ; }
+#define AMD_DEBUG2(params) { if (AMD_debug >= 2) PRINTF (params) ; }
+#define AMD_DEBUG3(params) { if (AMD_debug >= 3) PRINTF (params) ; }
+#define AMD_DEBUG4(params) { if (AMD_debug >= 4) PRINTF (params) ; }
+
+#else
+
+/* no debugging */
+#define ASSERT(expression)
+#define AMD_DEBUG0(params)
+#define AMD_DEBUG1(params)
+#define AMD_DEBUG2(params)
+#define AMD_DEBUG3(params)
+#define AMD_DEBUG4(params)
+
+#endif
diff --git a/src/C/SuiteSparse/AMD/Lib/libamd.def b/src/C/SuiteSparse/AMD/Lib/libamd.def
new file mode 100644
index 0000000..8ed43fc
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Lib/libamd.def
@@ -0,0 +1,12 @@
+LIBRARY libamd.dll
+EXPORTS
+amd_order
+amd_defaults
+amd_control
+amd_info
+amd_2
+amd_l_order
+amd_l_defaults
+amd_l_control
+amd_l_info
+amd_l2
diff --git a/src/C/SuiteSparse/AMD/Makefile b/src/C/SuiteSparse/AMD/Makefile
new file mode 100644
index 0000000..07c7aef
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Makefile
@@ -0,0 +1,67 @@
+#------------------------------------------------------------------------------
+# AMD Makefile (for GNU Make or original make)
+#------------------------------------------------------------------------------
+
+default: demo
+
+include ../UFconfig/UFconfig.mk
+
+# Compile all C code, including the C-callable routine and the mexFunctions.
+# Do not compile the FORTRAN versions, or MATLAB interface.
+demo:
+	( cd Source ; $(MAKE) )
+	( cd Demo   ; $(MAKE) )
+
+# Compile all C code, including the C-callable routine and the mexFunctions.
+# Do not compile the FORTRAN versions.
+all:
+	( cd Source ; $(MAKE) )
+	( cd Demo   ; $(MAKE) )
+	( cd MATLAB ; $(MAKE) )
+
+# compile just the C-callable libraries (not mexFunctions or Demos)
+library:
+	( cd Source ; $(MAKE) )
+
+# compile the FORTRAN libraries and demo programs (not compiled by "make all")
+fortran:
+	( cd Source ; $(MAKE) fortran )
+	( cd Demo   ; $(MAKE) fortran )
+
+# compile a FORTRAN demo program that calls the C version of AMD
+# (not compiled by "make all")
+cross:
+	( cd Demo   ; $(MAKE) cross )
+
+# remove object files, but keep the compiled programs and library archives
+clean:
+	( cd Source ; $(MAKE) clean )
+	( cd Demo   ; $(MAKE) clean )
+	( cd MATLAB ; $(MAKE) clean )
+	( cd Doc    ; $(MAKE) clean )
+
+# clean, and then remove compiled programs and library archives
+purge:
+	( cd Source ; $(MAKE) purge )
+	( cd Demo   ; $(MAKE) purge )
+	( cd MATLAB ; $(MAKE) purge )
+	( cd Doc    ; $(MAKE) purge )
+
+distclean: purge
+
+# create PDF documents for the original distribution
+doc:
+	( cd Doc    ; $(MAKE) )
+
+# get ready for distribution
+dist: purge
+	( cd Demo   ; $(MAKE) dist )
+	( cd Doc    ; $(MAKE) )
+
+ccode: library
+
+lib: library
+
+# compile the MATLAB mexFunction
+mex:
+	( cd MATLAB ; $(MAKE) )
diff --git a/src/C/SuiteSparse/AMD/README.txt b/src/C/SuiteSparse/AMD/README.txt
new file mode 100644
index 0000000..ea6b415
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/README.txt
@@ -0,0 +1,214 @@
+AMD:  a set of routines for permuting sparse matrices prior to
+    factorization.  Includes a version in C, a version in Fortran, and a MATLAB
+    mexFunction.
+
+Requires UFconfig, in the ../UFconfig directory relative to this directory.
+
+Quick start (Unix, or Windows with Cygwin):
+
+    To compile, test, and install AMD, you may wish to first configure the
+    installation by editting the ../UFconfig/UFconfig.mk file.  Next, cd to this
+    directory (AMD) and type "make" (or "make lib" if you do not have MATLAB).
+    To compile and run a demo program for the Fortran version, type
+    "make fortran".  When done, type "make clean" to remove unused *.o files
+    (keeps the compiled libraries and demo programs).  See the User Guide
+    (Doc/AMD_UserGuide.pdf), or ../UFconfig/UFconfig.mk for more details.
+
+Quick start (for MATLAB users);
+
+    To compile, test, and install the AMD mexFunction, cd to the
+    AMD/MATLAB directory and type amd_make at the MATLAB prompt.
+
+    NOTE: DO NOT ATTEMPT TO USE THIS CODE IN 64-BIT MATLAB (v7.3).
+    It is not yet ported to that version of MATLAB.
+
+-------------------------------------------------------------------------------
+
+AMD Version 2.0, Copyright (c) 2006 by Timothy A.
+Davis, Patrick R. Amestoy, and Iain S. Duff.  All Rights Reserved.
+AMD is available under alternate licences; contact T. Davis for details.
+
+AMD License:
+
+    Your use or distribution of AMD or any modified version of
+    AMD implies that you agree to this License.
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+    USA
+
+    Permission is hereby granted to use or copy this program under the
+    terms of the GNU LGPL, provided that the Copyright, this License,
+    and the Availability of the original version is retained on all copies.
+    User documentation of any code that uses this code or any modified
+    version of this code must cite the Copyright, this License, the
+    Availability note, and "Used by permission." Permission to modify
+    the code and to distribute modified code is granted, provided the
+    Copyright, this License, and the Availability note are retained,
+    and a notice that the code was modified is included.
+
+Availability:
+
+    http://www.cise.ufl.edu/research/sparse/amd
+
+-------------------------------------------------------------------------------
+
+This is the AMD README file.  It is a terse overview of AMD.
+Refer to the User Guide (Doc/AMD_UserGuide.pdf) for how to install
+and use AMD.
+
+Description:
+
+    AMD is a set of routines for pre-ordering sparse matrices prior to Cholesky
+    or LU factorization, using the approximate minimum degree ordering
+    algorithm.  Written in ANSI/ISO C with a MATLAB interface, and in
+    Fortran 77.
+
+Authors:
+
+    Timothy A. Davis (davis at cise.ufl.edu), University of Florida.
+    Patrick R. Amestory, ENSEEIHT, Toulouse, France.
+    Iain S. Duff, Rutherford Appleton Laboratory, UK.
+
+Acknowledgements:
+
+    This work was supported by the National Science Foundation, under
+    grants DMS-9504974, DMS-9803599, and CCR-0203270.
+
+    Portions of this work were done while on sabbatical at Stanford University
+    and Lawrence Berkeley National Laboratory (with funding from the SciDAC
+    program).  I would like to thank Gene Golub, Esmond Ng, and Horst Simon
+    for making this sabbatical possible.
+
+-------------------------------------------------------------------------------
+Files and directories in the AMD distribution:
+-------------------------------------------------------------------------------
+
+    ---------------------------------------------------------------------------
+    Subdirectories of the AMD directory:
+    ---------------------------------------------------------------------------
+
+    Doc		documentation
+    Source	primary source code
+    Include	include file for use in your code that calls AMD
+    Demo	demo programs.  also serves as test of the AMD installation.
+    MATLAB	AMD mexFunction for MATLAB, and supporting m-files
+    Lib		where the compiled C-callable and Fortran-callable
+		AMD libraries placed.
+
+    ---------------------------------------------------------------------------
+    Files in the AMD directory:
+    ---------------------------------------------------------------------------
+
+    Makefile	top-level Makefile for GNU make or original make.
+		Windows users would require Cygwin to use "make"
+
+    README.txt	this file
+
+    ---------------------------------------------------------------------------
+    Doc directory: documentation
+    ---------------------------------------------------------------------------
+
+    ChangeLog			change log
+    License			the AMD License
+    Makefile			for creating the documentation
+    AMD_UserGuide.bib		AMD User Guide (references)
+    AMD_UserGuide.tex		AMD User Guide (LaTeX)
+    AMD_UserGuide.pdf		AMD User Guide (PDF)
+    lesser.txt			the GNU LGPL license
+
+    ---------------------------------------------------------------------------
+    Source directory:
+    ---------------------------------------------------------------------------
+
+    GNUmakefile			a nice Makefile, for GNU make
+    Makefile			an ugly Unix Makefile (for older make's)
+
+    amd_order.c			user-callable, primary AMD ordering routine
+    amd_control.c		user-callable, prints the control parameters
+    amd_defaults.c		user-callable, sets default control parameters
+    amd_info.c			user-callable, prints the statistics from AMD
+
+    amd_1.c			non-user-callable, construct A+A'
+    amd_2.c			user-callable, primary ordering kernel
+				(a C version of amd.f and amdbar.f, with
+				post-ordering added)
+    amd_aat.c			non-user-callable, computes nnz (A+A')
+    amd_dump.c			non-user-callable, debugging routines
+    amd_postorder.c		non-user-callable, postorder
+    amd_post_tree.c		non-user-callable, postorder just one tree
+    amd_valid.c			non-user-callable, verifies a matrix
+    amd_preprocess.c		non-user-callable, computes A', removes duplic
+
+    amd.f			user-callable Fortran 77 version
+    amdbar.f			user-callable Fortran 77 version
+
+    ---------------------------------------------------------------------------
+    Include directory:
+    ---------------------------------------------------------------------------
+
+    amd.h			include file for C programs that use AMD
+    amd_internal.h		non-user-callable, include file for AMD
+
+    ---------------------------------------------------------------------------
+    Demo directory:
+    ---------------------------------------------------------------------------
+
+    Makefile			for GNU make or original make
+
+    amd_demo.c			C demo program for AMD
+    amd_demo.out		output of amd_demo.c
+
+    amd_demo2.c			C demo program for AMD, jumbled matrix
+    amd_demo2.out		output of amd_demo2.c
+
+    amd_l_demo.c		C demo program for AMD (UF_long version)
+    amd_l_demo.out		output of amd_l_demo.c
+
+    amd_simple.c		simple C demo program for AMD
+    amd_simple.out		output of amd_simple.c
+
+    amd_f77demo.f		Fortran 77 demo program for AMD
+    amd_f77demo.out		output of amd_f77demo.f
+
+    amd_f77simple.c		simple Fortran 77 demo program for AMD
+    amd_f77simple.out		output of amd_f77simple.f
+
+    amd_f77cross.f		Fortran 77 demo, calls the C version of AMD
+    amd_f77cross.out		output of amd_f77cross.f
+    amd_f77wrapper.c		Fortran-callable wrapper for C version of AMD
+
+    ---------------------------------------------------------------------------
+    MATLAB directory:
+    ---------------------------------------------------------------------------
+
+    GNUmakefile			a nice Makefile, for GNU make
+    Makefile			an ugly Unix Makefile (for older make's)
+
+    Contents.m			for "help amd2" listing of toolbox contents
+
+    amd2.m			MATLAB help file for AMD
+    amd_make.m			MATLAB m-file for compiling AMD mexFunction
+
+    amd_mex.c			AMD mexFunction for MATLAB
+
+    amd_demo.m			MATLAB demo for AMD
+    amd_demo.m.out		diary output of amd_demo.m
+    can_24.mat			input file for AMD demo
+
+    ---------------------------------------------------------------------------
+    Lib directory:  libamd.a and libamdf77.a libraries placed here
+    ---------------------------------------------------------------------------
+
+    libamd.def			AMD definitions for Windows
diff --git a/src/C/SuiteSparse/AMD/Source/GNUmakefile b/src/C/SuiteSparse/AMD/Source/GNUmakefile
new file mode 100644
index 0000000..571ad1c
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Source/GNUmakefile
@@ -0,0 +1,79 @@
+#-------------------------------------------------------------------------------
+# AMD Makefile for compiling on Unix systems (for GNU make only)
+#-------------------------------------------------------------------------------
+
+default: ../Lib/libamd.a
+
+include ../../UFconfig/UFconfig.mk
+
+C = $(CC) $(CFLAGS) $(CONFIG) -I../Include -I../../UFconfig
+
+#-------------------------------------------------------------------------------
+# source files
+#-------------------------------------------------------------------------------
+
+AMD = amd_aat amd_1 amd_2 amd_dump amd_postorder amd_post_tree amd_defaults \
+	amd_order amd_control amd_info amd_valid amd_preprocess
+
+UFCONFIG = ../../UFconfig/UFconfig.h
+
+INC = ../Include/amd.h ../Include/amd_internal.h $(UFCONFIG)
+
+#-------------------------------------------------------------------------------
+# object files for each version
+#-------------------------------------------------------------------------------
+
+AMDI = $(addsuffix .o, $(subst amd_,amd_i_,$(AMD)))
+AMDL = $(addsuffix .o, $(subst amd_,amd_l_,$(AMD)))
+
+#-------------------------------------------------------------------------------
+# compile each int and long routine (with no real/complex version)
+#-------------------------------------------------------------------------------
+
+amd_global.o: amd_global.c $(INC)
+	$(C) -c $< -o $@
+
+amd_i_%.o: amd_%.c $(INC)
+	$(C) -DDINT -c $< -o $@
+
+amd_l_%.o: amd_%.c $(INC)
+	$(C) -DDLONG -c $< -o $@
+
+#-------------------------------------------------------------------------------
+# Create the libamd.a library (C versions only)
+#-------------------------------------------------------------------------------
+
+../Lib/libamd.a: amd_global.o $(AMDI) $(AMDL)
+	$(AR) ../Lib/libamd.a $^
+	- $(RANLIB) ../Lib/libamd.a
+
+#-------------------------------------------------------------------------------
+# compile the Fortran versions and the libamdf77.a library
+#-------------------------------------------------------------------------------
+
+fortran: ../Lib/libamdf77.a
+
+AMDF77 = amd.o amdbar.o
+
+amd.o: amd.f
+	$(F77) $(F77FLAGS) -c amd.f -o amd.o
+
+amdbar.o: amdbar.f
+	$(F77) $(F77FLAGS) -c amdbar.f -o amdbar.o
+
+../Lib/libamdf77.a: $(AMDF77)
+	$(AR) ../Lib/libamdf77.a $^
+	- $(RANLIB) ../Lib/libamdf77.a
+
+#-------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#-------------------------------------------------------------------------------
+
+clean:
+	- $(RM) $(CLEAN)
+
+purge: distclean
+
+distclean: clean
+	- $(RM) ../Lib/libamd.a
+	- $(RM) ../Lib/libamdf77.a
diff --git a/src/C/SuiteSparse/AMD/Source/Makefile b/src/C/SuiteSparse/AMD/Source/Makefile
new file mode 100644
index 0000000..409046a
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Source/Makefile
@@ -0,0 +1,70 @@
+#-------------------------------------------------------------------------------
+# AMD Makefile for compiling on Unix systems (for original Make ONLY)
+#-------------------------------------------------------------------------------
+
+# This is a very ugly Makefile, and is only provided for those who do not
+# have GNU make.  Note that it is not used if you have GNU make.  It ignores
+# dependency checking and just compiles everything.
+
+default: everything
+
+include ../../UFconfig/UFconfig.mk
+
+C = $(CC) $(CFLAGS) $(CONFIG) -I../Include -I../../UFconfig
+
+everything:
+	$(C) -DDINT -c amd_aat.c -o amd_i_aat.o
+	$(C) -DDINT -c amd_1.c -o amd_i_1.o
+	$(C) -DDINT -c amd_2.c -o amd_i_2.o
+	$(C) -DDINT -c amd_dump.c -o amd_i_dump.o
+	$(C) -DDINT -c amd_postorder.c -o amd_i_postorder.o
+	$(C) -DDINT -c amd_post_tree.c -o amd_i_post_tree.o
+	$(C) -DDINT -c amd_defaults.c -o amd_i_defaults.o
+	$(C) -DDINT -c amd_order.c -o amd_i_order.o
+	$(C) -DDINT -c amd_control.c -o amd_i_control.o
+	$(C) -DDINT -c amd_info.c -o amd_i_info.o
+	$(C) -DDINT -c amd_valid.c -o amd_i_valid.o
+	$(C) -DDINT -c amd_preprocess.c -o amd_i_preprocess.o
+	$(C) -DDLONG -c amd_aat.c -o amd_l_aat.o
+	$(C) -DDLONG -c amd_1.c -o amd_l_1.o
+	$(C) -DDLONG -c amd_2.c -o amd_l_2.o
+	$(C) -DDLONG -c amd_dump.c -o amd_l_dump.o
+	$(C) -DDLONG -c amd_postorder.c -o amd_l_postorder.o
+	$(C) -DDLONG -c amd_post_tree.c -o amd_l_post_tree.o
+	$(C) -DDLONG -c amd_defaults.c -o amd_l_defaults.o
+	$(C) -DDLONG -c amd_order.c -o amd_l_order.o
+	$(C) -DDLONG -c amd_control.c -o amd_l_control.o
+	$(C) -DDLONG -c amd_info.c -o amd_l_info.o
+	$(C) -DDLONG -c amd_valid.c -o amd_l_valid.o
+	$(C) -DDLONG -c amd_preprocess.c -o amd_l_preprocess.o
+	$(C) -c amd_global.c
+	$(AR) ../Lib/libamd.a amd_i_aat.o amd_i_1.o amd_i_2.o amd_i_dump.o \
+	    amd_i_postorder.o amd_i_post_tree.o amd_i_defaults.o amd_i_order.o \
+	    amd_i_control.o amd_i_info.o amd_i_valid.o amd_l_aat.o amd_l_1.o \
+	    amd_l_2.o amd_l_dump.o amd_l_postorder.o amd_l_post_tree.o \
+	    amd_l_defaults.o amd_l_order.o amd_l_control.o amd_l_info.o \
+	    amd_l_valid.o amd_i_preprocess.o amd_l_preprocess.o amd_global.o
+	- $(RANLIB) ../Lib/libamd.a
+
+#-------------------------------------------------------------------------------
+# compile the Fortran versions and the libamdf77.a library
+#-------------------------------------------------------------------------------
+
+fortran:
+	$(F77) $(F77FLAGS) -c amd.f -o amd.o
+	$(F77) $(F77FLAGS) -c amdbar.f -o amdbar.o
+	$(AR) ../Lib/libamdf77.a amd.o amdbar.o
+	- $(RANLIB) ../Lib/libamdf77.a
+
+#-------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#-------------------------------------------------------------------------------
+
+clean:
+	- $(RM) $(CLEAN)
+
+purge: distclean
+
+distclean: clean
+	- $(RM) ../Lib/libamd.a
+	- $(RM) ../Lib/libamdf77.a
diff --git a/src/C/SuiteSparse/AMD/Source/amd.f b/src/C/SuiteSparse/AMD/Source/amd.f
new file mode 100644
index 0000000..ccfe3e8
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Source/amd.f
@@ -0,0 +1,1214 @@
+C-----------------------------------------------------------------------
+C AMD:  approximate minimum degree, with aggressive absorption
+C-----------------------------------------------------------------------
+
+        SUBROUTINE AMD
+     $          (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT,
+     $          LAST, HEAD, ELEN, DEGREE, NCMPA, W)
+
+        INTEGER N, IWLEN, PFREE, NCMPA, IW (IWLEN), PE (N),
+     $          DEGREE (N), NV (N), NEXT (N), LAST (N), HEAD (N),
+     $          ELEN (N), W (N), LEN (N)
+
+C Given a representation of the nonzero pattern of a symmetric matrix,
+C       A, (excluding the diagonal) perform an approximate minimum
+C       (UMFPACK/MA38-style) degree ordering to compute a pivot order
+C       such that the introduction of nonzeros (fill-in) in the Cholesky
+C       factors A = LL^T are kept low.  At each step, the pivot
+C       selected is the one with the minimum UMFPACK/MA38-style
+C       upper-bound on the external degree.
+C
+C       Aggresive absorption is used to tighten the bound on the degree.
+
+C **********************************************************************
+C ***** CAUTION:  ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT.  ******
+C **********************************************************************
+
+C       References:
+C
+C       [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern
+C           multifrontal method for sparse LU factorization", SIAM J.
+C           Matrix Analysis and Applications, vol. 18, no. 1, pp.
+C           140-158.  Discusses UMFPACK / MA38, which first introduced
+C           the approximate minimum degree used by this routine.
+C
+C       [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An
+C           approximate degree ordering algorithm," SIAM J. Matrix
+C           Analysis and Applications, vol. 17, no. 4, pp. 886-905,
+C           1996.  Discusses AMD, AMDBAR, and MC47B.
+C
+C       [3] Alan George and Joseph Liu, "The evolution of the minimum
+C           degree ordering algorithm," SIAM Review, vol. 31, no. 1,
+C           pp. 1-19, 1989.  We list below the features mentioned in
+C           that paper that this code includes:
+C
+C       mass elimination:
+C               Yes.  MA27 relied on supervariable detection for mass
+C               elimination.
+C       indistinguishable nodes:
+C               Yes (we call these "supervariables").  This was also in
+C               the MA27 code - although we modified the method of
+C               detecting them (the previous hash was the true degree,
+C               which we no longer keep track of).  A supervariable is
+C               a set of rows with identical nonzero pattern.  All
+C               variables in a supervariable are eliminated together.
+C               Each supervariable has as its numerical name that of
+C               one of its variables (its principal variable).
+C       quotient graph representation:
+C               Yes.  We use the term "element" for the cliques formed
+C               during elimination.  This was also in the MA27 code.
+C               The algorithm can operate in place, but it will work
+C               more efficiently if given some "elbow room."
+C       element absorption:
+C               Yes.  This was also in the MA27 code.
+C       external degree:
+C               Yes.  The MA27 code was based on the true degree.
+C       incomplete degree update and multiple elimination:
+C               No.  This was not in MA27, either.  Our method of
+C               degree update within MC47B/BD is element-based, not
+C               variable-based.  It is thus not well-suited for use
+C               with incomplete degree update or multiple elimination.
+
+C-----------------------------------------------------------------------
+C Authors, and Copyright (C) 1995 by:
+C       Timothy A. Davis, Patrick Amestoy, Iain S. Duff, & John K. Reid.
+C
+C Acknowledgements:
+C       This work (and the UMFPACK package) was supported by the
+C       National Science Foundation (ASC-9111263 and DMS-9223088).
+C       The UMFPACK/MA38 approximate degree update algorithm, the
+C       unsymmetric analog which forms the basis of MC47B/BD, was
+C       developed while Tim Davis was supported by CERFACS (Toulouse,
+C       France) in a post-doctoral position.
+C
+C Date:  September, 1995
+C-----------------------------------------------------------------------
+
+C-----------------------------------------------------------------------
+C INPUT ARGUMENTS (unaltered):
+C-----------------------------------------------------------------------
+
+C n:    The matrix order.
+C
+C       Restriction:  1 .le. n .lt. (iovflo/2)-2, where iovflo is
+C       the largest positive integer that your computer can represent.
+
+C iwlen:        The length of iw (1..iwlen).  On input, the matrix is
+C       stored in iw (1..pfree-1).  However, iw (1..iwlen) should be
+C       slightly larger than what is required to hold the matrix, at
+C       least iwlen .ge. pfree + n is recommended.  Otherwise,
+C       excessive compressions will take place.
+C       *** We do not recommend running this algorithm with ***
+C       ***      iwlen .lt. pfree + n.                      ***
+C       *** Better performance will be obtained if          ***
+C       ***      iwlen .ge. pfree + n                       ***
+C       *** or better yet                                   ***
+C       ***      iwlen .gt. 1.2 * pfree                     ***
+C       *** (where pfree is its value on input).            ***
+C       The algorithm will not run at all if iwlen .lt. pfree-1.
+C
+C       Restriction: iwlen .ge. pfree-1
+
+C-----------------------------------------------------------------------
+C INPUT/OUPUT ARGUMENTS:
+C-----------------------------------------------------------------------
+
+C pe:   On input, pe (i) is the index in iw of the start of row i, or
+C       zero if row i has no off-diagonal non-zeros.
+C
+C       During execution, it is used for both supervariables and
+C       elements:
+C
+C       * Principal supervariable i:  index into iw of the
+C               description of supervariable i.  A supervariable
+C               represents one or more rows of the matrix
+C               with identical nonzero pattern.
+C       * Non-principal supervariable i:  if i has been absorbed
+C               into another supervariable j, then pe (i) = -j.
+C               That is, j has the same pattern as i.
+C               Note that j might later be absorbed into another
+C               supervariable j2, in which case pe (i) is still -j,
+C               and pe (j) = -j2.
+C       * Unabsorbed element e:  the index into iw of the description
+C               of element e, if e has not yet been absorbed by a
+C               subsequent element.  Element e is created when
+C               the supervariable of the same name is selected as
+C               the pivot.
+C       * Absorbed element e:  if element e is absorbed into element
+C               e2, then pe (e) = -e2.  This occurs when the pattern of
+C               e (that is, Le) is found to be a subset of the pattern
+C               of e2 (that is, Le2).  If element e is "null" (it has
+C               no nonzeros outside its pivot block), then pe (e) = 0.
+C
+C       On output, pe holds the assembly tree/forest, which implicitly
+C       represents a pivot order with identical fill-in as the actual
+C       order (via a depth-first search of the tree).
+C
+C       On output:
+C       If nv (i) .gt. 0, then i represents a node in the assembly tree,
+C       and the parent of i is -pe (i), or zero if i is a root.
+C       If nv (i) = 0, then (i,-pe (i)) represents an edge in a
+C       subtree, the root of which is a node in the assembly tree.
+
+C pfree:        On input the tail end of the array, iw (pfree..iwlen),
+C       is empty, and the matrix is stored in iw (1..pfree-1).
+C       During execution, additional data is placed in iw, and pfree
+C       is modified so that iw (pfree..iwlen) is always the unused part
+C       of iw.  On output, pfree is set equal to the size of iw that
+C       would have been needed for no compressions to occur.  If
+C       ncmpa is zero, then pfree (on output) is less than or equal to
+C       iwlen, and the space iw (pfree+1 ... iwlen) was not used.
+C       Otherwise, pfree (on output) is greater than iwlen, and all the
+C       memory in iw was used.
+
+C-----------------------------------------------------------------------
+C INPUT/MODIFIED (undefined on output):
+C-----------------------------------------------------------------------
+
+C len:  On input, len (i) holds the number of entries in row i of the
+C       matrix, excluding the diagonal.  The contents of len (1..n)
+C       are undefined on output.
+
+C iw:   On input, iw (1..pfree-1) holds the description of each row i
+C       in the matrix.  The matrix must be symmetric, and both upper
+C       and lower triangular parts must be present.  The diagonal must
+C       not be present.  Row i is held as follows:
+C
+C               len (i):  the length of the row i data structure
+C               iw (pe (i) ... pe (i) + len (i) - 1):
+C                       the list of column indices for nonzeros
+C                       in row i (simple supervariables), excluding
+C                       the diagonal.  All supervariables start with
+C                       one row/column each (supervariable i is just
+C                       row i).
+C               if len (i) is zero on input, then pe (i) is ignored
+C               on input.
+C
+C               Note that the rows need not be in any particular order,
+C               and there may be empty space between the rows.
+C
+C       During execution, the supervariable i experiences fill-in.
+C       This is represented by placing in i a list of the elements
+C       that cause fill-in in supervariable i:
+C
+C               len (i):  the length of supervariable i
+C               iw (pe (i) ... pe (i) + elen (i) - 1):
+C                       the list of elements that contain i.  This list
+C                       is kept short by removing absorbed elements.
+C               iw (pe (i) + elen (i) ... pe (i) + len (i) - 1):
+C                       the list of supervariables in i.  This list
+C                       is kept short by removing nonprincipal
+C                       variables, and any entry j that is also
+C                       contained in at least one of the elements
+C                       (j in Le) in the list for i (e in row i).
+C
+C       When supervariable i is selected as pivot, we create an
+C       element e of the same name (e=i):
+C
+C               len (e):  the length of element e
+C               iw (pe (e) ... pe (e) + len (e) - 1):
+C                       the list of supervariables in element e.
+C
+C       An element represents the fill-in that occurs when supervariable
+C       i is selected as pivot (which represents the selection of row i
+C       and all non-principal variables whose principal variable is i).
+C       We use the term Le to denote the set of all supervariables
+C       in element e.  Absorbed supervariables and elements are pruned
+C       from these lists when computationally convenient.
+C
+C       CAUTION:  THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
+C       The contents of iw are undefined on output.
+
+C-----------------------------------------------------------------------
+C OUTPUT (need not be set on input):
+C-----------------------------------------------------------------------
+
+C nv:   During execution, abs (nv (i)) is equal to the number of rows
+C       that are represented by the principal supervariable i.  If i is
+C       a nonprincipal variable, then nv (i) = 0.  Initially,
+C       nv (i) = 1 for all i.  nv (i) .lt. 0 signifies that i is a
+C       principal variable in the pattern Lme of the current pivot
+C       element me.  On output, nv (e) holds the true degree of element
+C       e at the time it was created (including the diagonal part).
+
+C ncmpa:        The number of times iw was compressed.  If this is
+C       excessive, then the execution took longer than what could have
+C       been.  To reduce ncmpa, try increasing iwlen to be 10% or 20%
+C       larger than the value of pfree on input (or at least
+C       iwlen .ge. pfree + n).  The fastest performance will be
+C       obtained when ncmpa is returned as zero.  If iwlen is set to
+C       the value returned by pfree on *output*, then no compressions
+C       will occur.
+
+C elen: See the description of iw above.  At the start of execution,
+C       elen (i) is set to zero.  During execution, elen (i) is the
+C       number of elements in the list for supervariable i.  When e
+C       becomes an element, elen (e) = -nel is set, where nel is the
+C       current step of factorization.  elen (i) = 0 is done when i
+C       becomes nonprincipal.
+C
+C       For variables, elen (i) .ge. 0 holds until just before the
+C       permutation vectors are computed.  For elements,
+C       elen (e) .lt. 0 holds.
+C
+C       On output elen (1..n) holds the inverse permutation (the same
+C       as the 'INVP' argument in Sparspak).  That is, if k = elen (i),
+C       then row i is the kth pivot row.  Row i of A appears as the
+C       (elen(i))-th row in the permuted matrix, PAP^T.
+
+C last: In a degree list, last (i) is the supervariable preceding i,
+C       or zero if i is the head of the list.  In a hash bucket,
+C       last (i) is the hash key for i.  last (head (hash)) is also
+C       used as the head of a hash bucket if head (hash) contains a
+C       degree list (see head, below).
+C
+C       On output, last (1..n) holds the permutation (the same as the
+C       'PERM' argument in Sparspak).  That is, if i = last (k), then
+C       row i is the kth pivot row.  Row last (k) of A is the k-th row
+C       in the permuted matrix, PAP^T.
+
+C-----------------------------------------------------------------------
+C LOCAL (not input or output - used only during execution):
+C-----------------------------------------------------------------------
+
+C degree:       If i is a supervariable, then degree (i) holds the
+C       current approximation of the external degree of row i (an upper
+C       bound).  The external degree is the number of nonzeros in row i,
+C       minus abs (nv (i)) (the diagonal part).  The bound is equal to
+C       the external degree if elen (i) is less than or equal to two.
+C
+C       We also use the term "external degree" for elements e to refer
+C       to |Le \ Lme|.  If e is an element, then degree (e) holds |Le|,
+C       which is the degree of the off-diagonal part of the element e
+C       (not including the diagonal part).
+
+C head: head is used for degree lists.  head (deg) is the first
+C       supervariable in a degree list (all supervariables i in a
+C       degree list deg have the same approximate degree, namely,
+C       deg = degree (i)).  If the list deg is empty then
+C       head (deg) = 0.
+C
+C       During supervariable detection head (hash) also serves as a
+C       pointer to a hash bucket.
+C       If head (hash) .gt. 0, there is a degree list of degree hash.
+C               The hash bucket head pointer is last (head (hash)).
+C       If head (hash) = 0, then the degree list and hash bucket are
+C               both empty.
+C       If head (hash) .lt. 0, then the degree list is empty, and
+C               -head (hash) is the head of the hash bucket.
+C       After supervariable detection is complete, all hash buckets
+C       are empty, and the (last (head (hash)) = 0) condition is
+C       restored for the non-empty degree lists.
+
+C next: next (i) is the supervariable following i in a link list, or
+C       zero if i is the last in the list.  Used for two kinds of
+C       lists:  degree lists and hash buckets (a supervariable can be
+C       in only one kind of list at a time).
+
+C w:    The flag array w determines the status of elements and
+C       variables, and the external degree of elements.
+C
+C       for elements:
+C          if w (e) = 0, then the element e is absorbed
+C          if w (e) .ge. wflg, then w (e) - wflg is the size of
+C               the set |Le \ Lme|, in terms of nonzeros (the
+C               sum of abs (nv (i)) for each principal variable i that
+C               is both in the pattern of element e and NOT in the
+C               pattern of the current pivot element, me).
+C          if wflg .gt. w (e) .gt. 0, then e is not absorbed and has
+C               not yet been seen in the scan of the element lists in
+C               the computation of |Le\Lme| in loop 150 below.
+C
+C       for variables:
+C          during supervariable detection, if w (j) .ne. wflg then j is
+C          not in the pattern of variable i
+C
+C       The w array is initialized by setting w (i) = 1 for all i,
+C       and by setting wflg = 2.  It is reinitialized if wflg becomes
+C       too large (to ensure that wflg+n does not cause integer
+C       overflow).
+
+C-----------------------------------------------------------------------
+C LOCAL INTEGERS:
+C-----------------------------------------------------------------------
+
+        INTEGER DEG, DEGME, DEXT, DMAX, E, ELENME, ELN, HASH, HMOD, I,
+     $          ILAST, INEXT, J, JLAST, JNEXT, K, KNT1, KNT2, KNT3,
+     $          LENJ, LN, MAXMEM, ME, MEM, MINDEG, NEL, NEWMEM,
+     $          NLEFT, NVI, NVJ, NVPIV, SLENME, WE, WFLG, WNVI, X
+
+C deg:          the degree of a variable or element
+C degme:        size, |Lme|, of the current element, me (= degree (me))
+C dext:         external degree, |Le \ Lme|, of some element e
+C dmax:         largest |Le| seen so far
+C e:            an element
+C elenme:       the length, elen (me), of element list of pivotal var.
+C eln:          the length, elen (...), of an element list
+C hash:         the computed value of the hash function
+C hmod:         the hash function is computed modulo hmod = max (1,n-1)
+C i:            a supervariable
+C ilast:        the entry in a link list preceding i
+C inext:        the entry in a link list following i
+C j:            a supervariable
+C jlast:        the entry in a link list preceding j
+C jnext:        the entry in a link list, or path, following j
+C k:            the pivot order of an element or variable
+C knt1:         loop counter used during element construction
+C knt2:         loop counter used during element construction
+C knt3:         loop counter used during compression
+C lenj:         len (j)
+C ln:           length of a supervariable list
+C maxmem:       amount of memory needed for no compressions
+C me:           current supervariable being eliminated, and the
+C                       current element created by eliminating that
+C                       supervariable
+C mem:          memory in use assuming no compressions have occurred
+C mindeg:       current minimum degree
+C nel:          number of pivots selected so far
+C newmem:       amount of new memory needed for current pivot element
+C nleft:        n - nel, the number of nonpivotal rows/columns remaining
+C nvi:          the number of variables in a supervariable i (= nv (i))
+C nvj:          the number of variables in a supervariable j (= nv (j))
+C nvpiv:        number of pivots in current element
+C slenme:       number of variables in variable list of pivotal variable
+C we:           w (e)
+C wflg:         used for flagging the w array.  See description of iw.
+C wnvi:         wflg - nv (i)
+C x:            either a supervariable or an element
+
+C-----------------------------------------------------------------------
+C LOCAL POINTERS:
+C-----------------------------------------------------------------------
+
+        INTEGER P, P1, P2, P3, PDST, PEND, PJ, PME, PME1, PME2, PN, PSRC
+
+C               Any parameter (pe (...) or pfree) or local variable
+C               starting with "p" (for Pointer) is an index into iw,
+C               and all indices into iw use variables starting with
+C               "p."  The only exception to this rule is the iwlen
+C               input argument.
+
+C p:            pointer into lots of things
+C p1:           pe (i) for some variable i (start of element list)
+C p2:           pe (i) + elen (i) -  1 for some var. i (end of el. list)
+C p3:           index of first supervariable in clean list
+C pdst:         destination pointer, for compression
+C pend:         end of memory to compress
+C pj:           pointer into an element or variable
+C pme:          pointer into the current element (pme1...pme2)
+C pme1:         the current element, me, is stored in iw (pme1...pme2)
+C pme2:         the end of the current element
+C pn:           pointer into a "clean" variable, also used to compress
+C psrc:         source pointer, for compression
+
+C-----------------------------------------------------------------------
+C  FUNCTIONS CALLED:
+C-----------------------------------------------------------------------
+
+        INTRINSIC MAX, MIN, MOD
+
+C=======================================================================
+C  INITIALIZATIONS
+C=======================================================================
+
+        WFLG = 2
+        MINDEG = 1
+        NCMPA = 0
+        NEL = 0
+        HMOD = MAX (1, N-1)
+        DMAX = 0
+        MEM = PFREE - 1
+        MAXMEM = MEM
+	ME = 0
+
+        DO 10 I = 1, N
+           LAST (I) = 0
+           HEAD (I) = 0
+           NV (I) = 1
+           W (I) = 1
+           ELEN (I) = 0
+           DEGREE (I) = LEN (I)
+10         CONTINUE
+
+C       ----------------------------------------------------------------
+C       initialize degree lists and eliminate rows with no off-diag. nz.
+C       ----------------------------------------------------------------
+
+        DO 20 I = 1, N
+
+           DEG = DEGREE (I)
+
+           IF (DEG .GT. 0) THEN
+
+C             ----------------------------------------------------------
+C             place i in the degree list corresponding to its degree
+C             ----------------------------------------------------------
+
+              INEXT = HEAD (DEG)
+              IF (INEXT .NE. 0) LAST (INEXT) = I
+              NEXT (I) = INEXT
+              HEAD (DEG) = I
+
+           ELSE
+
+C             ----------------------------------------------------------
+C             we have a variable that can be eliminated at once because
+C             there is no off-diagonal non-zero in its row.
+C             ----------------------------------------------------------
+
+              NEL = NEL + 1
+              ELEN (I) = -NEL
+              PE (I) = 0
+              W (I) = 0
+
+              ENDIF
+
+20         CONTINUE
+
+C=======================================================================
+C  WHILE (selecting pivots) DO
+C=======================================================================
+
+30      CONTINUE
+        IF (NEL .LT. N) THEN
+
+C=======================================================================
+C  GET PIVOT OF MINIMUM DEGREE
+C=======================================================================
+
+C          -------------------------------------------------------------
+C          find next supervariable for elimination
+C          -------------------------------------------------------------
+
+           DO 40 DEG = MINDEG, N
+              ME = HEAD (DEG)
+              IF (ME .GT. 0) GOTO 50
+40            CONTINUE
+50         CONTINUE
+           MINDEG = DEG
+
+C          -------------------------------------------------------------
+C          remove chosen variable from link list
+C          -------------------------------------------------------------
+
+           INEXT = NEXT (ME)
+           IF (INEXT .NE. 0) LAST (INEXT) = 0
+           HEAD (DEG) = INEXT
+
+C          -------------------------------------------------------------
+C          me represents the elimination of pivots nel+1 to nel+nv(me).
+C          place me itself as the first in this set.  It will be moved
+C          to the nel+nv(me) position when the permutation vectors are
+C          computed.
+C          -------------------------------------------------------------
+
+           ELENME = ELEN (ME)
+           ELEN (ME) = - (NEL + 1)
+           NVPIV = NV (ME)
+           NEL = NEL + NVPIV
+
+C=======================================================================
+C  CONSTRUCT NEW ELEMENT
+C=======================================================================
+
+C          -------------------------------------------------------------
+C          At this point, me is the pivotal supervariable.  It will be
+C          converted into the current element.  Scan list of the
+C          pivotal supervariable, me, setting tree pointers and
+C          constructing new list of supervariables for the new element,
+C          me.  p is a pointer to the current position in the old list.
+C          -------------------------------------------------------------
+
+C          flag the variable "me" as being in Lme by negating nv (me)
+           NV (ME) = -NVPIV
+           DEGME = 0
+
+           IF (ELENME .EQ. 0) THEN
+
+C             ----------------------------------------------------------
+C             construct the new element in place
+C             ----------------------------------------------------------
+
+              PME1 = PE (ME)
+              PME2 = PME1 - 1
+
+              DO 60 P = PME1, PME1 + LEN (ME) - 1
+                 I = IW (P)
+                 NVI = NV (I)
+                 IF (NVI .GT. 0) THEN
+
+C                   ----------------------------------------------------
+C                   i is a principal variable not yet placed in Lme.
+C                   store i in new list
+C                   ----------------------------------------------------
+
+                    DEGME = DEGME + NVI
+C                   flag i as being in Lme by negating nv (i)
+                    NV (I) = -NVI
+                    PME2 = PME2 + 1
+                    IW (PME2) = I
+
+C                   ----------------------------------------------------
+C                   remove variable i from degree list.
+C                   ----------------------------------------------------
+
+                    ILAST = LAST (I)
+                    INEXT = NEXT (I)
+                    IF (INEXT .NE. 0) LAST (INEXT) = ILAST
+                    IF (ILAST .NE. 0) THEN
+                       NEXT (ILAST) = INEXT
+                    ELSE
+C                      i is at the head of the degree list
+                       HEAD (DEGREE (I)) = INEXT
+                       ENDIF
+
+                    ENDIF
+60               CONTINUE
+C             this element takes no new memory in iw:
+              NEWMEM = 0
+
+           ELSE
+
+C             ----------------------------------------------------------
+C             construct the new element in empty space, iw (pfree ...)
+C             ----------------------------------------------------------
+
+              P = PE (ME)
+              PME1 = PFREE
+              SLENME = LEN (ME) - ELENME
+
+              DO 120 KNT1 = 1, ELENME + 1
+
+                 IF (KNT1 .GT. ELENME) THEN
+C                   search the supervariables in me.
+                    E = ME
+                    PJ = P
+                    LN = SLENME
+                 ELSE
+C                   search the elements in me.
+                    E = IW (P)
+                    P = P + 1
+                    PJ = PE (E)
+                    LN = LEN (E)
+                    ENDIF
+
+C                -------------------------------------------------------
+C                search for different supervariables and add them to the
+C                new list, compressing when necessary. this loop is
+C                executed once for each element in the list and once for
+C                all the supervariables in the list.
+C                -------------------------------------------------------
+
+                 DO 110 KNT2 = 1, LN
+                    I = IW (PJ)
+                    PJ = PJ + 1
+                    NVI = NV (I)
+                    IF (NVI .GT. 0) THEN
+
+C                      -------------------------------------------------
+C                      compress iw, if necessary
+C                      -------------------------------------------------
+
+                       IF (PFREE .GT. IWLEN) THEN
+C                         prepare for compressing iw by adjusting
+C                         pointers and lengths so that the lists being
+C                         searched in the inner and outer loops contain
+C                         only the remaining entries.
+
+                          PE (ME) = P
+                          LEN (ME) = LEN (ME) - KNT1
+                          IF (LEN (ME) .EQ. 0) THEN
+C                            nothing left of supervariable me
+                             PE (ME) = 0
+                             ENDIF
+                          PE (E) = PJ
+                          LEN (E) = LN - KNT2
+                          IF (LEN (E) .EQ. 0) THEN
+C                            nothing left of element e
+                             PE (E) = 0
+                             ENDIF
+
+                          NCMPA = NCMPA + 1
+C                         store first item in pe
+C                         set first entry to -item
+                          DO 70 J = 1, N
+                             PN = PE (J)
+                             IF (PN .GT. 0) THEN
+                                PE (J) = IW (PN)
+                                IW (PN) = -J
+                                ENDIF
+70                           CONTINUE
+
+C                         psrc/pdst point to source/destination
+                          PDST = 1
+                          PSRC = 1
+                          PEND = PME1 - 1
+
+C                         while loop:
+80                        CONTINUE
+                          IF (PSRC .LE. PEND) THEN
+C                            search for next negative entry
+                             J = -IW (PSRC)
+                             PSRC = PSRC + 1
+                             IF (J .GT. 0) THEN
+                                IW (PDST) = PE (J)
+                                PE (J) = PDST
+                                PDST = PDST + 1
+C                               copy from source to destination
+                                LENJ = LEN (J)
+                                DO 90 KNT3 = 0, LENJ - 2
+                                   IW (PDST + KNT3) = IW (PSRC + KNT3)
+90                                 CONTINUE
+                                PDST = PDST + LENJ - 1
+                                PSRC = PSRC + LENJ - 1
+                                ENDIF
+                             GOTO 80
+                             ENDIF
+
+C                         move the new partially-constructed element
+                          P1 = PDST
+                          DO 100 PSRC = PME1, PFREE - 1
+                             IW (PDST) = IW (PSRC)
+                             PDST = PDST + 1
+100                          CONTINUE
+                          PME1 = P1
+                          PFREE = PDST
+                          PJ = PE (E)
+                          P = PE (ME)
+                          ENDIF
+
+C                      -------------------------------------------------
+C                      i is a principal variable not yet placed in Lme
+C                      store i in new list
+C                      -------------------------------------------------
+
+                       DEGME = DEGME + NVI
+C                      flag i as being in Lme by negating nv (i)
+                       NV (I) = -NVI
+                       IW (PFREE) = I
+                       PFREE = PFREE + 1
+
+C                      -------------------------------------------------
+C                      remove variable i from degree link list
+C                      -------------------------------------------------
+
+                       ILAST = LAST (I)
+                       INEXT = NEXT (I)
+                       IF (INEXT .NE. 0) LAST (INEXT) = ILAST
+                       IF (ILAST .NE. 0) THEN
+                          NEXT (ILAST) = INEXT
+                       ELSE
+C                         i is at the head of the degree list
+                          HEAD (DEGREE (I)) = INEXT
+                          ENDIF
+
+                       ENDIF
+110                 CONTINUE
+
+                 IF (E .NE. ME) THEN
+C                   set tree pointer and flag to indicate element e is
+C                   absorbed into new element me (the parent of e is me)
+                    PE (E) = -ME
+                    W (E) = 0
+                    ENDIF
+120              CONTINUE
+
+              PME2 = PFREE - 1
+C             this element takes newmem new memory in iw (possibly zero)
+              NEWMEM = PFREE - PME1
+              MEM = MEM + NEWMEM
+              MAXMEM = MAX (MAXMEM, MEM)
+              ENDIF
+
+C          -------------------------------------------------------------
+C          me has now been converted into an element in iw (pme1..pme2)
+C          -------------------------------------------------------------
+
+C          degme holds the external degree of new element
+           DEGREE (ME) = DEGME
+           PE (ME) = PME1
+           LEN (ME) = PME2 - PME1 + 1
+
+C          -------------------------------------------------------------
+C          make sure that wflg is not too large.  With the current
+C          value of wflg, wflg+n must not cause integer overflow
+C          -------------------------------------------------------------
+
+           IF (WFLG + N .LE. WFLG) THEN
+              DO 130 X = 1, N
+                 IF (W (X) .NE. 0) W (X) = 1
+130              CONTINUE
+              WFLG = 2
+              ENDIF
+
+C=======================================================================
+C  COMPUTE (w (e) - wflg) = |Le\Lme| FOR ALL ELEMENTS
+C=======================================================================
+
+C          -------------------------------------------------------------
+C          Scan 1:  compute the external degrees of previous elements
+C          with respect to the current element.  That is:
+C               (w (e) - wflg) = |Le \ Lme|
+C          for each element e that appears in any supervariable in Lme.
+C          The notation Le refers to the pattern (list of
+C          supervariables) of a previous element e, where e is not yet
+C          absorbed, stored in iw (pe (e) + 1 ... pe (e) + iw (pe (e))).
+C          The notation Lme refers to the pattern of the current element
+C          (stored in iw (pme1..pme2)).   If (w (e) - wflg) becomes
+C          zero, then the element e will be absorbed in scan 2.
+C          -------------------------------------------------------------
+
+           DO 150 PME = PME1, PME2
+              I = IW (PME)
+              ELN = ELEN (I)
+              IF (ELN .GT. 0) THEN
+C                note that nv (i) has been negated to denote i in Lme:
+                 NVI = -NV (I)
+                 WNVI = WFLG - NVI
+                 DO 140 P = PE (I), PE (I) + ELN - 1
+                    E = IW (P)
+                    WE = W (E)
+                    IF (WE .GE. WFLG) THEN
+C                      unabsorbed element e has been seen in this loop
+                       WE = WE - NVI
+                    ELSE IF (WE .NE. 0) THEN
+C                      e is an unabsorbed element
+C                      this is the first we have seen e in all of Scan 1
+                       WE = DEGREE (E) + WNVI
+                       ENDIF
+                    W (E) = WE
+140                 CONTINUE
+                 ENDIF
+150           CONTINUE
+
+C=======================================================================
+C  DEGREE UPDATE AND ELEMENT ABSORPTION
+C=======================================================================
+
+C          -------------------------------------------------------------
+C          Scan 2:  for each i in Lme, sum up the degree of Lme (which
+C          is degme), plus the sum of the external degrees of each Le
+C          for the elements e appearing within i, plus the
+C          supervariables in i.  Place i in hash list.
+C          -------------------------------------------------------------
+
+           DO 180 PME = PME1, PME2
+              I = IW (PME)
+              P1 = PE (I)
+              P2 = P1 + ELEN (I) - 1
+              PN = P1
+              HASH = 0
+              DEG = 0
+
+C             ----------------------------------------------------------
+C             scan the element list associated with supervariable i
+C             ----------------------------------------------------------
+
+              DO 160 P = P1, P2
+                 E = IW (P)
+C                dext = | Le \ Lme |
+                 DEXT = W (E) - WFLG
+                 IF (DEXT .GT. 0) THEN
+                    DEG = DEG + DEXT
+                    IW (PN) = E
+                    PN = PN + 1
+                    HASH = HASH + E
+                 ELSE IF (DEXT .EQ. 0) THEN
+C                   aggressive absorption: e is not adjacent to me, but
+C                   the |Le \ Lme| is 0, so absorb it into me
+                    PE (E) = -ME
+                    W (E) = 0
+                 ELSE
+C                   element e has already been absorbed, due to
+C                   regular absorption, in do loop 120 above. Ignore it.
+                    CONTINUE
+                    ENDIF
+160              CONTINUE
+
+C             count the number of elements in i (including me):
+              ELEN (I) = PN - P1 + 1
+
+C             ----------------------------------------------------------
+C             scan the supervariables in the list associated with i
+C             ----------------------------------------------------------
+
+              P3 = PN
+              DO 170 P = P2 + 1, P1 + LEN (I) - 1
+                 J = IW (P)
+                 NVJ = NV (J)
+                 IF (NVJ .GT. 0) THEN
+C                   j is unabsorbed, and not in Lme.
+C                   add to degree and add to new list
+                    DEG = DEG + NVJ
+                    IW (PN) = J
+                    PN = PN + 1
+                    HASH = HASH + J
+                    ENDIF
+170              CONTINUE
+
+C             ----------------------------------------------------------
+C             update the degree and check for mass elimination
+C             ----------------------------------------------------------
+
+              IF (DEG .EQ. 0) THEN
+
+C                -------------------------------------------------------
+C                mass elimination
+C                -------------------------------------------------------
+
+C                There is nothing left of this node except for an
+C                edge to the current pivot element.  elen (i) is 1,
+C                and there are no variables adjacent to node i.
+C                Absorb i into the current pivot element, me.
+
+                 PE (I) = -ME
+                 NVI = -NV (I)
+                 DEGME = DEGME - NVI
+                 NVPIV = NVPIV + NVI
+                 NEL = NEL + NVI
+                 NV (I) = 0
+                 ELEN (I) = 0
+
+              ELSE
+
+C                -------------------------------------------------------
+C                update the upper-bound degree of i
+C                -------------------------------------------------------
+
+C                the following degree does not yet include the size
+C                of the current element, which is added later:
+                 DEGREE (I) = MIN (DEGREE (I), DEG)
+
+C                -------------------------------------------------------
+C                add me to the list for i
+C                -------------------------------------------------------
+
+C                move first supervariable to end of list
+                 IW (PN) = IW (P3)
+C                move first element to end of element part of list
+                 IW (P3) = IW (P1)
+C                add new element to front of list.
+                 IW (P1) = ME
+C                store the new length of the list in len (i)
+                 LEN (I) = PN - P1 + 1
+
+C                -------------------------------------------------------
+C                place in hash bucket.  Save hash key of i in last (i).
+C                -------------------------------------------------------
+
+                 HASH = MOD (HASH, HMOD) + 1
+                 J = HEAD (HASH)
+                 IF (J .LE. 0) THEN
+C                   the degree list is empty, hash head is -j
+                    NEXT (I) = -J
+                    HEAD (HASH) = -I
+                 ELSE
+C                   degree list is not empty
+C                   use last (head (hash)) as hash head
+                    NEXT (I) = LAST (J)
+                    LAST (J) = I
+                    ENDIF
+                 LAST (I) = HASH
+                 ENDIF
+180           CONTINUE
+
+           DEGREE (ME) = DEGME
+
+C          -------------------------------------------------------------
+C          Clear the counter array, w (...), by incrementing wflg.
+C          -------------------------------------------------------------
+
+           DMAX = MAX (DMAX, DEGME)
+           WFLG = WFLG + DMAX
+
+C          make sure that wflg+n does not cause integer overflow
+           IF (WFLG + N .LE. WFLG) THEN
+              DO 190 X = 1, N
+                 IF (W (X) .NE. 0) W (X) = 1
+190              CONTINUE
+              WFLG = 2
+              ENDIF
+C          at this point, w (1..n) .lt. wflg holds
+
+C=======================================================================
+C  SUPERVARIABLE DETECTION
+C=======================================================================
+
+           DO 250 PME = PME1, PME2
+              I = IW (PME)
+              IF (NV (I) .LT. 0) THEN
+C                i is a principal variable in Lme
+
+C                -------------------------------------------------------
+C                examine all hash buckets with 2 or more variables.  We
+C                do this by examing all unique hash keys for super-
+C                variables in the pattern Lme of the current element, me
+C                -------------------------------------------------------
+
+                 HASH = LAST (I)
+C                let i = head of hash bucket, and empty the hash bucket
+                 J = HEAD (HASH)
+                 IF (J .EQ. 0) GOTO 250
+                 IF (J .LT. 0) THEN
+C                   degree list is empty
+                    I = -J
+                    HEAD (HASH) = 0
+                 ELSE
+C                   degree list is not empty, restore last () of head
+                    I = LAST (J)
+                    LAST (J) = 0
+                    ENDIF
+                 IF (I .EQ. 0) GOTO 250
+
+C                while loop:
+200              CONTINUE
+                 IF (NEXT (I) .NE. 0) THEN
+
+C                   ----------------------------------------------------
+C                   this bucket has one or more variables following i.
+C                   scan all of them to see if i can absorb any entries
+C                   that follow i in hash bucket.  Scatter i into w.
+C                   ----------------------------------------------------
+
+                    LN = LEN (I)
+                    ELN = ELEN (I)
+C                   do not flag the first element in the list (me)
+                    DO 210 P = PE (I) + 1, PE (I) + LN - 1
+                       W (IW (P)) = WFLG
+210                    CONTINUE
+
+C                   ----------------------------------------------------
+C                   scan every other entry j following i in bucket
+C                   ----------------------------------------------------
+
+                    JLAST = I
+                    J = NEXT (I)
+
+C                   while loop:
+220                 CONTINUE
+                    IF (J .NE. 0) THEN
+
+C                      -------------------------------------------------
+C                      check if j and i have identical nonzero pattern
+C                      -------------------------------------------------
+
+                       IF (LEN (J) .NE. LN) THEN
+C                         i and j do not have same size data structure
+                          GOTO 240
+                          ENDIF
+                       IF (ELEN (J) .NE. ELN) THEN
+C                         i and j do not have same number of adjacent el
+                          GOTO 240
+                          ENDIF
+C                      do not flag the first element in the list (me)
+                       DO 230 P = PE (J) + 1, PE (J) + LN - 1
+                          IF (W (IW (P)) .NE. WFLG) THEN
+C                            an entry (iw(p)) is in j but not in i
+                             GOTO 240
+                             ENDIF
+230                       CONTINUE
+
+C                      -------------------------------------------------
+C                      found it!  j can be absorbed into i
+C                      -------------------------------------------------
+
+                       PE (J) = -I
+C                      both nv (i) and nv (j) are negated since they
+C                      are in Lme, and the absolute values of each
+C                      are the number of variables in i and j:
+                       NV (I) = NV (I) + NV (J)
+                       NV (J) = 0
+                       ELEN (J) = 0
+C                      delete j from hash bucket
+                       J = NEXT (J)
+                       NEXT (JLAST) = J
+                       GOTO 220
+
+C                      -------------------------------------------------
+240                    CONTINUE
+C                      j cannot be absorbed into i
+C                      -------------------------------------------------
+
+                       JLAST = J
+                       J = NEXT (J)
+                       GOTO 220
+                       ENDIF
+
+C                   ----------------------------------------------------
+C                   no more variables can be absorbed into i
+C                   go to next i in bucket and clear flag array
+C                   ----------------------------------------------------
+
+                    WFLG = WFLG + 1
+                    I = NEXT (I)
+                    IF (I .NE. 0) GOTO 200
+                    ENDIF
+                 ENDIF
+250           CONTINUE
+
+C=======================================================================
+C  RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVAR. FROM ELEMENT
+C=======================================================================
+
+           P = PME1
+           NLEFT = N - NEL
+           DO 260 PME = PME1, PME2
+              I = IW (PME)
+              NVI = -NV (I)
+              IF (NVI .GT. 0) THEN
+C                i is a principal variable in Lme
+C                restore nv (i) to signify that i is principal
+                 NV (I) = NVI
+
+C                -------------------------------------------------------
+C                compute the external degree (add size of current elem)
+C                -------------------------------------------------------
+
+                 DEG = MIN (DEGREE (I) + DEGME - NVI, NLEFT - NVI)
+
+C                -------------------------------------------------------
+C                place the supervariable at the head of the degree list
+C                -------------------------------------------------------
+
+                 INEXT = HEAD (DEG)
+                 IF (INEXT .NE. 0) LAST (INEXT) = I
+                 NEXT (I) = INEXT
+                 LAST (I) = 0
+                 HEAD (DEG) = I
+
+C                -------------------------------------------------------
+C                save the new degree, and find the minimum degree
+C                -------------------------------------------------------
+
+                 MINDEG = MIN (MINDEG, DEG)
+                 DEGREE (I) = DEG
+
+C                -------------------------------------------------------
+C                place the supervariable in the element pattern
+C                -------------------------------------------------------
+
+                 IW (P) = I
+                 P = P + 1
+                 ENDIF
+260           CONTINUE
+
+C=======================================================================
+C  FINALIZE THE NEW ELEMENT
+C=======================================================================
+
+           NV (ME) = NVPIV + DEGME
+C          nv (me) is now the degree of pivot (including diagonal part)
+C          save the length of the list for the new element me
+           LEN (ME) = P - PME1
+           IF (LEN (ME) .EQ. 0) THEN
+C             there is nothing left of the current pivot element
+              PE (ME) = 0
+              W (ME) = 0
+              ENDIF
+           IF (NEWMEM .NE. 0) THEN
+C             element was not constructed in place: deallocate part
+C             of it (final size is less than or equal to newmem,
+C             since newly nonprincipal variables have been removed).
+              PFREE = P
+              MEM = MEM - NEWMEM + LEN (ME)
+              ENDIF
+
+C=======================================================================
+C          END WHILE (selecting pivots)
+           GOTO 30
+           ENDIF
+C=======================================================================
+
+C=======================================================================
+C  COMPUTE THE PERMUTATION VECTORS
+C=======================================================================
+
+C       ----------------------------------------------------------------
+C       The time taken by the following code is O(n).  At this
+C       point, elen (e) = -k has been done for all elements e,
+C       and elen (i) = 0 has been done for all nonprincipal
+C       variables i.  At this point, there are no principal
+C       supervariables left, and all elements are absorbed.
+C       ----------------------------------------------------------------
+
+C       ----------------------------------------------------------------
+C       compute the ordering of unordered nonprincipal variables
+C       ----------------------------------------------------------------
+
+        DO 290 I = 1, N
+           IF (ELEN (I) .EQ. 0) THEN
+
+C             ----------------------------------------------------------
+C             i is an un-ordered row.  Traverse the tree from i until
+C             reaching an element, e.  The element, e, was the
+C             principal supervariable of i and all nodes in the path
+C             from i to when e was selected as pivot.
+C             ----------------------------------------------------------
+
+              J = -PE (I)
+C             while (j is a variable) do:
+270           CONTINUE
+              IF (ELEN (J) .GE. 0) THEN
+                 J = -PE (J)
+                 GOTO 270
+                 ENDIF
+              E = J
+
+C             ----------------------------------------------------------
+C             get the current pivot ordering of e
+C             ----------------------------------------------------------
+
+              K = -ELEN (E)
+
+C             ----------------------------------------------------------
+C             traverse the path again from i to e, and compress the
+C             path (all nodes point to e).  Path compression allows
+C             this code to compute in O(n) time.  Order the unordered
+C             nodes in the path, and place the element e at the end.
+C             ----------------------------------------------------------
+
+              J = I
+C             while (j is a variable) do:
+280           CONTINUE
+              IF (ELEN (J) .GE. 0) THEN
+                 JNEXT = -PE (J)
+                 PE (J) = -E
+                 IF (ELEN (J) .EQ. 0) THEN
+C                   j is an unordered row
+                    ELEN (J) = K
+                    K = K + 1
+                    ENDIF
+                 J = JNEXT
+                 GOTO 280
+                 ENDIF
+C             leave elen (e) negative, so we know it is an element
+              ELEN (E) = -K
+              ENDIF
+290        CONTINUE
+
+C       ----------------------------------------------------------------
+C       reset the inverse permutation (elen (1..n)) to be positive,
+C       and compute the permutation (last (1..n)).
+C       ----------------------------------------------------------------
+
+        DO 300 I = 1, N
+           K = ABS (ELEN (I))
+           LAST (K) = I
+           ELEN (I) = K
+300        CONTINUE
+
+C=======================================================================
+C  RETURN THE MEMORY USAGE IN IW
+C=======================================================================
+
+C       If maxmem is less than or equal to iwlen, then no compressions
+C       occurred, and iw (maxmem+1 ... iwlen) was unused.  Otherwise
+C       compressions did occur, and iwlen would have had to have been
+C       greater than or equal to maxmem for no compressions to occur.
+C       Return the value of maxmem in the pfree argument.
+
+        PFREE = MAXMEM
+
+        RETURN
+        END
+
diff --git a/src/C/SuiteSparse/AMD/Source/amd_1.c b/src/C/SuiteSparse/AMD/Source/amd_1.c
new file mode 100644
index 0000000..a85c184
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Source/amd_1.c
@@ -0,0 +1,181 @@
+/* ========================================================================= */
+/* === AMD_1 =============================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 2.0, Copyright (c) 2006 by Timothy A. Davis,		     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_1: Construct A+A' for a sparse matrix A and perform the AMD ordering.
+ *
+ * The n-by-n sparse matrix A can be unsymmetric.  It is stored in MATLAB-style
+ * compressed-column form, with sorted row indices in each column, and no
+ * duplicate entries.  Diagonal entries may be present, but they are ignored.
+ * Row indices of column j of A are stored in Ai [Ap [j] ... Ap [j+1]-1].
+ * Ap [0] must be zero, and nz = Ap [n] is the number of entries in A.  The
+ * size of the matrix, n, must be greater than or equal to zero.
+ *
+ * This routine must be preceded by a call to AMD_aat, which computes the
+ * number of entries in each row/column in A+A', excluding the diagonal.
+ * Len [j], on input, is the number of entries in row/column j of A+A'.  This
+ * routine constructs the matrix A+A' and then calls AMD_2.  No error checking
+ * is performed (this was done in AMD_valid).
+ */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_1
+(
+    Int n,		/* n > 0 */
+    const Int Ap [ ],	/* input of size n+1, not modified */
+    const Int Ai [ ],	/* input of size nz = Ap [n], not modified */
+    Int P [ ],		/* size n output permutation */
+    Int Pinv [ ],	/* size n output inverse permutation */
+    Int Len [ ],	/* size n input, undefined on output */
+    Int slen,		/* slen >= sum (Len [0..n-1]) + 7n,
+			 * ideally slen = 1.2 * sum (Len) + 8n */
+    Int S [ ],		/* size slen workspace */
+    double Control [ ],	/* input array of size AMD_CONTROL */
+    double Info [ ]	/* output array of size AMD_INFO */
+)
+{
+    Int i, j, k, p, pfree, iwlen, pj, p1, p2, pj2, *Iw, *Pe, *Nv, *Head,
+	*Elen, *Degree, *s, *W, *Sp, *Tp ;
+
+    /* --------------------------------------------------------------------- */
+    /* construct the matrix for AMD_2 */
+    /* --------------------------------------------------------------------- */
+
+    ASSERT (n > 0) ;
+
+    iwlen = slen - 6*n ;
+    s = S ;
+    Pe = s ;	    s += n ;
+    Nv = s ;	    s += n ;
+    Head = s ;	    s += n ;
+    Elen = s ;	    s += n ;
+    Degree = s ;    s += n ;
+    W = s ;	    s += n ;
+    Iw = s ;	    s += iwlen ;
+
+    ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
+
+    /* construct the pointers for A+A' */
+    Sp = Nv ;			/* use Nv and W as workspace for Sp and Tp [ */
+    Tp = W ;
+    pfree = 0 ;
+    for (j = 0 ; j < n ; j++)
+    {
+	Pe [j] = pfree ;
+	Sp [j] = pfree ;
+	pfree += Len [j] ;
+    }
+
+    /* Note that this restriction on iwlen is slightly more restrictive than
+     * what is strictly required in AMD_2.  AMD_2 can operate with no elbow
+     * room at all, but it will be very slow.  For better performance, at
+     * least size-n elbow room is enforced. */
+    ASSERT (iwlen >= pfree + n) ;
+
+#ifndef NDEBUG
+    for (p = 0 ; p < iwlen ; p++) Iw [p] = EMPTY ;
+#endif
+
+    for (k = 0 ; k < n ; k++)
+    {
+	AMD_DEBUG1 (("Construct row/column k= "ID" of A+A'\n", k))  ;
+	p1 = Ap [k] ;
+	p2 = Ap [k+1] ;
+
+	/* construct A+A' */
+	for (p = p1 ; p < p2 ; )
+	{
+	    /* scan the upper triangular part of A */
+	    j = Ai [p] ;
+	    ASSERT (j >= 0 && j < n) ;
+	    if (j < k)
+	    {
+		/* entry A (j,k) in the strictly upper triangular part */
+		ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+		ASSERT (Sp [k] < (k == n-1 ? pfree : Pe [k+1])) ;
+		Iw [Sp [j]++] = k ;
+		Iw [Sp [k]++] = j ;
+		p++ ;
+	    }
+	    else if (j == k)
+	    {
+		/* skip the diagonal */
+		p++ ;
+		break ;
+	    }
+	    else /* j > k */
+	    {
+		/* first entry below the diagonal */
+		break ;
+	    }
+	    /* scan lower triangular part of A, in column j until reaching
+	     * row k.  Start where last scan left off. */
+	    ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
+	    pj2 = Ap [j+1] ;
+	    for (pj = Tp [j] ; pj < pj2 ; )
+	    {
+		i = Ai [pj] ;
+		ASSERT (i >= 0 && i < n) ;
+		if (i < k)
+		{
+		    /* A (i,j) is only in the lower part, not in upper */
+		    ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
+		    ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+		    Iw [Sp [i]++] = j ;
+		    Iw [Sp [j]++] = i ;
+		    pj++ ;
+		}
+		else if (i == k)
+		{
+		    /* entry A (k,j) in lower part and A (j,k) in upper */
+		    pj++ ;
+		    break ;
+		}
+		else /* i > k */
+		{
+		    /* consider this entry later, when k advances to i */
+		    break ;
+		}
+	    }
+	    Tp [j] = pj ;
+	}
+	Tp [k] = p ;
+    }
+
+    /* clean up, for remaining mismatched entries */
+    for (j = 0 ; j < n ; j++)
+    {
+	for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
+	{
+	    i = Ai [pj] ;
+	    ASSERT (i >= 0 && i < n) ;
+	    /* A (i,j) is only in the lower part, not in upper */
+	    ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
+	    ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+	    Iw [Sp [i]++] = j ;
+	    Iw [Sp [j]++] = i ;
+	}
+    }
+
+#ifndef NDEBUG
+    for (j = 0 ; j < n-1 ; j++) ASSERT (Sp [j] == Pe [j+1]) ;
+    ASSERT (Sp [n-1] == pfree) ;
+#endif
+
+    /* Tp and Sp no longer needed ] */
+
+    /* --------------------------------------------------------------------- */
+    /* order the matrix */
+    /* --------------------------------------------------------------------- */
+
+    AMD_2 (n, Pe, Iw, Len, iwlen, pfree,
+	Nv, Pinv, P, Head, Elen, Degree, W, Control, Info) ;
+}
diff --git a/src/C/SuiteSparse/AMD/Source/amd_2.c b/src/C/SuiteSparse/AMD/Source/amd_2.c
new file mode 100644
index 0000000..a760877
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Source/amd_2.c
@@ -0,0 +1,1842 @@
+/* ========================================================================= */
+/* === AMD_2 =============================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 2.0, Copyright (c) 2006 by Timothy A. Davis,		     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_2:  performs the AMD ordering on a symmetric sparse matrix A, followed
+ * by a postordering (via depth-first search) of the assembly tree using the
+ * AMD_postorder routine.
+ */
+
+#include "amd_internal.h"
+
+/* ========================================================================= */
+/* === clear_flag ========================================================== */
+/* ========================================================================= */
+
+static Int clear_flag (Int wflg, Int wbig, Int W [ ], Int n)
+{
+    Int x ;
+    if (wflg < 2 || wflg >= wbig)
+    {
+	for (x = 0 ; x < n ; x++)
+	{
+	    if (W [x] != 0) W [x] = 1 ;
+	}
+	wflg = 2 ;
+    }
+    /*  at this point, W [0..n-1] < wflg holds */
+    return (wflg) ;
+}
+
+
+/* ========================================================================= */
+/* === AMD_2 =============================================================== */
+/* ========================================================================= */
+
+GLOBAL void AMD_2
+(
+    Int n,		/* A is n-by-n, where n > 0 */
+    Int Pe [ ],		/* Pe [0..n-1]: index in Iw of row i on input */
+    Int Iw [ ],		/* workspace of size iwlen. Iw [0..pfree-1]
+			 * holds the matrix on input */
+    Int Len [ ],	/* Len [0..n-1]: length for row/column i on input */
+    Int iwlen,		/* length of Iw. iwlen >= pfree + n */
+    Int pfree,		/* Iw [pfree ... iwlen-1] is empty on input */
+
+    /* 7 size-n workspaces, not defined on input: */
+    Int Nv [ ],		/* the size of each supernode on output */
+    Int Next [ ],	/* the output inverse permutation */
+    Int Last [ ],	/* the output permutation */
+    Int Head [ ],
+    Int Elen [ ],	/* the size columns of L for each supernode */
+    Int Degree [ ],
+    Int W [ ],
+
+    /* control parameters and output statistics */
+    double Control [ ],	/* array of size AMD_CONTROL */
+    double Info [ ]	/* array of size AMD_INFO */
+)
+{
+
+/*
+ * Given a representation of the nonzero pattern of a symmetric matrix, A,
+ * (excluding the diagonal) perform an approximate minimum (UMFPACK/MA38-style)
+ * degree ordering to compute a pivot order such that the introduction of
+ * nonzeros (fill-in) in the Cholesky factors A = LL' is kept low.  At each
+ * step, the pivot selected is the one with the minimum UMFAPACK/MA38-style
+ * upper-bound on the external degree.  This routine can optionally perform
+ * aggresive absorption (as done by MC47B in the Harwell Subroutine
+ * Library).
+ *
+ * The approximate degree algorithm implemented here is the symmetric analog of
+ * the degree update algorithm in MA38 and UMFPACK (the Unsymmetric-pattern
+ * MultiFrontal PACKage, both by Davis and Duff).  The routine is based on the
+ * MA27 minimum degree ordering algorithm by Iain Duff and John Reid.
+ *
+ * This routine is a translation of the original AMDBAR and MC47B routines,
+ * in Fortran, with the following modifications:
+ *
+ * (1) dense rows/columns are removed prior to ordering the matrix, and placed
+ *	last in the output order.  The presence of a dense row/column can
+ *	increase the ordering time by up to O(n^2), unless they are removed
+ *	prior to ordering.
+ *
+ * (2) the minimum degree ordering is followed by a postordering (depth-first
+ *	search) of the assembly tree.  Note that mass elimination (discussed
+ *	below) combined with the approximate degree update can lead to the mass
+ *	elimination of nodes with lower exact degree than the current pivot
+ *	element.  No additional fill-in is caused in the representation of the
+ *	Schur complement.  The mass-eliminated nodes merge with the current
+ *	pivot element.  They are ordered prior to the current pivot element.
+ *	Because they can have lower exact degree than the current element, the
+ *	merger of two or more of these nodes in the current pivot element can
+ *	lead to a single element that is not a "fundamental supernode".  The
+ *	diagonal block can have zeros in it.  Thus, the assembly tree used here
+ *	is not guaranteed to be the precise supernodal elemination tree (with
+ *	"funadmental" supernodes), and the postordering performed by this
+ *	routine is not guaranteed to be a precise postordering of the
+ *	elimination tree.
+ *
+ * (3) input parameters are added, to control aggressive absorption and the
+ *	detection of "dense" rows/columns of A.
+ *
+ * (4) additional statistical information is returned, such as the number of
+ *	nonzeros in L, and the flop counts for subsequent LDL' and LU
+ *	factorizations.  These are slight upper bounds, because of the mass
+ *	elimination issue discussed above.
+ *
+ * (5) additional routines are added to interface this routine to MATLAB
+ *	to provide a simple C-callable user-interface, to check inputs for
+ *	errors, compute the symmetry of the pattern of A and the number of
+ *	nonzeros in each row/column of A+A', to compute the pattern of A+A',
+ *	to perform the assembly tree postordering, and to provide debugging
+ *	ouput.  Many of these functions are also provided by the Fortran
+ *	Harwell Subroutine Library routine MC47A.
+ *
+ * (6) both int and UF_long versions are provided.  In the descriptions below
+ *	and integer is and int or UF_long depending on which version is
+ *	being used.
+
+ **********************************************************************
+ ***** CAUTION:  ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT.  ******
+ **********************************************************************
+ ** If you want error checking, a more versatile input format, and a **
+ ** simpler user interface, use amd_order or amd_l_order instead.    **
+ ** This routine is not meant to be user-callable.                   **
+ **********************************************************************
+
+ * ----------------------------------------------------------------------------
+ * References:
+ * ----------------------------------------------------------------------------
+ *
+ *  [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern multifrontal
+ *	method for sparse LU factorization", SIAM J. Matrix Analysis and
+ *	Applications, vol. 18, no. 1, pp. 140-158.  Discusses UMFPACK / MA38,
+ *	which first introduced the approximate minimum degree used by this
+ *	routine.
+ *
+ *  [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An approximate
+ *	minimum degree ordering algorithm," SIAM J. Matrix Analysis and
+ *	Applications, vol. 17, no. 4, pp. 886-905, 1996.  Discusses AMDBAR and
+ *	MC47B, which are the Fortran versions of this routine.
+ *
+ *  [3] Alan George and Joseph Liu, "The evolution of the minimum degree
+ *	ordering algorithm," SIAM Review, vol. 31, no. 1, pp. 1-19, 1989.
+ *	We list below the features mentioned in that paper that this code
+ *	includes:
+ *
+ *	mass elimination:
+ *	    Yes.  MA27 relied on supervariable detection for mass elimination.
+ *
+ *	indistinguishable nodes:
+ *	    Yes (we call these "supervariables").  This was also in the MA27
+ *	    code - although we modified the method of detecting them (the
+ *	    previous hash was the true degree, which we no longer keep track
+ *	    of).  A supervariable is a set of rows with identical nonzero
+ *	    pattern.  All variables in a supervariable are eliminated together.
+ *	    Each supervariable has as its numerical name that of one of its
+ *	    variables (its principal variable).
+ *
+ *	quotient graph representation:
+ *	    Yes.  We use the term "element" for the cliques formed during
+ *	    elimination.  This was also in the MA27 code.  The algorithm can
+ *	    operate in place, but it will work more efficiently if given some
+ *	    "elbow room."
+ *
+ *	element absorption:
+ *	    Yes.  This was also in the MA27 code.
+ *
+ *	external degree:
+ *	    Yes.  The MA27 code was based on the true degree.
+ *
+ *	incomplete degree update and multiple elimination:
+ *	    No.  This was not in MA27, either.  Our method of degree update
+ *	    within MC47B is element-based, not variable-based.  It is thus
+ *	    not well-suited for use with incomplete degree update or multiple
+ *	    elimination.
+ *
+ * Authors, and Copyright (C) 2004 by:
+ * Timothy A. Davis, Patrick Amestoy, Iain S. Duff, John K. Reid.
+ *
+ * Acknowledgements: This work (and the UMFPACK package) was supported by the
+ * National Science Foundation (ASC-9111263, DMS-9223088, and CCR-0203270).
+ * The UMFPACK/MA38 approximate degree update algorithm, the unsymmetric analog
+ * which forms the basis of AMD, was developed while Tim Davis was supported by
+ * CERFACS (Toulouse, France) in a post-doctoral position.  This C version, and
+ * the etree postorder, were written while Tim Davis was on sabbatical at
+ * Stanford University and Lawrence Berkeley National Laboratory.
+
+ * ----------------------------------------------------------------------------
+ * INPUT ARGUMENTS (unaltered):
+ * ----------------------------------------------------------------------------
+
+ * n:  The matrix order.  Restriction:  n >= 1.
+ *
+ * iwlen:  The size of the Iw array.  On input, the matrix is stored in
+ *	Iw [0..pfree-1].  However, Iw [0..iwlen-1] should be slightly larger
+ *	than what is required to hold the matrix, at least iwlen >= pfree + n.
+ *	Otherwise, excessive compressions will take place.  The recommended
+ *	value of iwlen is 1.2 * pfree + n, which is the value used in the
+ *	user-callable interface to this routine (amd_order.c).  The algorithm
+ *	will not run at all if iwlen < pfree.  Restriction: iwlen >= pfree + n.
+ *	Note that this is slightly more restrictive than the actual minimum
+ *	(iwlen >= pfree), but AMD_2 will be very slow with no elbow room.
+ *	Thus, this routine enforces a bare minimum elbow room of size n.
+ *
+ * pfree: On input the tail end of the array, Iw [pfree..iwlen-1], is empty,
+ *	and the matrix is stored in Iw [0..pfree-1].  During execution,
+ *	additional data is placed in Iw, and pfree is modified so that
+ *	Iw [pfree..iwlen-1] is always the unused part of Iw.
+ *
+ * Control:  A double array of size AMD_CONTROL containing input parameters
+ *	that affect how the ordering is computed.  If NULL, then default
+ *	settings are used.
+ *
+ *	Control [AMD_DENSE] is used to determine whether or not a given input
+ *	row is "dense".  A row is "dense" if the number of entries in the row
+ *	exceeds Control [AMD_DENSE] times sqrt (n), except that rows with 16 or
+ *	fewer entries are never considered "dense".  To turn off the detection
+ *	of dense rows, set Control [AMD_DENSE] to a negative number, or to a
+ *	number larger than sqrt (n).  The default value of Control [AMD_DENSE]
+ *	is AMD_DEFAULT_DENSE, which is defined in amd.h as 10.
+ *
+ *	Control [AMD_AGGRESSIVE] is used to determine whether or not aggressive
+ *	absorption is to be performed.  If nonzero, then aggressive absorption
+ *	is performed (this is the default).
+
+ * ----------------------------------------------------------------------------
+ * INPUT/OUPUT ARGUMENTS:
+ * ----------------------------------------------------------------------------
+ *
+ * Pe:  An integer array of size n.  On input, Pe [i] is the index in Iw of
+ *	the start of row i.  Pe [i] is ignored if row i has no off-diagonal
+ *	entries.  Thus Pe [i] must be in the range 0 to pfree-1 for non-empty
+ *	rows.
+ *
+ *	During execution, it is used for both supervariables and elements:
+ *
+ *	Principal supervariable i:  index into Iw of the description of
+ *	    supervariable i.  A supervariable represents one or more rows of
+ *	    the matrix with identical nonzero pattern.  In this case,
+ *	    Pe [i] >= 0.
+ *
+ *	Non-principal supervariable i:  if i has been absorbed into another
+ *	    supervariable j, then Pe [i] = FLIP (j), where FLIP (j) is defined
+ *	    as (-(j)-2).  Row j has the same pattern as row i.  Note that j
+ *	    might later be absorbed into another supervariable j2, in which
+ *	    case Pe [i] is still FLIP (j), and Pe [j] = FLIP (j2) which is
+ *	    < EMPTY, where EMPTY is defined as (-1) in amd_internal.h.
+ *
+ *	Unabsorbed element e:  the index into Iw of the description of element
+ *	    e, if e has not yet been absorbed by a subsequent element.  Element
+ *	    e is created when the supervariable of the same name is selected as
+ *	    the pivot.  In this case, Pe [i] >= 0.
+ *
+ *	Absorbed element e:  if element e is absorbed into element e2, then
+ *	    Pe [e] = FLIP (e2).  This occurs when the pattern of e (which we
+ *	    refer to as Le) is found to be a subset of the pattern of e2 (that
+ *	    is, Le2).  In this case, Pe [i] < EMPTY.  If element e is "null"
+ *	    (it has no nonzeros outside its pivot block), then Pe [e] = EMPTY,
+ *	    and e is the root of an assembly subtree (or the whole tree if
+ *	    there is just one such root).
+ *
+ *	Dense variable i:  if i is "dense", then Pe [i] = EMPTY.
+ *
+ *	On output, Pe holds the assembly tree/forest, which implicitly
+ *	represents a pivot order with identical fill-in as the actual order
+ *	(via a depth-first search of the tree), as follows.  If Nv [i] > 0,
+ *	then i represents a node in the assembly tree, and the parent of i is
+ *	Pe [i], or EMPTY if i is a root.  If Nv [i] = 0, then (i, Pe [i])
+ *	represents an edge in a subtree, the root of which is a node in the
+ *	assembly tree.  Note that i refers to a row/column in the original
+ *	matrix, not the permuted matrix.
+ *
+ * Info:  A double array of size AMD_INFO.  If present, (that is, not NULL),
+ *	then statistics about the ordering are returned in the Info array.
+ *	See amd.h for a description.
+
+ * ----------------------------------------------------------------------------
+ * INPUT/MODIFIED (undefined on output):
+ * ----------------------------------------------------------------------------
+ *
+ * Len:  An integer array of size n.  On input, Len [i] holds the number of
+ *	entries in row i of the matrix, excluding the diagonal.  The contents
+ *	of Len are undefined on output.
+ *
+ * Iw:  An integer array of size iwlen.  On input, Iw [0..pfree-1] holds the
+ *	description of each row i in the matrix.  The matrix must be symmetric,
+ *	and both upper and lower triangular parts must be present.  The
+ *	diagonal must not be present.  Row i is held as follows:
+ *
+ *	    Len [i]:  the length of the row i data structure in the Iw array.
+ *	    Iw [Pe [i] ... Pe [i] + Len [i] - 1]:
+ *		the list of column indices for nonzeros in row i (simple
+ *		supervariables), excluding the diagonal.  All supervariables
+ *		start with one row/column each (supervariable i is just row i).
+ *		If Len [i] is zero on input, then Pe [i] is ignored on input.
+ *
+ *	    Note that the rows need not be in any particular order, and there
+ *	    may be empty space between the rows.
+ *
+ *	During execution, the supervariable i experiences fill-in.  This is
+ *	represented by placing in i a list of the elements that cause fill-in
+ *	in supervariable i:
+ *
+ *	    Len [i]:  the length of supervariable i in the Iw array.
+ *	    Iw [Pe [i] ... Pe [i] + Elen [i] - 1]:
+ *		the list of elements that contain i.  This list is kept short
+ *		by removing absorbed elements.
+ *	    Iw [Pe [i] + Elen [i] ... Pe [i] + Len [i] - 1]:
+ *		the list of supervariables in i.  This list is kept short by
+ *		removing nonprincipal variables, and any entry j that is also
+ *		contained in at least one of the elements (j in Le) in the list
+ *		for i (e in row i).
+ *
+ *	When supervariable i is selected as pivot, we create an element e of
+ *	the same name (e=i):
+ *
+ *	    Len [e]:  the length of element e in the Iw array.
+ *	    Iw [Pe [e] ... Pe [e] + Len [e] - 1]:
+ *		the list of supervariables in element e.
+ *
+ *	An element represents the fill-in that occurs when supervariable i is
+ *	selected as pivot (which represents the selection of row i and all
+ *	non-principal variables whose principal variable is i).  We use the
+ *	term Le to denote the set of all supervariables in element e.  Absorbed
+ *	supervariables and elements are pruned from these lists when
+ *	computationally convenient.
+ *
+ *  CAUTION:  THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
+ *  The contents of Iw are undefined on output.
+
+ * ----------------------------------------------------------------------------
+ * OUTPUT (need not be set on input):
+ * ----------------------------------------------------------------------------
+ *
+ * Nv:  An integer array of size n.  During execution, ABS (Nv [i]) is equal to
+ *	the number of rows that are represented by the principal supervariable
+ *	i.  If i is a nonprincipal or dense variable, then Nv [i] = 0.
+ *	Initially, Nv [i] = 1 for all i.  Nv [i] < 0 signifies that i is a
+ *	principal variable in the pattern Lme of the current pivot element me.
+ *	After element me is constructed, Nv [i] is set back to a positive
+ *	value.
+ *
+ *	On output, Nv [i] holds the number of pivots represented by super
+ *	row/column i of the original matrix, or Nv [i] = 0 for non-principal
+ *	rows/columns.  Note that i refers to a row/column in the original
+ *	matrix, not the permuted matrix.
+ *
+ * Elen:  An integer array of size n.  See the description of Iw above.  At the
+ *	start of execution, Elen [i] is set to zero for all rows i.  During
+ *	execution, Elen [i] is the number of elements in the list for
+ *	supervariable i.  When e becomes an element, Elen [e] = FLIP (esize) is
+ *	set, where esize is the size of the element (the number of pivots, plus
+ *	the number of nonpivotal entries).  Thus Elen [e] < EMPTY.
+ *	Elen (i) = EMPTY set when variable i becomes nonprincipal.
+ *
+ *	For variables, Elen (i) >= EMPTY holds until just before the
+ *	postordering and permutation vectors are computed.  For elements,
+ *	Elen [e] < EMPTY holds.
+ *
+ *	On output, Elen [i] is the degree of the row/column in the Cholesky
+ *	factorization of the permuted matrix, corresponding to the original row
+ *	i, if i is a super row/column.  It is equal to EMPTY if i is
+ *	non-principal.  Note that i refers to a row/column in the original
+ *	matrix, not the permuted matrix.
+ *
+ *	Note that the contents of Elen on output differ from the Fortran
+ *	version (Elen holds the inverse permutation in the Fortran version,
+ *	which is instead returned in the Next array in this C version,
+ *	described below).
+ *
+ * Last: In a degree list, Last [i] is the supervariable preceding i, or EMPTY
+ *	if i is the head of the list.  In a hash bucket, Last [i] is the hash
+ *	key for i.
+ *
+ *	Last [Head [hash]] is also used as the head of a hash bucket if
+ *	Head [hash] contains a degree list (see the description of Head,
+ *	below).
+ *
+ *	On output, Last [0..n-1] holds the permutation.  That is, if
+ *	i = Last [k], then row i is the kth pivot row (where k ranges from 0 to
+ *	n-1).  Row Last [k] of A is the kth row in the permuted matrix, PAP'.
+ *
+ * Next: Next [i] is the supervariable following i in a link list, or EMPTY if
+ *	i is the last in the list.  Used for two kinds of lists:  degree lists
+ *	and hash buckets (a supervariable can be in only one kind of list at a
+ *	time).
+ *
+ *	On output Next [0..n-1] holds the inverse permutation. 	That is, if
+ *	k = Next [i], then row i is the kth pivot row. Row i of A appears as
+ *	the (Next[i])-th row in the permuted matrix, PAP'.
+ *
+ *	Note that the contents of Next on output differ from the Fortran
+ *	version (Next is undefined on output in the Fortran version).
+
+ * ----------------------------------------------------------------------------
+ * LOCAL WORKSPACE (not input or output - used only during execution):
+ * ----------------------------------------------------------------------------
+ *
+ * Degree:  An integer array of size n.  If i is a supervariable, then
+ *	Degree [i] holds the current approximation of the external degree of
+ *	row i (an upper bound).  The external degree is the number of nonzeros
+ *	in row i, minus ABS (Nv [i]), the diagonal part.  The bound is equal to
+ *	the exact external degree if Elen [i] is less than or equal to two.
+ *
+ *	We also use the term "external degree" for elements e to refer to
+ *	|Le \ Lme|.  If e is an element, then Degree [e] is |Le|, which is the
+ *	degree of the off-diagonal part of the element e (not including the
+ *	diagonal part).
+ *
+ * Head:   An integer array of size n.  Head is used for degree lists.
+ *	Head [deg] is the first supervariable in a degree list.  All
+ *	supervariables i in a degree list Head [deg] have the same approximate
+ *	degree, namely, deg = Degree [i].  If the list Head [deg] is empty then
+ *	Head [deg] = EMPTY.
+ *
+ *	During supervariable detection Head [hash] also serves as a pointer to
+ *	a hash bucket.  If Head [hash] >= 0, there is a degree list of degree
+ *	hash.  The hash bucket head pointer is Last [Head [hash]].  If
+ *	Head [hash] = EMPTY, then the degree list and hash bucket are both
+ *	empty.  If Head [hash] < EMPTY, then the degree list is empty, and
+ *	FLIP (Head [hash]) is the head of the hash bucket.  After supervariable
+ *	detection is complete, all hash buckets are empty, and the
+ *	(Last [Head [hash]] = EMPTY) condition is restored for the non-empty
+ *	degree lists.
+ *
+ * W:  An integer array of size n.  The flag array W determines the status of
+ *	elements and variables, and the external degree of elements.
+ *
+ *	for elements:
+ *	    if W [e] = 0, then the element e is absorbed.
+ *	    if W [e] >= wflg, then W [e] - wflg is the size of the set
+ *		|Le \ Lme|, in terms of nonzeros (the sum of ABS (Nv [i]) for
+ *		each principal variable i that is both in the pattern of
+ *		element e and NOT in the pattern of the current pivot element,
+ *		me).
+ *	    if wflg > W [e] > 0, then e is not absorbed and has not yet been
+ *		seen in the scan of the element lists in the computation of
+ *		|Le\Lme| in Scan 1 below.
+ *
+ *	for variables:
+ *	    during supervariable detection, if W [j] != wflg then j is
+ *	    not in the pattern of variable i.
+ *
+ *	The W array is initialized by setting W [i] = 1 for all i, and by
+ *	setting wflg = 2.  It is reinitialized if wflg becomes too large (to
+ *	ensure that wflg+n does not cause integer overflow).
+
+ * ----------------------------------------------------------------------------
+ * LOCAL INTEGERS:
+ * ----------------------------------------------------------------------------
+ */
+
+    Int deg, degme, dext, lemax, e, elenme, eln, i, ilast, inext, j,
+	jlast, jnext, k, knt1, knt2, knt3, lenj, ln, me, mindeg, nel, nleft,
+	nvi, nvj, nvpiv, slenme, wbig, we, wflg, wnvi, ok, ndense, ncmpa,
+	dense, aggressive ;
+
+    unsigned Int hash ;	    /* unsigned, so that hash % n is well defined.*/
+
+/*
+ * deg:		the degree of a variable or element
+ * degme:	size, |Lme|, of the current element, me (= Degree [me])
+ * dext:	external degree, |Le \ Lme|, of some element e
+ * lemax:	largest |Le| seen so far (called dmax in Fortran version)
+ * e:		an element
+ * elenme:	the length, Elen [me], of element list of pivotal variable
+ * eln:		the length, Elen [...], of an element list
+ * hash:	the computed value of the hash function
+ * i:		a supervariable
+ * ilast:	the entry in a link list preceding i
+ * inext:	the entry in a link list following i
+ * j:		a supervariable
+ * jlast:	the entry in a link list preceding j
+ * jnext:	the entry in a link list, or path, following j
+ * k:		the pivot order of an element or variable
+ * knt1:	loop counter used during element construction
+ * knt2:	loop counter used during element construction
+ * knt3:	loop counter used during compression
+ * lenj:	Len [j]
+ * ln:		length of a supervariable list
+ * me:		current supervariable being eliminated, and the current
+ *		    element created by eliminating that supervariable
+ * mindeg:	current minimum degree
+ * nel:		number of pivots selected so far
+ * nleft:	n - nel, the number of nonpivotal rows/columns remaining
+ * nvi:		the number of variables in a supervariable i (= Nv [i])
+ * nvj:		the number of variables in a supervariable j (= Nv [j])
+ * nvpiv:	number of pivots in current element
+ * slenme:	number of variables in variable list of pivotal variable
+ * wbig:	= INT_MAX - n for the int version, UF_long_max - n for the
+ *		    UF_long version.  wflg is not allowed to be >= wbig.
+ * we:		W [e]
+ * wflg:	used for flagging the W array.  See description of Iw.
+ * wnvi:	wflg - Nv [i]
+ * x:		either a supervariable or an element
+ *
+ * ok:		true if supervariable j can be absorbed into i
+ * ndense:	number of "dense" rows/columns
+ * dense:	rows/columns with initial degree > dense are considered "dense"
+ * aggressive:	true if aggressive absorption is being performed
+ * ncmpa:	number of garbage collections
+
+ * ----------------------------------------------------------------------------
+ * LOCAL DOUBLES, used for statistical output only (except for alpha):
+ * ----------------------------------------------------------------------------
+ */
+
+    double f, r, ndiv, s, nms_lu, nms_ldl, dmax, alpha, lnz, lnzme ;
+
+/*
+ * f:		nvpiv
+ * r:		degme + nvpiv
+ * ndiv:	number of divisions for LU or LDL' factorizations
+ * s:		number of multiply-subtract pairs for LU factorization, for the
+ *		    current element me
+ * nms_lu	number of multiply-subtract pairs for LU factorization
+ * nms_ldl	number of multiply-subtract pairs for LDL' factorization
+ * dmax:	the largest number of entries in any column of L, including the
+ *		    diagonal
+ * alpha:	"dense" degree ratio
+ * lnz:		the number of nonzeros in L (excluding the diagonal)
+ * lnzme:	the number of nonzeros in L (excl. the diagonal) for the
+ *		    current element me
+
+ * ----------------------------------------------------------------------------
+ * LOCAL "POINTERS" (indices into the Iw array)
+ * ----------------------------------------------------------------------------
+*/
+
+    Int p, p1, p2, p3, p4, pdst, pend, pj, pme, pme1, pme2, pn, psrc ;
+
+/*
+ * Any parameter (Pe [...] or pfree) or local variable starting with "p" (for
+ * Pointer) is an index into Iw, and all indices into Iw use variables starting
+ * with "p."  The only exception to this rule is the iwlen input argument.
+ *
+ * p:           pointer into lots of things
+ * p1:          Pe [i] for some variable i (start of element list)
+ * p2:          Pe [i] + Elen [i] -  1 for some variable i
+ * p3:          index of first supervariable in clean list
+ * p4:		
+ * pdst:        destination pointer, for compression
+ * pend:        end of memory to compress
+ * pj:          pointer into an element or variable
+ * pme:         pointer into the current element (pme1...pme2)
+ * pme1:        the current element, me, is stored in Iw [pme1...pme2]
+ * pme2:        the end of the current element
+ * pn:          pointer into a "clean" variable, also used to compress
+ * psrc:        source pointer, for compression
+*/
+
+/* ========================================================================= */
+/*  INITIALIZATIONS */
+/* ========================================================================= */
+
+    /* Note that this restriction on iwlen is slightly more restrictive than
+     * what is actually required in AMD_2.  AMD_2 can operate with no elbow
+     * room at all, but it will be slow.  For better performance, at least
+     * size-n elbow room is enforced. */
+    ASSERT (iwlen >= pfree + n) ;
+    ASSERT (n > 0) ;
+
+    /* initialize output statistics */
+    lnz = 0 ;
+    ndiv = 0 ;
+    nms_lu = 0 ;
+    nms_ldl = 0 ;
+    dmax = 1 ;
+    me = EMPTY ;
+
+    mindeg = 0 ;
+    ncmpa = 0 ;
+    nel = 0 ;
+    lemax = 0 ;
+
+    /* get control parameters */
+    if (Control != (double *) NULL)
+    {
+	alpha = Control [AMD_DENSE] ;
+	aggressive = (Control [AMD_AGGRESSIVE] != 0) ;
+    }
+    else
+    {
+	alpha = AMD_DEFAULT_DENSE ;
+	aggressive = AMD_DEFAULT_AGGRESSIVE ;
+    }
+    /* Note: if alpha is NaN, this is undefined: */
+    if (alpha < 0)
+    {
+	/* only remove completely dense rows/columns */
+	dense = n-2 ;
+    }
+    else
+    {
+	dense = alpha * sqrt ((double) n) ;
+    }
+    dense = MAX (16, dense) ;
+    dense = MIN (n,  dense) ;
+    AMD_DEBUG1 (("\n\nAMD (debug), alpha %g, aggr. "ID"\n",
+	alpha, aggressive)) ;
+
+    for (i = 0 ; i < n ; i++)
+    {
+	Last [i] = EMPTY ;
+	Head [i] = EMPTY ;
+	Next [i] = EMPTY ;
+	/* if separate Hhead array is used for hash buckets: *
+	Hhead [i] = EMPTY ;
+	*/
+	Nv [i] = 1 ;
+	W [i] = 1 ;
+	Elen [i] = 0 ;
+	Degree [i] = Len [i] ;
+    }
+
+#ifndef NDEBUG
+    AMD_DEBUG1 (("\n======Nel "ID" initial\n", nel)) ;
+    AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, Last,
+		Head, Elen, Degree, W, -1) ;
+#endif
+
+    /* initialize wflg */
+    wbig = Int_MAX - n ;
+    wflg = clear_flag (0, wbig, W, n) ;
+
+    /* --------------------------------------------------------------------- */
+    /* initialize degree lists and eliminate dense and empty rows */
+    /* --------------------------------------------------------------------- */
+
+    ndense = 0 ;
+
+    for (i = 0 ; i < n ; i++)
+    {
+	deg = Degree [i] ;
+	ASSERT (deg >= 0 && deg < n) ;
+	if (deg == 0)
+	{
+
+	    /* -------------------------------------------------------------
+	     * we have a variable that can be eliminated at once because
+	     * there is no off-diagonal non-zero in its row.  Note that
+	     * Nv [i] = 1 for an empty variable i.  It is treated just
+	     * the same as an eliminated element i.
+	     * ------------------------------------------------------------- */
+
+	    Elen [i] = FLIP (1) ;
+	    nel++ ;
+	    Pe [i] = EMPTY ;
+	    W [i] = 0 ;
+
+	}
+	else if (deg > dense)
+	{
+
+	    /* -------------------------------------------------------------
+	     * Dense variables are not treated as elements, but as unordered,
+	     * non-principal variables that have no parent.  They do not take
+	     * part in the postorder, since Nv [i] = 0.  Note that the Fortran
+	     * version does not have this option.
+	     * ------------------------------------------------------------- */
+
+	    AMD_DEBUG1 (("Dense node "ID" degree "ID"\n", i, deg)) ;
+	    ndense++ ;
+	    Nv [i] = 0 ;		/* do not postorder this node */
+	    Elen [i] = EMPTY ;
+	    nel++ ;
+	    Pe [i] = EMPTY ;
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------
+	     * place i in the degree list corresponding to its degree
+	     * ------------------------------------------------------------- */
+
+	    inext = Head [deg] ;
+	    ASSERT (inext >= EMPTY && inext < n) ;
+	    if (inext != EMPTY) Last [inext] = i ;
+	    Next [i] = inext ;
+	    Head [deg] = i ;
+
+	}
+    }
+
+/* ========================================================================= */
+/* WHILE (selecting pivots) DO */
+/* ========================================================================= */
+
+    while (nel < n)
+    {
+
+#ifndef NDEBUG
+	AMD_DEBUG1 (("\n======Nel "ID"\n", nel)) ;
+	if (AMD_debug >= 2)
+	{
+	    AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next,
+		    Last, Head, Elen, Degree, W, nel) ;
+	}
+#endif
+
+/* ========================================================================= */
+/* GET PIVOT OF MINIMUM DEGREE */
+/* ========================================================================= */
+
+	/* ----------------------------------------------------------------- */
+	/* find next supervariable for elimination */
+	/* ----------------------------------------------------------------- */
+
+	ASSERT (mindeg >= 0 && mindeg < n) ;
+	for (deg = mindeg ; deg < n ; deg++)
+	{
+	    me = Head [deg] ;
+	    if (me != EMPTY) break ;
+	}
+	mindeg = deg ;
+	ASSERT (me >= 0 && me < n) ;
+	AMD_DEBUG1 (("=================me: "ID"\n", me)) ;
+
+	/* ----------------------------------------------------------------- */
+	/* remove chosen variable from link list */
+	/* ----------------------------------------------------------------- */
+
+	inext = Next [me] ;
+	ASSERT (inext >= EMPTY && inext < n) ;
+	if (inext != EMPTY) Last [inext] = EMPTY ;
+	Head [deg] = inext ;
+
+	/* ----------------------------------------------------------------- */
+	/* me represents the elimination of pivots nel to nel+Nv[me]-1. */
+	/* place me itself as the first in this set. */
+	/* ----------------------------------------------------------------- */
+
+	elenme = Elen [me] ;
+	nvpiv = Nv [me] ;
+	ASSERT (nvpiv > 0) ;
+	nel += nvpiv ;
+
+/* ========================================================================= */
+/* CONSTRUCT NEW ELEMENT */
+/* ========================================================================= */
+
+	/* -----------------------------------------------------------------
+	 * At this point, me is the pivotal supervariable.  It will be
+	 * converted into the current element.  Scan list of the pivotal
+	 * supervariable, me, setting tree pointers and constructing new list
+	 * of supervariables for the new element, me.  p is a pointer to the
+	 * current position in the old list.
+	 * ----------------------------------------------------------------- */
+
+	/* flag the variable "me" as being in Lme by negating Nv [me] */
+	Nv [me] = -nvpiv ;
+	degme = 0 ;
+	ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
+
+	if (elenme == 0)
+	{
+
+	    /* ------------------------------------------------------------- */
+	    /* construct the new element in place */
+	    /* ------------------------------------------------------------- */
+
+	    pme1 = Pe [me] ;
+	    pme2 = pme1 - 1 ;
+
+	    for (p = pme1 ; p <= pme1 + Len [me] - 1 ; p++)
+	    {
+		i = Iw [p] ;
+		ASSERT (i >= 0 && i < n && Nv [i] >= 0) ;
+		nvi = Nv [i] ;
+		if (nvi > 0)
+		{
+
+		    /* ----------------------------------------------------- */
+		    /* i is a principal variable not yet placed in Lme. */
+		    /* store i in new list */
+		    /* ----------------------------------------------------- */
+
+		    /* flag i as being in Lme by negating Nv [i] */
+		    degme += nvi ;
+		    Nv [i] = -nvi ;
+		    Iw [++pme2] = i ;
+
+		    /* ----------------------------------------------------- */
+		    /* remove variable i from degree list. */
+		    /* ----------------------------------------------------- */
+
+		    ilast = Last [i] ;
+		    inext = Next [i] ;
+		    ASSERT (ilast >= EMPTY && ilast < n) ;
+		    ASSERT (inext >= EMPTY && inext < n) ;
+		    if (inext != EMPTY) Last [inext] = ilast ;
+		    if (ilast != EMPTY)
+		    {
+			Next [ilast] = inext ;
+		    }
+		    else
+		    {
+			/* i is at the head of the degree list */
+			ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
+			Head [Degree [i]] = inext ;
+		    }
+		}
+	    }
+	}
+	else
+	{
+
+	    /* ------------------------------------------------------------- */
+	    /* construct the new element in empty space, Iw [pfree ...] */
+	    /* ------------------------------------------------------------- */
+
+	    p = Pe [me] ;
+	    pme1 = pfree ;
+	    slenme = Len [me] - elenme ;
+
+	    for (knt1 = 1 ; knt1 <= elenme + 1 ; knt1++)
+	    {
+
+		if (knt1 > elenme)
+		{
+		    /* search the supervariables in me. */
+		    e = me ;
+		    pj = p ;
+		    ln = slenme ;
+		    AMD_DEBUG2 (("Search sv: "ID" "ID" "ID"\n", me,pj,ln)) ;
+		}
+		else
+		{
+		    /* search the elements in me. */
+		    e = Iw [p++] ;
+		    ASSERT (e >= 0 && e < n) ;
+		    pj = Pe [e] ;
+		    ln = Len [e] ;
+		    AMD_DEBUG2 (("Search element e "ID" in me "ID"\n", e,me)) ;
+		    ASSERT (Elen [e] < EMPTY && W [e] > 0 && pj >= 0) ;
+		}
+		ASSERT (ln >= 0 && (ln == 0 || (pj >= 0 && pj < iwlen))) ;
+
+		/* ---------------------------------------------------------
+		 * search for different supervariables and add them to the
+		 * new list, compressing when necessary. this loop is
+		 * executed once for each element in the list and once for
+		 * all the supervariables in the list.
+		 * --------------------------------------------------------- */
+
+		for (knt2 = 1 ; knt2 <= ln ; knt2++)
+		{
+		    i = Iw [pj++] ;
+		    ASSERT (i >= 0 && i < n && (i == me || Elen [i] >= EMPTY));
+		    nvi = Nv [i] ;
+		    AMD_DEBUG2 ((": "ID" "ID" "ID" "ID"\n",
+				i, Elen [i], Nv [i], wflg)) ;
+
+		    if (nvi > 0)
+		    {
+
+			/* ------------------------------------------------- */
+			/* compress Iw, if necessary */
+			/* ------------------------------------------------- */
+
+			if (pfree >= iwlen)
+			{
+
+			    AMD_DEBUG1 (("GARBAGE COLLECTION\n")) ;
+
+			    /* prepare for compressing Iw by adjusting pointers
+			     * and lengths so that the lists being searched in
+			     * the inner and outer loops contain only the
+			     * remaining entries. */
+
+			    Pe [me] = p ;
+			    Len [me] -= knt1 ;
+			    /* check if nothing left of supervariable me */
+			    if (Len [me] == 0) Pe [me] = EMPTY ;
+			    Pe [e] = pj ;
+			    Len [e] = ln - knt2 ;
+			    /* nothing left of element e */
+			    if (Len [e] == 0) Pe [e] = EMPTY ;
+
+			    ncmpa++ ;	/* one more garbage collection */
+
+			    /* store first entry of each object in Pe */
+			    /* FLIP the first entry in each object */
+			    for (j = 0 ; j < n ; j++)
+			    {
+				pn = Pe [j] ;
+				if (pn >= 0)
+				{
+				    ASSERT (pn >= 0 && pn < iwlen) ;
+				    Pe [j] = Iw [pn] ;
+				    Iw [pn] = FLIP (j) ;
+				}
+			    }
+
+			    /* psrc/pdst point to source/destination */
+			    psrc = 0 ;
+			    pdst = 0 ;
+			    pend = pme1 - 1 ;
+
+			    while (psrc <= pend)
+			    {
+				/* search for next FLIP'd entry */
+				j = FLIP (Iw [psrc++]) ;
+				if (j >= 0)
+				{
+				    AMD_DEBUG2 (("Got object j: "ID"\n", j)) ;
+				    Iw [pdst] = Pe [j] ;
+				    Pe [j] = pdst++ ;
+				    lenj = Len [j] ;
+				    /* copy from source to destination */
+				    for (knt3 = 0 ; knt3 <= lenj - 2 ; knt3++)
+				    {
+					Iw [pdst++] = Iw [psrc++] ;
+				    }
+				}
+			    }
+
+			    /* move the new partially-constructed element */
+			    p1 = pdst ;
+			    for (psrc = pme1 ; psrc <= pfree-1 ; psrc++)
+			    {
+				Iw [pdst++] = Iw [psrc] ;
+			    }
+			    pme1 = p1 ;
+			    pfree = pdst ;
+			    pj = Pe [e] ;
+			    p = Pe [me] ;
+
+			}
+
+			/* ------------------------------------------------- */
+			/* i is a principal variable not yet placed in Lme */
+			/* store i in new list */
+			/* ------------------------------------------------- */
+
+			/* flag i as being in Lme by negating Nv [i] */
+			degme += nvi ;
+			Nv [i] = -nvi ;
+			Iw [pfree++] = i ;
+			AMD_DEBUG2 (("     s: "ID"     nv "ID"\n", i, Nv [i]));
+
+			/* ------------------------------------------------- */
+			/* remove variable i from degree link list */
+			/* ------------------------------------------------- */
+
+			ilast = Last [i] ;
+			inext = Next [i] ;
+			ASSERT (ilast >= EMPTY && ilast < n) ;
+			ASSERT (inext >= EMPTY && inext < n) ;
+			if (inext != EMPTY) Last [inext] = ilast ;
+			if (ilast != EMPTY)
+			{
+			    Next [ilast] = inext ;
+			}
+			else
+			{
+			    /* i is at the head of the degree list */
+			    ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
+			    Head [Degree [i]] = inext ;
+			}
+		    }
+		}
+
+		if (e != me)
+		{
+		    /* set tree pointer and flag to indicate element e is
+		     * absorbed into new element me (the parent of e is me) */
+		    AMD_DEBUG1 ((" Element "ID" => "ID"\n", e, me)) ;
+		    Pe [e] = FLIP (me) ;
+		    W [e] = 0 ;
+		}
+	    }
+
+	    pme2 = pfree - 1 ;
+	}
+
+	/* ----------------------------------------------------------------- */
+	/* me has now been converted into an element in Iw [pme1..pme2] */
+	/* ----------------------------------------------------------------- */
+
+	/* degme holds the external degree of new element */
+	Degree [me] = degme ;
+	Pe [me] = pme1 ;
+	Len [me] = pme2 - pme1 + 1 ;
+	ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
+
+	Elen [me] = FLIP (nvpiv + degme) ;
+	/* FLIP (Elen (me)) is now the degree of pivot (including
+	 * diagonal part). */
+
+#ifndef NDEBUG
+	AMD_DEBUG2 (("New element structure: length= "ID"\n", pme2-pme1+1)) ;
+	for (pme = pme1 ; pme <= pme2 ; pme++) AMD_DEBUG3 ((" "ID"", Iw[pme]));
+	AMD_DEBUG3 (("\n")) ;
+#endif
+
+	/* ----------------------------------------------------------------- */
+	/* make sure that wflg is not too large. */
+	/* ----------------------------------------------------------------- */
+
+	/* With the current value of wflg, wflg+n must not cause integer
+	 * overflow */
+
+	wflg = clear_flag (wflg, wbig, W, n) ;
+
+/* ========================================================================= */
+/* COMPUTE (W [e] - wflg) = |Le\Lme| FOR ALL ELEMENTS */
+/* ========================================================================= */
+
+	/* -----------------------------------------------------------------
+	 * Scan 1:  compute the external degrees of previous elements with
+	 * respect to the current element.  That is:
+	 *       (W [e] - wflg) = |Le \ Lme|
+	 * for each element e that appears in any supervariable in Lme.  The
+	 * notation Le refers to the pattern (list of supervariables) of a
+	 * previous element e, where e is not yet absorbed, stored in
+	 * Iw [Pe [e] + 1 ... Pe [e] + Len [e]].  The notation Lme
+	 * refers to the pattern of the current element (stored in
+	 * Iw [pme1..pme2]).   If aggressive absorption is enabled, and
+	 * (W [e] - wflg) becomes zero, then the element e will be absorbed
+	 * in Scan 2.
+	 * ----------------------------------------------------------------- */
+
+	AMD_DEBUG2 (("me: ")) ;
+	for (pme = pme1 ; pme <= pme2 ; pme++)
+	{
+	    i = Iw [pme] ;
+	    ASSERT (i >= 0 && i < n) ;
+	    eln = Elen [i] ;
+	    AMD_DEBUG3 ((""ID" Elen "ID": \n", i, eln)) ;
+	    if (eln > 0)
+	    {
+		/* note that Nv [i] has been negated to denote i in Lme: */
+		nvi = -Nv [i] ;
+		ASSERT (nvi > 0 && Pe [i] >= 0 && Pe [i] < iwlen) ;
+		wnvi = wflg - nvi ;
+		for (p = Pe [i] ; p <= Pe [i] + eln - 1 ; p++)
+		{
+		    e = Iw [p] ;
+		    ASSERT (e >= 0 && e < n) ;
+		    we = W [e] ;
+		    AMD_DEBUG4 (("    e "ID" we "ID" ", e, we)) ;
+		    if (we >= wflg)
+		    {
+			/* unabsorbed element e has been seen in this loop */
+			AMD_DEBUG4 (("    unabsorbed, first time seen")) ;
+			we -= nvi ;
+		    }
+		    else if (we != 0)
+		    {
+			/* e is an unabsorbed element */
+			/* this is the first we have seen e in all of Scan 1 */
+			AMD_DEBUG4 (("    unabsorbed")) ;
+			we = Degree [e] + wnvi ;
+		    }
+		    AMD_DEBUG4 (("\n")) ;
+		    W [e] = we ;
+		}
+	    }
+	}
+	AMD_DEBUG2 (("\n")) ;
+
+/* ========================================================================= */
+/* DEGREE UPDATE AND ELEMENT ABSORPTION */
+/* ========================================================================= */
+
+	/* -----------------------------------------------------------------
+	 * Scan 2:  for each i in Lme, sum up the degree of Lme (which is
+	 * degme), plus the sum of the external degrees of each Le for the
+	 * elements e appearing within i, plus the supervariables in i.
+	 * Place i in hash list.
+	 * ----------------------------------------------------------------- */
+
+	for (pme = pme1 ; pme <= pme2 ; pme++)
+	{
+	    i = Iw [pme] ;
+	    ASSERT (i >= 0 && i < n && Nv [i] < 0 && Elen [i] >= 0) ;
+	    AMD_DEBUG2 (("Updating: i "ID" "ID" "ID"\n", i, Elen[i], Len [i]));
+	    p1 = Pe [i] ;
+	    p2 = p1 + Elen [i] - 1 ;
+	    pn = p1 ;
+	    hash = 0 ;
+	    deg = 0 ;
+	    ASSERT (p1 >= 0 && p1 < iwlen && p2 >= -1 && p2 < iwlen) ;
+
+	    /* ------------------------------------------------------------- */
+	    /* scan the element list associated with supervariable i */
+	    /* ------------------------------------------------------------- */
+
+	    /* UMFPACK/MA38-style approximate degree: */
+	    if (aggressive)
+	    {
+		for (p = p1 ; p <= p2 ; p++)
+		{
+		    e = Iw [p] ;
+		    ASSERT (e >= 0 && e < n) ;
+		    we = W [e] ;
+		    if (we != 0)
+		    {
+			/* e is an unabsorbed element */
+			/* dext = | Le \ Lme | */
+			dext = we - wflg ;
+			if (dext > 0)
+			{
+			    deg += dext ;
+			    Iw [pn++] = e ;
+			    hash += e ;
+			    AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ;
+			}
+			else
+			{
+			    /* external degree of e is zero, absorb e into me*/
+			    AMD_DEBUG1 ((" Element "ID" =>"ID" (aggressive)\n",
+				e, me)) ;
+			    ASSERT (dext == 0) ;
+			    Pe [e] = FLIP (me) ;
+			    W [e] = 0 ;
+			}
+		    }
+		}
+	    }
+	    else
+	    {
+		for (p = p1 ; p <= p2 ; p++)
+		{
+		    e = Iw [p] ;
+		    ASSERT (e >= 0 && e < n) ;
+		    we = W [e] ;
+		    if (we != 0)
+		    {
+			/* e is an unabsorbed element */
+			dext = we - wflg ;
+			ASSERT (dext >= 0) ;
+			deg += dext ;
+			Iw [pn++] = e ;
+			hash += e ;
+			AMD_DEBUG4 (("	e: "ID" hash = "ID"\n",e,hash)) ;
+		    }
+		}
+	    }
+
+	    /* count the number of elements in i (including me): */
+	    Elen [i] = pn - p1 + 1 ;
+
+	    /* ------------------------------------------------------------- */
+	    /* scan the supervariables in the list associated with i */
+	    /* ------------------------------------------------------------- */
+
+	    /* The bulk of the AMD run time is typically spent in this loop,
+	     * particularly if the matrix has many dense rows that are not
+	     * removed prior to ordering. */
+	    p3 = pn ;
+	    p4 = p1 + Len [i] ;
+	    for (p = p2 + 1 ; p < p4 ; p++)
+	    {
+		j = Iw [p] ;
+		ASSERT (j >= 0 && j < n) ;
+		nvj = Nv [j] ;
+		if (nvj > 0)
+		{
+		    /* j is unabsorbed, and not in Lme. */
+		    /* add to degree and add to new list */
+		    deg += nvj ;
+		    Iw [pn++] = j ;
+		    hash += j ;
+		    AMD_DEBUG4 (("  s: "ID" hash "ID" Nv[j]= "ID"\n",
+				j, hash, nvj)) ;
+		}
+	    }
+
+	    /* ------------------------------------------------------------- */
+	    /* update the degree and check for mass elimination */
+	    /* ------------------------------------------------------------- */
+
+	    /* with aggressive absorption, deg==0 is identical to the
+	     * Elen [i] == 1 && p3 == pn test, below. */
+	    ASSERT (IMPLIES (aggressive, (deg==0) == (Elen[i]==1 && p3==pn))) ;
+
+	    if (Elen [i] == 1 && p3 == pn)
+	    {
+
+		/* --------------------------------------------------------- */
+		/* mass elimination */
+		/* --------------------------------------------------------- */
+
+		/* There is nothing left of this node except for an edge to
+		 * the current pivot element.  Elen [i] is 1, and there are
+		 * no variables adjacent to node i.  Absorb i into the
+		 * current pivot element, me.  Note that if there are two or
+		 * more mass eliminations, fillin due to mass elimination is
+		 * possible within the nvpiv-by-nvpiv pivot block.  It is this
+		 * step that causes AMD's analysis to be an upper bound.
+		 *
+		 * The reason is that the selected pivot has a lower
+		 * approximate degree than the true degree of the two mass
+		 * eliminated nodes.  There is no edge between the two mass
+		 * eliminated nodes.  They are merged with the current pivot
+		 * anyway.
+		 *
+		 * No fillin occurs in the Schur complement, in any case,
+		 * and this effect does not decrease the quality of the
+		 * ordering itself, just the quality of the nonzero and
+		 * flop count analysis.  It also means that the post-ordering
+		 * is not an exact elimination tree post-ordering. */
+
+		AMD_DEBUG1 (("  MASS i "ID" => parent e "ID"\n", i, me)) ;
+		Pe [i] = FLIP (me) ;
+		nvi = -Nv [i] ;
+		degme -= nvi ;
+		nvpiv += nvi ;
+		nel += nvi ;
+		Nv [i] = 0 ;
+		Elen [i] = EMPTY ;
+
+	    }
+	    else
+	    {
+
+		/* --------------------------------------------------------- */
+		/* update the upper-bound degree of i */
+		/* --------------------------------------------------------- */
+
+		/* the following degree does not yet include the size
+		 * of the current element, which is added later: */
+
+		Degree [i] = MIN (Degree [i], deg) ;
+
+		/* --------------------------------------------------------- */
+		/* add me to the list for i */
+		/* --------------------------------------------------------- */
+
+		/* move first supervariable to end of list */
+		Iw [pn] = Iw [p3] ;
+		/* move first element to end of element part of list */
+		Iw [p3] = Iw [p1] ;
+		/* add new element, me, to front of list. */
+		Iw [p1] = me ;
+		/* store the new length of the list in Len [i] */
+		Len [i] = pn - p1 + 1 ;
+
+		/* --------------------------------------------------------- */
+		/* place in hash bucket.  Save hash key of i in Last [i]. */
+		/* --------------------------------------------------------- */
+
+		/* NOTE: this can fail if hash is negative, because the ANSI C
+		 * standard does not define a % b when a and/or b are negative.
+		 * That's why hash is defined as an unsigned Int, to avoid this
+		 * problem. */
+		hash = hash % n ;
+		ASSERT (((Int) hash) >= 0 && ((Int) hash) < n) ;
+
+		/* if the Hhead array is not used: */
+		j = Head [hash] ;
+		if (j <= EMPTY)
+		{
+		    /* degree list is empty, hash head is FLIP (j) */
+		    Next [i] = FLIP (j) ;
+		    Head [hash] = FLIP (i) ;
+		}
+		else
+		{
+		    /* degree list is not empty, use Last [Head [hash]] as
+		     * hash head. */
+		    Next [i] = Last [j] ;
+		    Last [j] = i ;
+		}
+
+		/* if a separate Hhead array is used: *
+		Next [i] = Hhead [hash] ;
+		Hhead [hash] = i ;
+		*/
+
+		Last [i] = hash ;
+	    }
+	}
+
+	Degree [me] = degme ;
+
+	/* ----------------------------------------------------------------- */
+	/* Clear the counter array, W [...], by incrementing wflg. */
+	/* ----------------------------------------------------------------- */
+
+	/* make sure that wflg+n does not cause integer overflow */
+	lemax =  MAX (lemax, degme) ;
+	wflg += lemax ;
+	wflg = clear_flag (wflg, wbig, W, n) ;
+	/*  at this point, W [0..n-1] < wflg holds */
+
+/* ========================================================================= */
+/* SUPERVARIABLE DETECTION */
+/* ========================================================================= */
+
+	AMD_DEBUG1 (("Detecting supervariables:\n")) ;
+	for (pme = pme1 ; pme <= pme2 ; pme++)
+	{
+	    i = Iw [pme] ;
+	    ASSERT (i >= 0 && i < n) ;
+	    AMD_DEBUG2 (("Consider i "ID" nv "ID"\n", i, Nv [i])) ;
+	    if (Nv [i] < 0)
+	    {
+		/* i is a principal variable in Lme */
+
+		/* ---------------------------------------------------------
+		 * examine all hash buckets with 2 or more variables.  We do
+		 * this by examing all unique hash keys for supervariables in
+		 * the pattern Lme of the current element, me
+		 * --------------------------------------------------------- */
+
+		/* let i = head of hash bucket, and empty the hash bucket */
+		ASSERT (Last [i] >= 0 && Last [i] < n) ;
+		hash = Last [i] ;
+
+		/* if Hhead array is not used: */
+		j = Head [hash] ;
+		if (j == EMPTY)
+		{
+		    /* hash bucket and degree list are both empty */
+		    i = EMPTY ;
+		}
+		else if (j < EMPTY)
+		{
+		    /* degree list is empty */
+		    i = FLIP (j) ;
+		    Head [hash] = EMPTY ;
+		}
+		else
+		{
+		    /* degree list is not empty, restore Last [j] of head j */
+		    i = Last [j] ;
+		    Last [j] = EMPTY ;
+		}
+
+		/* if separate Hhead array is used: *
+		i = Hhead [hash] ;
+		Hhead [hash] = EMPTY ;
+		*/
+
+		ASSERT (i >= EMPTY && i < n) ;
+		AMD_DEBUG2 (("----i "ID" hash "ID"\n", i, hash)) ;
+
+		while (i != EMPTY && Next [i] != EMPTY)
+		{
+
+		    /* -----------------------------------------------------
+		     * this bucket has one or more variables following i.
+		     * scan all of them to see if i can absorb any entries
+		     * that follow i in hash bucket.  Scatter i into w.
+		     * ----------------------------------------------------- */
+
+		    ln = Len [i] ;
+		    eln = Elen [i] ;
+		    ASSERT (ln >= 0 && eln >= 0) ;
+		    ASSERT (Pe [i] >= 0 && Pe [i] < iwlen) ;
+		    /* do not flag the first element in the list (me) */
+		    for (p = Pe [i] + 1 ; p <= Pe [i] + ln - 1 ; p++)
+		    {
+			ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
+			W [Iw [p]] = wflg ;
+		    }
+
+		    /* ----------------------------------------------------- */
+		    /* scan every other entry j following i in bucket */
+		    /* ----------------------------------------------------- */
+
+		    jlast = i ;
+		    j = Next [i] ;
+		    ASSERT (j >= EMPTY && j < n) ;
+
+		    while (j != EMPTY)
+		    {
+			/* ------------------------------------------------- */
+			/* check if j and i have identical nonzero pattern */
+			/* ------------------------------------------------- */
+
+			AMD_DEBUG3 (("compare i "ID" and j "ID"\n", i,j)) ;
+
+			/* check if i and j have the same Len and Elen */
+			ASSERT (Len [j] >= 0 && Elen [j] >= 0) ;
+			ASSERT (Pe [j] >= 0 && Pe [j] < iwlen) ;
+			ok = (Len [j] == ln) && (Elen [j] == eln) ;
+			/* skip the first element in the list (me) */
+			for (p = Pe [j] + 1 ; ok && p <= Pe [j] + ln - 1 ; p++)
+			{
+			    ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
+			    if (W [Iw [p]] != wflg) ok = 0 ;
+			}
+			if (ok)
+			{
+			    /* --------------------------------------------- */
+			    /* found it!  j can be absorbed into i */
+			    /* --------------------------------------------- */
+
+			    AMD_DEBUG1 (("found it! j "ID" => i "ID"\n", j,i));
+			    Pe [j] = FLIP (i) ;
+			    /* both Nv [i] and Nv [j] are negated since they */
+			    /* are in Lme, and the absolute values of each */
+			    /* are the number of variables in i and j: */
+			    Nv [i] += Nv [j] ;
+			    Nv [j] = 0 ;
+			    Elen [j] = EMPTY ;
+			    /* delete j from hash bucket */
+			    ASSERT (j != Next [j]) ;
+			    j = Next [j] ;
+			    Next [jlast] = j ;
+
+			}
+			else
+			{
+			    /* j cannot be absorbed into i */
+			    jlast = j ;
+			    ASSERT (j != Next [j]) ;
+			    j = Next [j] ;
+			}
+			ASSERT (j >= EMPTY && j < n) ;
+		    }
+
+		    /* -----------------------------------------------------
+		     * no more variables can be absorbed into i
+		     * go to next i in bucket and clear flag array
+		     * ----------------------------------------------------- */
+
+		    wflg++ ;
+		    i = Next [i] ;
+		    ASSERT (i >= EMPTY && i < n) ;
+
+		}
+	    }
+	}
+	AMD_DEBUG2 (("detect done\n")) ;
+
+/* ========================================================================= */
+/* RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVARIABLES FROM ELEMENT */
+/* ========================================================================= */
+
+	p = pme1 ;
+	nleft = n - nel ;
+	for (pme = pme1 ; pme <= pme2 ; pme++)
+	{
+	    i = Iw [pme] ;
+	    ASSERT (i >= 0 && i < n) ;
+	    nvi = -Nv [i] ;
+	    AMD_DEBUG3 (("Restore i "ID" "ID"\n", i, nvi)) ;
+	    if (nvi > 0)
+	    {
+		/* i is a principal variable in Lme */
+		/* restore Nv [i] to signify that i is principal */
+		Nv [i] = nvi ;
+
+		/* --------------------------------------------------------- */
+		/* compute the external degree (add size of current element) */
+		/* --------------------------------------------------------- */
+
+		deg = Degree [i] + degme - nvi ;
+		deg = MIN (deg, nleft - nvi) ;
+		ASSERT (IMPLIES (aggressive, deg > 0) && deg >= 0 && deg < n) ;
+
+		/* --------------------------------------------------------- */
+		/* place the supervariable at the head of the degree list */
+		/* --------------------------------------------------------- */
+
+		inext = Head [deg] ;
+		ASSERT (inext >= EMPTY && inext < n) ;
+		if (inext != EMPTY) Last [inext] = i ;
+		Next [i] = inext ;
+		Last [i] = EMPTY ;
+		Head [deg] = i ;
+
+		/* --------------------------------------------------------- */
+		/* save the new degree, and find the minimum degree */
+		/* --------------------------------------------------------- */
+
+		mindeg = MIN (mindeg, deg) ;
+		Degree [i] = deg ;
+
+		/* --------------------------------------------------------- */
+		/* place the supervariable in the element pattern */
+		/* --------------------------------------------------------- */
+
+		Iw [p++] = i ;
+
+	    }
+	}
+	AMD_DEBUG2 (("restore done\n")) ;
+
+/* ========================================================================= */
+/* FINALIZE THE NEW ELEMENT */
+/* ========================================================================= */
+
+	AMD_DEBUG2 (("ME = "ID" DONE\n", me)) ;
+	Nv [me] = nvpiv ;
+	/* save the length of the list for the new element me */
+	Len [me] = p - pme1 ;
+	if (Len [me] == 0)
+	{
+	    /* there is nothing left of the current pivot element */
+	    /* it is a root of the assembly tree */
+	    Pe [me] = EMPTY ;
+	    W [me] = 0 ;
+	}
+	if (elenme != 0)
+	{
+	    /* element was not constructed in place: deallocate part of */
+	    /* it since newly nonprincipal variables may have been removed */
+	    pfree = p ;
+	}
+
+	/* The new element has nvpiv pivots and the size of the contribution
+	 * block for a multifrontal method is degme-by-degme, not including
+	 * the "dense" rows/columns.  If the "dense" rows/columns are included,
+	 * the frontal matrix is no larger than
+	 * (degme+ndense)-by-(degme+ndense).
+	 */
+
+	if (Info != (double *) NULL)
+	{
+	    f = nvpiv ;
+	    r = degme + ndense ;
+	    dmax = MAX (dmax, f + r) ;
+
+	    /* number of nonzeros in L (excluding the diagonal) */
+	    lnzme = f*r + (f-1)*f/2 ;
+	    lnz += lnzme ;
+
+	    /* number of divide operations for LDL' and for LU */
+	    ndiv += lnzme ;
+
+	    /* number of multiply-subtract pairs for LU */
+	    s = f*r*r + r*(f-1)*f + (f-1)*f*(2*f-1)/6 ;
+	    nms_lu += s ;
+
+	    /* number of multiply-subtract pairs for LDL' */
+	    nms_ldl += (s + lnzme)/2 ;
+	}
+
+#ifndef NDEBUG
+	AMD_DEBUG2 (("finalize done nel "ID" n "ID"\n   ::::\n", nel, n)) ;
+	for (pme = Pe [me] ; pme <= Pe [me] + Len [me] - 1 ; pme++)
+	{
+	      AMD_DEBUG3 ((" "ID"", Iw [pme])) ;
+	}
+	AMD_DEBUG3 (("\n")) ;
+#endif
+
+    }
+
+/* ========================================================================= */
+/* DONE SELECTING PIVOTS */
+/* ========================================================================= */
+
+    if (Info != (double *) NULL)
+    {
+
+	/* count the work to factorize the ndense-by-ndense submatrix */
+	f = ndense ;
+	dmax = MAX (dmax, (double) ndense) ;
+
+	/* number of nonzeros in L (excluding the diagonal) */
+	lnzme = (f-1)*f/2 ;
+	lnz += lnzme ;
+
+	/* number of divide operations for LDL' and for LU */
+	ndiv += lnzme ;
+
+	/* number of multiply-subtract pairs for LU */
+	s = (f-1)*f*(2*f-1)/6 ;
+	nms_lu += s ;
+
+	/* number of multiply-subtract pairs for LDL' */
+	nms_ldl += (s + lnzme)/2 ;
+
+	/* number of nz's in L (excl. diagonal) */
+	Info [AMD_LNZ] = lnz ;
+
+	/* number of divide ops for LU and LDL' */
+	Info [AMD_NDIV] = ndiv ;
+
+	/* number of multiply-subtract pairs for LDL' */
+	Info [AMD_NMULTSUBS_LDL] = nms_ldl ;
+
+	/* number of multiply-subtract pairs for LU */
+	Info [AMD_NMULTSUBS_LU] = nms_lu ;
+
+	/* number of "dense" rows/columns */
+	Info [AMD_NDENSE] = ndense ;
+
+	/* largest front is dmax-by-dmax */
+	Info [AMD_DMAX] = dmax ;
+
+	/* number of garbage collections in AMD */
+	Info [AMD_NCMPA] = ncmpa ;
+
+	/* successful ordering */
+	Info [AMD_STATUS] = AMD_OK ;
+    }
+
+/* ========================================================================= */
+/* POST-ORDERING */
+/* ========================================================================= */
+
+/* -------------------------------------------------------------------------
+ * Variables at this point:
+ *
+ * Pe: holds the elimination tree.  The parent of j is FLIP (Pe [j]),
+ *	or EMPTY if j is a root.  The tree holds both elements and
+ *	non-principal (unordered) variables absorbed into them.
+ *	Dense variables are non-principal and unordered.
+ *
+ * Elen: holds the size of each element, including the diagonal part.
+ *	FLIP (Elen [e]) > 0 if e is an element.  For unordered
+ *	variables i, Elen [i] is EMPTY.
+ *
+ * Nv: Nv [e] > 0 is the number of pivots represented by the element e.
+ *	For unordered variables i, Nv [i] is zero.
+ *
+ * Contents no longer needed:
+ *	W, Iw, Len, Degree, Head, Next, Last.
+ *
+ * The matrix itself has been destroyed.
+ *
+ * n: the size of the matrix.
+ * No other scalars needed (pfree, iwlen, etc.)
+ * ------------------------------------------------------------------------- */
+
+    /* restore Pe */
+    for (i = 0 ; i < n ; i++)
+    {
+	Pe [i] = FLIP (Pe [i]) ;
+    }
+
+    /* restore Elen, for output information, and for postordering */
+    for (i = 0 ; i < n ; i++)
+    {
+	Elen [i] = FLIP (Elen [i]) ;
+    }
+
+/* Now the parent of j is Pe [j], or EMPTY if j is a root.  Elen [e] > 0
+ * is the size of element e.  Elen [i] is EMPTY for unordered variable i. */
+
+#ifndef NDEBUG
+    AMD_DEBUG2 (("\nTree:\n")) ;
+    for (i = 0 ; i < n ; i++)
+    {
+	AMD_DEBUG2 ((" "ID" parent: "ID"   ", i, Pe [i])) ;
+	ASSERT (Pe [i] >= EMPTY && Pe [i] < n) ;
+	if (Nv [i] > 0)
+	{
+	    /* this is an element */
+	    e = i ;
+	    AMD_DEBUG2 ((" element, size is "ID"\n", Elen [i])) ;
+	    ASSERT (Elen [e] > 0) ;
+	}
+	AMD_DEBUG2 (("\n")) ;
+    }
+    AMD_DEBUG2 (("\nelements:\n")) ;
+    for (e = 0 ; e < n ; e++)
+    {
+	if (Nv [e] > 0)
+	{
+	    AMD_DEBUG3 (("Element e= "ID" size "ID" nv "ID" \n", e,
+		Elen [e], Nv [e])) ;
+	}
+    }
+    AMD_DEBUG2 (("\nvariables:\n")) ;
+    for (i = 0 ; i < n ; i++)
+    {
+	Int cnt ;
+	if (Nv [i] == 0)
+	{
+	    AMD_DEBUG3 (("i unordered: "ID"\n", i)) ;
+	    j = Pe [i] ;
+	    cnt = 0 ;
+	    AMD_DEBUG3 (("  j: "ID"\n", j)) ;
+	    if (j == EMPTY)
+	    {
+		AMD_DEBUG3 (("	i is a dense variable\n")) ;
+	    }
+	    else
+	    {
+		ASSERT (j >= 0 && j < n) ;
+		while (Nv [j] == 0)
+		{
+		    AMD_DEBUG3 (("	j : "ID"\n", j)) ;
+		    j = Pe [j] ;
+		    AMD_DEBUG3 (("	j:: "ID"\n", j)) ;
+		    cnt++ ;
+		    if (cnt > n) break ;
+		}
+		e = j ;
+		AMD_DEBUG3 (("	got to e: "ID"\n", e)) ;
+	    }
+	}
+    }
+#endif
+
+/* ========================================================================= */
+/* compress the paths of the variables */
+/* ========================================================================= */
+
+    for (i = 0 ; i < n ; i++)
+    {
+	if (Nv [i] == 0)
+	{
+
+	    /* -------------------------------------------------------------
+	     * i is an un-ordered row.  Traverse the tree from i until
+	     * reaching an element, e.  The element, e, was the principal
+	     * supervariable of i and all nodes in the path from i to when e
+	     * was selected as pivot.
+	     * ------------------------------------------------------------- */
+
+	    AMD_DEBUG1 (("Path compression, i unordered: "ID"\n", i)) ;
+	    j = Pe [i] ;
+	    ASSERT (j >= EMPTY && j < n) ;
+	    AMD_DEBUG3 (("	j: "ID"\n", j)) ;
+	    if (j == EMPTY)
+	    {
+		/* Skip a dense variable.  It has no parent. */
+		AMD_DEBUG3 (("      i is a dense variable\n")) ;
+		continue ;
+	    }
+
+	    /* while (j is a variable) */
+	    while (Nv [j] == 0)
+	    {
+		AMD_DEBUG3 (("		j : "ID"\n", j)) ;
+		j = Pe [j] ;
+		AMD_DEBUG3 (("		j:: "ID"\n", j)) ;
+		ASSERT (j >= 0 && j < n) ;
+	    }
+	    /* got to an element e */
+	    e = j ;
+	    AMD_DEBUG3 (("got to e: "ID"\n", e)) ;
+
+	    /* -------------------------------------------------------------
+	     * traverse the path again from i to e, and compress the path
+	     * (all nodes point to e).  Path compression allows this code to
+	     * compute in O(n) time.
+	     * ------------------------------------------------------------- */
+
+	    j = i ;
+	    /* while (j is a variable) */
+	    while (Nv [j] == 0)
+	    {
+		jnext = Pe [j] ;
+		AMD_DEBUG3 (("j "ID" jnext "ID"\n", j, jnext)) ;
+		Pe [j] = e ;
+		j = jnext ;
+		ASSERT (j >= 0 && j < n) ;
+	    }
+	}
+    }
+
+/* ========================================================================= */
+/* postorder the assembly tree */
+/* ========================================================================= */
+
+    AMD_postorder (n, Pe, Nv, Elen,
+	W,			/* output order */
+	Head, Next, Last) ;	/* workspace */
+
+/* ========================================================================= */
+/* compute output permutation and inverse permutation */
+/* ========================================================================= */
+
+    /* W [e] = k means that element e is the kth element in the new
+     * order.  e is in the range 0 to n-1, and k is in the range 0 to
+     * the number of elements.  Use Head for inverse order. */
+
+    for (k = 0 ; k < n ; k++)
+    {
+	Head [k] = EMPTY ;
+	Next [k] = EMPTY ;
+    }
+    for (e = 0 ; e < n ; e++)
+    {
+	k = W [e] ;
+	ASSERT ((k == EMPTY) == (Nv [e] == 0)) ;
+	if (k != EMPTY)
+	{
+	    ASSERT (k >= 0 && k < n) ;
+	    Head [k] = e ;
+	}
+    }
+
+    /* construct output inverse permutation in Next,
+     * and permutation in Last */
+    nel = 0 ;
+    for (k = 0 ; k < n ; k++)
+    {
+	e = Head [k] ;
+	if (e == EMPTY) break ;
+	ASSERT (e >= 0 && e < n && Nv [e] > 0) ;
+	Next [e] = nel ;
+	nel += Nv [e] ;
+    }
+    ASSERT (nel == n - ndense) ;
+
+    /* order non-principal variables (dense, & those merged into supervar's) */
+    for (i = 0 ; i < n ; i++)
+    {
+	if (Nv [i] == 0)
+	{
+	    e = Pe [i] ;
+	    ASSERT (e >= EMPTY && e < n) ;
+	    if (e != EMPTY)
+	    {
+		/* This is an unordered variable that was merged
+		 * into element e via supernode detection or mass
+		 * elimination of i when e became the pivot element.
+		 * Place i in order just before e. */
+		ASSERT (Next [i] == EMPTY && Nv [e] > 0) ;
+		Next [i] = Next [e] ;
+		Next [e]++ ;
+	    }
+	    else
+	    {
+		/* This is a dense unordered variable, with no parent.
+		 * Place it last in the output order. */
+		Next [i] = nel++ ;
+	    }
+	}
+    }
+    ASSERT (nel == n) ;
+
+    AMD_DEBUG2 (("\n\nPerm:\n")) ;
+    for (i = 0 ; i < n ; i++)
+    {
+	k = Next [i] ;
+	ASSERT (k >= 0 && k < n) ;
+	Last [k] = i ;
+	AMD_DEBUG2 (("   perm ["ID"] = "ID"\n", k, i)) ;
+    }
+}
diff --git a/src/C/SuiteSparse/AMD/Source/amd_aat.c b/src/C/SuiteSparse/AMD/Source/amd_aat.c
new file mode 100644
index 0000000..5c92931
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Source/amd_aat.c
@@ -0,0 +1,185 @@
+/* ========================================================================= */
+/* === AMD_aat ============================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 2.0, Copyright (c) 2006 by Timothy A. Davis,		     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_aat:  compute the symmetry of the pattern of A, and count the number of
+ * nonzeros each column of A+A' (excluding the diagonal).  Assumes the input
+ * matrix has no errors, with sorted columns and no duplicates
+ * (AMD_valid (n, n, Ap, Ai) must be AMD_OK, but this condition is not
+ * checked).
+ */
+
+#include "amd_internal.h"
+
+GLOBAL size_t AMD_aat	/* returns nz in A+A' */
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    Int Len [ ],	/* Len [j]: length of column j of A+A', excl diagonal*/
+    Int Tp [ ],		/* workspace of size n */
+    double Info [ ]
+)
+{
+    Int p1, p2, p, i, j, pj, pj2, k, nzdiag, nzboth, nz ;
+    double sym ;
+    size_t nzaat ;
+
+#ifndef NDEBUG
+    AMD_debug_init ("AMD AAT") ;
+    for (k = 0 ; k < n ; k++) Tp [k] = EMPTY ;
+    ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
+#endif
+
+    if (Info != (double *) NULL)
+    {
+	/* clear the Info array, if it exists */
+	for (i = 0 ; i < AMD_INFO ; i++)
+	{
+	    Info [i] = EMPTY ;
+	}
+	Info [AMD_STATUS] = AMD_OK ;
+    }
+
+    for (k = 0 ; k < n ; k++)
+    {
+	Len [k] = 0 ;
+    }
+
+    nzdiag = 0 ;
+    nzboth = 0 ;
+    nz = Ap [n] ;
+
+    for (k = 0 ; k < n ; k++)
+    {
+	p1 = Ap [k] ;
+	p2 = Ap [k+1] ;
+	AMD_DEBUG2 (("\nAAT Column: "ID" p1: "ID" p2: "ID"\n", k, p1, p2)) ;
+
+	/* construct A+A' */
+	for (p = p1 ; p < p2 ; )
+	{
+	    /* scan the upper triangular part of A */
+	    j = Ai [p] ;
+	    if (j < k)
+	    {
+		/* entry A (j,k) is in the strictly upper triangular part,
+		 * add both A (j,k) and A (k,j) to the matrix A+A' */
+		Len [j]++ ;
+		Len [k]++ ;
+		AMD_DEBUG3 (("    upper ("ID","ID") ("ID","ID")\n", j,k, k,j));
+		p++ ;
+	    }
+	    else if (j == k)
+	    {
+		/* skip the diagonal */
+		p++ ;
+		nzdiag++ ;
+		break ;
+	    }
+	    else /* j > k */
+	    {
+		/* first entry below the diagonal */
+		break ;
+	    }
+	    /* scan lower triangular part of A, in column j until reaching
+	     * row k.  Start where last scan left off. */
+	    ASSERT (Tp [j] != EMPTY) ;
+	    ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
+	    pj2 = Ap [j+1] ;
+	    for (pj = Tp [j] ; pj < pj2 ; )
+	    {
+		i = Ai [pj] ;
+		if (i < k)
+		{
+		    /* A (i,j) is only in the lower part, not in upper.
+		     * add both A (i,j) and A (j,i) to the matrix A+A' */
+		    Len [i]++ ;
+		    Len [j]++ ;
+		    AMD_DEBUG3 (("    lower ("ID","ID") ("ID","ID")\n",
+			i,j, j,i)) ;
+		    pj++ ;
+		}
+		else if (i == k)
+		{
+		    /* entry A (k,j) in lower part and A (j,k) in upper */
+		    pj++ ;
+		    nzboth++ ;
+		    break ;
+		}
+		else /* i > k */
+		{
+		    /* consider this entry later, when k advances to i */
+		    break ;
+		}
+	    }
+	    Tp [j] = pj ;
+	}
+	/* Tp [k] points to the entry just below the diagonal in column k */
+	Tp [k] = p ;
+    }
+
+    /* clean up, for remaining mismatched entries */
+    for (j = 0 ; j < n ; j++)
+    {
+	for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
+	{
+	    i = Ai [pj] ;
+	    /* A (i,j) is only in the lower part, not in upper.
+	     * add both A (i,j) and A (j,i) to the matrix A+A' */
+	    Len [i]++ ;
+	    Len [j]++ ;
+	    AMD_DEBUG3 (("    lower cleanup ("ID","ID") ("ID","ID")\n",
+		i,j, j,i)) ;
+	}
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* compute the symmetry of the nonzero pattern of A */
+    /* --------------------------------------------------------------------- */
+
+    /* Given a matrix A, the symmetry of A is:
+     *	B = tril (spones (A), -1) + triu (spones (A), 1) ;
+     *  sym = nnz (B & B') / nnz (B) ;
+     *  or 1 if nnz (B) is zero.
+     */
+
+    if (nz == nzdiag)
+    {
+	sym = 1 ;
+    }
+    else
+    {
+	sym = (2 * (double) nzboth) / ((double) (nz - nzdiag)) ;
+    }
+
+    nzaat = 0 ;
+    for (k = 0 ; k < n ; k++)
+    {
+	nzaat += Len [k] ;
+    }
+
+    AMD_DEBUG1 (("AMD nz in A+A', excluding diagonal (nzaat) = %g\n",
+	(double) nzaat)) ;
+    AMD_DEBUG1 (("   nzboth: "ID" nz: "ID" nzdiag: "ID" symmetry: %g\n",
+		nzboth, nz, nzdiag, sym)) ;
+
+    if (Info != (double *) NULL)
+    {
+	Info [AMD_STATUS] = AMD_OK ;
+	Info [AMD_N] = n ;
+	Info [AMD_NZ] = nz ;
+	Info [AMD_SYMMETRY] = sym ;	    /* symmetry of pattern of A */
+	Info [AMD_NZDIAG] = nzdiag ;	    /* nonzeros on diagonal of A */
+	Info [AMD_NZ_A_PLUS_AT] = nzaat ;   /* nonzeros in A+A' */
+    }
+
+    return (nzaat) ;
+}
diff --git a/src/C/SuiteSparse/AMD/Source/amd_control.c b/src/C/SuiteSparse/AMD/Source/amd_control.c
new file mode 100644
index 0000000..a38eb4d
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Source/amd_control.c
@@ -0,0 +1,62 @@
+/* ========================================================================= */
+/* === AMD_control ========================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 2.0, Copyright (c) 2006 by Timothy A. Davis,		     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable.  Prints the control parameters for AMD.  See amd.h
+ * for details.  If the Control array is not present, the defaults are
+ * printed instead.
+ */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_control
+(
+    double Control [ ]
+)
+{
+    double alpha ;
+    Int aggressive ;
+
+    if (Control != (double *) NULL)
+    {
+	alpha = Control [AMD_DENSE] ;
+	aggressive = Control [AMD_AGGRESSIVE] != 0 ;
+    }
+    else
+    {
+	alpha = AMD_DEFAULT_DENSE ;
+	aggressive = AMD_DEFAULT_AGGRESSIVE ;
+    }
+
+    PRINTF (("\namd version %d.%d, %s:  approximate minimum degree ordering:\n"
+	"    dense row parameter: %g\n", AMD_MAIN_VERSION, AMD_SUB_VERSION,
+	AMD_DATE, alpha)) ;
+
+    if (alpha < 0)
+    {
+	PRINTF (("    no rows treated as dense\n")) ;
+    }
+    else
+    {
+	PRINTF ((
+	"    (rows with more than max (%g * sqrt (n), 16) entries are\n"
+	"    considered \"dense\", and placed last in output permutation)\n",
+	alpha)) ;
+    }
+
+    if (aggressive)
+    {
+	PRINTF (("    aggressive absorption:  yes\n\n")) ;
+    }
+    else
+    {
+	PRINTF (("    aggressive absorption:  no\n\n")) ;
+    }
+}
diff --git a/src/C/SuiteSparse/AMD/Source/amd_defaults.c b/src/C/SuiteSparse/AMD/Source/amd_defaults.c
new file mode 100644
index 0000000..59c10e4
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Source/amd_defaults.c
@@ -0,0 +1,37 @@
+/* ========================================================================= */
+/* === AMD_defaults ======================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 2.0, Copyright (c) 2006 by Timothy A. Davis,		     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable.  Sets default control parameters for AMD.  See amd.h
+ * for details.
+ */
+
+#include "amd_internal.h"
+
+/* ========================================================================= */
+/* === AMD defaults ======================================================== */
+/* ========================================================================= */
+
+GLOBAL void AMD_defaults
+(
+    double Control [ ]
+)
+{
+    Int i ;
+    if (Control != (double *) NULL)
+    {
+	for (i = 0 ; i < AMD_CONTROL ; i++)
+	{
+	    Control [i] = 0 ;
+	}
+	Control [AMD_DENSE] = AMD_DEFAULT_DENSE ;
+	Control [AMD_AGGRESSIVE] = AMD_DEFAULT_AGGRESSIVE ;
+    }
+}
diff --git a/src/C/SuiteSparse/AMD/Source/amd_dump.c b/src/C/SuiteSparse/AMD/Source/amd_dump.c
new file mode 100644
index 0000000..cac782e
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Source/amd_dump.c
@@ -0,0 +1,177 @@
+/* ========================================================================= */
+/* === AMD_dump ============================================================ */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 2.0, Copyright (c) 2006 by Timothy A. Davis,		     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* Debugging routines for AMD.  Not used if NDEBUG is not defined at compile-
+ * time (the default).  See comments in amd_internal.h on how to enable
+ * debugging.  Not user-callable.
+ */
+
+#include "amd_internal.h"
+
+#ifndef NDEBUG
+
+/* This global variable is present only when debugging */
+GLOBAL Int AMD_debug = -999 ;		/* default is no debug printing */
+
+/* ========================================================================= */
+/* === AMD_debug_init ====================================================== */
+/* ========================================================================= */
+
+/* Sets the debug print level, by reading the file debug.amd (if it exists) */
+
+GLOBAL void AMD_debug_init ( char *s )
+{
+    FILE *f ;
+    f = fopen ("debug.amd", "r") ;
+    if (f == (FILE *) NULL)
+    {
+	AMD_debug = -999 ;
+    }
+    else
+    {
+	fscanf (f, ID, &AMD_debug) ;
+	fclose (f) ;
+    }
+    if (AMD_debug >= 0) printf ("%s: AMD_debug_init, D= "ID"\n", s, AMD_debug);
+}
+
+/* ========================================================================= */
+/* === AMD_dump ============================================================ */
+/* ========================================================================= */
+
+/* Dump AMD's data structure, except for the hash buckets.  This routine
+ * cannot be called when the hash buckets are non-empty.
+ */
+
+GLOBAL void AMD_dump (
+    Int n,	    /* A is n-by-n */
+    Int Pe [ ],	    /* pe [0..n-1]: index in iw of start of row i */
+    Int Iw [ ],	    /* workspace of size iwlen, iwlen [0..pfree-1]
+		     * holds the matrix on input */
+    Int Len [ ],    /* len [0..n-1]: length for row i */
+    Int iwlen,	    /* length of iw */
+    Int pfree,	    /* iw [pfree ... iwlen-1] is empty on input */
+    Int Nv [ ],	    /* nv [0..n-1] */
+    Int Next [ ],   /* next [0..n-1] */
+    Int Last [ ],   /* last [0..n-1] */
+    Int Head [ ],   /* head [0..n-1] */
+    Int Elen [ ],   /* size n */
+    Int Degree [ ], /* size n */
+    Int W [ ],	    /* size n */
+    Int nel
+)
+{
+    Int i, pe, elen, nv, len, e, p, k, j, deg, w, cnt, ilast ;
+
+    if (AMD_debug < 0) return ;
+    ASSERT (pfree <= iwlen) ;
+    AMD_DEBUG3 (("\nAMD dump, pfree: "ID"\n", pfree)) ;
+    for (i = 0 ; i < n ; i++)
+    {
+	pe = Pe [i] ;
+	elen = Elen [i] ;
+	nv = Nv [i] ;
+	len = Len [i] ;
+	w = W [i] ;
+
+	if (elen >= EMPTY)
+	{
+	    if (nv == 0)
+	    {
+		AMD_DEBUG3 (("\nI "ID": nonprincipal:    ", i)) ;
+		ASSERT (elen == EMPTY) ;
+		if (pe == EMPTY)
+		{
+		    AMD_DEBUG3 ((" dense node\n")) ;
+		    ASSERT (w == 1) ;
+		}
+		else
+		{
+		    ASSERT (pe < EMPTY) ;
+		    AMD_DEBUG3 ((" i "ID" -> parent "ID"\n", i, FLIP (Pe[i])));
+		}
+	    }
+	    else
+	    {
+		AMD_DEBUG3 (("\nI "ID": active principal supervariable:\n",i));
+		AMD_DEBUG3 (("   nv(i): "ID"  Flag: %d\n", nv, (nv < 0))) ;
+		ASSERT (elen >= 0) ;
+		ASSERT (nv > 0 && pe >= 0) ;
+		p = pe ;
+		AMD_DEBUG3 (("   e/s: ")) ;
+		if (elen == 0) AMD_DEBUG3 ((" : ")) ;
+		ASSERT (pe + len <= pfree) ;
+		for (k = 0 ; k < len ; k++)
+		{
+		    j = Iw [p] ;
+		    AMD_DEBUG3 (("  "ID"", j)) ;
+		    ASSERT (j >= 0 && j < n) ;
+		    if (k == elen-1) AMD_DEBUG3 ((" : ")) ;
+		    p++ ;
+		}
+		AMD_DEBUG3 (("\n")) ;
+	    }
+	}
+	else
+	{
+	    e = i ;
+	    if (w == 0)
+	    {
+		AMD_DEBUG3 (("\nE "ID": absorbed element: w "ID"\n", e, w)) ;
+		ASSERT (nv > 0 && pe < 0) ;
+		AMD_DEBUG3 ((" e "ID" -> parent "ID"\n", e, FLIP (Pe [e]))) ;
+	    }
+	    else
+	    {
+		AMD_DEBUG3 (("\nE "ID": unabsorbed element: w "ID"\n", e, w)) ;
+		ASSERT (nv > 0 && pe >= 0) ;
+		p = pe ;
+		AMD_DEBUG3 ((" : ")) ;
+		ASSERT (pe + len <= pfree) ;
+		for (k = 0 ; k < len ; k++)
+		{
+		    j = Iw [p] ;
+		    AMD_DEBUG3 (("  "ID"", j)) ;
+		    ASSERT (j >= 0 && j < n) ;
+		    p++ ;
+		}
+		AMD_DEBUG3 (("\n")) ;
+	    }
+	}
+    }
+
+    /* this routine cannot be called when the hash buckets are non-empty */
+    AMD_DEBUG3 (("\nDegree lists:\n")) ;
+    if (nel >= 0)
+    {
+	cnt = 0 ;
+	for (deg = 0 ; deg < n ; deg++)
+	{
+	    if (Head [deg] == EMPTY) continue ;
+	    ilast = EMPTY ;
+	    AMD_DEBUG3 ((ID": \n", deg)) ;
+	    for (i = Head [deg] ; i != EMPTY ; i = Next [i])
+	    {
+		AMD_DEBUG3 (("   "ID" : next "ID" last "ID" deg "ID"\n",
+		    i, Next [i], Last [i], Degree [i])) ;
+		ASSERT (i >= 0 && i < n && ilast == Last [i] &&
+		    deg == Degree [i]) ;
+		cnt += Nv [i] ;
+		ilast = i ;
+	    }
+	    AMD_DEBUG3 (("\n")) ;
+	}
+	ASSERT (cnt == n - nel) ;
+    }
+
+}
+
+#endif
diff --git a/src/C/SuiteSparse/AMD/Source/amd_global.c b/src/C/SuiteSparse/AMD/Source/amd_global.c
new file mode 100644
index 0000000..f306593
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Source/amd_global.c
@@ -0,0 +1,84 @@
+/* ========================================================================= */
+/* === amd_global ========================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 2.0, Copyright (c) 2006 by Timothy A. Davis,		     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+#include <stdlib.h>
+
+#ifdef MATLAB_MEX_FILE
+#include "mex.h"
+#include "matrix.h"
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* ========================================================================= */
+/* === Default AMD memory manager ========================================== */
+/* ========================================================================= */
+
+/* The user can redefine these global pointers at run-time to change the memory
+ * manager used by AMD.  AMD only uses malloc and free; realloc and calloc are
+ * include for completeness, in case another package wants to use the same
+ * memory manager as AMD.
+ *
+ * If compiling as a MATLAB mexFunction, the default memory manager is mxMalloc.
+ * You can also compile AMD as a standard ANSI-C library and link a mexFunction
+ * against it, and then redefine these pointers at run-time, in your
+ * mexFunction.
+ *
+ * If -DNMALLOC is defined at compile-time, no memory manager is specified at
+ * compile-time.  You must then define these functions at run-time, before
+ * calling AMD, for AMD to work properly.
+ */
+
+#ifndef NMALLOC
+#ifdef MATLAB_MEX_FILE
+/* MATLAB mexFunction: */
+void *(*amd_malloc) (size_t) = mxMalloc ;
+void (*amd_free) (void *) = mxFree ;
+void *(*amd_realloc) (void *, size_t) = mxRealloc ;
+void *(*amd_calloc) (size_t, size_t) = mxCalloc ;
+#else
+/* standard ANSI-C: */
+void *(*amd_malloc) (size_t) = malloc ;
+void (*amd_free) (void *) = free ;
+void *(*amd_realloc) (void *, size_t) = realloc ;
+void *(*amd_calloc) (size_t, size_t) = calloc ;
+#endif
+#else
+/* no memory manager defined at compile-time; you MUST define one at run-time */
+void *(*amd_malloc) (size_t) = NULL ;
+void (*amd_free) (void *) = NULL ;
+void *(*amd_realloc) (void *, size_t) = NULL ;
+void *(*amd_calloc) (size_t, size_t) = NULL ;
+#endif
+
+/* ========================================================================= */
+/* === Default AMD printf routine ========================================== */
+/* ========================================================================= */
+
+/* The user can redefine this global pointer at run-time to change the printf
+ * routine used by AMD.  If NULL, no printing occurs.  
+ *
+ * If -DNPRINT is defined at compile-time, stdio.h is not included.  Printing
+ * can then be enabled at run-time by setting amd_printf to a non-NULL function.
+ */
+
+#ifndef NPRINT
+#ifdef MATLAB_MEX_FILE
+int (*amd_printf) (const char *, ...) = mexPrintf ;
+#else
+#include <stdio.h>
+int (*amd_printf) (const char *, ...) = printf ;
+#endif
+#else
+int (*amd_printf) (const char *, ...) = NULL ;
+#endif
diff --git a/src/C/SuiteSparse/AMD/Source/amd_info.c b/src/C/SuiteSparse/AMD/Source/amd_info.c
new file mode 100644
index 0000000..9cce8a9
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Source/amd_info.c
@@ -0,0 +1,119 @@
+/* ========================================================================= */
+/* === AMD_info ============================================================ */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 2.0, Copyright (c) 2006 by Timothy A. Davis,		     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* 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 if (Info [AMD_STATUS] == AMD_OK_BUT_JUMBLED)
+    {
+	PRINTF (("OK, but jumbled\n")) ;
+    }
+    else
+    {
+	PRINTF (("unknown\n")) ;
+    }
+
+    /* statistics about the input matrix */
+    PRI ("    n, dimension of A:                                  %.20g\n", n);
+    PRI ("    nz, number of nonzeros in A:                        %.20g\n",
+	Info [AMD_NZ]) ;
+    PRI ("    symmetry of A:                                      %.4f\n",
+	Info [AMD_SYMMETRY]) ;
+    PRI ("    number of nonzeros on diagonal:                     %.20g\n",
+	Info [AMD_NZDIAG]) ;
+    PRI ("    nonzeros in pattern of A+A' (excl. diagonal):       %.20g\n",
+	Info [AMD_NZ_A_PLUS_AT]) ;
+    PRI ("    # dense rows/columns of A+A':                       %.20g\n",
+	Info [AMD_NDENSE]) ;
+
+    /* statistics about AMD's behavior  */
+    PRI ("    memory used, in bytes:                              %.20g\n",
+	Info [AMD_MEMORY]) ;
+    PRI ("    # of memory compactions:                            %.20g\n",
+	Info [AMD_NCMPA]) ;
+
+    /* statistics about the ordering quality */
+    PRINTF (("\n"
+	"    The following approximate statistics are for a subsequent\n"
+	"    factorization of A(P,P) + A(P,P)'.  They are slight upper\n"
+	"    bounds if there are no dense rows/columns in A+A', and become\n"
+	"    looser if dense rows/columns exist.\n\n")) ;
+
+    PRI ("    nonzeros in L (excluding diagonal):                 %.20g\n",
+	lnz) ;
+    PRI ("    nonzeros in L (including diagonal):                 %.20g\n",
+	lnzd) ;
+    PRI ("    # divide operations for LDL' or LU:                 %.20g\n",
+	ndiv) ;
+    PRI ("    # multiply-subtract operations for LDL':            %.20g\n",
+	nmultsubs_ldl) ;
+    PRI ("    # multiply-subtract operations for LU:              %.20g\n",
+	nmultsubs_lu) ;
+    PRI ("    max nz. in any column of L (incl. diagonal):        %.20g\n",
+	Info [AMD_DMAX]) ;
+
+    /* total flop counts for various factorizations */
+
+    if (n >= 0 && ndiv >= 0 && nmultsubs_ldl >= 0 && nmultsubs_lu >= 0)
+    {
+	PRINTF (("\n"
+	"    chol flop count for real A, sqrt counted as 1 flop: %.20g\n"
+	"    LDL' flop count for real A:                         %.20g\n"
+	"    LDL' flop count for complex A:                      %.20g\n"
+	"    LU flop count for real A (with no pivoting):        %.20g\n"
+	"    LU flop count for complex A (with no pivoting):     %.20g\n\n",
+	n + ndiv + 2*nmultsubs_ldl,
+	    ndiv + 2*nmultsubs_ldl,
+	  9*ndiv + 8*nmultsubs_ldl,
+	    ndiv + 2*nmultsubs_lu,
+	  9*ndiv + 8*nmultsubs_lu)) ;
+    }
+}
diff --git a/src/C/SuiteSparse/AMD/Source/amd_order.c b/src/C/SuiteSparse/AMD/Source/amd_order.c
new file mode 100644
index 0000000..438d3b7
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Source/amd_order.c
@@ -0,0 +1,200 @@
+/* ========================================================================= */
+/* === AMD_order =========================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 2.0, Copyright (c) 2006 by Timothy A. Davis,		     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable AMD minimum degree ordering routine.  See amd.h for
+ * documentation.
+ */
+
+#include "amd_internal.h"
+
+/* ========================================================================= */
+/* === AMD_order =========================================================== */
+/* ========================================================================= */
+
+GLOBAL Int AMD_order
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    Int P [ ],
+    double Control [ ],
+    double Info [ ]
+)
+{
+    Int *Len, *S, nz, i, *Pinv, info, status, *Rp, *Ri, *Cp, *Ci, ok ;
+    size_t nzaat, slen ;
+    double mem = 0 ;
+
+#ifndef NDEBUG
+    AMD_debug_init ("amd") ;
+#endif
+
+    /* clear the Info array, if it exists */
+    info = Info != (double *) NULL ;
+    if (info)
+    {
+	for (i = 0 ; i < AMD_INFO ; i++)
+	{
+	    Info [i] = EMPTY ;
+	}
+	Info [AMD_N] = n ;
+	Info [AMD_STATUS] = AMD_OK ;
+    }
+
+    /* make sure inputs exist and n is >= 0 */
+    if (Ai == (Int *) NULL || Ap == (Int *) NULL || P == (Int *) NULL || n < 0)
+    {
+	if (info) Info [AMD_STATUS] = AMD_INVALID ;
+	return (AMD_INVALID) ;	    /* arguments are invalid */
+    }
+
+    if (n == 0)
+    {
+	return (AMD_OK) ;	    /* n is 0 so there's nothing to do */
+    }
+
+    nz = Ap [n] ;
+    if (info)
+    {
+	Info [AMD_NZ] = nz ;
+    }
+    if (nz < 0)
+    {
+	if (info) Info [AMD_STATUS] = AMD_INVALID ;
+	return (AMD_INVALID) ;
+    }
+
+    /* check if n or nz will cause size_t overflow */
+    if (((size_t) n) >= SIZE_T_MAX / sizeof (Int)
+     || ((size_t) nz) >= SIZE_T_MAX / sizeof (Int))
+    {
+	if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+	return (AMD_OUT_OF_MEMORY) ;	    /* problem too large */
+    }
+
+    /* check the input matrix:	AMD_OK, AMD_INVALID, or AMD_OK_BUT_JUMBLED */
+    status = AMD_valid (n, n, Ap, Ai) ;
+
+    if (status == AMD_INVALID)
+    {
+	if (info) Info [AMD_STATUS] = AMD_INVALID ;
+	return (AMD_INVALID) ;	    /* matrix is invalid */
+    }
+
+    /* allocate two size-n integer workspaces */
+    Len = amd_malloc (n * sizeof (Int)) ;
+    Pinv = amd_malloc (n * sizeof (Int)) ;
+    mem += n ;
+    mem += n ;
+    if (!Len || !Pinv)
+    {
+	/* :: out of memory :: */
+	amd_free (Len) ;
+	amd_free (Pinv) ;
+	if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+	return (AMD_OUT_OF_MEMORY) ;
+    }
+
+    if (status == AMD_OK_BUT_JUMBLED)
+    {
+	/* sort the input matrix and remove duplicate entries */
+	AMD_DEBUG1 (("Matrix is jumbled\n")) ;
+	Rp = amd_malloc ((n+1) * sizeof (Int)) ;
+	Ri = amd_malloc (MAX (nz,1) * sizeof (Int)) ;
+	mem += (n+1) ;
+	mem += MAX (nz,1) ;
+	if (!Rp || !Ri)
+	{
+	    /* :: out of memory :: */
+	    amd_free (Rp) ;
+	    amd_free (Ri) ;
+	    amd_free (Len) ;
+	    amd_free (Pinv) ;
+	    if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+	    return (AMD_OUT_OF_MEMORY) ;
+	}
+	/* use Len and Pinv as workspace to create R = A' */
+	AMD_preprocess (n, Ap, Ai, Rp, Ri, Len, Pinv) ;
+	Cp = Rp ;
+	Ci = Ri ;
+    }
+    else
+    {
+	/* order the input matrix as-is.  No need to compute R = A' first */
+	Rp = NULL ;
+	Ri = NULL ;
+	Cp = (Int *) Ap ;
+	Ci = (Int *) Ai ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* determine the symmetry and count off-diagonal nonzeros in A+A' */
+    /* --------------------------------------------------------------------- */
+
+    nzaat = AMD_aat (n, Cp, Ci, Len, P, Info) ;
+    AMD_DEBUG1 (("nzaat: %g\n", (double) nzaat)) ;
+    ASSERT ((MAX (nz-n, 0) <= nzaat) && (nzaat <= 2 * (size_t) nz)) ;
+
+    /* --------------------------------------------------------------------- */
+    /* allocate workspace for matrix, elbow room, and 6 size-n vectors */
+    /* --------------------------------------------------------------------- */
+
+    S = NULL ;
+    slen = nzaat ;			/* space for matrix */
+    ok = ((slen + nzaat/5) >= slen) ;	/* check for size_t overflow */
+    slen += nzaat/5 ;			/* add elbow room */
+    for (i = 0 ; ok && i < 7 ; i++)
+    {
+	ok = ((slen + n) > slen) ;	/* check for size_t overflow */
+	slen += n ;			/* size-n elbow room, 6 size-n work */
+    }
+    mem += slen ;
+    ok = ok && (slen < SIZE_T_MAX / sizeof (Int)) ; /* check for overflow */
+    ok = ok && (slen < Int_MAX) ;	/* S[i] for Int i must be OK */
+    if (ok)
+    {
+	S = amd_malloc (slen * sizeof (Int)) ;
+    }
+    AMD_DEBUG1 (("slen %g\n", (double) slen)) ;
+    if (!S)
+    {
+	/* :: out of memory :: (or problem too large) */
+	amd_free (Rp) ;
+	amd_free (Ri) ;
+	amd_free (Len) ;
+	amd_free (Pinv) ;
+	if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+	return (AMD_OUT_OF_MEMORY) ;
+    }
+    if (info)
+    {
+	/* memory usage, in bytes. */
+	Info [AMD_MEMORY] = mem * sizeof (Int) ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* order the matrix */
+    /* --------------------------------------------------------------------- */
+
+    AMD_1 (n, Cp, Ci, P, Pinv, Len, slen, S, Control, Info) ;
+
+    /* --------------------------------------------------------------------- */
+    /* free the workspace */
+    /* --------------------------------------------------------------------- */
+
+    amd_free (Rp) ;
+    amd_free (Ri) ;
+    amd_free (Len) ;
+    amd_free (Pinv) ;
+    amd_free (S) ;
+    if (info) Info [AMD_STATUS] = status ;
+    return (status) ;	    /* successful ordering */
+}
diff --git a/src/C/SuiteSparse/AMD/Source/amd_post_tree.c b/src/C/SuiteSparse/AMD/Source/amd_post_tree.c
new file mode 100644
index 0000000..9695b18
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Source/amd_post_tree.c
@@ -0,0 +1,121 @@
+/* ========================================================================= */
+/* === AMD_post_tree ======================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 2.0, Copyright (c) 2006 by Timothy A. Davis,		     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* 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) ;
+}
diff --git a/src/C/SuiteSparse/AMD/Source/amd_postorder.c b/src/C/SuiteSparse/AMD/Source/amd_postorder.c
new file mode 100644
index 0000000..57c6ef2
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Source/amd_postorder.c
@@ -0,0 +1,207 @@
+/* ========================================================================= */
+/* === AMD_postorder ======================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 2.0, Copyright (c) 2006 by Timothy A. Davis,		     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* 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
+		) ;
+	}
+    }
+}
diff --git a/src/C/SuiteSparse/AMD/Source/amd_preprocess.c b/src/C/SuiteSparse/AMD/Source/amd_preprocess.c
new file mode 100644
index 0000000..6b8bd66
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Source/amd_preprocess.c
@@ -0,0 +1,119 @@
+/* ========================================================================= */
+/* === AMD_preprocess ====================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 2.0, Copyright (c) 2006 by Timothy A. Davis,		     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* Sorts, removes duplicate entries, and transposes from the nonzero pattern of
+ * a column-form matrix A, to obtain the matrix R.  The input matrix can have
+ * duplicate entries and/or unsorted columns (AMD_valid (n,Ap,Ai) must not be
+ * AMD_INVALID).
+ *
+ * This input condition is NOT checked.  This routine is not user-callable.
+ */
+
+#include "amd_internal.h"
+
+/* ========================================================================= */
+/* === AMD_preprocess ====================================================== */
+/* ========================================================================= */
+
+/* AMD_preprocess does not check its input for errors or allocate workspace.
+ * On input, the condition (AMD_valid (n,n,Ap,Ai) != AMD_INVALID) must hold.
+ */
+
+GLOBAL void AMD_preprocess
+(
+    Int n,		/* input matrix: A is n-by-n */
+    const Int Ap [ ],	/* size n+1 */
+    const Int Ai [ ],	/* size nz = Ap [n] */
+
+    /* output matrix R: */
+    Int Rp [ ],		/* size n+1 */
+    Int Ri [ ],		/* size nz (or less, if duplicates present) */
+
+    Int W [ ],		/* workspace of size n */
+    Int Flag [ ]	/* workspace of size n */
+)
+{
+
+    /* --------------------------------------------------------------------- */
+    /* local variables */
+    /* --------------------------------------------------------------------- */
+
+    Int i, j, p, p2 ;
+
+    ASSERT (AMD_valid (n, n, Ap, Ai) != AMD_INVALID) ;
+
+    /* --------------------------------------------------------------------- */
+    /* count the entries in each row of A (excluding duplicates) */
+    /* --------------------------------------------------------------------- */
+
+    for (i = 0 ; i < n ; i++)
+    {
+	W [i] = 0 ;		/* # of nonzeros in row i (excl duplicates) */
+	Flag [i] = EMPTY ;	/* Flag [i] = j if i appears in column j */
+    }
+    for (j = 0 ; j < n ; j++)
+    {
+	p2 = Ap [j+1] ;
+	for (p = Ap [j] ; p < p2 ; p++)
+	{
+	    i = Ai [p] ;
+	    if (Flag [i] != j)
+	    {
+		/* row index i has not yet appeared in column j */
+		W [i]++ ;	    /* one more entry in row i */
+		Flag [i] = j ;	    /* flag row index i as appearing in col j*/
+	    }
+	}
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* compute the row pointers for R */
+    /* --------------------------------------------------------------------- */
+
+    Rp [0] = 0 ;
+    for (i = 0 ; i < n ; i++)
+    {
+	Rp [i+1] = Rp [i] + W [i] ;
+    }
+    for (i = 0 ; i < n ; i++)
+    {
+	W [i] = Rp [i] ;
+	Flag [i] = EMPTY ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* construct the row form matrix R */
+    /* --------------------------------------------------------------------- */
+
+    /* R = row form of pattern of A */
+    for (j = 0 ; j < n ; j++)
+    {
+	p2 = Ap [j+1] ;
+	for (p = Ap [j] ; p < p2 ; p++)
+	{
+	    i = Ai [p] ;
+	    if (Flag [i] != j)
+	    {
+		/* row index i has not yet appeared in column j */
+		Ri [W [i]++] = j ;  /* put col j in row i */
+		Flag [i] = j ;	    /* flag row index i as appearing in col j*/
+	    }
+	}
+    }
+
+#ifndef NDEBUG
+    ASSERT (AMD_valid (n, n, Rp, Ri) == AMD_OK) ;
+    for (j = 0 ; j < n ; j++)
+    {
+	ASSERT (W [j] == Rp [j+1]) ;
+    }
+#endif
+}
diff --git a/src/C/SuiteSparse/AMD/Source/amd_valid.c b/src/C/SuiteSparse/AMD/Source/amd_valid.c
new file mode 100644
index 0000000..cd91e21
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Source/amd_valid.c
@@ -0,0 +1,92 @@
+/* ========================================================================= */
+/* === AMD_valid =========================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 2.0, Copyright (c) 2006 by Timothy A. Davis,		     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* Check if a column-form matrix is valid or not.  The matrix A is
+ * n_row-by-n_col.  The row indices of entries in column j are in
+ * Ai [Ap [j] ... Ap [j+1]-1].  Required conditions are:
+ *
+ *	n_row >= 0
+ *	n_col >= 0
+ *	nz = Ap [n_col] >= 0	    number of entries in the matrix
+ *	Ap [0] == 0
+ *	Ap [j] <= Ap [j+1] for all j in the range 0 to n_col.
+ *      Ai [0 ... nz-1] must be in the range 0 to n_row-1.
+ *
+ * If any of the above conditions hold, AMD_INVALID is returned.  If the
+ * following condition holds, AMD_OK_BUT_JUMBLED is returned (a warning,
+ * not an error):
+ *
+ *	row indices in Ai [Ap [j] ... Ap [j+1]-1] are not sorted in ascending
+ *	    order, and/or duplicate entries exist.
+ *
+ * Otherwise, AMD_OK is returned.
+ *
+ * In v1.2 and earlier, this function returned TRUE if the matrix was valid
+ * (now returns AMD_OK), or FALSE otherwise (now returns AMD_INVALID or
+ * AMD_OK_BUT_JUMBLED).
+ */
+
+#include "amd_internal.h"
+
+GLOBAL Int AMD_valid
+(
+    /* inputs, not modified on output: */
+    Int n_row,		/* A is n_row-by-n_col */
+    Int n_col,
+    const Int Ap [ ],	/* column pointers of A, of size n_col+1 */
+    const Int Ai [ ]	/* row indices of A, of size nz = Ap [n_col] */
+)
+{
+    Int nz, j, p1, p2, ilast, i, p, result = AMD_OK ;
+    if (n_row < 0 || n_col < 0 || Ap == NULL || Ai == NULL)
+    {
+	return (AMD_INVALID) ;
+    }
+    nz = Ap [n_col] ;
+    if (Ap [0] != 0 || nz < 0)
+    {
+	/* column pointers must start at Ap [0] = 0, and Ap [n] must be >= 0 */
+	AMD_DEBUG0 (("column 0 pointer bad or nz < 0\n")) ;
+	return (AMD_INVALID) ;
+    }
+    for (j = 0 ; j < n_col ; j++)
+    {
+	p1 = Ap [j] ;
+	p2 = Ap [j+1] ;
+	AMD_DEBUG2 (("\nColumn: "ID" p1: "ID" p2: "ID"\n", j, p1, p2)) ;
+	if (p1 > p2)
+	{
+	    /* column pointers must be ascending */
+	    AMD_DEBUG0 (("column "ID" pointer bad\n", j)) ;
+	    return (AMD_INVALID) ;
+	}
+	ilast = EMPTY ;
+	for (p = p1 ; p < p2 ; p++)
+	{
+	    i = Ai [p] ;
+	    AMD_DEBUG3 (("row: "ID"\n", i)) ;
+	    if (i < 0 || i >= n_row)
+	    {
+		/* row index out of range */
+		AMD_DEBUG0 (("index out of range, col "ID" row "ID"\n", j, i));
+		return (AMD_INVALID) ;
+	    }
+	    if (i <= ilast)
+	    {
+		/* row index unsorted, or duplicate entry present */
+		AMD_DEBUG1 (("index unsorted/dupl col "ID" row "ID"\n", j, i));
+		result = AMD_OK_BUT_JUMBLED ;
+	    }
+	    ilast = i ;
+	}
+    }
+    return (result) ;
+}
diff --git a/src/C/SuiteSparse/AMD/Source/amdbar.f b/src/C/SuiteSparse/AMD/Source/amdbar.f
new file mode 100644
index 0000000..1384392
--- /dev/null
+++ b/src/C/SuiteSparse/AMD/Source/amdbar.f
@@ -0,0 +1,1206 @@
+C-----------------------------------------------------------------------
+C AMDBAR:  approximate minimum degree, without aggressive absorption
+C-----------------------------------------------------------------------
+
+        SUBROUTINE AMDBAR
+     $          (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT,
+     $          LAST, HEAD, ELEN, DEGREE, NCMPA, W)
+
+        INTEGER N, IWLEN, PFREE, NCMPA, IW (IWLEN), PE (N),
+     $          DEGREE (N), NV (N), NEXT (N), LAST (N), HEAD (N),
+     $          ELEN (N), W (N), LEN (N)
+
+C Given a representation of the nonzero pattern of a symmetric matrix,
+C       A, (excluding the diagonal) perform an approximate minimum
+C       (UMFPACK/MA38-style) degree ordering to compute a pivot order
+C       such that the introduction of nonzeros (fill-in) in the Cholesky
+C       factors A = LL^T are kept low.  At each step, the pivot
+C       selected is the one with the minimum UMFPACK/MA38-style
+C       upper-bound on the external degree.
+C
+C       This routine does not do aggresive absorption (as done by AMD).
+
+C **********************************************************************
+C ***** CAUTION:  ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT.  ******
+C **********************************************************************
+
+C       References:
+C
+C       [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern
+C           multifrontal method for sparse LU factorization", SIAM J.
+C           Matrix Analysis and Applications, vol. 18, no. 1, pp.
+C           140-158.  Discusses UMFPACK / MA38, which first introduced
+C           the approximate minimum degree used by this routine.
+C
+C       [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An
+C           approximate degree ordering algorithm," SIAM J. Matrix
+C           Analysis and Applications, vol. 17, no. 4, pp. 886-905,
+C           1996.  Discusses AMD, AMDBAR, and MC47B.
+C
+C       [3] Alan George and Joseph Liu, "The evolution of the minimum
+C           degree ordering algorithm," SIAM Review, vol. 31, no. 1,
+C           pp. 1-19, 1989.  We list below the features mentioned in
+C           that paper that this code includes:
+C
+C       mass elimination:
+C               Yes.  MA27 relied on supervariable detection for mass
+C               elimination.
+C       indistinguishable nodes:
+C               Yes (we call these "supervariables").  This was also in
+C               the MA27 code - although we modified the method of
+C               detecting them (the previous hash was the true degree,
+C               which we no longer keep track of).  A supervariable is
+C               a set of rows with identical nonzero pattern.  All
+C               variables in a supervariable are eliminated together.
+C               Each supervariable has as its numerical name that of
+C               one of its variables (its principal variable).
+C       quotient graph representation:
+C               Yes.  We use the term "element" for the cliques formed
+C               during elimination.  This was also in the MA27 code.
+C               The algorithm can operate in place, but it will work
+C               more efficiently if given some "elbow room."
+C       element absorption:
+C               Yes.  This was also in the MA27 code.
+C       external degree:
+C               Yes.  The MA27 code was based on the true degree.
+C       incomplete degree update and multiple elimination:
+C               No.  This was not in MA27, either.  Our method of
+C               degree update within MC47B/BD is element-based, not
+C               variable-based.  It is thus not well-suited for use
+C               with incomplete degree update or multiple elimination.
+
+C-----------------------------------------------------------------------
+C Authors, and Copyright (C) 1995 by:
+C       Timothy A. Davis, Patrick Amestoy, Iain S. Duff, & John K. Reid.
+C
+C Acknowledgements:
+C       This work (and the UMFPACK package) was supported by the
+C       National Science Foundation (ASC-9111263 and DMS-9223088).
+C       The UMFPACK/MA38 approximate degree update algorithm, the
+C       unsymmetric analog which forms the basis of MC47B/BD, was
+C       developed while Tim Davis was supported by CERFACS (Toulouse,
+C       France) in a post-doctoral position.
+C
+C Date:  September, 1995
+C-----------------------------------------------------------------------
+
+C-----------------------------------------------------------------------
+C INPUT ARGUMENTS (unaltered):
+C-----------------------------------------------------------------------
+
+C n:    The matrix order.
+C
+C       Restriction:  1 .le. n .lt. (iovflo/2)-2, where iovflo is
+C       the largest positive integer that your computer can represent.
+
+C iwlen:        The length of iw (1..iwlen).  On input, the matrix is
+C       stored in iw (1..pfree-1).  However, iw (1..iwlen) should be
+C       slightly larger than what is required to hold the matrix, at
+C       least iwlen .ge. pfree + n is recommended.  Otherwise,
+C       excessive compressions will take place.
+C       *** We do not recommend running this algorithm with ***
+C       ***      iwlen .lt. pfree + n.                      ***
+C       *** Better performance will be obtained if          ***
+C       ***      iwlen .ge. pfree + n                       ***
+C       *** or better yet                                   ***
+C       ***      iwlen .gt. 1.2 * pfree                     ***
+C       *** (where pfree is its value on input).            ***
+C       The algorithm will not run at all if iwlen .lt. pfree-1.
+C
+C       Restriction: iwlen .ge. pfree-1
+
+C-----------------------------------------------------------------------
+C INPUT/OUPUT ARGUMENTS:
+C-----------------------------------------------------------------------
+
+C pe:   On input, pe (i) is the index in iw of the start of row i, or
+C       zero if row i has no off-diagonal non-zeros.
+C
+C       During execution, it is used for both supervariables and
+C       elements:
+C
+C       * Principal supervariable i:  index into iw of the
+C               description of supervariable i.  A supervariable
+C               represents one or more rows of the matrix
+C               with identical nonzero pattern.
+C       * Non-principal supervariable i:  if i has been absorbed
+C               into another supervariable j, then pe (i) = -j.
+C               That is, j has the same pattern as i.
+C               Note that j might later be absorbed into another
+C               supervariable j2, in which case pe (i) is still -j,
+C               and pe (j) = -j2.
+C       * Unabsorbed element e:  the index into iw of the description
+C               of element e, if e has not yet been absorbed by a
+C               subsequent element.  Element e is created when
+C               the supervariable of the same name is selected as
+C               the pivot.
+C       * Absorbed element e:  if element e is absorbed into element
+C               e2, then pe (e) = -e2.  This occurs when the pattern of
+C               e (that is, Le) is found to be a subset of the pattern
+C               of e2 (that is, Le2).  If element e is "null" (it has
+C               no nonzeros outside its pivot block), then pe (e) = 0.
+C
+C       On output, pe holds the assembly tree/forest, which implicitly
+C       represents a pivot order with identical fill-in as the actual
+C       order (via a depth-first search of the tree).
+C
+C       On output:
+C       If nv (i) .gt. 0, then i represents a node in the assembly tree,
+C       and the parent of i is -pe (i), or zero if i is a root.
+C       If nv (i) = 0, then (i,-pe (i)) represents an edge in a
+C       subtree, the root of which is a node in the assembly tree.
+
+C pfree:        On input the tail end of the array, iw (pfree..iwlen),
+C       is empty, and the matrix is stored in iw (1..pfree-1).
+C       During execution, additional data is placed in iw, and pfree
+C       is modified so that iw (pfree..iwlen) is always the unused part
+C       of iw.  On output, pfree is set equal to the size of iw that
+C       would have been needed for no compressions to occur.  If
+C       ncmpa is zero, then pfree (on output) is less than or equal to
+C       iwlen, and the space iw (pfree+1 ... iwlen) was not used.
+C       Otherwise, pfree (on output) is greater than iwlen, and all the
+C       memory in iw was used.
+
+C-----------------------------------------------------------------------
+C INPUT/MODIFIED (undefined on output):
+C-----------------------------------------------------------------------
+
+C len:  On input, len (i) holds the number of entries in row i of the
+C       matrix, excluding the diagonal.  The contents of len (1..n)
+C       are undefined on output.
+
+C iw:   On input, iw (1..pfree-1) holds the description of each row i
+C       in the matrix.  The matrix must be symmetric, and both upper
+C       and lower triangular parts must be present.  The diagonal must
+C       not be present.  Row i is held as follows:
+C
+C               len (i):  the length of the row i data structure
+C               iw (pe (i) ... pe (i) + len (i) - 1):
+C                       the list of column indices for nonzeros
+C                       in row i (simple supervariables), excluding
+C                       the diagonal.  All supervariables start with
+C                       one row/column each (supervariable i is just
+C                       row i).
+C               if len (i) is zero on input, then pe (i) is ignored
+C               on input.
+C
+C               Note that the rows need not be in any particular order,
+C               and there may be empty space between the rows.
+C
+C       During execution, the supervariable i experiences fill-in.
+C       This is represented by placing in i a list of the elements
+C       that cause fill-in in supervariable i:
+C
+C               len (i):  the length of supervariable i
+C               iw (pe (i) ... pe (i) + elen (i) - 1):
+C                       the list of elements that contain i.  This list
+C                       is kept short by removing absorbed elements.
+C               iw (pe (i) + elen (i) ... pe (i) + len (i) - 1):
+C                       the list of supervariables in i.  This list
+C                       is kept short by removing nonprincipal
+C                       variables, and any entry j that is also
+C                       contained in at least one of the elements
+C                       (j in Le) in the list for i (e in row i).
+C
+C       When supervariable i is selected as pivot, we create an
+C       element e of the same name (e=i):
+C
+C               len (e):  the length of element e
+C               iw (pe (e) ... pe (e) + len (e) - 1):
+C                       the list of supervariables in element e.
+C
+C       An element represents the fill-in that occurs when supervariable
+C       i is selected as pivot (which represents the selection of row i
+C       and all non-principal variables whose principal variable is i).
+C       We use the term Le to denote the set of all supervariables
+C       in element e.  Absorbed supervariables and elements are pruned
+C       from these lists when computationally convenient.
+C
+C       CAUTION:  THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
+C       The contents of iw are undefined on output.
+
+C-----------------------------------------------------------------------
+C OUTPUT (need not be set on input):
+C-----------------------------------------------------------------------
+
+C nv:   During execution, abs (nv (i)) is equal to the number of rows
+C       that are represented by the principal supervariable i.  If i is
+C       a nonprincipal variable, then nv (i) = 0.  Initially,
+C       nv (i) = 1 for all i.  nv (i) .lt. 0 signifies that i is a
+C       principal variable in the pattern Lme of the current pivot
+C       element me.  On output, nv (e) holds the true degree of element
+C       e at the time it was created (including the diagonal part).
+
+C ncmpa:        The number of times iw was compressed.  If this is
+C       excessive, then the execution took longer than what could have
+C       been.  To reduce ncmpa, try increasing iwlen to be 10% or 20%
+C       larger than the value of pfree on input (or at least
+C       iwlen .ge. pfree + n).  The fastest performance will be
+C       obtained when ncmpa is returned as zero.  If iwlen is set to
+C       the value returned by pfree on *output*, then no compressions
+C       will occur.
+
+C elen: See the description of iw above.  At the start of execution,
+C       elen (i) is set to zero.  During execution, elen (i) is the
+C       number of elements in the list for supervariable i.  When e
+C       becomes an element, elen (e) = -nel is set, where nel is the
+C       current step of factorization.  elen (i) = 0 is done when i
+C       becomes nonprincipal.
+C
+C       For variables, elen (i) .ge. 0 holds until just before the
+C       permutation vectors are computed.  For elements,
+C       elen (e) .lt. 0 holds.
+C
+C       On output elen (1..n) holds the inverse permutation (the same
+C       as the 'INVP' argument in Sparspak).  That is, if k = elen (i),
+C       then row i is the kth pivot row.  Row i of A appears as the
+C       (elen(i))-th row in the permuted matrix, PAP^T.
+
+C last: In a degree list, last (i) is the supervariable preceding i,
+C       or zero if i is the head of the list.  In a hash bucket,
+C       last (i) is the hash key for i.  last (head (hash)) is also
+C       used as the head of a hash bucket if head (hash) contains a
+C       degree list (see head, below).
+C
+C       On output, last (1..n) holds the permutation (the same as the
+C       'PERM' argument in Sparspak).  That is, if i = last (k), then
+C       row i is the kth pivot row.  Row last (k) of A is the k-th row
+C       in the permuted matrix, PAP^T.
+
+C-----------------------------------------------------------------------
+C LOCAL (not input or output - used only during execution):
+C-----------------------------------------------------------------------
+
+C degree:       If i is a supervariable, then degree (i) holds the
+C       current approximation of the external degree of row i (an upper
+C       bound).  The external degree is the number of nonzeros in row i,
+C       minus abs (nv (i)) (the diagonal part).  The bound is equal to
+C       the external degree if elen (i) is less than or equal to two.
+C
+C       We also use the term "external degree" for elements e to refer
+C       to |Le \ Lme|.  If e is an element, then degree (e) holds |Le|,
+C       which is the degree of the off-diagonal part of the element e
+C       (not including the diagonal part).
+
+C head: head is used for degree lists.  head (deg) is the first
+C       supervariable in a degree list (all supervariables i in a
+C       degree list deg have the same approximate degree, namely,
+C       deg = degree (i)).  If the list deg is empty then
+C       head (deg) = 0.
+C
+C       During supervariable detection head (hash) also serves as a
+C       pointer to a hash bucket.
+C       If head (hash) .gt. 0, there is a degree list of degree hash.
+C               The hash bucket head pointer is last (head (hash)).
+C       If head (hash) = 0, then the degree list and hash bucket are
+C               both empty.
+C       If head (hash) .lt. 0, then the degree list is empty, and
+C               -head (hash) is the head of the hash bucket.
+C       After supervariable detection is complete, all hash buckets
+C       are empty, and the (last (head (hash)) = 0) condition is
+C       restored for the non-empty degree lists.
+
+C next: next (i) is the supervariable following i in a link list, or
+C       zero if i is the last in the list.  Used for two kinds of
+C       lists:  degree lists and hash buckets (a supervariable can be
+C       in only one kind of list at a time).
+
+C w:    The flag array w determines the status of elements and
+C       variables, and the external degree of elements.
+C
+C       for elements:
+C          if w (e) = 0, then the element e is absorbed
+C          if w (e) .ge. wflg, then w (e) - wflg is the size of
+C               the set |Le \ Lme|, in terms of nonzeros (the
+C               sum of abs (nv (i)) for each principal variable i that
+C               is both in the pattern of element e and NOT in the
+C               pattern of the current pivot element, me).
+C          if wflg .gt. w (e) .gt. 0, then e is not absorbed and has
+C               not yet been seen in the scan of the element lists in
+C               the computation of |Le\Lme| in loop 150 below.
+C
+C       for variables:
+C          during supervariable detection, if w (j) .ne. wflg then j is
+C          not in the pattern of variable i
+C
+C       The w array is initialized by setting w (i) = 1 for all i,
+C       and by setting wflg = 2.  It is reinitialized if wflg becomes
+C       too large (to ensure that wflg+n does not cause integer
+C       overflow).
+
+C-----------------------------------------------------------------------
+C LOCAL INTEGERS:
+C-----------------------------------------------------------------------
+
+        INTEGER DEG, DEGME, DMAX, E, ELENME, ELN, HASH, HMOD, I,
+     $          ILAST, INEXT, J, JLAST, JNEXT, K, KNT1, KNT2, KNT3,
+     $          LENJ, LN, MAXMEM, ME, MEM, MINDEG, NEL, NEWMEM,
+     $          NLEFT, NVI, NVJ, NVPIV, SLENME, WE, WFLG, WNVI, X
+
+C deg:          the degree of a variable or element
+C degme:        size, |Lme|, of the current element, me (= degree (me))
+C dext:         external degree, |Le \ Lme|, of some element e
+C dmax:         largest |Le| seen so far
+C e:            an element
+C elenme:       the length, elen (me), of element list of pivotal var.
+C eln:          the length, elen (...), of an element list
+C hash:         the computed value of the hash function
+C hmod:         the hash function is computed modulo hmod = max (1,n-1)
+C i:            a supervariable
+C ilast:        the entry in a link list preceding i
+C inext:        the entry in a link list following i
+C j:            a supervariable
+C jlast:        the entry in a link list preceding j
+C jnext:        the entry in a link list, or path, following j
+C k:            the pivot order of an element or variable
+C knt1:         loop counter used during element construction
+C knt2:         loop counter used during element construction
+C knt3:         loop counter used during compression
+C lenj:         len (j)
+C ln:           length of a supervariable list
+C maxmem:       amount of memory needed for no compressions
+C me:           current supervariable being eliminated, and the
+C                       current element created by eliminating that
+C                       supervariable
+C mem:          memory in use assuming no compressions have occurred
+C mindeg:       current minimum degree
+C nel:          number of pivots selected so far
+C newmem:       amount of new memory needed for current pivot element
+C nleft:        n - nel, the number of nonpivotal rows/columns remaining
+C nvi:          the number of variables in a supervariable i (= nv (i))
+C nvj:          the number of variables in a supervariable j (= nv (j))
+C nvpiv:        number of pivots in current element
+C slenme:       number of variables in variable list of pivotal variable
+C we:           w (e)
+C wflg:         used for flagging the w array.  See description of iw.
+C wnvi:         wflg - nv (i)
+C x:            either a supervariable or an element
+
+C-----------------------------------------------------------------------
+C LOCAL POINTERS:
+C-----------------------------------------------------------------------
+
+        INTEGER P, P1, P2, P3, PDST, PEND, PJ, PME, PME1, PME2, PN, PSRC
+
+C               Any parameter (pe (...) or pfree) or local variable
+C               starting with "p" (for Pointer) is an index into iw,
+C               and all indices into iw use variables starting with
+C               "p."  The only exception to this rule is the iwlen
+C               input argument.
+
+C p:            pointer into lots of things
+C p1:           pe (i) for some variable i (start of element list)
+C p2:           pe (i) + elen (i) -  1 for some var. i (end of el. list)
+C p3:           index of first supervariable in clean list
+C pdst:         destination pointer, for compression
+C pend:         end of memory to compress
+C pj:           pointer into an element or variable
+C pme:          pointer into the current element (pme1...pme2)
+C pme1:         the current element, me, is stored in iw (pme1...pme2)
+C pme2:         the end of the current element
+C pn:           pointer into a "clean" variable, also used to compress
+C psrc:         source pointer, for compression
+
+C-----------------------------------------------------------------------
+C  FUNCTIONS CALLED:
+C-----------------------------------------------------------------------
+
+        INTRINSIC MAX, MIN, MOD
+
+C=======================================================================
+C  INITIALIZATIONS
+C=======================================================================
+
+        WFLG = 2
+        MINDEG = 1
+        NCMPA = 0
+        NEL = 0
+        HMOD = MAX (1, N-1)
+        DMAX = 0
+        MEM = PFREE - 1
+        MAXMEM = MEM
+	ME = 0
+
+        DO 10 I = 1, N
+           LAST (I) = 0
+           HEAD (I) = 0
+           NV (I) = 1
+           W (I) = 1
+           ELEN (I) = 0
+           DEGREE (I) = LEN (I)
+10         CONTINUE
+
+C       ----------------------------------------------------------------
+C       initialize degree lists and eliminate rows with no off-diag. nz.
+C       ----------------------------------------------------------------
+
+        DO 20 I = 1, N
+
+           DEG = DEGREE (I)
+
+           IF (DEG .GT. 0) THEN
+
+C             ----------------------------------------------------------
+C             place i in the degree list corresponding to its degree
+C             ----------------------------------------------------------
+
+              INEXT = HEAD (DEG)
+              IF (INEXT .NE. 0) LAST (INEXT) = I
+              NEXT (I) = INEXT
+              HEAD (DEG) = I
+
+           ELSE
+
+C             ----------------------------------------------------------
+C             we have a variable that can be eliminated at once because
+C             there is no off-diagonal non-zero in its row.
+C             ----------------------------------------------------------
+
+              NEL = NEL + 1
+              ELEN (I) = -NEL
+              PE (I) = 0
+              W (I) = 0
+
+              ENDIF
+
+20         CONTINUE
+
+C=======================================================================
+C  WHILE (selecting pivots) DO
+C=======================================================================
+
+30      CONTINUE
+        IF (NEL .LT. N) THEN
+
+C=======================================================================
+C  GET PIVOT OF MINIMUM DEGREE
+C=======================================================================
+
+C          -------------------------------------------------------------
+C          find next supervariable for elimination
+C          -------------------------------------------------------------
+
+           DO 40 DEG = MINDEG, N
+              ME = HEAD (DEG)
+              IF (ME .GT. 0) GOTO 50
+40            CONTINUE
+50         CONTINUE
+           MINDEG = DEG
+
+C          -------------------------------------------------------------
+C          remove chosen variable from link list
+C          -------------------------------------------------------------
+
+           INEXT = NEXT (ME)
+           IF (INEXT .NE. 0) LAST (INEXT) = 0
+           HEAD (DEG) = INEXT
+
+C          -------------------------------------------------------------
+C          me represents the elimination of pivots nel+1 to nel+nv(me).
+C          place me itself as the first in this set.  It will be moved
+C          to the nel+nv(me) position when the permutation vectors are
+C          computed.
+C          -------------------------------------------------------------
+
+           ELENME = ELEN (ME)
+           ELEN (ME) = - (NEL + 1)
+           NVPIV = NV (ME)
+           NEL = NEL + NVPIV
+
+C=======================================================================
+C  CONSTRUCT NEW ELEMENT
+C=======================================================================
+
+C          -------------------------------------------------------------
+C          At this point, me is the pivotal supervariable.  It will be
+C          converted into the current element.  Scan list of the
+C          pivotal supervariable, me, setting tree pointers and
+C          constructing new list of supervariables for the new element,
+C          me.  p is a pointer to the current position in the old list.
+C          -------------------------------------------------------------
+
+C          flag the variable "me" as being in Lme by negating nv (me)
+           NV (ME) = -NVPIV
+           DEGME = 0
+
+           IF (ELENME .EQ. 0) THEN
+
+C             ----------------------------------------------------------
+C             construct the new element in place
+C             ----------------------------------------------------------
+
+              PME1 = PE (ME)
+              PME2 = PME1 - 1
+
+              DO 60 P = PME1, PME1 + LEN (ME) - 1
+                 I = IW (P)
+                 NVI = NV (I)
+                 IF (NVI .GT. 0) THEN
+
+C                   ----------------------------------------------------
+C                   i is a principal variable not yet placed in Lme.
+C                   store i in new list
+C                   ----------------------------------------------------
+
+                    DEGME = DEGME + NVI
+C                   flag i as being in Lme by negating nv (i)
+                    NV (I) = -NVI
+                    PME2 = PME2 + 1
+                    IW (PME2) = I
+
+C                   ----------------------------------------------------
+C                   remove variable i from degree list.
+C                   ----------------------------------------------------
+
+                    ILAST = LAST (I)
+                    INEXT = NEXT (I)
+                    IF (INEXT .NE. 0) LAST (INEXT) = ILAST
+                    IF (ILAST .NE. 0) THEN
+                       NEXT (ILAST) = INEXT
+                    ELSE
+C                      i is at the head of the degree list
+                       HEAD (DEGREE (I)) = INEXT
+                       ENDIF
+
+                    ENDIF
+60               CONTINUE
+C             this element takes no new memory in iw:
+              NEWMEM = 0
+
+           ELSE
+
+C             ----------------------------------------------------------
+C             construct the new element in empty space, iw (pfree ...)
+C             ----------------------------------------------------------
+
+              P = PE (ME)
+              PME1 = PFREE
+              SLENME = LEN (ME) - ELENME
+
+              DO 120 KNT1 = 1, ELENME + 1
+
+                 IF (KNT1 .GT. ELENME) THEN
+C                   search the supervariables in me.
+                    E = ME
+                    PJ = P
+                    LN = SLENME
+                 ELSE
+C                   search the elements in me.
+                    E = IW (P)
+                    P = P + 1
+                    PJ = PE (E)
+                    LN = LEN (E)
+                    ENDIF
+
+C                -------------------------------------------------------
+C                search for different supervariables and add them to the
+C                new list, compressing when necessary. this loop is
+C                executed once for each element in the list and once for
+C                all the supervariables in the list.
+C                -------------------------------------------------------
+
+                 DO 110 KNT2 = 1, LN
+                    I = IW (PJ)
+                    PJ = PJ + 1
+                    NVI = NV (I)
+                    IF (NVI .GT. 0) THEN
+
+C                      -------------------------------------------------
+C                      compress iw, if necessary
+C                      -------------------------------------------------
+
+                       IF (PFREE .GT. IWLEN) THEN
+C                         prepare for compressing iw by adjusting
+C                         pointers and lengths so that the lists being
+C                         searched in the inner and outer loops contain
+C                         only the remaining entries.
+
+                          PE (ME) = P
+                          LEN (ME) = LEN (ME) - KNT1
+                          IF (LEN (ME) .EQ. 0) THEN
+C                            nothing left of supervariable me
+                             PE (ME) = 0
+                             ENDIF
+                          PE (E) = PJ
+                          LEN (E) = LN - KNT2
+                          IF (LEN (E) .EQ. 0) THEN
+C                            nothing left of element e
+                             PE (E) = 0
+                             ENDIF
+
+                          NCMPA = NCMPA + 1
+C                         store first item in pe
+C                         set first entry to -item
+                          DO 70 J = 1, N
+                             PN = PE (J)
+                             IF (PN .GT. 0) THEN
+                                PE (J) = IW (PN)
+                                IW (PN) = -J
+                                ENDIF
+70                           CONTINUE
+
+C                         psrc/pdst point to source/destination
+                          PDST = 1
+                          PSRC = 1
+                          PEND = PME1 - 1
+
+C                         while loop:
+80                        CONTINUE
+                          IF (PSRC .LE. PEND) THEN
+C                            search for next negative entry
+                             J = -IW (PSRC)
+                             PSRC = PSRC + 1
+                             IF (J .GT. 0) THEN
+                                IW (PDST) = PE (J)
+                                PE (J) = PDST
+                                PDST = PDST + 1
+C                               copy from source to destination
+                                LENJ = LEN (J)
+                                DO 90 KNT3 = 0, LENJ - 2
+                                   IW (PDST + KNT3) = IW (PSRC + KNT3)
+90                                 CONTINUE
+                                PDST = PDST + LENJ - 1
+                                PSRC = PSRC + LENJ - 1
+                                ENDIF
+                             GOTO 80
+                             ENDIF
+
+C                         move the new partially-constructed element
+                          P1 = PDST
+                          DO 100 PSRC = PME1, PFREE - 1
+                             IW (PDST) = IW (PSRC)
+                             PDST = PDST + 1
+100                          CONTINUE
+                          PME1 = P1
+                          PFREE = PDST
+                          PJ = PE (E)
+                          P = PE (ME)
+                          ENDIF
+
+C                      -------------------------------------------------
+C                      i is a principal variable not yet placed in Lme
+C                      store i in new list
+C                      -------------------------------------------------
+
+                       DEGME = DEGME + NVI
+C                      flag i as being in Lme by negating nv (i)
+                       NV (I) = -NVI
+                       IW (PFREE) = I
+                       PFREE = PFREE + 1
+
+C                      -------------------------------------------------
+C                      remove variable i from degree link list
+C                      -------------------------------------------------
+
+                       ILAST = LAST (I)
+                       INEXT = NEXT (I)
+                       IF (INEXT .NE. 0) LAST (INEXT) = ILAST
+                       IF (ILAST .NE. 0) THEN
+                          NEXT (ILAST) = INEXT
+                       ELSE
+C                         i is at the head of the degree list
+                          HEAD (DEGREE (I)) = INEXT
+                          ENDIF
+
+                       ENDIF
+110                 CONTINUE
+
+                 IF (E .NE. ME) THEN
+C                   set tree pointer and flag to indicate element e is
+C                   absorbed into new element me (the parent of e is me)
+                    PE (E) = -ME
+                    W (E) = 0
+                    ENDIF
+120              CONTINUE
+
+              PME2 = PFREE - 1
+C             this element takes newmem new memory in iw (possibly zero)
+              NEWMEM = PFREE - PME1
+              MEM = MEM + NEWMEM
+              MAXMEM = MAX (MAXMEM, MEM)
+              ENDIF
+
+C          -------------------------------------------------------------
+C          me has now been converted into an element in iw (pme1..pme2)
+C          -------------------------------------------------------------
+
+C          degme holds the external degree of new element
+           DEGREE (ME) = DEGME
+           PE (ME) = PME1
+           LEN (ME) = PME2 - PME1 + 1
+
+C          -------------------------------------------------------------
+C          make sure that wflg is not too large.  With the current
+C          value of wflg, wflg+n must not cause integer overflow
+C          -------------------------------------------------------------
+
+           IF (WFLG + N .LE. WFLG) THEN
+              DO 130 X = 1, N
+                 IF (W (X) .NE. 0) W (X) = 1
+130              CONTINUE
+              WFLG = 2
+              ENDIF
+
+C=======================================================================
+C  COMPUTE (w (e) - wflg) = |Le\Lme| FOR ALL ELEMENTS
+C=======================================================================
+
+C          -------------------------------------------------------------
+C          Scan 1:  compute the external degrees of previous elements
+C          with respect to the current element.  That is:
+C               (w (e) - wflg) = |Le \ Lme|
+C          for each element e that appears in any supervariable in Lme.
+C          The notation Le refers to the pattern (list of
+C          supervariables) of a previous element e, where e is not yet
+C          absorbed, stored in iw (pe (e) + 1 ... pe (e) + iw (pe (e))).
+C          The notation Lme refers to the pattern of the current element
+C          (stored in iw (pme1..pme2)).   If (w (e) - wflg) becomes
+C          zero, then the element e will be absorbed in scan 2.
+C          -------------------------------------------------------------
+
+           DO 150 PME = PME1, PME2
+              I = IW (PME)
+              ELN = ELEN (I)
+              IF (ELN .GT. 0) THEN
+C                note that nv (i) has been negated to denote i in Lme:
+                 NVI = -NV (I)
+                 WNVI = WFLG - NVI
+                 DO 140 P = PE (I), PE (I) + ELN - 1
+                    E = IW (P)
+                    WE = W (E)
+                    IF (WE .GE. WFLG) THEN
+C                      unabsorbed element e has been seen in this loop
+                       WE = WE - NVI
+                    ELSE IF (WE .NE. 0) THEN
+C                      e is an unabsorbed element
+C                      this is the first we have seen e in all of Scan 1
+                       WE = DEGREE (E) + WNVI
+                       ENDIF
+                    W (E) = WE
+140                 CONTINUE
+                 ENDIF
+150           CONTINUE
+
+C=======================================================================
+C  DEGREE UPDATE AND ELEMENT ABSORPTION
+C=======================================================================
+
+C          -------------------------------------------------------------
+C          Scan 2:  for each i in Lme, sum up the degree of Lme (which
+C          is degme), plus the sum of the external degrees of each Le
+C          for the elements e appearing within i, plus the
+C          supervariables in i.  Place i in hash list.
+C          -------------------------------------------------------------
+
+           DO 180 PME = PME1, PME2
+              I = IW (PME)
+              P1 = PE (I)
+              P2 = P1 + ELEN (I) - 1
+              PN = P1
+              HASH = 0
+              DEG = 0
+
+C             ----------------------------------------------------------
+C             scan the element list associated with supervariable i
+C             ----------------------------------------------------------
+
+C             UMFPACK/MA38-style approximate degree:
+              DO 160 P = P1, P2
+                 E = IW (P)
+                 WE = W (E)
+                 IF (WE .NE. 0) THEN
+C                   e is an unabsorbed element
+                    DEG = DEG + WE - WFLG
+                    IW (PN) = E
+                    PN = PN + 1
+                    HASH = HASH + E
+                    ENDIF
+160              CONTINUE
+
+C             count the number of elements in i (including me):
+              ELEN (I) = PN - P1 + 1
+
+C             ----------------------------------------------------------
+C             scan the supervariables in the list associated with i
+C             ----------------------------------------------------------
+
+              P3 = PN
+              DO 170 P = P2 + 1, P1 + LEN (I) - 1
+                 J = IW (P)
+                 NVJ = NV (J)
+                 IF (NVJ .GT. 0) THEN
+C                   j is unabsorbed, and not in Lme.
+C                   add to degree and add to new list
+                    DEG = DEG + NVJ
+                    IW (PN) = J
+                    PN = PN + 1
+                    HASH = HASH + J
+                    ENDIF
+170              CONTINUE
+
+C             ----------------------------------------------------------
+C             update the degree and check for mass elimination
+C             ----------------------------------------------------------
+
+              IF (ELEN (I) .EQ. 1 .AND. P3 .EQ. PN) THEN
+
+C                -------------------------------------------------------
+C                mass elimination
+C                -------------------------------------------------------
+
+C                There is nothing left of this node except for an
+C                edge to the current pivot element.  elen (i) is 1,
+C                and there are no variables adjacent to node i.
+C                Absorb i into the current pivot element, me.
+
+                 PE (I) = -ME
+                 NVI = -NV (I)
+                 DEGME = DEGME - NVI
+                 NVPIV = NVPIV + NVI
+                 NEL = NEL + NVI
+                 NV (I) = 0
+                 ELEN (I) = 0
+
+              ELSE
+
+C                -------------------------------------------------------
+C                update the upper-bound degree of i
+C                -------------------------------------------------------
+
+C                the following degree does not yet include the size
+C                of the current element, which is added later:
+                 DEGREE (I) = MIN (DEGREE (I), DEG)
+
+C                -------------------------------------------------------
+C                add me to the list for i
+C                -------------------------------------------------------
+
+C                move first supervariable to end of list
+                 IW (PN) = IW (P3)
+C                move first element to end of element part of list
+                 IW (P3) = IW (P1)
+C                add new element to front of list.
+                 IW (P1) = ME
+C                store the new length of the list in len (i)
+                 LEN (I) = PN - P1 + 1
+
+C                -------------------------------------------------------
+C                place in hash bucket.  Save hash key of i in last (i).
+C                -------------------------------------------------------
+
+                 HASH = MOD (HASH, HMOD) + 1
+                 J = HEAD (HASH)
+                 IF (J .LE. 0) THEN
+C                   the degree list is empty, hash head is -j
+                    NEXT (I) = -J
+                    HEAD (HASH) = -I
+                 ELSE
+C                   degree list is not empty
+C                   use last (head (hash)) as hash head
+                    NEXT (I) = LAST (J)
+                    LAST (J) = I
+                    ENDIF
+                 LAST (I) = HASH
+                 ENDIF
+180           CONTINUE
+
+           DEGREE (ME) = DEGME
+
+C          -------------------------------------------------------------
+C          Clear the counter array, w (...), by incrementing wflg.
+C          -------------------------------------------------------------
+
+           DMAX = MAX (DMAX, DEGME)
+           WFLG = WFLG + DMAX
+
+C          make sure that wflg+n does not cause integer overflow
+           IF (WFLG + N .LE. WFLG) THEN
+              DO 190 X = 1, N
+                 IF (W (X) .NE. 0) W (X) = 1
+190              CONTINUE
+              WFLG = 2
+              ENDIF
+C          at this point, w (1..n) .lt. wflg holds
+
+C=======================================================================
+C  SUPERVARIABLE DETECTION
+C=======================================================================
+
+           DO 250 PME = PME1, PME2
+              I = IW (PME)
+              IF (NV (I) .LT. 0) THEN
+C                i is a principal variable in Lme
+
+C                -------------------------------------------------------
+C                examine all hash buckets with 2 or more variables.  We
+C                do this by examing all unique hash keys for super-
+C                variables in the pattern Lme of the current element, me
+C                -------------------------------------------------------
+
+                 HASH = LAST (I)
+C                let i = head of hash bucket, and empty the hash bucket
+                 J = HEAD (HASH)
+                 IF (J .EQ. 0) GOTO 250
+                 IF (J .LT. 0) THEN
+C                   degree list is empty
+                    I = -J
+                    HEAD (HASH) = 0
+                 ELSE
+C                   degree list is not empty, restore last () of head
+                    I = LAST (J)
+                    LAST (J) = 0
+                    ENDIF
+                 IF (I .EQ. 0) GOTO 250
+
+C                while loop:
+200              CONTINUE
+                 IF (NEXT (I) .NE. 0) THEN
+
+C                   ----------------------------------------------------
+C                   this bucket has one or more variables following i.
+C                   scan all of them to see if i can absorb any entries
+C                   that follow i in hash bucket.  Scatter i into w.
+C                   ----------------------------------------------------
+
+                    LN = LEN (I)
+                    ELN = ELEN (I)
+C                   do not flag the first element in the list (me)
+                    DO 210 P = PE (I) + 1, PE (I) + LN - 1
+                       W (IW (P)) = WFLG
+210                    CONTINUE
+
+C                   ----------------------------------------------------
+C                   scan every other entry j following i in bucket
+C                   ----------------------------------------------------
+
+                    JLAST = I
+                    J = NEXT (I)
+
+C                   while loop:
+220                 CONTINUE
+                    IF (J .NE. 0) THEN
+
+C                      -------------------------------------------------
+C                      check if j and i have identical nonzero pattern
+C                      -------------------------------------------------
+
+                       IF (LEN (J) .NE. LN) THEN
+C                         i and j do not have same size data structure
+                          GOTO 240
+                          ENDIF
+                       IF (ELEN (J) .NE. ELN) THEN
+C                         i and j do not have same number of adjacent el
+                          GOTO 240
+                          ENDIF
+C                      do not flag the first element in the list (me)
+                       DO 230 P = PE (J) + 1, PE (J) + LN - 1
+                          IF (W (IW (P)) .NE. WFLG) THEN
+C                            an entry (iw(p)) is in j but not in i
+                             GOTO 240
+                             ENDIF
+230                       CONTINUE
+
+C                      -------------------------------------------------
+C                      found it!  j can be absorbed into i
+C                      -------------------------------------------------
+
+                       PE (J) = -I
+C                      both nv (i) and nv (j) are negated since they
+C                      are in Lme, and the absolute values of each
+C                      are the number of variables in i and j:
+                       NV (I) = NV (I) + NV (J)
+                       NV (J) = 0
+                       ELEN (J) = 0
+C                      delete j from hash bucket
+                       J = NEXT (J)
+                       NEXT (JLAST) = J
+                       GOTO 220
+
+C                      -------------------------------------------------
+240                    CONTINUE
+C                      j cannot be absorbed into i
+C                      -------------------------------------------------
+
+                       JLAST = J
+                       J = NEXT (J)
+                       GOTO 220
+                       ENDIF
+
+C                   ----------------------------------------------------
+C                   no more variables can be absorbed into i
+C                   go to next i in bucket and clear flag array
+C                   ----------------------------------------------------
+
+                    WFLG = WFLG + 1
+                    I = NEXT (I)
+                    IF (I .NE. 0) GOTO 200
+                    ENDIF
+                 ENDIF
+250           CONTINUE
+
+C=======================================================================
+C  RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVAR. FROM ELEMENT
+C=======================================================================
+
+           P = PME1
+           NLEFT = N - NEL
+           DO 260 PME = PME1, PME2
+              I = IW (PME)
+              NVI = -NV (I)
+              IF (NVI .GT. 0) THEN
+C                i is a principal variable in Lme
+C                restore nv (i) to signify that i is principal
+                 NV (I) = NVI
+
+C                -------------------------------------------------------
+C                compute the external degree (add size of current elem)
+C                -------------------------------------------------------
+
+                 DEG = MAX (1, MIN (DEGREE (I) + DEGME-NVI, NLEFT-NVI))
+
+C                -------------------------------------------------------
+C                place the supervariable at the head of the degree list
+C                -------------------------------------------------------
+
+                 INEXT = HEAD (DEG)
+                 IF (INEXT .NE. 0) LAST (INEXT) = I
+                 NEXT (I) = INEXT
+                 LAST (I) = 0
+                 HEAD (DEG) = I
+
+C                -------------------------------------------------------
+C                save the new degree, and find the minimum degree
+C                -------------------------------------------------------
+
+                 MINDEG = MIN (MINDEG, DEG)
+                 DEGREE (I) = DEG
+
+C                -------------------------------------------------------
+C                place the supervariable in the element pattern
+C                -------------------------------------------------------
+
+                 IW (P) = I
+                 P = P + 1
+                 ENDIF
+260           CONTINUE
+
+C=======================================================================
+C  FINALIZE THE NEW ELEMENT
+C=======================================================================
+
+           NV (ME) = NVPIV + DEGME
+C          nv (me) is now the degree of pivot (including diagonal part)
+C          save the length of the list for the new element me
+           LEN (ME) = P - PME1
+           IF (LEN (ME) .EQ. 0) THEN
+C             there is nothing left of the current pivot element
+              PE (ME) = 0
+              W (ME) = 0
+              ENDIF
+           IF (NEWMEM .NE. 0) THEN
+C             element was not constructed in place: deallocate part
+C             of it (final size is less than or equal to newmem,
+C             since newly nonprincipal variables have been removed).
+              PFREE = P
+              MEM = MEM - NEWMEM + LEN (ME)
+              ENDIF
+
+C=======================================================================
+C          END WHILE (selecting pivots)
+           GOTO 30
+           ENDIF
+C=======================================================================
+
+C=======================================================================
+C  COMPUTE THE PERMUTATION VECTORS
+C=======================================================================
+
+C       ----------------------------------------------------------------
+C       The time taken by the following code is O(n).  At this
+C       point, elen (e) = -k has been done for all elements e,
+C       and elen (i) = 0 has been done for all nonprincipal
+C       variables i.  At this point, there are no principal
+C       supervariables left, and all elements are absorbed.
+C       ----------------------------------------------------------------
+
+C       ----------------------------------------------------------------
+C       compute the ordering of unordered nonprincipal variables
+C       ----------------------------------------------------------------
+
+        DO 290 I = 1, N
+           IF (ELEN (I) .EQ. 0) THEN
+
+C             ----------------------------------------------------------
+C             i is an un-ordered row.  Traverse the tree from i until
+C             reaching an element, e.  The element, e, was the
+C             principal supervariable of i and all nodes in the path
+C             from i to when e was selected as pivot.
+C             ----------------------------------------------------------
+
+              J = -PE (I)
+C             while (j is a variable) do:
+270           CONTINUE
+              IF (ELEN (J) .GE. 0) THEN
+                 J = -PE (J)
+                 GOTO 270
+                 ENDIF
+              E = J
+
+C             ----------------------------------------------------------
+C             get the current pivot ordering of e
+C             ----------------------------------------------------------
+
+              K = -ELEN (E)
+
+C             ----------------------------------------------------------
+C             traverse the path again from i to e, and compress the
+C             path (all nodes point to e).  Path compression allows
+C             this code to compute in O(n) time.  Order the unordered
+C             nodes in the path, and place the element e at the end.
+C             ----------------------------------------------------------
+
+              J = I
+C             while (j is a variable) do:
+280           CONTINUE
+              IF (ELEN (J) .GE. 0) THEN
+                 JNEXT = -PE (J)
+                 PE (J) = -E
+                 IF (ELEN (J) .EQ. 0) THEN
+C                   j is an unordered row
+                    ELEN (J) = K
+                    K = K + 1
+                    ENDIF
+                 J = JNEXT
+                 GOTO 280
+                 ENDIF
+C             leave elen (e) negative, so we know it is an element
+              ELEN (E) = -K
+              ENDIF
+290        CONTINUE
+
+C       ----------------------------------------------------------------
+C       reset the inverse permutation (elen (1..n)) to be positive,
+C       and compute the permutation (last (1..n)).
+C       ----------------------------------------------------------------
+
+        DO 300 I = 1, N
+           K = ABS (ELEN (I))
+           LAST (K) = I
+           ELEN (I) = K
+300        CONTINUE
+
+C=======================================================================
+C  RETURN THE MEMORY USAGE IN IW
+C=======================================================================
+
+C       If maxmem is less than or equal to iwlen, then no compressions
+C       occurred, and iw (maxmem+1 ... iwlen) was unused.  Otherwise
+C       compressions did occur, and iwlen would have had to have been
+C       greater than or equal to maxmem for no compressions to occur.
+C       Return the value of maxmem in the pfree argument.
+
+        PFREE = MAXMEM
+
+        RETURN
+        END
+
diff --git a/src/C/SuiteSparse/CHOLMOD/Check/License.txt b/src/C/SuiteSparse/CHOLMOD/Check/License.txt
new file mode 100644
index 0000000..8a20b17
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Check/License.txt
@@ -0,0 +1,24 @@
+CHOLMOD/Check Module.  Copyright (C) 2005-2006, Timothy A. Davis
+CHOLMOD is also available under other licenses; contact authors for details.
+http://www.cise.ufl.edu/research/sparse
+
+Note that this license is for the CHOLMOD/Check module only.
+All CHOLMOD modules are licensed separately.
+
+
+--------------------------------------------------------------------------------
+
+
+This Module is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This Module is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this Module; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
diff --git a/src/C/SuiteSparse/CHOLMOD/Check/cholmod_check.c b/src/C/SuiteSparse/CHOLMOD/Check/cholmod_check.c
new file mode 100644
index 0000000..49a638b
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Check/cholmod_check.c
@@ -0,0 +1,2618 @@
+/* ========================================================================== */
+/* === Check/cholmod_check ================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Check Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Check Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Routines to check and print the contents of the 5 CHOLMOD objects:
+ *
+ * No CHOLMOD routine calls the check or print routines.  If a user wants to
+ * check CHOLMOD's input parameters, a separate call to the appropriate check
+ * routine should be used before calling other CHOLMOD routines.
+ *
+ * cholmod_check_common		check statistics and workspace in Common
+ * cholmod_check_sparse		check sparse matrix in compressed column form
+ * cholmod_check_dense		check dense matrix
+ * cholmod_check_factor		check factorization
+ * cholmod_check_triplet	check sparse matrix in triplet form
+ *
+ * cholmod_print_common		print statistics in Common
+ * cholmod_print_sparse		print sparse matrix in compressed column form
+ * cholmod_print_dense		print dense matrix
+ * cholmod_print_factor		print factorization
+ * cholmod_print_triplet	print sparse matrix in triplet form
+ *
+ * In addition, this file contains routines to check and print three types of
+ * integer vectors:
+ * 
+ * cholmod_check_perm		check a permutation of 0:n-1 (no duplicates)
+ * cholmod_check_subset		check a subset of 0:n-1 (duplicates OK)
+ * cholmod_check_parent		check an elimination tree
+ *
+ * cholmod_print_perm		print a permutation
+ * cholmod_print_subset		print a subset
+ * cholmod_print_parent		print an elimination tree
+ *
+ * Each Common->print level prints the items at or below the given level:
+ *
+ *	0: print nothing; just check the data structures and return TRUE/FALSE
+ *	1: error messages
+ *	2: warning messages
+ *	3: one-line summary of each object printed
+ *	4: short summary of each object (first and last few entries)
+ *	5: entire contents of the object
+ *
+ * No CHOLMOD routine calls these routines, so no printing occurs unless
+ * the user specifically calls a cholmod_print_* routine.  Thus, the default
+ * print level is 3.
+ *
+ * Common->precise controls the # of digits printed for numerical entries
+ * (5 if FALSE, 15 if TRUE).
+ *
+ * If Common->print_function is NULL, then no printing occurs.  The
+ * cholmod_check_* and cholmod_print_* routines still check their inputs and
+ * return TRUE/FALSE if the object is valid or not.
+ *
+ * This file also includes debugging routines that are enabled only when
+ * NDEBUG is defined in cholmod_internal.h (cholmod_dump_*).
+ */
+
+#ifndef NCHECK
+
+#include "cholmod_internal.h"
+#include "cholmod_check.h"
+
+/* ========================================================================== */
+/* === printing definitions ================================================= */
+/* ========================================================================== */
+
+#ifdef LONG
+#define I8 "%8ld"
+#define I_8 "%-8ld"
+#else
+#define I8 "%8d"
+#define I_8 "%-8d"
+#endif
+
+#define PR(i,format,arg) \
+{ \
+    if (print >= i && Common->print_function != NULL) \
+    { \
+	(Common->print_function) (format, arg) ; \
+    } \
+}
+
+#define P1(format,arg) PR(1,format,arg)
+#define P2(format,arg) PR(2,format,arg)
+#define P3(format,arg) PR(3,format,arg)
+#define P4(format,arg) PR(4,format,arg)
+
+#define ERR(msg) \
+{ \
+    P1 ("\nCHOLMOD ERROR: %s: ", type) ; \
+    if (name != NULL) \
+    { \
+	P1 ("%s", name) ; \
+    } \
+    P1 (": %s\n", msg) ; \
+    ERROR (CHOLMOD_INVALID, "invalid") ; \
+    return (FALSE) ; \
+}
+
+/* print a numerical value */
+#define PRINTVALUE(value) \
+{ \
+    if (Common->precise) \
+    { \
+	P4 (" %23.15e", value) ; \
+    } \
+    else \
+    { \
+	P4 (" %.5g", value) ; \
+    } \
+}
+
+/* start printing */
+#define ETC_START(count,limit) \
+{ \
+    count = (init_print == 4) ? (limit) : (-1) ; \
+}
+
+/* re-enable printing if condition is met */
+#define ETC_ENABLE(condition,count,limit) \
+{ \
+    if ((condition) && init_print == 4) \
+    { \
+	count = limit ; \
+	print = 4 ; \
+    } \
+}
+
+/* turn off printing if limit is reached */
+#define ETC_DISABLE(count) \
+{ \
+    if ((count >= 0) && (count-- == 0) && print == 4) \
+    { \
+	P4 ("%s", "    ...\n")  ; \
+	print = 3 ; \
+    } \
+}
+
+/* re-enable printing, or turn if off after limit is reached */
+#define ETC(condition,count,limit) \
+{ \
+    ETC_ENABLE (condition, count, limit) ; \
+    ETC_DISABLE (count) ; \
+}
+
+#define BOOLSTR(x) ((x) ? "true " : "false")
+
+/* ========================================================================== */
+/* === print_value ========================================================== */
+/* ========================================================================== */
+
+static void print_value
+(
+    Int print,
+    Int xtype,
+    double *Xx,
+    double *Xz,
+    Int p,
+    cholmod_common *Common)
+{
+    if (xtype == CHOLMOD_REAL)
+    {
+	PRINTVALUE (Xx [p]) ;
+    }
+    else if (xtype == CHOLMOD_COMPLEX)
+    {
+	P4 ("%s", "(") ;
+	PRINTVALUE (Xx [2*p  ]) ;
+	P4 ("%s", " , ") ;
+	PRINTVALUE (Xx [2*p+1]) ;
+	P4 ("%s", ")") ;
+    }
+    else if (xtype == CHOLMOD_ZOMPLEX)
+    {
+	P4 ("%s", "(") ;
+	PRINTVALUE (Xx [p]) ;
+	P4 ("%s", " , ") ;
+	PRINTVALUE (Xz [p]) ;
+	P4 ("%s", ")") ;
+    }
+}
+
+/* ========================================================================== */
+/* === cholmod_check_common ================================================= */
+/* ========================================================================== */
+
+/* Print and verify the contents of Common */
+
+static int check_common
+(
+    Int print,
+    char *name,
+    cholmod_common *Common
+)
+{
+    double fl, lnz ;
+    double *Xwork ;
+    Int *Flag, *Head ;
+    UF_long mark ;
+    Int i, nrow, nmethods, ordering, xworksize, amd_printed, init_print ;
+    char *type = "common" ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print control parameters and statistics */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    init_print = print ;
+
+    P2 ("%s", "\n") ;
+
+    P1 ("CHOLMOD version %d", CHOLMOD_MAIN_VERSION) ;
+    P1 (".%d", CHOLMOD_SUB_VERSION) ;
+    P1 (".%d", CHOLMOD_SUBSUB_VERSION) ;
+    P1 (", %s: ", CHOLMOD_DATE) ;
+
+    if (name != NULL)
+    {
+	P1 ("%s: ", name) ;
+    }
+    switch (Common->status)
+    {
+
+	case CHOLMOD_OK:
+	    P1 ("%s", "status: OK\n") ;
+	    break ;
+
+	case CHOLMOD_OUT_OF_MEMORY:
+	    P1 ("%s", "status: ERROR, out of memory\n") ;
+	    break ;
+
+	case CHOLMOD_INVALID:
+	    P1 ("%s", "status: ERROR, invalid parameter\n") ;
+	    break ;
+
+	case CHOLMOD_TOO_LARGE:
+	    P1 ("%s", "status: ERROR, problem too large\n") ;
+	    break ;
+
+	case CHOLMOD_NOT_INSTALLED:
+	    P1 ("%s", "status: ERROR, method not installed\n") ;
+	    break ;
+
+	case CHOLMOD_NOT_POSDEF:
+	    P1 ("%s", "status: warning, matrix not positive definite\n") ;
+	    break ;
+
+	case CHOLMOD_DSMALL:
+	    P1 ("%s", "status: warning, diagonal entry has tiny abs. value\n") ;
+	    break ;
+
+	default:
+	    ERR ("unknown status") ;
+    }
+
+    P2 ("  Architecture: %s\n", CHOLMOD_ARCHITECTURE) ;
+    P3 ("    sizeof(int):      %d\n", (int) sizeof (int)) ;
+    P3 ("    sizeof(UF_long):  %d\n", (int) sizeof (UF_long)) ;
+    P3 ("    sizeof(void *):   %d\n", (int) sizeof (void *)) ;
+    P3 ("    sizeof(double):   %d\n", (int) sizeof (double)) ;
+    P3 ("    sizeof(Int):      %d (CHOLMOD's basic integer)\n", (int) sizeof (Int)) ;
+    P3 ("    sizeof(BLAS_INT): %d (integer used in the BLAS)\n",
+	    (int) sizeof (BLAS_INT)) ;
+
+    if (Common->fl != EMPTY)
+    {
+	P2 ("%s", "  Results from most recent analysis:\n") ;
+	P2 ("    Cholesky flop count: %.5g\n", Common->fl) ;
+	P2 ("    Nonzeros in L:       %.5g\n", Common->lnz) ;
+    }
+    if (Common->modfl != EMPTY)
+    {
+	P2 ("    Update/downdate flop count: %.5g\n", Common->modfl) ;
+    }
+
+    P2 ("  memory blocks in use:    %8.0f\n", (double) (Common->malloc_count)) ;
+    P2 ("  memory in use (MB):      %8.1f\n", 
+	(double) (Common->memory_inuse) / 1048576.) ;
+    P2 ("  peak memory usage (MB):  %8.1f\n", 
+	(double) (Common->memory_usage) / 1048576.) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* primary control parameters and related ordering statistics */
+    /* ---------------------------------------------------------------------- */
+
+    P3 ("  maxrank:    update/downdate rank:   "ID"\n",
+	    (Int) CHOLMOD(maxrank) (0, Common)) ;
+    P3 ("  supernodal control: %d", Common->supernodal) ;
+    P3 (" %g ", Common->supernodal_switch) ;
+    if (Common->supernodal <= CHOLMOD_SIMPLICIAL)
+    {
+	P3 ("%s", "(always do simplicial)\n") ;
+    }
+    else if (Common->supernodal == CHOLMOD_AUTO)
+    {
+	P3 ("(supernodal if flops/lnz >= %g)\n", Common->supernodal_switch) ;
+    }
+    else
+    {
+	P3 ("%s", "(always do supernodal)\n") ;
+    }
+
+    nmethods = MIN (Common->nmethods, CHOLMOD_MAXMETHODS) ;
+    nmethods = MAX (0, nmethods) ;
+
+    if (nmethods > 0)
+    {
+	P3 ("%s", "  nmethods:   number of ordering methods to try: ") ;
+	P3 (""ID"\n", nmethods) ;
+    }
+    else
+    {
+	P3 ("%s", "  nmethods=0: default strategy:  Try user permutation if "
+		"given.  Try AMD.\n") ;
+#ifndef NPARTITION
+	if (Common->default_nesdis)
+	{
+	    P3 ("%s", "    Try NESDIS if AMD reports flops/nnz(L) >= 500 and "
+		"nnz(L)/nnz(A) >= 5.\n") ;
+	}
+	else
+	{
+	    P3 ("%s", "    Try METIS if AMD reports flops/nnz(L) >= 500 and "
+		"nnz(L)/nnz(A) >= 5.\n") ;
+	}
+#endif
+	P3 ("%s", "    Select best ordering tried.\n") ;
+	Common->method [0].ordering = CHOLMOD_GIVEN ;
+	Common->method [1].ordering = CHOLMOD_AMD ;
+	Common->method [2].ordering = CHOLMOD_METIS ;
+#ifndef NPARTITION
+	nmethods = 3 ;
+#else
+	nmethods = 2 ;
+#endif
+    }
+
+    amd_printed = FALSE ;
+    for (i = 0 ; i < nmethods ; i++)
+    {
+	P3 ("    method "ID": ", i) ;
+	ordering = Common->method [i].ordering ;
+	fl = Common->method [i].fl ;
+	lnz = Common->method [i].lnz ;
+	switch (ordering)
+	{
+
+	    case CHOLMOD_NATURAL:
+		P3 ("%s", "natural\n") ;
+		break ;
+
+	    case CHOLMOD_GIVEN:
+		P3 ("%s", "user permutation (if given)\n") ;
+		break ;
+
+	    case CHOLMOD_AMD:
+		P3 ("%s", "AMD (or COLAMD if factorizing AA')\n") ;
+		amd_printed = TRUE ;
+		break ;
+
+	    case CHOLMOD_COLAMD:
+		P3 ("%s", "AMD if factorizing A, COLAMD if factorizing AA')\n");
+		amd_printed = TRUE ;
+		break ;
+
+	    case CHOLMOD_METIS:
+		P3 ("%s", "METIS_NodeND nested dissection\n") ;
+		break ;
+
+	    case CHOLMOD_NESDIS:
+		P3 ("%s", "CHOLMOD nested dissection\n") ;
+
+		P3 ("        nd_small: # nodes in uncut subgraph: "ID"\n",
+			(Int) (Common->method [i].nd_small)) ;
+		P3 ("        nd_compress: compress the graph:     %s\n",
+			BOOLSTR (Common->method [i].nd_compress)) ;
+		P3 ("        nd_camd: use constrained min degree: %s\n",
+			BOOLSTR (Common->method [i].nd_camd)) ;
+		break ;
+
+	    default:
+		P3 (ID, ordering) ;
+		ERR ("unknown ordering method") ;
+		break ;
+
+	}
+
+	if (!(ordering == CHOLMOD_NATURAL || ordering == CHOLMOD_GIVEN))
+	{
+	    if (Common->method [i].prune_dense < 0)
+	    {
+		P3 ("        prune_dense: for pruning dense nodes:   %s\n",
+			" none pruned") ;
+	    }
+	    else
+	    {
+		P3 ("        prune_dense: for pruning dense nodes:   "
+		    "%.5g\n",
+		    Common->method [i].prune_dense) ;
+		P3 ("        a dense node has degree "
+			">= max(16,(%.5g)*sqrt(n))\n",
+		    Common->method [i].prune_dense) ;
+	    }
+	}
+
+	if (ordering == CHOLMOD_COLAMD || ordering == CHOLMOD_NESDIS)
+	{
+	    if (Common->method [i].prune_dense2 < 0)
+	    {
+		P3 ("        prune_dense2: for pruning dense rows for AA':"
+			"  %s\n", " none pruned") ;
+	    }
+	    else
+	    {
+		P3 ("        prune_dense2: for pruning dense rows for AA':"
+		    " %.5g\n", Common->method [i].prune_dense2) ;
+		P3 ("        a dense row has degree "
+			">= max(16,(%.5g)*sqrt(ncol))\n",
+		    Common->method [i].prune_dense2) ;
+	    }
+	}
+
+	if (fl  != EMPTY) P3 ("        flop count: %.5g\n", fl) ;
+	if (lnz != EMPTY) P3 ("        nnz(L):     %.5g\n", lnz) ;
+    }
+
+    /* backup AMD results, if any */
+    if (!amd_printed)
+    {
+	P3 ("%s", "    backup method: ") ;
+	P3 ("%s", "AMD (or COLAMD if factorizing AA')\n") ;
+	fl = Common->method [nmethods].fl ;
+	lnz = Common->method [nmethods].lnz ;
+	if (fl  != EMPTY) P3 ("        AMD flop count: %.5g\n", fl) ;
+	if (lnz != EMPTY) P3 ("        AMD nnz(L):     %.5g\n", lnz) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* arcane control parameters */
+    /* ---------------------------------------------------------------------- */
+
+    if (Common->final_asis)
+    {
+	P4 ("%s", "  final_asis: TRUE, leave as is\n") ;
+    }
+    else
+    {
+	P4 ("%s", "  final_asis: FALSE, convert when done\n") ;
+	if (Common->final_super)
+	{
+	    P4 ("%s", "  final_super: TRUE, leave in supernodal form\n") ;
+	}
+	else
+	{
+	    P4 ("%s", "  final_super: FALSE, convert to simplicial form\n") ;
+	}
+	if (Common->final_ll)
+	{
+	    P4 ("%s", "  final_ll: TRUE, convert to LL' form\n") ;
+	}
+	else
+	{
+	    P4 ("%s", "  final_ll: FALSE, convert to LDL' form\n") ;
+	}
+	if (Common->final_pack)
+	{
+	    P4 ("%s", "  final_pack: TRUE, pack when done\n") ;
+	}
+	else
+	{
+	    P4 ("%s", "  final_pack: FALSE, do not pack when done\n") ;
+	}
+	if (Common->final_monotonic)
+	{
+	    P4 ("%s", "  final_monotonic: TRUE, ensure L is monotonic\n") ;
+	}
+	else
+	{
+	    P4 ("%s",
+		"  final_monotonic: FALSE, do not ensure L is monotonic\n") ;
+	}
+	P4 ("  final_resymbol: remove zeros from amalgamation: %s\n",
+		BOOLSTR (Common->final_resymbol)) ;
+    }
+
+    P4 ("  dbound:  LDL' diagonal threshold: % .5g\n    Entries with abs. value"
+	    " less than dbound are replaced with +/- dbound.\n",
+	    Common->dbound) ;
+
+    P4 ("  grow0: memory reallocation: % .5g\n", Common->grow0) ;
+    P4 ("  grow1: memory reallocation: % .5g\n", Common->grow1) ;
+    P4 ("  grow2: memory reallocation: %g\n", (double) (Common->grow2)) ;
+
+    P4 ("%s", "  nrelax, zrelax:  supernodal amalgamation rule:\n") ;
+    P4 ("%s", "    s = # columns in two adjacent supernodes\n") ;
+    P4 ("%s", "    z = % of zeros in new supernode if they are merged.\n") ;
+    P4 ("%s", "    Two supernodes are merged if") ;
+    P4 (" (s <= %g) or (no new zero entries) or\n",
+	    (double) (Common->nrelax [0])) ;
+    P4 ("    (s <= %g and ",  (double) (Common->nrelax [1])) ;
+    P4 ("z < %.5g%%) or",      Common->zrelax [0] * 100) ;
+    P4 (" (s <= %g and ",     (double) (Common->nrelax [2])) ;
+    P4 ("z < %.5g%%) or",      Common->zrelax [1] * 100) ;
+    P4 (" (z < %.5g%%)\n",     Common->zrelax [2] * 100) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check workspace */
+    /* ---------------------------------------------------------------------- */
+
+    mark = Common->mark ;
+    nrow = Common->nrow ;
+    Flag = Common->Flag ;
+    Head = Common->Head ;
+    if (nrow > 0)
+    {
+	if (mark < 0 || Flag == NULL || Head == NULL)
+	{
+	    ERR ("workspace corrupted (Flag and/or Head missing)") ;
+	}
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    if (Flag [i] >= mark)
+	    {
+		PRINT0 (("Flag ["ID"]="ID", mark = %ld\n", i, Flag [i], mark)) ;
+		ERR ("workspace corrupted (Flag)") ;
+	    }
+	}
+	for (i = 0 ; i <= nrow ; i++)
+	{
+	    if (Head [i] != EMPTY)
+	    {
+		PRINT0 (("Head ["ID"] = "ID",\n", i, Head [i])) ;
+		ERR ("workspace corrupted (Head)") ;
+	    }
+	}
+    }
+    xworksize = Common->xworksize ;
+    Xwork = Common->Xwork ;
+    if (xworksize > 0)
+    {
+	if (Xwork == NULL)
+	{
+	    ERR ("workspace corrupted (Xwork missing)") ;
+	}
+	for (i = 0 ; i < xworksize ; i++)
+	{
+	    if (Xwork [i] != 0.)
+	    {
+		PRINT0 (("Xwork ["ID"] = %g\n", i, Xwork [i])) ;
+		ERR ("workspace corrupted (Xwork)") ;
+	    }
+	}
+    }
+
+    /* workspace and parameters are valid */
+    P3 ("%s", "  OK\n") ;
+    return (TRUE) ;
+}
+
+
+int CHOLMOD(check_common)
+(
+    cholmod_common *Common
+)
+{
+    return (check_common (0, NULL, Common)) ;
+}
+
+
+int CHOLMOD(print_common)
+(
+    /* ---- input ---- */
+    char *name,		/* printed name of Common object */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int print = (Common == NULL) ? 3 : (Common->print) ;
+    return (check_common (print, name, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_check_sparse ================================================= */
+/* ========================================================================== */
+
+/* Ensure that a sparse matrix in column-oriented form is valid, and optionally
+ * print it.  Returns the number of entries on the diagonal or -1 if error.
+ *
+ * workspace: Iwork (nrow)
+ */
+
+static UF_long check_sparse
+(
+    Int *Wi,
+    Int print,
+    char *name,
+    cholmod_sparse *A,
+    UF_long *nnzdiag,
+    cholmod_common *Common
+)
+{
+    double *Ax, *Az ;
+    Int *Ap, *Ai, *Anz ;
+    Int nrow, ncol, nzmax, sorted, packed, j, p, pend, i, nz, ilast,
+	space, init_print, dnz, count, xtype ;
+    char *type = "sparse" ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print header information */
+    /* ---------------------------------------------------------------------- */
+
+    P4 ("%s", "\n") ;
+    P3 ("%s", "CHOLMOD sparse:  ") ;
+    if (name != NULL)
+    {
+	P3 ("%s: ", name) ;
+    }
+
+    if (A == NULL)
+    {
+	ERR ("null") ;
+    }
+
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+    nzmax = A->nzmax ;
+    sorted = A->sorted ;
+    packed = A->packed ;
+    xtype = A->xtype ;
+    Ap = A->p ;
+    Ai = A->i ;
+    Ax = A->x ;
+    Az = A->z ;
+    Anz = A->nz ;
+    nz = CHOLMOD(nnz) (A, Common) ;
+
+    P3 (" "ID"", nrow) ;
+    P3 ("-by-"ID", ", ncol) ;
+    P3 ("nz "ID",", nz) ;
+    if (A->stype > 0)
+    {
+	P3 ("%s", " upper.") ;
+    }
+    else if (A->stype < 0)
+    {
+	P3 ("%s", " lower.") ;
+    }
+    else
+    {
+	P3 ("%s", " up/lo.") ;
+    }
+
+    P4 ("\n  nzmax "ID", ", nzmax) ;
+    if (nz > nzmax)
+    {
+	ERR ("nzmax too small") ;
+    }
+    if (!sorted)
+    {
+	P4 ("%s", "un") ;
+    }
+    P4 ("%s", "sorted, ") ;
+    if (!packed)
+    {
+	P4 ("%s", "un") ;
+    }
+    P4 ("%s", "packed, ") ;
+
+    switch (A->itype)
+    {
+	case CHOLMOD_INT:     P4 ("%s", "\n  scalar types: int, ") ; break ;
+	case CHOLMOD_INTLONG: ERR ("mixed int/UF_long type unsupported") ;
+	case CHOLMOD_LONG:    P4 ("%s", "\n  scalar types: UF_long, ") ; break ;
+	default:	      ERR ("unknown itype") ;
+    }
+
+    switch (A->xtype)
+    {
+	case CHOLMOD_PATTERN: P4 ("%s", "pattern") ;	break ;
+	case CHOLMOD_REAL:    P4 ("%s", "real") ;	break ;
+	case CHOLMOD_COMPLEX: P4 ("%s", "complex") ;	break ;
+	case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ;	break ;
+	default:	      ERR ("unknown xtype") ;
+    }
+
+    switch (A->dtype)
+    {
+	case CHOLMOD_DOUBLE:  P4 ("%s", ", double\n") ;	       break ;
+	case CHOLMOD_SINGLE:  ERR ("float unsupported") ;
+	default:	      ERR ("unknown dtype") ;
+    }
+
+    if (A->itype != ITYPE || A->dtype != DTYPE)
+    {
+	ERR ("integer and real type must match routine") ;
+    }
+
+    if (A->stype && nrow != ncol)
+    {
+	ERR ("symmetric but not square") ;
+    }
+
+    /* check for existence of Ap, Ai, Anz, Ax, and Az arrays */
+    if (Ap == NULL)
+    {
+	ERR ("p array not present") ;
+    }
+    if (Ai == NULL)
+    {
+	ERR ("i array not present") ;
+    }
+    if (!packed && Anz == NULL)
+    {
+	ERR ("nz array not present") ;
+    }
+    if (xtype != CHOLMOD_PATTERN && Ax == NULL)
+    {
+	ERR ("x array not present") ;
+    }
+    if (xtype == CHOLMOD_ZOMPLEX && Az == NULL)
+    {
+	ERR ("z array not present") ;
+    }
+
+    /* packed matrices must start at Ap [0] = 0 */
+    if (packed && Ap [0] != 0)
+    {
+	ERR ("p [0] must be zero") ;
+    }
+    if (packed && (Ap [ncol] < Ap [0] || Ap [ncol] > nzmax))
+    {
+	ERR ("p [ncol] invalid") ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace if needed */
+    /* ---------------------------------------------------------------------- */
+
+    if (!sorted)
+    {
+	if (Wi == NULL)
+	{
+	    CHOLMOD(allocate_work) (0, nrow, 0, Common) ;
+	    Wi = Common->Iwork ;	/* size nrow, (i/i/l) */
+	}
+	if (Common->status < CHOLMOD_OK)
+	{
+	    return (FALSE) ;	    /* out of memory */
+	}
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    Wi [i] = EMPTY ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* check and print each column */
+    /* ---------------------------------------------------------------------- */
+
+    init_print = print ;
+    dnz = 0 ;
+    ETC_START (count, 8) ;
+
+    for (j = 0 ; j < ncol ; j++)
+    {
+	ETC (j == ncol-1, count, 4) ;
+	p = Ap [j] ;
+	if (packed)
+	{
+	    pend = Ap [j+1] ;
+	    nz = pend - p ;
+	}
+	else
+	{
+	    /* Note that Anz [j] < 0 is treated as zero */
+	    nz = MAX (0, Anz [j]) ;
+	    pend = p + nz ;
+	}
+	/* Note that space can be negative if the matrix is non-monotonic */
+	space = Ap [j+1] - p ;
+	P4 ("  col "ID":", j) ;
+	P4 (" nz "ID"", nz) ;
+	P4 (" start "ID"", p) ;
+	P4 (" end "ID"", pend) ;
+	if (!packed)
+	{
+	    P4 (" space "ID"", space) ;
+	}
+	P4 ("%s", ":\n") ;
+	if (p < 0 || pend > nzmax)
+	{
+	    ERR ("pointer invalid") ;
+	}
+	if (nz < 0 || nz > nrow)
+	{
+	    ERR ("nz invalid") ;
+	}
+	ilast = EMPTY ;
+
+	for ( ; p < pend ; p++)
+	{
+	    ETC (j == ncol-1 && p >= pend-4, count, -1) ;
+	    i = Ai [p] ;
+	    P4 ("  "I8":", i) ;
+
+	    print_value (print, xtype, Ax, Az, p, Common) ;
+
+	    if (i == j)
+	    {
+		dnz++ ;
+	    }
+	    if (i < 0 || i >= nrow)
+	    {
+		ERR ("row index out of range") ;
+	    }
+	    if (sorted && i <= ilast)
+	    {
+		ERR ("row indices out of order") ;
+	    }
+	    if (!sorted && Wi [i] == j)
+	    {
+		ERR ("duplicate row index") ;
+	    }
+	    P4 ("%s", "\n") ;
+	    ilast = i ;
+	    if (!sorted)
+	    {
+		Wi [i] = j ;
+	    }
+	}
+    }
+
+    /* matrix is valid */
+    P4 ("  nnz on diagonal: "ID"\n", dnz) ;
+    P3 ("%s", "  OK\n") ;
+    *nnzdiag = dnz ;
+    return (TRUE) ;
+}
+
+
+int CHOLMOD(check_sparse)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* sparse matrix to check */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    UF_long nnzdiag ;
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_sparse (NULL, 0, NULL, A, &nnzdiag, Common)) ;
+}
+
+
+int CHOLMOD(print_sparse)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* sparse matrix to print */
+    char *name,		/* printed name of sparse matrix */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    UF_long nnzdiag ;
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_sparse (NULL, Common->print, name, A, &nnzdiag, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_check_dense ================================================== */
+/* ========================================================================== */
+
+/* Ensure a dense matrix is valid, and optionally print it. */
+
+static int check_dense
+(
+    Int print,
+    char *name,
+    cholmod_dense *X,
+    cholmod_common *Common
+)
+{
+    double *Xx, *Xz ;
+    Int i, j, d, nrow, ncol, nzmax, nz, init_print, count, xtype ;
+    char *type = "dense" ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print header information */
+    /* ---------------------------------------------------------------------- */
+
+    P4 ("%s", "\n") ;
+    P3 ("%s", "CHOLMOD dense:   ") ;
+    if (name != NULL)
+    {
+	P3 ("%s: ", name) ;
+    }
+
+    if (X == NULL)
+    {
+	ERR ("null") ;
+    }
+
+    nrow = X->nrow ;
+    ncol = X->ncol ;
+    nzmax = X->nzmax ;
+    d = X->d ;
+    Xx = X->x ;
+    Xz = X->z ;
+    xtype = X->xtype ;
+
+    P3 (" "ID"", nrow) ;
+    P3 ("-by-"ID", ", ncol) ;
+    P4 ("\n  leading dimension "ID", ", d) ;
+    P4 ("nzmax "ID", ", nzmax) ;
+    if (d * ncol > nzmax)
+    {
+	ERR ("nzmax too small") ;
+    }
+    if (d < nrow)
+    {
+	ERR ("leading dimension must be >= # of rows") ;
+    }
+    if (Xx == NULL)
+    {
+	ERR ("null") ;
+    }
+
+    switch (X->xtype)
+    {
+	case CHOLMOD_PATTERN: ERR ("pattern unsupported") ;  break ;
+	case CHOLMOD_REAL:    P4 ("%s", "real") ;	break ;
+	case CHOLMOD_COMPLEX: P4 ("%s", "complex") ;	break ;
+	case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ;	break ;
+	default:	      ERR ("unknown xtype") ;
+    }
+
+    switch (X->dtype)
+    {
+	case CHOLMOD_DOUBLE:  P4 ("%s", ", double\n") ;	       break ;
+	case CHOLMOD_SINGLE:  ERR ("single unsupported") ;
+	default:	      ERR ("unknown dtype") ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* check and print each entry */
+    /* ---------------------------------------------------------------------- */
+
+    if (print >= 4)
+    {
+	init_print = print ;
+	ETC_START (count, 9) ;
+	nz = nrow * ncol ;
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    ETC (j == ncol-1, count, 5) ;
+	    P4 ("  col "ID":\n", j) ;
+	    for (i = 0 ; i < nrow ; i++)
+	    {
+		ETC (j == ncol-1 && i >= nrow-4, count, -1) ;
+		P4 ("  "I8":", i) ;
+
+		print_value (print, xtype, Xx, Xz, i+j*d, Common) ;
+
+		P4 ("%s", "\n") ;
+	    }
+	}
+    }
+
+    /* dense  is valid */
+    P3 ("%s", "  OK\n") ;
+    return (TRUE) ;
+}
+
+
+int CHOLMOD(check_dense)
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* dense matrix to check */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_dense (0, NULL, X, Common)) ;
+}
+
+
+int CHOLMOD(print_dense)
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* dense matrix to print */
+    char *name,		/* printed name of dense matrix */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_dense (Common->print, name, X, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_check_subset ================================================= */
+/* ========================================================================== */
+
+/* Ensure S (0:len-1) is a subset of 0:n-1.  Duplicates are allowed.  S may be
+ * NULL.  A negative len denotes the set 0:n-1.
+ *
+ * To check the rset and cset for A(rset,cset), where nc and nr are the length
+ * of cset and rset respectively:
+ *
+ *	cholmod_check_subset (cset, nc, A->ncol, Common) ;
+ *	cholmod_check_subset (rset, nr, A->nrow, Common) ;
+ *
+ * workspace: none
+ */
+
+static int check_subset
+(
+    Int *S,
+    UF_long len,
+    size_t n,
+    Int print,
+    char *name,
+    cholmod_common *Common
+)
+{
+    Int i, k, init_print, count ;
+    char *type = "subset" ;
+
+    init_print = print ;
+
+    if (S == NULL)
+    {
+	/* zero len denotes S = [ ], negative len denotes S = 0:n-1 */
+	len = (len < 0) ? (-1) : 0 ;
+    }
+
+    P4 ("%s", "\n") ;
+    P3 ("%s", "CHOLMOD subset:  ") ;
+    if (name != NULL)
+    {
+	P3 ("%s: ", name) ;
+    }
+
+    P3 (" len: %ld ", len) ;
+    if (len < 0)
+    {
+	P3 ("%s", "(denotes 0:n-1) ") ;
+    }
+    P3 ("n: "ID"", (Int) n) ;
+    P4 ("%s", "\n") ;
+
+    if (len <= 0 || S == NULL)
+    {
+	P3 ("%s", "  OK\n") ;
+	return (TRUE) ;
+    }
+
+    if (print >= 4)
+    {
+	ETC_START (count, 8) ;
+	for (k = 0 ; k < ((Int) len) ; k++)
+	{
+	    ETC (k == ((Int) len) - 4, count, -1) ;
+	    i = S [k] ;
+	    P4 ("  "I8":", k) ;
+	    P4 (" "ID"\n", i) ;
+	    if (i < 0 || i >= ((Int) n))
+	    {
+		ERR ("entry out range") ;
+	    }
+	}
+    }
+    else
+    {
+	for (k = 0 ; k < ((Int) len) ; k++)
+	{
+	    i = S [k] ;
+	    if (i < 0 || i >= ((Int) n))
+	    {
+		ERR ("entry out range") ;
+	    }
+	}
+    }
+    P3 ("%s", "  OK\n") ;
+    return (TRUE) ;
+}
+
+
+int CHOLMOD(check_subset)
+(
+    /* ---- input ---- */
+    Int *Set,		/* Set [0:len-1] is a subset of 0:n-1.  Duplicates OK */
+    UF_long len,	/* size of Set (an integer array), or < 0 if 0:n-1 */
+    size_t n,		/* 0:n-1 is valid range */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_subset (Set, len, n, 0, NULL, Common)) ;
+}
+
+
+int CHOLMOD(print_subset)
+(
+    /* ---- input ---- */
+    Int *Set,		/* Set [0:len-1] is a subset of 0:n-1.  Duplicates OK */
+    UF_long len,	/* size of Set (an integer array), or < 0 if 0:n-1 */
+    size_t n,		/* 0:n-1 is valid range */
+    char *name,		/* printed name of Set */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_subset (Set, len, n, Common->print, name, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_check_perm =================================================== */
+/* ========================================================================== */
+
+/* Ensure that Perm [0..len-1] is a permutation of a subset of 0:n-1.  Perm
+ * may be NULL, which is interpreted as the identity permutation.  There can
+ * be no duplicate entries (len must be <= n).
+ *
+ * If n <= Common->nrow, then this routine takes O(len) time and does not
+ * allocate any memory, by using Common->Flag.  Otherwise, it takes O(n) time
+ * and ensures that Common->Iwork is at least n*sizeof(Int) in size.
+ *
+ * To check the fset:	    cholmod_check_perm (fset, fsize, ncol, Common) ;
+ * To check a permutation:  cholmod_check_perm (Perm, n, n, Common) ;
+ *
+ * workspace:  Flag (n) if n <= Common->nrow, Iwork (n) otherwise.
+ */
+
+static int check_perm
+(
+    Int *Wi,
+    Int print,
+    char *name,
+    Int *Perm,
+    size_t len,
+    size_t n,
+    cholmod_common *Common
+)
+{
+    Int *Flag ;
+    Int i, k, mark, init_print, count ;
+    char *type = "perm" ;
+
+    /* ---------------------------------------------------------------------- */
+    /* checks that take O(1) time */
+    /* ---------------------------------------------------------------------- */
+
+    if (Perm == NULL || n == 0)
+    {
+	/* Perm is valid implicit identity, or empty */
+	return (TRUE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* checks that take O(n) time or require memory allocation */
+    /* ---------------------------------------------------------------------- */
+
+    init_print = print ;
+    ETC_START (count, 8) ;
+
+    if (Wi == NULL && n <= Common->nrow)
+    {
+	/* use the Common->Flag array if it's big enough */
+	mark = CHOLMOD(clear_flag) (Common) ;
+	Flag = Common->Flag ;
+	ASSERT (CHOLMOD(dump_work) (TRUE, FALSE, 0, Common)) ;
+	if (print >= 4)
+	{
+	    for (k = 0 ; k < ((Int) len) ; k++)
+	    {
+		ETC (k >= ((Int) len) - 4, count, -1) ;
+		i = Perm [k] ;
+		P4 ("  "I8":", k) ;
+		P4 (""ID"\n", i) ;
+		if (i < 0 || i >= ((Int) n) || Flag [i] == mark)
+		{
+		    CHOLMOD(clear_flag) (Common) ;
+		    ERR ("invalid permutation") ;
+		}
+		Flag [i] = mark ;
+	    }
+	}
+	else
+	{
+	    for (k = 0 ; k < ((Int) len) ; k++)
+	    {
+		i = Perm [k] ;
+		if (i < 0 || i >= ((Int) n) || Flag [i] == mark)
+		{
+		    CHOLMOD(clear_flag) (Common) ;
+		    ERR ("invalid permutation") ;
+		}
+		Flag [i] = mark ;
+	    }
+	}
+	CHOLMOD(clear_flag) (Common) ;
+	ASSERT (CHOLMOD(dump_work) (TRUE, FALSE, 0, Common)) ;
+    }
+    else
+    {
+	if (Wi == NULL)
+	{
+	    /* use Common->Iwork instead, but initialize it first */
+	    CHOLMOD(allocate_work) (0, n, 0, Common) ;
+	    Wi = Common->Iwork ;		    /* size n, (i/i/i) is OK */
+	}
+	if (Common->status < CHOLMOD_OK)
+	{
+	    return (FALSE) ;	    /* out of memory */
+	}
+	for (i = 0 ; i < ((Int) n) ; i++)
+	{
+	    Wi [i] = FALSE ;
+	}
+	if (print >= 4)
+	{
+	    for (k = 0 ; k < ((Int) len) ; k++)
+	    {
+		ETC (k >= ((Int) len) - 4, count, -1) ;
+		i = Perm [k] ;
+		P4 ("  "I8":", k) ;
+		P4 (""ID"\n", i) ;
+		if (i < 0 || i >= ((Int) n) || Wi [i])
+		{
+		    ERR ("invalid permutation") ;
+		}
+		Wi [i] = TRUE ;
+	    }
+	}
+	else
+	{
+	    for (k = 0 ; k < ((Int) len) ; k++)
+	    {
+		i = Perm [k] ;
+		if (i < 0 || i >= ((Int) n) || Wi [i])
+		{
+		    ERR ("invalid permutation") ;
+		}
+		Wi [i] = TRUE ;
+	    }
+	}
+    }
+
+    /* perm is valid */
+    return (TRUE) ;
+}
+
+
+int CHOLMOD(check_perm)
+(
+    /* ---- input ---- */
+    Int *Perm,		/* Perm [0:len-1] is a permutation of subset of 0:n-1 */
+    size_t len,		/* size of Perm (an integer array) */
+    size_t n,		/* 0:n-1 is valid range */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_perm (NULL, 0, NULL, Perm, len, n, Common)) ;
+}
+
+
+int CHOLMOD(print_perm)
+(
+    /* ---- input ---- */
+    Int *Perm,		/* Perm [0:len-1] is a permutation of subset of 0:n-1 */
+    size_t len,		/* size of Perm (an integer array) */
+    size_t n,		/* 0:n-1 is valid range */
+    char *name,		/* printed name of Perm */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int ok, print ;
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    print = Common->print ;
+    P4 ("%s", "\n") ;
+    P3 ("%s", "CHOLMOD perm:    ") ;
+    if (name != NULL)
+    {
+	P3 ("%s: ", name) ;
+    }
+    P3 (" len: "ID"", (Int) len) ;
+    P3 (" n: "ID"", (Int) n) ;
+    P4 ("%s", "\n") ;
+    ok = check_perm (NULL, print, name, Perm, len, n, Common) ;
+    if (ok)
+    {
+	P3 ("%s", "  OK\n") ;
+    }
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_check_parent ================================================= */
+/* ========================================================================== */
+
+/* Ensure that Parent is a valid elimination tree of nodes 0 to n-1.
+ * If j is a root of the tree then Parent [j] is EMPTY (-1).
+ *
+ * NOTE: this check will fail if applied to the component tree (CParent) in
+ * cholmod_nested_dissection, unless it has been postordered and renumbered.
+ *
+ * workspace: none
+ */
+
+static int check_parent
+(
+    Int *Parent,
+    size_t n,
+    Int print,
+    char *name,
+    cholmod_common *Common
+)
+{
+    Int j, p, init_print, count ;
+    char *type = "parent" ;
+
+    init_print = print ;
+
+    P4 ("%s", "\n") ;
+    P3 ("%s", "CHOLMOD parent:  ") ;
+    if (name != NULL)
+    {
+	P3 ("%s: ", name) ;
+    }
+
+    P3 (" n: "ID"", (Int) n) ;
+    P4 ("%s", "\n") ;
+
+    if (Parent == NULL)
+    {
+	ERR ("null") ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* checks that take O(n) time */
+    /* ---------------------------------------------------------------------- */
+
+    ETC_START (count, 8) ;
+    for (j = 0 ; j < ((Int) n) ; j++)
+    {
+	ETC (j == ((Int) n) - 4, count, -1) ;
+	p = Parent [j] ;
+	P4 ("  "I8":", j) ;
+	P4 (" "ID"\n", p) ;
+	if (!(p == EMPTY || p > j))
+	{
+	    ERR ("invalid") ;
+	}
+    }
+    P3 ("%s", "  OK\n") ;
+    return (TRUE) ;
+}
+
+
+int CHOLMOD(check_parent)
+(
+    /* ---- input ---- */
+    Int *Parent,	/* Parent [0:n-1] is an elimination tree */
+    size_t n,		/* size of Parent */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_parent (Parent, n, 0, NULL, Common)) ;
+}
+
+
+int CHOLMOD(print_parent)
+(
+    /* ---- input ---- */
+    Int *Parent,	/* Parent [0:n-1] is an elimination tree */
+    size_t n,		/* size of Parent */
+    char *name,		/* printed name of Parent */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_parent (Parent, n, Common->print, name, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_check_factor ================================================= */
+/* ========================================================================== */
+
+static int check_factor
+(
+    Int *Wi,
+    Int print,
+    char *name,
+    cholmod_factor *L,
+    cholmod_common *Common
+)
+{
+    double *Lx, *Lz ;
+    Int *Lp, *Li, *Lnz, *Lnext, *Lprev, *Perm, *ColCount, *Lpi, *Lpx, *Super,
+	*Ls ;
+    Int n, nzmax, j, p, pend, i, nz, ordering, space, is_monotonic, minor,
+	count, precise, init_print, ilast, lnz, head, tail, jprev, plast,
+	jnext, examine_super, nsuper, s, k1, k2, psi, psend, psx, nsrow, nscol,
+	ps2, psxend, ssize, xsize, maxcsize, maxesize, nsrow2, jj, ii, xtype ;
+    char *type = "factor" ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print header information */
+    /* ---------------------------------------------------------------------- */
+
+    P4 ("%s", "\n") ;
+    P3 ("%s", "CHOLMOD factor:  ") ;
+    if (name != NULL)
+    {
+	P3 ("%s: ", name) ;
+    }
+
+    if (L == NULL)
+    {
+	ERR ("null") ;
+    }
+
+    n = L->n ;
+    minor = L->minor ;
+    ordering = L->ordering ;
+    xtype = L->xtype ;
+
+    Perm = L->Perm ;
+    ColCount = L->ColCount ;
+    lnz = 0 ;
+
+    precise = Common->precise ;
+
+    P3 (" "ID"", n) ;
+    P3 ("-by-"ID"", n) ;
+
+    if (minor < n)
+    {
+	P3 (" not positive definite (column "ID")", minor) ;
+    }
+
+    switch (L->itype)
+    {
+	case CHOLMOD_INT:     P4 ("%s", "\n  scalar types: int, ") ; break ;
+	case CHOLMOD_INTLONG: ERR ("mixed int/UF_long type unsupported") ;
+	case CHOLMOD_LONG:    P4 ("%s", "\n  scalar types: UF_long, ") ; break ;
+	default:	      ERR ("unknown itype") ;
+    }
+
+    switch (L->xtype)
+    {
+	case CHOLMOD_PATTERN: P4 ("%s", "pattern") ;	break ;
+	case CHOLMOD_REAL:    P4 ("%s", "real") ;	break ;
+	case CHOLMOD_COMPLEX: P4 ("%s", "complex") ;	break ;
+	case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ;	break ;
+	default:	      ERR ("unknown xtype") ;
+    }
+
+    switch (L->dtype)
+    {
+	case CHOLMOD_DOUBLE:  P4 ("%s", ", double\n") ;	       break ;
+	case CHOLMOD_SINGLE:  ERR ("single unsupported") ;
+	default:	      ERR ("unknown dtype") ;
+    }
+
+    if (L->itype != ITYPE || L->dtype != DTYPE)
+    {
+	ERR ("integer and real type must match routine") ;
+    }
+
+    if (L->is_super)
+    {
+	P3 ("%s", "  supernodal") ;
+    }
+    else
+    {
+	P3 ("%s", "  simplicial") ;
+    }
+
+    if (L->is_ll)
+    {
+	P3 ("%s", ", LL'.") ;
+    }
+    else
+    {
+	P3 ("%s", ", LDL'.") ;
+    }
+
+    P4 ("%s", "\n  ordering method used: ") ;
+    switch (L->ordering)
+    {
+	case CHOLMOD_POSTORDERED:P4 ("%s", "natural (postordered)") ;	 break ;
+	case CHOLMOD_NATURAL:	P4 ("%s", "natural") ;			 break ;
+	case CHOLMOD_GIVEN:	P4 ("%s", "user-provided") ;		 break ;
+	case CHOLMOD_AMD:	P4 ("%s", "AMD") ;			 break ;
+	case CHOLMOD_COLAMD:	P4 ("%s", "AMD for A, COLAMD for A*A'") ;break ;
+#ifndef NPARTITION
+	case CHOLMOD_METIS:	P4 ("%s", "METIS NodeND") ;		 break ;
+	case CHOLMOD_NESDIS:	P4 ("%s", "CHOLMOD nested dissection") ; break ;
+#endif
+	default:		ERR ("unknown ordering") ;
+    }
+
+    P4 ("%s", "\n") ;
+
+    init_print = print ;
+
+    if (L->is_super && L->xtype == CHOLMOD_ZOMPLEX)
+    {
+	ERR ("Supernodal zomplex L not supported") ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* check L->Perm */
+    /* ---------------------------------------------------------------------- */
+
+    if (!check_perm (Wi, print, name, Perm, n, n, Common))
+    {
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* check L->ColCount */
+    /* ---------------------------------------------------------------------- */
+
+    if (ColCount == NULL)
+    {
+	ERR ("ColCount vector invalid") ;
+    }
+
+    ETC_START (count, 8) ;
+    for (j = 0 ; j < n ; j++)
+    {
+	ETC (j >= n-4, count, -1) ;
+	P4 ("  col: "ID" ", j) ;
+	nz = ColCount [j] ;
+	P4 ("colcount: "ID"\n", nz) ;
+	if (nz < 0 || nz > n-j)
+	{
+	    ERR ("ColCount out of range") ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* check factor */
+    /* ---------------------------------------------------------------------- */
+
+    if (L->xtype == CHOLMOD_PATTERN && !(L->is_super))
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* check simplicial symbolic factor */
+	/* ------------------------------------------------------------------ */
+
+	/* nothing else to do */ ;
+
+    }
+    else if (L->xtype != CHOLMOD_PATTERN && !(L->is_super))
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* check simplicial numerical factor */
+	/* ------------------------------------------------------------------ */
+
+	P4 ("monotonic: %d\n", L->is_monotonic) ;
+	nzmax = L->nzmax ;
+	P3 (" nzmax "ID".", nzmax) ;
+	P4 ("%s", "\n") ;
+	Lp = L->p ;
+	Li = L->i ;
+	Lx = L->x ;
+	Lz = L->z ;
+	Lnz = L->nz ;
+	Lnext = L->next ;
+	Lprev = L->prev ;
+
+	/* check for existence of Lp, Li, Lnz, Lnext, Lprev, and Lx arrays */
+	if (Lp == NULL)
+	{
+	    ERR ("p array not present") ;
+	}
+	if (Li == NULL)
+	{
+	    ERR ("i array not present") ;
+	}
+	if (Lnz == NULL)
+	{
+	    ERR ("nz array not present") ;
+	}
+	if (Lx == NULL)
+	{
+	    ERR ("x array not present") ;
+	}
+	if (xtype == CHOLMOD_ZOMPLEX && Lz == NULL)
+	{
+	    ERR ("z array not present") ;
+	}
+	if (Lnext == NULL)
+	{
+	    ERR ("next array not present") ;
+	}
+	if (Lprev == NULL)
+	{
+	    ERR ("prev array not present") ;
+	}
+
+	ETC_START (count, 8) ;
+
+	/* check each column of L */
+	plast = 0 ;
+	is_monotonic = TRUE ;
+	for (j = 0 ; j < n ; j++)
+	{
+	    ETC (j >= n-3, count, -1) ;
+	    p = Lp [j] ;
+	    nz = Lnz [j] ;
+	    pend = p + nz ;
+	    lnz += nz ;
+
+	    P4 ("  col "ID":", j) ;
+	    P4 (" nz "ID"", nz) ;
+	    P4 (" start "ID"", p) ;
+	    P4 (" end "ID"", pend) ;
+
+	    if (Lnext [j] < 0 || Lnext [j] > n)
+	    {
+		ERR ("invalid link list")  ;
+	    }
+	    space = Lp [Lnext [j]] - p ;
+
+	    P4 (" space "ID"", space) ;
+	    P4 (" free "ID":\n", space - nz) ;
+
+	    if (p < 0 || pend > nzmax || space < 1)
+	    {
+		ERR ("pointer invalid") ;
+	    }
+	    if (nz < 1 || nz > (n-j) || nz > space)
+	    {
+		ERR ("nz invalid") ;
+	    }
+	    ilast = j-1 ;
+
+	    if (p < plast)
+	    {
+		is_monotonic = FALSE ;
+	    }
+	    plast = p ;
+
+	    i = Li [p] ;
+	    P4 ("  "I8":", i) ;
+	    if (i != j)
+	    {
+		ERR ("diagonal missing") ;
+	    }
+
+	    print_value (print, xtype, Lx, Lz, p, Common) ;
+
+	    P4 ("%s", "\n") ;
+	    ilast = j ;
+	    for (p++ ; p < pend ; p++)
+	    {
+		ETC_DISABLE (count) ;
+		i = Li [p] ;
+		P4 ("  "I8":", i) ;
+		if (i < j || i >= n)
+		{
+		    ERR ("row index out of range") ;
+		}
+		if (i <= ilast)
+		{
+		    ERR ("row indices out of order") ;
+		}
+
+		print_value (print, xtype, Lx, Lz, p, Common) ;
+
+		P4 ("%s", "\n") ;
+		ilast = i ;
+	    }
+	}
+
+	if (L->is_monotonic && !is_monotonic)
+	{
+	    ERR ("columns not monotonic") ;
+	}
+
+	/* check the link list */
+	head = n+1 ;
+	tail = n ;
+	j = head ;
+	jprev = EMPTY ;
+	count = 0 ;
+	for ( ; ; )
+	{
+	    if (j < 0 || j > n+1 || count > n+2)
+	    {
+		ERR ("invalid link list") ;
+	    }
+	    jnext = Lnext [j] ;
+	    if (j >= 0 && j < n)
+	    {
+		if (jprev != Lprev [j])
+		{
+		    ERR ("invalid link list") ;
+		}
+	    }
+	    count++ ;
+	    if (j == tail)
+	    {
+		break ;
+	    }
+	    jprev = j ;
+	    j = jnext ;
+	}
+	if (Lnext [tail] != EMPTY || count != n+2)
+	{
+	    ERR ("invalid link list") ;
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* check supernodal numeric or symbolic factor */
+	/* ------------------------------------------------------------------ */
+
+	nsuper = L->nsuper ;
+	ssize = L->ssize ;
+	xsize = L->xsize ;
+	maxcsize = L->maxcsize ;
+	maxesize = L->maxesize ;
+	Ls = L->s ;
+	Lpi = L->pi ;
+	Lpx = L->px ;
+	Super = L->super ;
+	Lx = L->x ;
+	ETC_START (count, 8) ;
+
+	P4 ("  ssize "ID" ", ssize) ;
+	P4 ("xsize "ID" ", xsize) ;
+	P4 ("maxcsize "ID" ", maxcsize) ;
+	P4 ("maxesize "ID"\n", maxesize) ;
+
+	if (Ls == NULL)
+	{
+	    ERR ("invalid: L->s missing") ;
+	}
+	if (Lpi == NULL)
+	{
+	    ERR ("invalid: L->pi missing") ;
+	}
+	if (Lpx == NULL)
+	{
+	    ERR ("invalid: L->px missing") ;
+	}
+	if (Super == NULL)
+	{
+	    ERR ("invalid: L->super missing") ;
+	}
+
+	if (L->xtype != CHOLMOD_PATTERN)
+	{
+	    /* numerical supernodal factor */
+	    if (Lx == NULL)
+	    {
+		ERR ("invalid: L->x missing") ;
+	    }
+	    if (Ls [0] == EMPTY)
+	    {
+		ERR ("invalid: L->s not defined") ;
+	    }
+	    examine_super = TRUE ;
+	}
+	else
+	{
+	    /* symbolic supernodal factor, but only if it has been computed */
+	    examine_super = (Ls [0] != EMPTY) ;
+	}
+
+	if (examine_super)
+	{
+	    if (Lpi [0] != 0 || MAX (1, Lpi [nsuper]) != ssize)
+	    {
+		PRINT0 (("Lpi [0] "ID", Lpi [nsuper = "ID"] = "ID"\n",
+			Lpi [0], nsuper, Lpi [nsuper])) ;
+		ERR ("invalid: L->pi invalid") ;
+	    }
+	    if (Lpx [0] != 0 || MAX (1, Lpx [nsuper]) != xsize)
+	    {
+		ERR ("invalid: L->px invalid") ;
+	    }
+
+	    /* check and print each supernode */
+	    for (s = 0 ; s < nsuper ; s++)
+	    {
+		k1 = Super [s] ;
+		k2 = Super [s+1] ;
+		psi = Lpi [s] ;
+		psend = Lpi [s+1] ;
+		psx = Lpx [s] ;
+		nsrow = psend - psi ;
+		nscol = k2 - k1 ;
+		nsrow2 = nsrow - nscol ;
+		ps2 = psi + nscol ;
+		psxend = Lpx [s+1] ;
+
+		ETC (s == nsuper-1, count, 4) ;
+
+		P4 ("  supernode "ID", ", s) ;
+		P4 ("col "ID" ", k1) ;
+		P4 ("to "ID". ", k2-1) ;
+		P4 ("nz in first col: "ID".\n", nsrow) ;
+		P4 ("  values start "ID", ", psx) ;
+		P4 ("end "ID"\n", psxend) ;
+
+		if (k1 > k2 || k1 < 0 || k2 > n || nsrow < nscol || nsrow2 < 0
+		    || psxend - psx != nsrow * nscol)
+		{
+		    ERR ("invalid supernode") ;
+		}
+
+		lnz += nscol * nsrow - (nscol*nscol - nscol)/2 ;
+
+		if (L->xtype != CHOLMOD_PATTERN)
+		{
+		    /* print each column of the supernode */
+		    for (jj = 0 ; jj < nscol ; jj++)
+		    {
+			ETC_ENABLE (s == nsuper-1 && jj >= nscol-3, count, -1) ;
+			j = k1 + jj ;
+			P4 ("  col "ID"\n", j) ;
+			ilast = j ;
+			i = Ls [psi + jj] ;
+			P4 ("  "I8":", i) ;
+			if (i != j)
+			{
+			    ERR ("row index invalid") ;
+			}
+
+			/* PRINTVALUE (Lx [psx + jj + jj*nsrow]) ; */
+			print_value (print, xtype, Lx, NULL,
+				psx + jj + jj*nsrow, Common) ;
+
+			P4 ("%s", "\n") ;
+			for (ii = jj + 1 ; ii < nsrow ; ii++)
+			{
+			    ETC_DISABLE (count) ;
+			    i = Ls [psi + ii] ;
+			    P4 ("  "I8":", i) ;
+			    if (i <= ilast || i > n)
+			    {
+				ERR ("row index out of range") ;
+			    }
+
+			    /* PRINTVALUE (Lx [psx + ii + jj*nsrow]) ; */
+			    print_value (print, xtype, Lx, NULL,
+				    psx + ii + jj*nsrow, Common) ;
+
+			    P4 ("%s", "\n") ;
+			    ilast = i ;
+			}
+		    }
+		}
+		else
+		{
+		    /* just print the leading column of the supernode */
+		    P4 ("  col "ID"\n", k1) ;
+		    for (jj = 0 ; jj < nscol ; jj++)
+		    {
+			ETC (s == nsuper-1 && jj >= nscol-3, count, -1) ;
+			j = k1 + jj ;
+			i = Ls [psi + jj] ;
+			P4 ("  "I8"", i) ;
+			if (i != j)
+			{
+			    ERR ("row index invalid") ;
+			}
+			P4 ("%s", "\n") ;
+		    }
+		    ilast = j ;
+		    for (ii = nscol ; ii < nsrow ; ii++)
+		    {
+			ETC_DISABLE (count) ;
+			i = Ls [psi + ii] ;
+			P4 ("  "I8"", i) ;
+			if (i <= ilast || i > n)
+			{
+			    ERR ("row index out of range") ;
+			}
+			P4 ("%s", "\n") ;
+			ilast = i ;
+		    }
+		}
+	    }
+	}
+    }
+
+    /* factor is valid */
+    P3 ("  nz "ID"", lnz) ;
+    P3 ("%s", "  OK\n") ;
+    return (TRUE) ;
+}
+
+
+int CHOLMOD(check_factor)
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to check */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_factor (NULL, 0, NULL, L, Common)) ;
+}
+
+
+int CHOLMOD(print_factor)
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to print */
+    char *name,		/* printed name of factor */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_factor (NULL, Common->print, name, L, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_check_triplet ================================================ */
+/* ========================================================================== */
+
+/* Ensure a triplet matrix is valid, and optionally print it. */
+
+static int check_triplet
+(
+    Int print,
+    char *name,
+    cholmod_triplet *T,
+    cholmod_common *Common
+)
+{
+    double *Tx, *Tz ;
+    Int *Ti, *Tj ;
+    Int i, j, p, nrow, ncol, nzmax, nz, xtype, init_print, count ;
+    char *type = "triplet" ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print header information */
+    /* ---------------------------------------------------------------------- */
+
+    P4 ("%s", "\n") ;
+    P3 ("%s", "CHOLMOD triplet: ") ;
+    if (name != NULL)
+    {
+	P3 ("%s: ", name) ;
+    }
+
+    if (T == NULL)
+    {
+	ERR ("null") ;
+    }
+
+    nrow = T->nrow ;
+    ncol = T->ncol ;
+    nzmax = T->nzmax ;
+    nz = T->nnz ;
+    Ti = T->i ;
+    Tj = T->j ;
+    Tx = T->x ;
+    Tz = T->z ;
+    xtype = T->xtype ;
+
+
+    P3 (" "ID"", nrow) ;
+    P3 ("-by-"ID", ", ncol) ;
+    P3 ("nz "ID",", nz) ;
+    if (T->stype > 0)
+    {
+	P3 ("%s", " upper.") ;
+    }
+    else if (T->stype < 0)
+    {
+	P3 ("%s", " lower.") ;
+    }
+    else
+    {
+	P3 ("%s", " up/lo.") ;
+    }
+
+    P4 ("\n  nzmax "ID", ", nzmax) ;
+    if (nz > nzmax)
+    {
+	ERR ("nzmax too small") ;
+    }
+
+    switch (T->itype)
+    {
+	case CHOLMOD_INT:     P4 ("%s", "\n  scalar types: int, ") ; break ;
+	case CHOLMOD_INTLONG: ERR ("mixed int/UF_long type unsupported") ;
+	case CHOLMOD_LONG:    P4 ("%s", "\n  scalar types: UF_long, ") ; break ;
+	default:	      ERR ("unknown itype") ;
+    }
+
+    switch (T->xtype)
+    {
+	case CHOLMOD_PATTERN: P4 ("%s", "pattern") ;	break ;
+	case CHOLMOD_REAL:    P4 ("%s", "real") ;	break ;
+	case CHOLMOD_COMPLEX: P4 ("%s", "complex") ;	break ;
+	case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ;	break ;
+	default:	      ERR ("unknown xtype") ;
+    }
+
+    switch (T->dtype)
+    {
+	case CHOLMOD_DOUBLE:  P4 ("%s", ", double\n") ;	       break ;
+	case CHOLMOD_SINGLE:  ERR ("single unsupported") ;
+	default:	      ERR ("unknown dtype") ;
+    }
+
+    if (T->itype != ITYPE || T->dtype != DTYPE)
+    {
+	ERR ("integer and real type must match routine") ;
+    }
+
+    if (T->stype && nrow != ncol)
+    {
+	ERR ("symmetric but not square") ;
+    }
+
+    /* check for existence of Ti, Tj, Tx arrays */
+    if (Tj == NULL)
+    {
+	ERR ("j array not present") ;
+    }
+    if (Ti == NULL)
+    {
+	ERR ("i array not present") ;
+    }
+
+    if (xtype != CHOLMOD_PATTERN && Tx == NULL)
+    {
+	ERR ("x array not present") ;
+    }
+    if (xtype == CHOLMOD_ZOMPLEX && Tz == NULL)
+    {
+	ERR ("z array not present") ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* check and print each entry */
+    /* ---------------------------------------------------------------------- */
+
+    init_print = print ;
+    ETC_START (count, 8) ;
+
+    for (p = 0 ; p < nz ; p++)
+    {
+	ETC (p >= nz-4, count, -1) ;
+	i = Ti [p] ;
+	P4 ("  "I8":", p) ;
+	P4 (" "I_8"", i) ;
+	if (i < 0 || i >= nrow)
+	{
+	    ERR ("row index out of range") ;
+	}
+	j = Tj [p] ;
+	P4 (" "I_8"", j) ;
+	if (j < 0 || j >= ncol)
+	{
+	    ERR ("column index out of range") ;
+	}
+
+	print_value (print, xtype, Tx, Tz, p, Common) ;
+
+	P4 ("%s", "\n") ;
+    }
+
+    /* triplet matrix is valid */
+    P3 ("%s", "  OK\n") ;
+    return (TRUE) ;
+}
+
+
+
+int CHOLMOD(check_triplet)
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* triplet matrix to check */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_triplet (0, NULL, T, Common)) ;
+}
+
+
+int CHOLMOD(print_triplet)
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* triplet matrix to print */
+    char *name,		/* printed name of triplet matrix */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_triplet (Common->print, name, T, Common)) ;
+}
+
+
+
+/* ========================================================================== */
+/* === CHOLMOD debugging routines =========================================== */
+/* ========================================================================== */
+
+#ifndef NDEBUG
+
+/* The global variables present only when debugging enabled. */
+int CHOLMOD(dump) = 0 ;
+int CHOLMOD(dump_malloc) = -1 ;
+
+/* workspace: no debug routines use workspace in Common */
+
+/* ========================================================================== */
+/* === cholmod_dump_init ==================================================== */
+/* ========================================================================== */
+
+void CHOLMOD(dump_init) (char *s, cholmod_common *Common)
+{
+    FILE *f ;
+    f = fopen ("debug", "r") ;
+    if (f == NULL)
+    {
+	CHOLMOD(dump) = 0 ;
+    }
+    else
+    {
+	fscanf (f, "%d", &CHOLMOD(dump)) ;
+	fclose (f) ;
+    }
+    PRINT1 (("%s: cholmod_dump_init, D = %d\n", s, CHOLMOD(dump))) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_sparse ================================================== */
+/* ========================================================================== */
+
+UF_long CHOLMOD(dump_sparse)	/* returns nnz (diag (A)) or EMPTY if error */
+(
+    cholmod_sparse *A,
+    char *name,
+    cholmod_common *Common
+)
+{
+    Int *Wi ;
+    UF_long nnzdiag ;
+    Int ok ;
+
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return (0) ;
+    }
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    Wi = malloc (MAX (1, A->nrow) * sizeof (Int)) ;
+    ok = check_sparse (Wi, CHOLMOD(dump), name, A, &nnzdiag, Common) ;
+    if (Wi != NULL) free (Wi) ;
+    return (ok ? nnzdiag : EMPTY) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_factor ================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(dump_factor)
+(
+    cholmod_factor *L,
+    char *name,
+    cholmod_common *Common
+)
+{
+    Int *Wi ;
+    int ok ;
+
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return (TRUE) ;
+    }
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    Wi = malloc (MAX (1, L->n) * sizeof (Int)) ;
+    ok = check_factor (Wi, CHOLMOD(dump), name, L, Common) ;
+    if (Wi != NULL) free (Wi) ;
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_perm ==================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(dump_perm)
+(
+    Int *Perm,
+    size_t len,
+    size_t n,
+    char *name,
+    cholmod_common *Common
+)
+{
+    Int *Wi ;
+    int ok ;
+
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return (TRUE) ;
+    }
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Wi = malloc (MAX (1, n) * sizeof (Int)) ;
+    ok = check_perm (Wi, CHOLMOD(dump), name, Perm, len, n,Common) ;
+    if (Wi != NULL) free (Wi) ;
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_dense =================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(dump_dense)
+(
+    cholmod_dense *X,
+    char *name,
+    cholmod_common *Common
+)
+{
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return (TRUE) ;
+    }
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    return (check_dense (CHOLMOD(dump), name, X, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_triplet ================================================= */
+/* ========================================================================== */
+
+int CHOLMOD(dump_triplet)
+(
+    cholmod_triplet *T,
+    char *name,
+    cholmod_common *Common
+)
+{
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return (TRUE) ;
+    }
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    return (check_triplet (CHOLMOD(dump), name, T, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_subset ================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(dump_subset)
+(
+    Int *S,
+    size_t len,
+    size_t n,
+    char *name,
+    cholmod_common *Common
+)
+{
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return (TRUE) ;
+    }
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    return (check_subset (S, len, n, CHOLMOD(dump), name, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_parent ================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(dump_parent)
+(
+    Int *Parent,
+    size_t n,
+    char *name,
+    cholmod_common *Common
+)
+{
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return (TRUE) ;
+    }
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    return (check_parent (Parent, n, CHOLMOD(dump), name, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_real ==================================================== */
+/* ========================================================================== */
+
+void CHOLMOD(dump_real)
+(
+    char *name, Real *X, UF_long nrow, UF_long ncol, int lower, int xentry,
+    cholmod_common *Common
+)
+{
+    /* dump an nrow-by-ncol real dense matrix */
+    UF_long i, j ;
+    double x, z ;
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return ;
+    }
+    PRINT1 (("%s: dump_real, nrow: %ld ncol: %ld lower: %d\n",
+		name, nrow, ncol, lower)) ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	PRINT2 (("    col %ld\n", j)) ;
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    /* X is stored in column-major form */
+	    if (lower && i < j)
+	    {
+		PRINT2 (("        %5ld: -", i)) ;
+	    }
+	    else
+	    {
+		x = *X ;
+		PRINT2 (("        %5ld: %e", i, x)) ;
+		if (xentry == 2)
+		{
+		    z = *(X+1) ;
+		    PRINT2 ((", %e", z)) ;
+		}
+	    }
+	    PRINT2 (("\n")) ;
+	    X += xentry ;
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_super =================================================== */
+/* ========================================================================== */
+
+void CHOLMOD(dump_super)
+(
+    UF_long s,
+    Int *Super, Int *Lpi, Int *Ls, Int *Lpx, double *Lx,
+    int xentry,
+    cholmod_common *Common
+)
+{
+    Int k1, k2, do_values, psi, psx, nsrow, nscol, psend, ilast, p, i ;
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return ;
+    }
+    k1 = Super [s] ;
+    k2 = Super [s+1] ;
+    nscol = k2 - k1 ;
+    do_values = (Lpx != NULL) && (Lx != NULL) ;
+    psi = Lpi [s] ;
+    psend = Lpi [s+1] ;
+    nsrow = psend - psi ;
+    PRINT1 (("\nSuper %ld, columns "ID" to "ID", "ID" rows "ID" cols\n",
+		s, k1, k2-1, nsrow, nscol)) ;
+    ilast = -1 ;
+    for (p = psi ; p < psend ; p++)
+    {
+	i = Ls [p] ;
+	PRINT2 (("  "ID" : p-psi "ID"\n", i, p-psi)) ;
+	ASSERT (IMPLIES (p-psi < nscol, i == k1 + (p-psi))) ;
+	if (p-psi == nscol-1) PRINT2 (("------\n")) ;
+	ASSERT (i > ilast) ;
+	ilast = i ;
+    }
+    if (do_values)
+    {
+	psx = Lpx [s] ;
+	CHOLMOD(dump_real) ("Supernode", Lx + xentry*psx, nsrow, nscol, TRUE, 
+		xentry, Common) ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_mem ===================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(dump_mem) (char *where, UF_long should, cholmod_common *Common)
+{
+    UF_long diff = should - Common->memory_inuse ;
+    if (diff != 0)
+    {
+	PRINT0 (("mem: %-15s peak %10g inuse %10g should %10g\n",
+	    where, (double) Common->memory_usage, (double) Common->memory_inuse,
+	    (double) should)) ;
+	PRINT0 (("mem: %s diff %ld !\n", where, diff)) ;
+    }
+    return (diff == 0) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_partition =============================================== */
+/* ========================================================================== */
+
+/* make sure we have a proper separator (for debugging only)
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(dump_partition)
+(
+    UF_long n,
+    Int *Cp,
+    Int *Ci,
+    Int *Cnw,
+    Int *Part,
+    UF_long sepsize,
+    cholmod_common *Common
+)
+{
+    Int chek [3], which, ok, i, j, p ;
+    PRINT1 (("bisect sepsize %ld\n", sepsize)) ;
+    ok = TRUE ;
+    chek [0] = 0 ;
+    chek [1] = 0 ;
+    chek [2] = 0 ;
+    for (j = 0 ; j < n ; j++)
+    {
+	PRINT2 (("--------j "ID" in part "ID" nw "ID"\n", j, Part [j], Cnw[j]));
+	which = Part [j] ;
+	for (p = Cp [j] ; p < Cp [j+1] ; p++)
+	{
+	    i = Ci [p] ;
+	    PRINT3 (("i "ID", part "ID"\n", i, Part [i])) ;
+	    if (which == 0)
+	    {
+		if (Part [i] == 1)
+		{
+		    PRINT0 (("Error! "ID" "ID"\n", i, j)) ;
+		    ok = FALSE ;
+		}
+	    }
+	    else if (which == 1)
+	    {
+		if (Part [i] == 0)
+		{
+		    PRINT0 (("Error! "ID" "ID"\n", i, j)) ;
+		    ok = FALSE ;
+		}
+	    }
+	}
+	if (which < 0 || which > 2)
+	{
+	    PRINT0 (("Part out of range\n")) ;
+	    ok = FALSE ;
+	}
+	chek [which] += Cnw [j] ;
+    }
+    PRINT1 (("sepsize %ld check "ID" "ID" "ID"\n",
+		sepsize, chek[0], chek[1],chek[2]));
+    if (sepsize != chek[2])
+    {
+	PRINT0 (("mismatch!\n")) ;
+	ok = FALSE ;
+    }
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_work ==================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(dump_work) (int flag, int head, UF_long wsize,
+    cholmod_common *Common)
+{
+    double *W ;
+    Int *Flag, *Head ;
+    Int k, nrow, mark ;
+
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return (TRUE) ;
+    }
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    nrow = Common->nrow ;
+    Flag = Common->Flag ;
+    Head = Common->Head ;
+    W = Common->Xwork ;
+    mark = Common->mark ;
+
+    if (wsize < 0)
+    {
+	/* check all of Xwork */
+	wsize = Common->xworksize ;
+    }
+    else
+    {
+	/* check on the first wsize doubles in Xwork */
+	wsize = MIN (wsize, (Int) (Common->xworksize)) ;
+    }
+
+    if (flag)
+    {
+	for (k = 0 ; k < nrow ; k++)
+	{
+	    if (Flag [k] >= mark)
+	    {
+		PRINT0 (("Flag invalid, Flag ["ID"] = "ID", mark = "ID"\n",
+			    k, Flag [k], mark)) ;
+		ASSERT (0) ;
+		return (FALSE) ;
+	    }
+	}
+    }
+
+    if (head)
+    {
+	for (k = 0 ; k < nrow ; k++)
+	{
+	    if (Head [k] != EMPTY)
+	    {
+		PRINT0 (("Head invalid, Head ["ID"] = "ID"\n", k, Head [k])) ;
+		ASSERT (0) ;
+		return (FALSE) ;
+	    }
+	}
+    }
+
+    for (k = 0 ; k < wsize ; k++)
+    {
+	if (W [k] != 0.)
+	{
+	    PRINT0 (("W invalid, W ["ID"] = %g\n", k, W [k])) ;
+	    ASSERT (0) ;
+	    return (FALSE) ;
+	}
+    }
+
+    return (TRUE) ;
+}
+#endif
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Check/cholmod_read.c b/src/C/SuiteSparse/CHOLMOD/Check/cholmod_read.c
new file mode 100644
index 0000000..afdbddf
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Check/cholmod_read.c
@@ -0,0 +1,1319 @@
+/* ========================================================================== */
+/* === Check/cholmod_read =================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Check Module.  Copyright (C) 2005-2006, Timothy A. Davis.
+ * The CHOLMOD/Check Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Read a sparse matrix in triplet or dense form.  A triplet matrix can be
+ * returned as compressed-column sparse matrix.  The file format is compatible
+ * with all variations of the Matrix Market "coordinate" and "array" format
+ * (http://www.nist.gov/MatrixMarket).  The format supported by these routines
+ * also allow other formats, where the Matrix Market header is optional.
+ *
+ * Although the Matrix Market header is optional, I recommend that users stick
+ * with the strict Matrix Market format.  The optional format appears here to
+ * support the reading of symmetric matrices stored with just their upper
+ * triangular parts present, for testing and development of the A->stype > 0
+ * format in CHOLMOD.  That format is not included in the Matrix Market format.
+ *
+ * If the first line of the file starts with %%MatrixMarket, then it is
+ * interpretted as a file in Matrix Market format.  This line must have
+ * the following format:
+ *
+ *	%%MatrixMarket matrix <fmt> <type> <storage>
+ *
+ *	<fmt> is one of: coordinate or array.  The former is a sparse matrix in
+ *	triplet form.  The latter is a dense matrix in column-major form.
+ *
+ *	<type> is one of: real, complex, pattern, or integer.
+ *	The functions here convert the  "integer" and "pattern" types to real.  
+ *
+ *	<storage> is one of: general, hermitian, symmetric, or skew-symmetric
+ *
+ *	The strings are case-insensitive.  Only the first character is
+ *	significant (or the first two for skew-symmetric).
+ *
+ *	<type> is ignored for all matrices; the actual type (real, complex,
+ *	or pattern) is inferred from the number of tokens in each line of the
+ *	file.  For a "coordinate" matrix: 2: pattern, 3: real, 4: complex; for
+ *	a dense "array" matrix: 1: real, 2: complex.  This is compatible with
+ *	the Matrix Market format, since pattern matrices must have two tokens
+ *	per line, real matrices must have 3, and complex matrices must have 4.
+ *	A storage of "general" implies an stype of zero (see below). 
+ *	"symmetric" and "hermitian" imply an stype of -1. Skew-symmetric and
+ *	complex symmetric matrices are always returned with both upper and lower
+ *	triangular parts present, with an stype of zero, since CHOLMOD does not
+ *	have a method for representing skew-symmetric and complex symmetric
+ *	matrices.  Real symmetric and complex Hermitian matrices may optionally
+ *	be returned with both parts present.
+ *
+ * Any other lines starting with "%" are treated as comments, and are ignored.
+ * Blank lines are ignored.  The Matrix Market header is optional in this
+ * routine (it is not optional in the Matrix Market format).
+ *
+ * Note that complex matrices are always returned in CHOLMOD_COMPLEX format,
+ * not CHOLMOD_ZOMPLEX.
+ *
+ * -----------------------------------------------------------------------------
+ * Triplet matrices:
+ * -----------------------------------------------------------------------------
+ *
+ * The first data line of a triplet matrix contains 3 or 4 integers:
+ *
+ *	nrow ncol nnz stype
+ *
+ * where stype is optional (stype does not appear in the Matrix Market format).
+ * The matrix is nrow-by-ncol.  The following nnz lines (excluding comments
+ * and blank lines) each contain a single entry.  Duplicates are permitted,
+ * and are summed in the output matrix.
+ *
+ * The stype is first derived from the Matrix Market header.  If the stype
+ * appears as the fourth integer in the first data line, it is determined from
+ * that line.
+ * 
+ * If stype is present, it denotes the storage format for the matrix.
+ * stype = 0 denotes an unsymmetric matrix (same as Matrix Market "general").
+ * stype = -1 denotes a real symmetric or complex Hermitian matrix whose lower
+ *	triangular entries are stored.  Entries may be present in the upper
+ *	triangular part, but these are ignored (same as Matrix Market
+ *	"real symmetric" and "complex Hermitian").
+ * stype = 1 denotes a real symmetric or complex Hermitian matrix whose upper
+ *	triangular entries are stored.  Entries may be present in the lower
+ *	triangular part, but these are ignored.  This option is not present
+ *	in the Matrix Market format.
+ *
+ * If stype is not present (no Matrix Market header and not in the first data
+ * line) it is inferred from the rest of the data.  If the matrix is
+ * rectangular, or has entries in both the upper and lower triangular parts,
+ * then it is assumed to be unsymmetric (stype=0).  If only entries in the
+ * lower triangular part are present, the matrix is assumed to have stype = -1.
+ * If only entries in the upper triangular part are present, the matrix is
+ * assumed to have stype = 1.
+ *
+ * After the first data line (with nrow, ncol, nnz, and optionally stype),
+ * each nonzero consists of one line with 2, 3, or 4 entries.  All lines must
+ * have the same number of entries.  The first two entries are the row and
+ * column indices of the nonzero.  If 3 entries are present, the 3rd entry is
+ * the numerical value, and the matrix is real.  If 4 entries are present,
+ * the 3rd and 4th entries in the line are the real and imaginary parts of
+ * a complex value.
+ *
+ * The matrix can be either 0-based or 1-based.  It is first assumed to be
+ * one-based (all matrices in the Matrix Market are one-based), with row indices
+ * in the range 1 to ncol and column indices in the range 1 to nrow.  If a row
+ * or column index of zero is found, the matrix is assumed to be zero-based
+ * (with row indices in the range 0 to ncol-1 and column indices in the range 0
+ * to nrow-1).
+ *
+ * If Common->prefer_binary is set to its default value of FALSE, then
+ * for symmetric pattern-only matrices, the kth diagonal (if present) is set to
+ * one plus the degree of the row/column k, and the off-diagonal entries are set
+ * to -1.  A symmetric pattern-only matrix with a zero-free diagonal is thus
+ * converted into a symmetric positive definite matrix.  All entries are set to
+ * one for an unsymmetric pattern-only matrix.  This differs from the
+ * Matrix Market format (A = mmread ('file') returns a binary pattern for A for
+ * symmetric pattern-only matrices).  If Common->prefer_binary is TRUE, then
+ * this function returns a binary matrix (just like mmread('file')).
+ *
+ * -----------------------------------------------------------------------------
+ * Dense matrices:
+ * -----------------------------------------------------------------------------
+ *
+ * A dense matrix is specified by the Matrix Market "array" format.  The
+ * Matrix Market header is optional; if not present, the matrix is assumed to
+ * be in the Matrix Market "general" format.  The first data line contains just
+ * two integers:
+ *
+ *	nrow ncol
+ *
+ * The <type> can be real, integer, or complex (not pattern).  These functions
+ * convert an integer type to real.  The entries in the matrix are stored in
+ * column-major format, with one line per entry.  Two entries are present in
+ * each line for complex matrices, one for real and integer matrices.  In
+ * rectangular and unsymmetric matrices, all entries are present.  For real
+ * symmetric or complex Hermitian matrices, only entries in the lower triangular
+ * part appear.  For skew-symmetric matrices, only entries in the strictly
+ * lower triangular part appear.
+ *
+ * Since CHOLMOD does not have a data structure for presenting dense symmetric/
+ * Hermitian matrices, these functions always return a dense matrix in its
+ * general form, with both upper and lower parts present.
+ */
+
+#ifndef NCHECK
+
+#include "cholmod_internal.h"
+#include "cholmod_check.h"
+#include <string.h>
+#include <ctype.h>
+
+/* The MatrixMarket format specificies a maximum line length of 1024 */
+#define MAXLINE 1030
+
+/* ========================================================================== */
+/* === get_line ============================================================= */
+/* ========================================================================== */
+
+/* Read one line of the file, return TRUE if successful, FALSE if EOF. */
+
+static int get_line (FILE *f, char *buf)
+{
+    buf [0] = '\0' ;
+    buf [1] = '\0' ;
+    buf [MAXLINE] = '\0' ;
+    return (fgets (buf, MAXLINE, f) != NULL) ;
+}
+
+/* ========================================================================== */
+/* === fix_inf ============================================================== */
+/* ========================================================================== */
+
+/* Replace huge values with +/- Inf's, since scanf and printf don't deal
+ * with Inf's properly.
+ */
+
+static double fix_inf (double x)
+{
+    if ((x >= HUGE_DOUBLE) || (x <= -HUGE_DOUBLE))
+    {
+	/* treat this as +/- Inf (assume 2*x leads to overflow) */
+	x = 2*x ;
+    }
+    return (x) ;
+}
+
+/* ========================================================================== */
+/* === is_blank_line ======================================================== */
+/* ========================================================================== */
+
+/* TRUE if s is a blank line or comment, FALSE otherwise */
+
+static int is_blank_line
+(
+    char *s
+)
+{
+    int c, k ;
+    if (s [0] == '%')
+    {
+	/* a comment line */
+	return (TRUE) ;
+    }
+    for (k = 0 ; k <= MAXLINE ; k++)
+    {
+	c = s [k] ;
+	if (c == '\0')
+	{
+	    /* end of line */
+	    break ;
+	}
+	if (!isspace (c))
+	{
+	    /* non-space character */
+	    return (FALSE) ;
+	}
+    }
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === read_header ========================================================== */
+/* ========================================================================== */
+
+/* Read the header.  This consists of zero or more comment lines (blank, or
+ * starting with a "%" in the first column), followed by a single data line
+ * containing up to four numerical values.
+ *
+ * The first line may optionally be a Matrix Market header line, of the form
+ *
+ *	%%MatrixMarket matrix <fmt> <type> <storage>
+ *
+ * The first data line of a sparse matrix in triplet form consists of 3 or 4
+ * numerical values:
+ *
+ *	nrow ncol nnz stype
+ *
+ * where stype is optional (it does not appear in the Matrix Market file
+ * format).  The first line of a dense matrix in column-major form consists of
+ * two numerical values:
+ *
+ *	nrow ncol
+ *
+ * The stype of the matrix is determine either from the Matrix Market header,
+ * or (optionally) from the first data line.  stypes of 0 to -3 directly
+ * correlate with the Matrix Market format; stype = 1 is an extension to that
+ * format.
+ *
+ *	999: unknown (will be inferred from the data)
+ *	1: real symmetric or complex Hermitian with upper part stored
+ *		(not in the Matrix Market format)
+ *	0: unsymmetric (same as Matrix Market "general")
+ *	-1: real symmetric or complex Hermitian, with lower part stored
+ *		(Matrix Market "real symmetric" or "complex hermitian")
+ *	-2: real or complex skew symmetric (lower part stored, can only be
+ *		specified by Matrix Market header)
+ *	-3: complex symmetric (lower part stored)
+ *		specified by Matrix Market header)
+ *
+ * The Matrix Market header is optional.  If stype appears in the first data
+ * line, it is determine by that data line.  Otherwise, if the Matrix Market
+ * header appears, stype is determined from that header.  If stype does not
+ * appear, it is set to "unknown" (999).
+ */
+
+#define STYPE_UNKNOWN 999
+#define STYPE_SYMMETRIC_UPPER 1
+#define STYPE_UNSYMMETRIC 0
+#define STYPE_SYMMETRIC_LOWER -1
+#define STYPE_SKEW_SYMMETRIC -2
+#define STYPE_COMPLEX_SYMMETRIC_LOWER -3
+
+static int read_header	/* returns TRUE if successful, FALSE on error */
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from */
+    /* ---- output --- */
+    char *buf,		/* a character array of size MAXLINE+1 */
+    int *mtype,		/* CHOLMOD_TRIPLET or CHOLMOD_DENSE */
+    size_t *nrow,	/* number of rows in the matrix */
+    size_t *ncol,	/* number of columns in the matrix */
+    size_t *nnz,	/* number of entries in a triplet matrix (0 for dense)*/
+    int *stype		/* stype (see above) */
+)
+{
+    char *p ;
+    int first = TRUE, got_mm_header = FALSE, c, c2, is_complex, nitems ;
+    double l1, l2, l3, l4 ;
+
+    *mtype = CHOLMOD_TRIPLET ;
+    *nrow = 0 ;
+    *ncol = 0 ;
+    *nnz = 0 ;
+    *stype = STYPE_UNKNOWN ;
+
+    for ( ; ; )
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* get the next line */
+	/* ------------------------------------------------------------------ */
+
+	if (!get_line (f, buf))
+	{
+	    /* premature end of file */
+	    return (FALSE) ;
+	}
+
+	if (first && (strncmp (buf, "%%MatrixMarket", 14) == 0))
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* read a Matrix Market header */
+	    /* -------------------------------------------------------------- */
+
+	    got_mm_header = TRUE ;
+	    p = buf ;
+
+	    /* -------------------------------------------------------------- */
+	    /* get "matrix" token */
+	    /* -------------------------------------------------------------- */
+
+	    while (*p && !isspace (*p)) p++ ;
+	    while (*p &&  isspace (*p)) p++ ;
+	    c = tolower (*p) ;
+	    if (c != 'm')
+	    {
+		/* bad format */
+		return (FALSE) ;
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* get the fmt token ("coord" or "array") */
+	    /* -------------------------------------------------------------- */
+
+	    while (*p && !isspace (*p)) p++ ;
+	    while (*p &&  isspace (*p)) p++ ;
+	    c = tolower (*p) ;
+	    if (c == 'c')
+	    {
+		*mtype = CHOLMOD_TRIPLET  ;
+	    }
+	    else if (c == 'a')
+	    {
+		*mtype = CHOLMOD_DENSE  ;
+	    }
+	    else
+	    {
+		/* bad format, neither "coordinate" nor "array" */
+		return (FALSE) ;
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* get type token (real, pattern, complex, integer) */
+	    /* -------------------------------------------------------------- */
+
+	    while (*p && !isspace (*p)) p++ ;
+	    while (*p &&  isspace (*p)) p++ ;
+	    c = tolower (*p) ;
+	    if (!(c == 'r' || c == 'p' || c == 'c' || c == 'i'))
+	    {
+		/* bad format */
+		return (FALSE) ;
+	    }
+	    is_complex = (c == 'c') ;
+
+	    /* -------------------------------------------------------------- */
+	    /* get storage token (general, hermitian, symmetric, skew) */
+	    /* -------------------------------------------------------------- */
+
+	    while (*p && !isspace (*p)) p++ ;
+	    while (*p &&  isspace (*p)) p++ ;
+	    c = tolower (*p) ;
+	    c2 = tolower (*(p+1)) ;
+	    if (c == 'g')
+	    {
+		/* "general" storage (unsymmetric matrix), both parts present */
+		*stype = STYPE_UNSYMMETRIC ;
+	    }
+	    else if (c == 's' && c2 == 'y')
+	    {
+		/* "symmetric" */
+		if (is_complex)
+		{
+		    /* complex symmetric, lower triangular part present */
+		    *stype = STYPE_COMPLEX_SYMMETRIC_LOWER ;
+		}
+		else
+		{
+		    /* real symmetric, lower triangular part present */
+		    *stype = STYPE_SYMMETRIC_LOWER ;
+		}
+	    }
+	    else if (c == 'h')
+	    {
+		/* "hermitian" matrix, lower triangular part present */
+		*stype = STYPE_SYMMETRIC_LOWER ;
+	    }
+	    else if (c == 's' && c2 == 'k')
+	    {
+		/* "skew-symmetric" (real or complex), lower part present */
+		*stype = STYPE_SKEW_SYMMETRIC ;
+	    }
+	    else
+	    {
+		/* bad format */
+		return (FALSE) ;
+	    }
+
+	}
+	else if (is_blank_line (buf))
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* blank line or comment line */
+	    /* -------------------------------------------------------------- */
+
+	    continue ;
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* read the first data line and return */
+	    /* -------------------------------------------------------------- */
+
+	    /* format: nrow ncol nnz stype */
+	    l1 = EMPTY ;
+	    l2 = EMPTY ;
+	    l3 = 0 ;
+	    l4 = 0 ;
+	    nitems = sscanf (buf, "%lg %lg %lg %lg\n", &l1, &l2, &l3, &l4) ;
+	    if (nitems < 2 || nitems > 4 || l1 > Int_max || l2 > Int_max)
+	    {
+		/* invalid matrix */
+		return (FALSE) ;
+	    }
+	    *nrow = l1 ;
+	    *ncol = l2 ;
+	    if (nitems == 2)
+	    {
+		/* a dense matrix */
+		if (!got_mm_header)
+		{
+		    *mtype = CHOLMOD_DENSE ;
+		    *stype = STYPE_UNSYMMETRIC ;
+		}
+	    }
+	    if (nitems == 3 || nitems == 4)
+	    {
+		/* a sparse triplet matrix */
+		*nnz = l3 ;
+		if (!got_mm_header)
+		{
+		    *mtype = CHOLMOD_TRIPLET ;
+		}
+	    }
+	    if (nitems == 4)
+	    {
+		/* an stype specified here can only be 1, 0, or -1 */
+		if (l4 < 0)
+		{
+		    *stype = STYPE_SYMMETRIC_LOWER ;
+		}
+		else if (l4 > 0)
+		{
+		    *stype = STYPE_SYMMETRIC_UPPER ;
+		}
+		else
+		{
+		    *stype = STYPE_UNSYMMETRIC ;
+		}
+	    }
+	    if (*nrow != *ncol)
+	    {
+		/* a rectangular matrix must be unsymmetric */
+		*stype = STYPE_UNSYMMETRIC ;
+	    }
+	    return (TRUE) ;
+	}
+
+	first = FALSE ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === read_triplet ========================================================= */
+/* ========================================================================== */
+
+/* Header has already been read in, including first line (nrow ncol nnz stype).
+ * Read the triplets. */
+
+static cholmod_triplet *read_triplet
+(
+    /* ---- input ---- */
+    FILE *f,		    /* file to read from, must already be open */
+    size_t nrow,	    /* number of rows */
+    size_t ncol,	    /* number of columns */
+    size_t nnz,		    /* number of triplets in file to read */
+    int stype,		    /* stype from header, or "unknown" */
+    int prefer_unsym,	    /* if TRUE, always return T->stype of zero */
+    /* ---- workspace */
+    char *buf,		    /* of size MAXLINE+1 */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double x, z ;
+    double *Tx ;
+    Int *Ti, *Tj, *Rdeg, *Cdeg ;
+    cholmod_triplet *T ;
+    double l1, l2 ;
+    Int nitems, xtype, unknown, k, nshould, is_lower, is_upper, one_based, i, j,
+	imax, jmax, ignore, skew_symmetric, p, complex_symmetric ;
+    size_t s, nnz2, extra ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* quick return for empty matrix */
+    /* ---------------------------------------------------------------------- */
+
+    if (nrow == 0 || ncol == 0 || nnz == 0)
+    {
+	/* return an empty matrix */
+	return (CHOLMOD(allocate_triplet) (nrow, ncol, 0, 0, CHOLMOD_REAL,
+		    Common)) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* special stype cases: unknown, skew symmetric, and complex symmetric  */
+    /* ---------------------------------------------------------------------- */
+
+    unknown = (stype == STYPE_UNKNOWN) ;
+    skew_symmetric = (stype == STYPE_SKEW_SYMMETRIC) ;
+    complex_symmetric = (stype == STYPE_COMPLEX_SYMMETRIC_LOWER) ;
+
+    extra = 0 ;
+    if (stype < STYPE_SYMMETRIC_LOWER
+	|| (prefer_unsym && stype != STYPE_UNSYMMETRIC))
+    {
+	/* 999: unknown might be converted to unsymmetric */
+	/*  1:  symmetric upper converted to unsym. if prefer_unsym is TRUE */
+	/* -1:  symmetric lower converted to unsym. if prefer_unsym is TRUE */
+	/* -2:  real or complex skew symmetric converted to unsymmetric */
+	/* -3:  complex symmetric converted to unsymmetric */
+	stype = STYPE_UNSYMMETRIC ;
+	extra = nnz ;
+    }
+    nnz2 = CHOLMOD(add_size_t) (nnz, extra, &ok) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* s = nrow + ncol */
+    s = CHOLMOD(add_size_t) (nrow, ncol, &ok) ;
+    if (!ok || nrow > Int_max || ncol > Int_max || nnz > Int_max)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (NULL) ;
+    }
+
+    CHOLMOD(allocate_work) (0, s, 0, Common) ;
+    Rdeg = Common->Iwork ;	/* size nrow */
+    Cdeg = Rdeg + nrow ;	/* size ncol */
+
+    /* ---------------------------------------------------------------------- */
+    /* read the triplets */
+    /* ---------------------------------------------------------------------- */
+
+    is_lower = TRUE ;
+    is_upper = TRUE ;
+    one_based = TRUE ;
+    imax = 0 ;
+    jmax = 0 ;
+
+    Tx = NULL ;
+    Ti = NULL ;
+    Tj = NULL ;
+    xtype = 999 ;
+    nshould = 0 ;
+
+    for (k = 0 ; k < (Int) nnz ; k++)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* get the next triplet, skipping blank lines and comment lines */
+	/* ------------------------------------------------------------------ */
+
+	l1 = EMPTY ;
+	l2 = EMPTY ;
+	x = 0 ;
+	z = 0 ;
+
+	for ( ; ; )
+	{
+	    if (!get_line (f, buf))
+	    {
+		/* premature end of file - not enough triplets read in */
+		ERROR (CHOLMOD_INVALID, "premature EOF") ;
+		return (NULL) ;
+	    }
+	    if (is_blank_line (buf))
+	    {
+		/* blank line or comment */
+		continue ;
+	    }
+	    nitems = sscanf (buf, "%lg %lg %lg %lg\n", &l1, &l2, &x, &z) ;
+	    x = fix_inf (x) ;
+	    z = fix_inf (z) ;
+	    break ;
+	}
+
+	nitems = (nitems == EOF) ? 0 : nitems ;
+	i = l1 ;
+	j = l2 ;
+
+	/* ------------------------------------------------------------------ */
+	/* for first triplet: determine type and allocate triplet matrix */
+	/* ------------------------------------------------------------------ */
+
+	if (k == 0)
+	{
+	    if (nitems < 2 || nitems > 4)
+	    {
+		/* invalid matrix */
+		ERROR (CHOLMOD_INVALID, "invalid format") ;
+		return (NULL) ;
+	    }
+	    else if (nitems == 2)
+	    {
+		/* this will be converted into a real matrix later */
+		xtype = CHOLMOD_PATTERN ;
+	    }
+	    else if (nitems == 3)
+	    {
+		xtype = CHOLMOD_REAL ;
+	    }
+	    else if (nitems == 4)
+	    {
+		xtype = CHOLMOD_COMPLEX ;
+	    }
+
+	    /* the rest of the lines should have the same number of entries */
+	    nshould = nitems ;
+
+	    /* allocate triplet matrix */
+	    T = CHOLMOD(allocate_triplet) (nrow, ncol, nnz2, stype,
+		    (xtype == CHOLMOD_PATTERN ? CHOLMOD_REAL : xtype), Common) ;
+	    if (Common->status < CHOLMOD_OK)
+	    {
+		/* out of memory */
+		return (NULL) ;
+	    }
+	    Ti = T->i ;
+	    Tj = T->j ;
+	    Tx = T->x ;
+	    T->nnz = nnz ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* save the entry in the triplet matrix */
+	/* ------------------------------------------------------------------ */
+
+	if (nitems != nshould || i < 0 || j < 0)
+	{
+	    /* wrong format, premature end-of-file, or negative indices */
+	    CHOLMOD(free_triplet) (&T, Common) ;
+	    ERROR (CHOLMOD_INVALID, "invalid matrix file") ;
+	    return (NULL) ;
+	}
+
+	Ti [k] = i ;
+	Tj [k] = j ;
+
+	if (i < j)
+	{
+	    /* this entry is in the upper triangular part */
+	    is_lower = FALSE ;
+	}
+	if (i > j)
+	{
+	    /* this entry is in the lower triangular part */
+	    is_upper = FALSE ;
+	}
+
+	if (xtype == CHOLMOD_REAL)
+	{
+	    Tx [k] = x ;
+	}
+	else if (xtype == CHOLMOD_COMPLEX)
+	{
+	    Tx [2*k  ] = x ;	/* real part */
+	    Tx [2*k+1] = z ;	/* imaginary part */
+	}
+
+	if (i == 0 || j == 0)
+	{
+	    one_based = FALSE ;
+	}
+
+	imax = MAX (i, imax) ;
+	jmax = MAX (j, jmax) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* convert to zero-based */
+    /* ---------------------------------------------------------------------- */
+
+    if (one_based)
+    {
+	/* input matrix is one-based; convert matrix to zero-based */
+	for (k = 0 ; k < (Int) nnz ; k++)
+	{
+	    Ti [k]-- ;
+	    Tj [k]-- ;
+	}
+    }
+
+    if (one_based ?
+	(imax >  (Int) nrow || jmax >  (Int) ncol) :
+	(imax >= (Int) nrow || jmax >= (Int) ncol))
+    {
+	/* indices out of range */
+	CHOLMOD(free_triplet) (&T, Common) ;
+	ERROR (CHOLMOD_INVALID, "indices out of range") ;
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the stype, if not yet known */
+    /* ---------------------------------------------------------------------- */
+
+    if (unknown)
+    {
+	if (is_lower && is_upper)
+	{
+	    /* diagonal matrix, symmetric with upper part present */
+	    stype = STYPE_SYMMETRIC_UPPER ;
+	}
+	else if (is_lower && !is_upper)
+	{
+	    /* symmetric, lower triangular part present */
+	    stype = STYPE_SYMMETRIC_LOWER ;
+	}
+	else if (!is_lower && is_upper)
+	{
+	    /* symmetric, upper triangular part present */
+	    stype = STYPE_SYMMETRIC_UPPER ;
+	}
+	else
+	{
+	    /* unsymmetric */
+	    stype = STYPE_UNSYMMETRIC ;
+	    extra = 0 ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* add the remainder of symmetric, skew-symmetric or Hermitian matrices */
+    /* ---------------------------------------------------------------------- */
+
+    /* note that this step is not done for real symmetric or complex Hermitian
+     * matrices, unless prefer_unsym is TRUE */
+    if (extra > 0)
+    {
+	p = nnz ;
+	for (k = 0 ; k < (Int) nnz ; k++)
+	{
+	    i = Ti [k] ;
+	    j = Tj [k] ;
+	    if (i != j)
+	    {
+		Ti [p] = j ;
+		Tj [p] = i ;
+		if (xtype == CHOLMOD_REAL)
+		{
+		    if (skew_symmetric)
+		    {
+			Tx [p] = -Tx [k] ;
+		    }
+		    else
+		    {
+			Tx [p] =  Tx [k] ;
+		    }
+		}
+		else if (xtype == CHOLMOD_COMPLEX)
+		{
+		    if (skew_symmetric)
+		    {
+			Tx [2*p  ] = -Tx [2*k ] ;
+			Tx [2*p+1] = -Tx [2*k+1] ;
+		    }
+		    else if (complex_symmetric)
+		    {
+			Tx [2*p  ] =  Tx [2*k ] ;
+			Tx [2*p+1] =  Tx [2*k+1] ;
+		    }
+		    else /* Hermitian */
+		    {
+			Tx [2*p  ] =  Tx [2*k ] ;
+			Tx [2*p+1] = -Tx [2*k+1] ;
+		    }
+		}
+		p++ ;
+	    }
+	}
+	T->nnz = p ;
+	nnz = p ;
+    }
+
+    T->stype = stype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* create values for a pattern-only matrix */
+    /* ---------------------------------------------------------------------- */
+
+    if (xtype == CHOLMOD_PATTERN)
+    {
+	if (stype == STYPE_UNSYMMETRIC || Common->prefer_binary)
+	{
+	    /* unsymmetric case, or binary case */
+	    for (k = 0 ; k < (Int) nnz ; k++)
+	    {
+		Tx [k] = 1 ;
+	    }
+	}
+	else
+	{
+	    /* compute the row and columm degrees (excluding the diagonal) */
+	    for (i = 0 ; i < (Int) nrow ; i++)
+	    {
+		Rdeg [i] = 0 ;
+	    }
+	    for (j = 0 ; j < (Int) ncol ; j++)
+	    {
+		Cdeg [j] = 0 ;
+	    }
+	    for (k = 0 ; k < (Int) nnz ; k++)
+	    {
+		i = Ti [k] ;
+		j = Tj [k] ;
+		if ((stype < 0 && i > j) || (stype > 0 && i < j))
+		{
+		    /* both a(i,j) and a(j,i) appear in the matrix */
+		    Rdeg [i]++ ;
+		    Cdeg [j]++ ;
+		    Rdeg [j]++ ;
+		    Cdeg [i]++ ;
+		}
+	    }
+	    /* assign the numerical values */
+	    for (k = 0 ; k < (Int) nnz ; k++)
+	    {
+		i = Ti [k] ;
+		j = Tj [k] ;
+		Tx [k] = (i == j) ? (1 + MAX (Rdeg [i], Cdeg [j])) : (-1) ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the new triplet matrix */
+    /* ---------------------------------------------------------------------- */
+
+    return (T) ;
+}
+
+
+/* ========================================================================== */
+/* === read_dense =========================================================== */
+/* ========================================================================== */
+
+/* Header has already been read in, including first line (nrow ncol).
+ * Read a dense matrix. */
+
+static cholmod_dense *read_dense
+(
+    /* ---- input ---- */
+    FILE *f,		    /* file to read from, must already be open */
+    size_t nrow,	    /* number of rows */
+    size_t ncol,	    /* number of columns */
+    int stype,		    /* stype from header */
+    /* ---- workspace */
+    char *buf,		    /* of size MAXLINE+1 */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double x, z ;
+    double *Xx ;
+    cholmod_dense *X ;
+    Int nitems, xtype, nshould, i, j, k, kup, first ;
+
+    /* ---------------------------------------------------------------------- */
+    /* quick return for empty matrix */
+    /* ---------------------------------------------------------------------- */
+
+    if (nrow == 0 || ncol == 0)
+    {
+	/* return an empty dense matrix */
+	return (CHOLMOD(zeros) (nrow, ncol, CHOLMOD_REAL, Common)) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* read the entries */
+    /* ---------------------------------------------------------------------- */
+
+    first = TRUE ;
+
+    for (j = 0 ; j < (Int) ncol ; j++)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* get the row index of the first entry in the file for column j */
+	/* ------------------------------------------------------------------ */
+
+	if (stype == STYPE_UNSYMMETRIC)
+	{
+	    i = 0 ;
+	}
+	else if (stype == STYPE_SKEW_SYMMETRIC)
+	{
+	    i = j+1 ;
+	}
+	else /* real symmetric or complex Hermitian lower */
+	{
+	    i = j ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* get column j */
+	/* ------------------------------------------------------------------ */
+
+	for ( ; i < (Int) nrow ; i++)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* get the next entry, skipping blank lines and comment lines */
+	    /* -------------------------------------------------------------- */
+
+	    x = 0 ;
+	    z = 0 ;
+	    for ( ; ; )
+	    {
+
+		if (!get_line (f, buf))
+		{
+		    /* premature end of file - not enough entries read in */
+		    ERROR (CHOLMOD_INVALID, "premature EOF") ;
+		    return (NULL) ;
+		}
+
+		if (is_blank_line (buf))
+		{
+		    /* blank line or comment */
+		    continue ;
+		}
+		nitems = sscanf (buf, "%lg %lg\n", &x, &z) ;
+		x = fix_inf (x) ;
+		z = fix_inf (z) ;
+		break ;
+	    }
+
+	    nitems = (nitems == EOF) ? 0 : nitems ;
+
+	    /* -------------------------------------------------------------- */
+	    /* for first entry: determine type and allocate dense matrix */
+	    /* -------------------------------------------------------------- */
+
+	    if (first)
+	    {
+		first = FALSE ;
+
+		if (nitems < 1 || nitems > 2)
+		{
+		    /* invalid matrix */
+		    ERROR (CHOLMOD_INVALID, "invalid format") ;
+		    return (NULL) ;
+		}
+		else if (nitems == 1)
+		{
+		    /* a real matrix */
+		    xtype = CHOLMOD_REAL ;
+		}
+		else if (nitems == 2)
+		{
+		    /* a complex matrix */
+		    xtype = CHOLMOD_COMPLEX ;
+		}
+
+		/* the rest of the lines should have same number of entries */
+		nshould = nitems ;
+
+		/* allocate the result */
+		X = CHOLMOD(zeros) (nrow, ncol, xtype, Common) ;
+		if (Common->status < CHOLMOD_OK)
+		{
+		    /* out of memory */
+		    return (NULL) ;
+		}
+		Xx = X->x ;
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* save the entry in the dense matrix */
+	    /* -------------------------------------------------------------- */
+
+	    if (nitems != nshould)
+	    {
+		/* wrong format or premature end-of-file */
+		CHOLMOD(free_dense) (&X, Common) ;
+		ERROR (CHOLMOD_INVALID, "invalid matrix file") ;
+		return (NULL) ;
+	    }
+
+	    k = i + j*nrow ;
+	    kup = j + i*nrow ;
+
+	    if (xtype == CHOLMOD_REAL)
+	    {
+		/* real matrix */
+		Xx [k] = x ;
+		if (k != kup)
+		{
+		    if (stype == STYPE_SYMMETRIC_LOWER)
+		    {
+			/* real symmetric matrix */
+			Xx [kup] = x ;
+		    }
+		    else if (stype == STYPE_SKEW_SYMMETRIC)
+		    {
+			/* real skew symmetric matrix */
+			Xx [kup] = -x ;
+		    }
+		}
+	    }
+	    else if (xtype == CHOLMOD_COMPLEX)
+	    {
+		Xx [2*k  ] = x ;	    /* real part */
+		Xx [2*k+1] = z ;	    /* imaginary part */
+		if (k != kup)
+		{
+		    if (stype == STYPE_SYMMETRIC_LOWER)
+		    {
+			/* complex Hermitian */
+			Xx [2*kup  ] = x ;	    /* real part */
+			Xx [2*kup+1] = -z ;	    /* imaginary part */
+		    }
+		    else if (stype == STYPE_SKEW_SYMMETRIC)
+		    {
+			/* complex skew symmetric */
+			Xx [2*kup  ] = -x ;	    /* real part */
+			Xx [2*kup+1] = -z ;	    /* imaginary part */
+		    }
+		    if (stype == STYPE_COMPLEX_SYMMETRIC_LOWER)
+		    {
+			/* complex symmetric */
+			Xx [2*kup  ] = x ;	    /* real part */
+			Xx [2*kup+1] = z ;	    /* imaginary part */
+		    }
+		}
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the new dense matrix */
+    /* ---------------------------------------------------------------------- */
+
+    return (X) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_read_triplet ================================================= */
+/* ========================================================================== */
+
+/* Read in a triplet matrix from a file. */
+
+cholmod_triplet *CHOLMOD(read_triplet)
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from, must already be open */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    char buf [MAXLINE+1] ;
+    size_t nrow, ncol, nnz ;
+    int stype, mtype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (f, NULL) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* read the header and first data line */
+    /* ---------------------------------------------------------------------- */
+
+    if (!read_header (f, buf, &mtype, &nrow, &ncol, &nnz, &stype) ||
+	mtype != CHOLMOD_TRIPLET)
+    {
+	/* invalid matrix - this function can only read in a triplet matrix */
+	ERROR (CHOLMOD_INVALID, "invalid format") ;
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* read the triplet matrix */
+    /* ---------------------------------------------------------------------- */
+
+    return (read_triplet (f, nrow, ncol, nnz, stype, FALSE, buf, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_read_sparse ================================================== */
+/* ========================================================================== */
+
+/* Read a sparse matrix from a file.  See cholmod_read_triplet for a discussion
+ * of the file format.
+ *
+ * If Common->prefer_upper is TRUE (the default case), a symmetric matrix is
+ * returned stored in upper-triangular form (A->stype == 1).
+ */
+
+cholmod_sparse *CHOLMOD(read_sparse)
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from, must already be open */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *A, *A2 ;
+    cholmod_triplet *T ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (f, NULL) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert to a sparse matrix in compressed-column form */
+    /* ---------------------------------------------------------------------- */
+
+    T = CHOLMOD(read_triplet) (f, Common) ;
+    A = CHOLMOD(triplet_to_sparse) (T, 0, Common) ;
+    CHOLMOD(free_triplet) (&T, Common) ;
+
+    if (Common->prefer_upper && A != NULL && A->stype == -1)
+    {
+	/* A=A' */
+	A2 = CHOLMOD(transpose) (A, 2, Common) ;
+	CHOLMOD(free_sparse) (&A, Common) ;
+	A = A2 ;
+    }
+    return (A) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_read_dense =================================================== */
+/* ========================================================================== */
+
+/* Read a dense matrix from a file. */
+
+cholmod_dense *CHOLMOD(read_dense)
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from, must already be open */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    char buf [MAXLINE+1] ;
+    size_t nrow, ncol, nnz ;
+    int stype, mtype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (f, NULL) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* read the header and first data line */
+    /* ---------------------------------------------------------------------- */
+
+    if (!read_header (f, buf, &mtype, &nrow, &ncol, &nnz, &stype) ||
+	mtype != CHOLMOD_DENSE)
+    {
+	/* invalid matrix - this function can only read in a dense matrix */
+	ERROR (CHOLMOD_INVALID, "invalid format") ;
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* read the dense matrix */
+    /* ---------------------------------------------------------------------- */
+
+    return (read_dense (f, nrow, ncol, stype, buf, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_read_matrix ================================================== */
+/* ========================================================================== */
+
+/* Read a triplet matrix, sparse matrix or a dense matrix from a file.  Returns
+ * a void pointer to either a cholmod_triplet, cholmod_sparse, or cholmod_dense
+ * object.  The type of object is passed back to the caller as the mtype
+ * argument. */
+
+void *CHOLMOD(read_matrix)
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from, must already be open */
+    int prefer,		/* If 0, a sparse matrix is always return as a
+			 *	cholmod_triplet form.  It can have any stype
+			 *	(symmetric-lower, unsymmetric, or
+			 *	symmetric-upper).
+			 * If 1, a sparse matrix is returned as an unsymmetric
+			 *	cholmod_sparse form (A->stype == 0), with both
+			 *	upper and lower triangular parts present.
+			 *	This is what the MATLAB mread mexFunction does,
+			 *	since MATLAB does not have an stype.
+			 * If 2, a sparse matrix is returned with an stype of 0
+			 *	or 1 (unsymmetric, or symmetric with upper part
+			 *	stored).
+			 * This argument has no effect for dense matrices.
+			 */
+    /* ---- output---- */
+    int *mtype,		/* CHOLMOD_TRIPLET, CHOLMOD_SPARSE or CHOLMOD_DENSE */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    void *G = NULL ;
+    cholmod_sparse *A, *A2 ;
+    cholmod_triplet *T ;
+    char buf [MAXLINE+1] ;
+    size_t nrow, ncol, nnz ;
+    int stype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (f, NULL) ;
+    RETURN_IF_NULL (mtype, NULL) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* read the header to determine the mtype */
+    /* ---------------------------------------------------------------------- */
+
+    if (!read_header (f, buf, mtype, &nrow, &ncol, &nnz, &stype))
+    {
+	/* invalid matrix */
+	ERROR (CHOLMOD_INVALID, "invalid format") ;
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* read a matrix */
+    /* ---------------------------------------------------------------------- */
+
+    if (*mtype == CHOLMOD_TRIPLET)
+    {
+	/* read in the triplet matrix */
+	T = read_triplet (f, nrow, ncol, nnz, stype, prefer == 1, buf, Common) ;
+	if (prefer == 0)
+	{
+	    /* return matrix in its original triplet form */
+	    G = T ;
+	}
+	else
+	{
+	    /* return matrix in a compressed-column form */
+	    A = CHOLMOD(triplet_to_sparse) (T, 0, Common) ;
+	    CHOLMOD(free_triplet) (&T, Common) ;
+	    if (A != NULL && prefer == 2 && A->stype == -1)
+	    {
+		/* convert A from symmetric-lower to symmetric-upper */
+		A2 = CHOLMOD(transpose) (A, 2, Common) ;
+		CHOLMOD(free_sparse) (&A, Common) ;
+		A = A2 ;
+	    }
+	    *mtype = CHOLMOD_SPARSE ;
+	    G = A ;
+	}
+    }
+    else if (*mtype == CHOLMOD_DENSE)
+    {
+	/* return a dense matrix */
+	G = read_dense (f, nrow, ncol, stype, buf, Common) ;
+    }
+    return (G) ;
+}
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Check/cholmod_write.c b/src/C/SuiteSparse/CHOLMOD/Check/cholmod_write.c
new file mode 100644
index 0000000..dc461ba
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Check/cholmod_write.c
@@ -0,0 +1,742 @@
+/* ========================================================================== */
+/* === Check/cholmod_write ================================================== */
+/* ========================================================================== */
+
+/* Write a matrix to a file in Matrix Market form.
+ *
+ * A can be sparse or full.
+ *
+ * If present and non-empty, A and Z must have the same dimension.  Z contains
+ * the explicit zero entries in the matrix (which MATLAB drops).  The entries
+ * of Z appear as explicit zeros in the output file.  Z is optional.  If it is
+ * an empty matrix it is ignored.  Z must be sparse or empty, if present.
+ * It is ignored if A is full.
+ *
+ * filename is the name of the output file.  comments is file whose
+ * contents are include after the Matrix Market header and before the first
+ * data line.  Ignored if an empty string or not present.
+ *
+ * Except for the workspace used by cholmod_symmetry (ncol integers) for
+ * the sparse case, these routines use no workspace at all.
+ */
+
+#ifndef NCHECK
+
+#include "cholmod_internal.h"
+#include "cholmod_check.h"
+#include <string.h>
+#include <ctype.h>
+
+#define MMLEN 1024
+#define MAXLINE MMLEN+6
+
+/* ========================================================================== */
+/* === include_comments ===================================================== */
+/* ========================================================================== */
+
+/* Read in the comments file, if it exists, and copy it to the Matrix Market
+ * file.  A "%" is prepended to each line.  Returns TRUE if successful, FALSE
+ * otherwise.
+ */
+
+static int include_comments (FILE *f, char *comments)
+{
+    FILE *cf = NULL ;
+    char buffer [MAXLINE] ;
+    int ok = TRUE ;
+    if (comments != NULL && comments [0] != '\0')
+    {
+	cf = fopen (comments, "r") ;
+	if (cf == NULL)
+	{
+	    return (FALSE) ;
+	}
+	while (ok && fgets (buffer, MAXLINE, cf) != NULL)
+	{
+	    /* ensure the line is not too long */
+	    buffer [MMLEN-1] = '\0' ;
+	    buffer [MMLEN-2] = '\n' ;
+	    ok = ok && (fprintf (f, "%%%s", buffer) > 0) ;
+	}
+	fclose (cf) ;
+    }
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === get_value ============================================================ */
+/* ========================================================================== */
+
+/* Get the pth value in the matrix. */
+
+static void get_value
+(
+    double *Ax,	    /* real values, or real/imag. for CHOLMOD_COMPLEX type */
+    double *Az,	    /* imaginary values for CHOLMOD_ZOMPLEX type */
+    Int p,	    /* get the pth entry */
+    Int xtype,	    /* A->xtype: pattern, real, complex, or zomplex */
+    double *x,	    /* the real part */
+    double *z	    /* the imaginary part */
+)
+{
+    switch (xtype)
+    {
+	case CHOLMOD_PATTERN:
+	    *x = 1 ;
+	    *z = 0 ;
+	    break ;
+
+	case CHOLMOD_REAL:
+	    *x = Ax [p] ;
+	    *z = 0 ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    *x = Ax [2*p] ;
+	    *z = Ax [2*p+1] ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    *x = Ax [p] ;
+	    *z = Az [p] ;
+	    break ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === print_value ========================================================== */
+/* ========================================================================== */
+
+/* Print a numeric value to the file, using the shortest format that ensures
+ * the value is written precisely.  Returns TRUE if successful, FALSE otherwise.
+ */ 
+
+static int print_value
+(
+    FILE *f,	    /* file to print to */
+    double x,	    /* value to print */
+    Int is_integer  /* TRUE if printing as an integer */
+)
+{
+    double y, z ;
+    char s [MAXLINE], *p ;
+    Int width, i, c, dest, src ;
+    int ok ;
+
+    if (is_integer)
+    {
+	i = (Int) x ;
+	ok = (fprintf (f, ID, i) > 0) ;
+	return (ok) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* handle Inf and NaN */
+    /* ---------------------------------------------------------------------- */
+
+    /* change -inf to -HUGE_DOUBLE, and change +inf and nan to +HUGE_DOUBLE */
+    if (CHOLMOD_IS_NAN (x) || x >= HUGE_DOUBLE)
+    {
+	x = HUGE_DOUBLE ;
+    }
+    else if (x <= -HUGE_DOUBLE)
+    {
+	x = -HUGE_DOUBLE ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* find the smallest acceptable precision */
+    /* ---------------------------------------------------------------------- */
+
+    for (width = 6 ; width < 20 ; width++)
+    {
+	sprintf (s, "%.*g", width, x) ;
+	sscanf (s, "%lg", &y) ;
+	if (x == y) break ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* shorten the string */
+    /* ---------------------------------------------------------------------- */
+
+    /* change "e+0" to "e", change "e+" to "e", and change "e-0" to "e-" */
+    for (i = 0 ; i < MAXLINE && s [i] != '\0' ; i++)
+    {
+	if (s [i] == 'e')
+	{
+	    if (s [i+1] == '+')
+	    {
+		dest = i+1 ;
+		if (s [i+2] == '0')
+		{
+		    /* delete characters s[i+1] and s[i+2] */
+		    src = i+3 ;
+		}
+		else
+		{
+		    /* delete characters s[i+1] */
+		    src = i+2 ;
+		}
+	    }
+	    else if (s [i+1] == '-')
+	    {
+		dest = i+2 ;
+		if (s [i+2] == '0')
+		{
+		    /* delete character s[i+2] */
+		    src = i+3 ;
+		}
+		else
+		{
+		    /* no change */
+		    break ;
+		}
+	    }
+	    while (s [src] != '\0')
+	    {
+		s [dest++] = s [src++] ;
+	    }
+	    s [dest] = '\0' ;
+	    break ;
+	}
+    }
+
+    /* delete the leading "0" if present and not necessary */
+    p = s ;
+    s [MAXLINE-1] = '\0' ;
+    i = strlen (s) ;
+    if (i > 2 && s [0] == '0' && s [1] == '.')
+    {
+	/* change "0.x" to ".x" */
+	p = s + 1 ;
+    }
+    else if (i > 3 && s [0] == '-' && s [1] == '0' && s [2] == '.')
+    {
+	/* change "-0.x" to "-.x" */
+	s [1] = '-' ;
+	p = s + 1 ;
+    }
+
+#if 0
+    /* double-check */
+    i = sscanf (p, "%lg", &z) ;
+    if (i != 1 || y != z)
+    {
+	/* oops! something went wrong in the "e+0" edit, above. */
+	/* this "cannot" happen */
+	sprintf (s, "%.*g", width, x) ;
+	p = s ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* print the value to the file */
+    /* ---------------------------------------------------------------------- */
+
+    ok = (fprintf (f, "%s", p) > 0) ;
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === print_triplet ======================================================== */
+/* ========================================================================== */
+
+/* Print a triplet, converting it to one-based.  Returns TRUE if successful,
+ * FALSE otherwise.
+ */
+
+static int print_triplet
+(
+    FILE *f,		/* file to print to */
+    Int is_binary,	/* TRUE if file is "pattern" */
+    Int is_complex,	/* TRUE if file is "complex" */
+    Int is_integer,	/* TRUE if file is "integer" */
+    Int i,		/* row index (zero-based) */
+    Int j,		/* column index (zero-based) */
+    double x,		/* real part */
+    double z		/* imaginary part */
+)
+{
+    int ok ; 
+    ok = (fprintf (f, ID " " ID, 1+i, 1+j) > 0) ;
+    if (!is_binary)
+    {
+	fprintf (f, " ") ;
+	ok = ok && print_value (f, x, is_integer) ;
+	if (is_complex)
+	{
+	    fprintf (f, " ") ;
+	    ok = ok && print_value (f, z, is_integer) ;
+	}
+    }
+    ok = ok && (fprintf (f, "\n") > 0) ;
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === ntriplets ============================================================ */
+/* ========================================================================== */
+
+/* Compute the number of triplets that will be printed to the file
+ * from the matrix A. */
+
+static Int ntriplets
+(
+    cholmod_sparse *A,	    /* matrix that will be printed */
+    Int is_sym		    /* TRUE if the file is symmetric (lower part only)*/
+)
+{
+    Int *Ap, *Ai, *Anz, packed, i, j, p, pend, ncol, stype, nz = 0 ;
+    if (A == NULL)
+    {
+	/* the Z matrix is NULL */
+	return (0) ;
+    }
+    stype = A->stype ;
+    Ap = A->p ;
+    Ai = A->i ;
+    Anz = A->nz ;
+    packed = A->packed ;
+    ncol = A->ncol ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	p = Ap [j] ;
+	pend = (packed) ? Ap [j+1] : p + Anz [j] ;
+	for ( ; p < pend ; p++)
+	{
+	    i = Ai [p] ;
+	    if ((stype < 0 && i >= j) || (stype == 0 && (i >= j || !is_sym)))
+	    {
+		/* CHOLMOD matrix is symmetric-lower (and so is the file);
+		 * or CHOLMOD matrix is unsymmetric and either A(i,j) is in
+		 * the lower part or the file is unsymmetric. */
+		nz++ ;
+	    }
+	    else if (stype > 0 && i <= j)
+	    {
+		/* CHOLMOD matrix is symmetric-upper, but the file is
+		 * symmetric-lower.  Need to transpose the entry. */
+		nz++ ;
+	    }
+	}
+    }
+    return (nz) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_write_sparse ================================================= */
+/* ========================================================================== */
+
+/* Write a sparse matrix to a file in Matrix Market format.   Optionally include
+ * comments, and print explicit zero entries given by the pattern of the Z
+ * matrix.  If not NULL, the Z matrix must have the same dimensions and stype
+ * as A.
+ *
+ * Returns the symmetry in which the matrix was printed (1 to 7, see the
+ * CHOLMOD_MM_* codes in CHOLMOD/Include/cholmod_core.h), or -1 on failure.
+ *
+ * If A and Z are sorted on input, and either unsymmetric (stype = 0) or
+ * symmetric-lower (stype < 0), and if A and Z do not overlap, then the triplets
+ * are sorted, first by column and then by row index within each column, with
+ * no duplicate entries.  If all the above holds except stype > 0, then the
+ * triplets are sorted by row first and then column.
+ */
+
+int CHOLMOD(write_sparse)
+(
+    /* ---- input ---- */
+    FILE *f,		    /* file to write to, must already be open */
+    cholmod_sparse *A,	    /* matrix to print */
+    cholmod_sparse *Z,	    /* optional matrix with pattern of explicit zeros */
+    char *comments,	    /* optional filename of comments to include */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double x, z ;
+    double *Ax, *Az ;
+    Int *Ap, *Ai, *Anz, *Zp, *Zi, *Znz ;
+    Int nrow, ncol, is_complex, symmetry, i, j, q, iz, p, nz, is_binary, stype,
+	is_integer, asym, is_sym, xtype, apacked, zpacked, pend, qend, k, zsym ;
+    int ok ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (EMPTY) ;
+    RETURN_IF_NULL (f, EMPTY) ;
+    RETURN_IF_NULL (A, EMPTY) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ;
+    if (Z != NULL && (Z->nrow == 0 || Z->ncol == 0))
+    {
+	/* Z is non-NULL but empty, so treat it as a NULL matrix */
+	Z = NULL ;
+    }
+    if (Z != NULL)
+    {
+	RETURN_IF_XTYPE_INVALID (Z, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ;
+	if (Z->nrow != A->nrow || Z->ncol != A->ncol || Z->stype != A->stype)
+	{
+	    ERROR (CHOLMOD_INVALID, "dimension or type of A and Z mismatch") ;
+	    return (EMPTY) ;
+	}
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get the A matrix */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;
+    Ai = A->i ;
+    Ax = A->x ;
+    Az = A->z ;
+    Anz = A->nz ;
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+    xtype = A->xtype ;
+    apacked = A->packed ;
+
+    if (xtype == CHOLMOD_PATTERN)
+    {
+	/* a CHOLMOD pattern matrix is printed as "pattern" in the file */
+	is_binary = TRUE ;
+	is_integer = FALSE ;
+	is_complex = FALSE ;
+    }
+    else if (xtype == CHOLMOD_REAL)
+    {
+	/* determine if a real matrix is in fact binary or integer */
+	is_binary = TRUE ;
+	is_integer = TRUE ;
+	is_complex = FALSE ;
+	for (j = 0 ; (is_binary || is_integer) && j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (apacked) ? Ap [j+1] : p + Anz [j] ;
+	    for ( ; (is_binary || is_integer) && p < pend ; p++)
+	    {
+		x = Ax [p] ;
+		if (x != 1)
+		{
+		    is_binary = FALSE ;
+		}
+		/* convert to Int and then back to double */
+		i = (Int) x ;
+		z = (double) i ;
+		if (z != x)
+		{
+		    is_integer = FALSE ;
+		}
+	    }
+	}
+    }
+    else
+    {
+	/* a CHOLMOD complex matrix is printed as "complex" in the file */
+	is_binary = FALSE ;
+	is_integer = FALSE ;
+	is_complex = TRUE ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get the Z matrix (only consider the pattern) */
+    /* ---------------------------------------------------------------------- */
+
+    Zp = NULL ;
+    Zi = NULL ;
+    Znz = NULL ;
+    zpacked = TRUE ;
+    if (Z != NULL)
+    {
+	Zp = Z->p ;
+	Zi = Z->i ;
+	Znz = Z->nz ;
+	zpacked = Z->packed ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the symmetry of A and Z */
+    /* ---------------------------------------------------------------------- */
+
+    stype = A->stype ;
+    if (A->nrow != A->ncol)
+    {
+	asym = CHOLMOD_MM_RECTANGULAR ;
+    }
+    else if (stype != 0)
+    {
+	/* CHOLMOD's A and Z matrices have a symmetric (and matching) stype.
+	 * Note that the diagonal is not checked. */
+	asym = is_complex ? CHOLMOD_MM_HERMITIAN : CHOLMOD_MM_SYMMETRIC ;
+    }
+    else if (!A->sorted)
+    {
+	/* A is in unsymmetric storage, but unsorted */
+	asym = CHOLMOD_MM_UNSYMMETRIC ;
+    }
+    else
+    {
+	/* CHOLMOD's stype is zero (stored in unsymmetric form) */
+	asym = EMPTY ;
+	zsym = EMPTY ;
+
+#ifndef NMATRIXOPS
+	/* determine if the matrices are in fact symmetric or Hermitian */
+	asym = CHOLMOD(symmetry) (A, 1, NULL, NULL, NULL, NULL, Common) ;
+	zsym = (Z == NULL) ? 999 :
+	       CHOLMOD(symmetry) (Z, 1, NULL, NULL, NULL, NULL, Common) ;
+#endif
+
+	if (asym == EMPTY || zsym <= CHOLMOD_MM_UNSYMMETRIC)
+	{
+	    /* not computed, out of memory, or Z is unsymmetric */
+	    asym = CHOLMOD_MM_UNSYMMETRIC ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* write the Matrix Market header */
+    /* ---------------------------------------------------------------------- */
+
+    ok = fprintf (f, "%%%%MatrixMarket matrix coordinate") > 0 ;
+
+    if (is_complex)
+    {
+	ok = ok && (fprintf (f, " complex") > 0) ;
+    }
+    else if (is_binary)
+    {
+	ok = ok && (fprintf (f, " pattern") > 0) ;
+    }
+    else if (is_integer)
+    {
+	ok = ok && (fprintf (f, " integer") > 0) ;
+    }
+    else
+    {
+	ok = ok && (fprintf (f, " real") > 0) ;
+    }
+
+    switch (asym)
+    {
+	case CHOLMOD_MM_RECTANGULAR:
+	case CHOLMOD_MM_UNSYMMETRIC:
+	    /* A is rectangular or unsymmetric */
+	    ok = ok && (fprintf (f, " general\n") > 0) ;
+	    is_sym = FALSE ;
+	    symmetry = CHOLMOD_MM_UNSYMMETRIC ;
+	    break ;
+
+	case CHOLMOD_MM_SYMMETRIC:
+	case CHOLMOD_MM_SYMMETRIC_POSDIAG:
+	    /* A is symmetric */
+	    ok = ok && (fprintf (f, " symmetric\n") > 0) ;
+	    is_sym = TRUE ;
+	    symmetry = CHOLMOD_MM_SYMMETRIC ;
+	    break ;
+
+	case CHOLMOD_MM_HERMITIAN:
+	case CHOLMOD_MM_HERMITIAN_POSDIAG:
+	    /* A is Hermitian */
+	    ok = ok && (fprintf (f, " Hermitian\n") > 0) ;
+	    is_sym = TRUE ;
+	    symmetry = CHOLMOD_MM_HERMITIAN ;
+	    break ;
+
+	case CHOLMOD_MM_SKEW_SYMMETRIC:
+	    /* A is skew symmetric */
+	    ok = ok && (fprintf (f, " skew-symmetric\n") > 0) ;
+	    is_sym = TRUE ;
+	    symmetry = CHOLMOD_MM_SKEW_SYMMETRIC ;
+	    break ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* include the comments if present */
+    /* ---------------------------------------------------------------------- */
+
+    ok = ok && include_comments (f, comments) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* write a sparse matrix (A and Z) */
+    /* ---------------------------------------------------------------------- */
+
+    nz = ntriplets (A, is_sym) + ntriplets (Z, is_sym) ;
+
+    /* write the first data line, with nrow, ncol, and # of triplets */
+    ok = ok && (fprintf (f, ID " " ID " " ID "\n", nrow, ncol, nz) > 0) ;
+
+    for (j = 0 ; ok && j < ncol ; j++)
+    {
+	/* merge column of A and Z */
+	p = Ap [j] ;
+	pend = (apacked) ? Ap [j+1] : p + Anz [j] ;
+	q = (Z == NULL) ? 0 : Zp [j] ;
+	qend = (Z == NULL) ? 0 : ((zpacked) ? Zp [j+1] : q + Znz [j]) ;
+	while (ok)
+	{
+	    /* get the next row index from A and Z */
+	    i  = (p < pend) ? Ai [p] : (nrow+1) ;
+	    iz = (q < qend) ? Zi [q] : (nrow+2) ;
+	    if (i <= iz)
+	    {
+		/* get A(i,j), or quit if both A and Z are exhausted */
+		if (i == nrow+1) break ;
+		get_value (Ax, Az, p, xtype, &x, &z) ;
+		p++ ;
+	    }
+	    else
+	    {
+		/* get Z(i,j) */
+		i = iz ;
+		x = 0 ;
+		z = 0 ;
+		q++ ;
+	    }
+	    if ((stype < 0 && i >= j) || (stype == 0 && (i >= j || !is_sym)))
+	    {
+		/* CHOLMOD matrix is symmetric-lower (and so is the file);
+		 * or CHOLMOD matrix is unsymmetric and either A(i,j) is in
+		 * the lower part or the file is unsymmetric. */
+		ok = ok && print_triplet (f, is_binary, is_complex, is_integer,
+		    i,j, x,z) ;
+	    }
+	    else if (stype > 0 && i <= j)
+	    {
+		/* CHOLMOD matrix is symmetric-upper, but the file is
+		 * symmetric-lower.  Need to transpose the entry.   If the
+		 * matrix is real, the complex part is ignored.  If the matrix
+		 * is complex, it Hermitian.
+		 */
+		ASSERT (IMPLIES (is_complex, asym == CHOLMOD_MM_HERMITIAN)) ;
+		if (z != 0)
+		{
+		    z = -z ;
+		}
+		ok = ok && print_triplet (f, is_binary, is_complex, is_integer,
+		    j,i, x,z) ;
+	    }
+	}
+    }
+
+    if (!ok)
+    {
+	ERROR (CHOLMOD_INVALID, "error reading/writing file") ;
+	return (EMPTY) ;
+    }
+
+    return (asym) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_write_dense ================================================== */
+/* ========================================================================== */
+
+/* Write a dense matrix to a file in Matrix Market format.   Optionally include
+ * comments.  Returns > 0 if successful, -1 otherwise (1 if rectangular, 2 if
+ * square).  Future versions may return 1 to 7 on success (a CHOLMOD_MM_* code,
+ * just as cholmod_write_sparse does).
+ *
+ * A dense matrix is written in "general" format; symmetric formats in the
+ * Matrix Market standard are not exploited.
+ */
+
+int CHOLMOD(write_dense)
+(
+    /* ---- input ---- */
+    FILE *f,		    /* file to write to, must already be open */
+    cholmod_dense *X,	    /* matrix to print */
+    char *comments,	    /* optional filename of comments to include */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double x, z ;
+    FILE *cf ;
+    double *Xx, *Xz ;
+    Int nrow, ncol, is_complex, i, j, nz, xtype, p ;
+    int ok ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (EMPTY) ;
+    RETURN_IF_NULL (f, EMPTY) ;
+    RETURN_IF_NULL (X, EMPTY) ;
+    RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, EMPTY) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get the X matrix */
+    /* ---------------------------------------------------------------------- */
+
+    Xx = X->x ;
+    Xz = X->z ;
+    nrow = X->nrow ;
+    ncol = X->ncol ;
+    xtype = X->xtype ;
+    is_complex = (xtype == CHOLMOD_COMPLEX) || (xtype == CHOLMOD_ZOMPLEX) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* write the Matrix Market header */
+    /* ---------------------------------------------------------------------- */
+
+    ok = (fprintf (f, "%%%%MatrixMarket matrix array") > 0) ;
+    if (is_complex)
+    {
+	ok = ok && (fprintf (f, " complex general\n") > 0) ;
+    }
+    else
+    {
+	ok = ok && (fprintf (f, " real general\n") > 0) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* include the comments if present */
+    /* ---------------------------------------------------------------------- */
+
+    ok = ok && include_comments (f, comments) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* write a dense matrix */
+    /* ---------------------------------------------------------------------- */
+
+    /* write the first data line, with nrow and ncol */
+    ok = ok && (fprintf (f, ID " " ID "\n", nrow, ncol) > 0) ;
+
+    Xx = X->x ;
+    Xz = X->z ;
+    for (j = 0 ; ok && j < ncol ; j++)
+    {
+	for (i = 0 ; ok && i < nrow ; i++)
+	{
+	    p = i + j*nrow ;
+	    get_value (Xx, Xz, p, xtype, &x, &z) ;
+	    ok = ok && print_value (f, x, FALSE) ;
+	    if (is_complex)
+	    {
+		ok = ok && (fprintf (f, " ") > 0) ;
+		ok = ok && print_value (f, z, FALSE) ;
+	    }
+	    ok = ok && (fprintf (f, "\n") > 0) ;
+	}
+    }
+
+    if (!ok)
+    {
+	ERROR (CHOLMOD_INVALID, "error reading/writing file") ;
+	return (EMPTY) ;
+    }
+
+    return ((nrow == ncol) ? CHOLMOD_MM_UNSYMMETRIC : CHOLMOD_MM_RECTANGULAR) ;
+}
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Check/lesser.txt b/src/C/SuiteSparse/CHOLMOD/Check/lesser.txt
new file mode 100644
index 0000000..8add30a
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Check/lesser.txt
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+

+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+

+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+

+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+

+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+

+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+

+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+

+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+

+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/License.txt b/src/C/SuiteSparse/CHOLMOD/Cholesky/License.txt
new file mode 100644
index 0000000..b444856
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/License.txt
@@ -0,0 +1,24 @@
+CHOLMOD/Cholesky module, Copyright (C) 2005-2006, Timothy A. Davis
+CHOLMOD is also available under other licenses; contact authors for details.
+http://www.cise.ufl.edu/research/sparse
+
+Note that this license is for the CHOLMOD/Cholesky module only.
+All CHOLMOD modules are licensed separately.
+
+
+--------------------------------------------------------------------------------
+
+
+This Module is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This Module is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this Module; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_amd.c b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_amd.c
new file mode 100644
index 0000000..09f8ec1
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_amd.c
@@ -0,0 +1,212 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_amd ================================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD interface to the AMD ordering routine.  Orders A if the matrix is
+ * symmetric.  On output, Perm [k] = i if row/column i of A is the kth
+ * row/column of P*A*P'.  This corresponds to A(p,p) in MATLAB notation.
+ *
+ * If A is unsymmetric, cholmod_amd orders A*A'.  On output, Perm [k] = i if
+ * row/column i of A*A' is the kth row/column of P*A*A'*P'.  This corresponds to
+ * A(p,:)*A(p,:)' in MATLAB notation.  If f is present, A(p,f)*A(p,f)' is
+ * ordered.
+ *
+ * Computes the flop count for a subsequent LL' factorization, the number
+ * of nonzeros in L, and the number of nonzeros in the matrix ordered (A,
+ * A*A' or A(:,f)*A(:,f)').
+ *
+ * workspace: Iwork (6*nrow). Head (nrow).
+ *
+ * Allocates a temporary copy of A+A' or A*A' (with
+ * both upper and lower triangular parts) as input to AMD.
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex)
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "amd.h"
+#include "cholmod_cholesky.h"
+
+#if (!defined (AMD_VERSION) || (AMD_VERSION < AMD_VERSION_CODE (2,0)))
+#error "AMD v2.0 or later is required"
+#endif
+
+/* ========================================================================== */
+/* === cholmod_amd ========================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(amd)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- output --- */
+    Int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double Info [AMD_INFO], Control2 [AMD_CONTROL], *Control ;
+    Int *Cp, *Len, *Nv, *Head, *Elen, *Degree, *Wi, *Iwork, *Next ;
+    cholmod_sparse *C ;
+    Int j, n, cnz ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    n = A->nrow ;
+
+    RETURN_IF_NULL (Perm, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    if (n == 0)
+    {
+	/* nothing to do */
+	Common->fl = 0 ;
+	Common->lnz = 0 ;
+	Common->anz = 0 ;
+	return (TRUE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* Note: this is less than the space used in cholmod_analyze, so if
+     * cholmod_amd is being called by that routine, no space will be
+     * allocated.
+     */
+
+    /* s = MAX (6*n, A->ncol) */
+    s = CHOLMOD(mult_size_t) (n, 6, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+    s = MAX (s, A->ncol) ;
+
+    CHOLMOD(allocate_work) (n, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+
+    Iwork  = Common->Iwork ;
+    Degree = Iwork ;			/* size n */
+    Wi     = Iwork + n ;		/* size n */
+    Len    = Iwork + 2*((size_t) n) ;	/* size n */
+    Nv     = Iwork + 3*((size_t) n) ;   /* size n */
+    Next   = Iwork + 4*((size_t) n) ;   /* size n */
+    Elen   = Iwork + 5*((size_t) n) ;   /* size n */
+
+    Head = Common->Head ;   /* size n+1, but only n is used */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the input matrix for AMD */
+    /* ---------------------------------------------------------------------- */
+
+    if (A->stype == 0)
+    {
+	/* C = A*A' or A(:,f)*A(:,f)', add extra space of nnz(C)/2+n to C */
+	C = CHOLMOD(aat) (A, fset, fsize, -2, Common) ;
+    }
+    else
+    {
+	/* C = A+A', but use only the upper triangular part of A if A->stype = 1
+	 * and only the lower part of A if A->stype = -1.  Add extra space of
+	 * nnz(C)/2+n to C. */
+	C = CHOLMOD(copy) (A, 0, -2, Common) ;
+    }
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory, fset invalid, or other error */
+	return (FALSE) ;
+    }
+
+    Cp = C->p ;
+    for (j = 0 ; j < n ; j++)
+    {
+	Len [j] = Cp [j+1] - Cp [j] ;
+    }
+
+    /* C does not include the diagonal, and both upper and lower parts.
+     * Common->anz includes the diagonal, and just the lower part of C */
+    cnz = Cp [n] ;
+    Common->anz = cnz / 2 + n ;
+
+    /* ---------------------------------------------------------------------- */
+    /* order C using AMD */
+    /* ---------------------------------------------------------------------- */
+
+    /* get parameters */
+    if (Common->current < 0 || Common->current >= CHOLMOD_MAXMETHODS)
+    {
+	/* use AMD defaults */
+	Control = NULL ;
+    }
+    else
+    {
+	Control = Control2 ;
+	Control [AMD_DENSE] = Common->method [Common->current].prune_dense ;
+	Control [AMD_AGGRESSIVE] = Common->method [Common->current].aggressive ;
+    }
+
+    /* AMD_2 does not use amd_malloc and amd_free, but set these pointers just
+     * be safe. */
+    amd_malloc = Common->malloc_memory ;
+    amd_free = Common->free_memory ;
+    amd_calloc = Common->calloc_memory ;
+    amd_realloc = Common->realloc_memory ;
+
+    /* AMD_2 doesn't print anything either, but future versions might,
+     * so set the amd_printf pointer too. */
+    amd_printf = Common->print_function ;
+
+#ifdef LONG
+    amd_l2 (n, C->p,  C->i, Len, C->nzmax, cnz, Nv, Next, Perm, Head, Elen,
+	    Degree, Wi, Control, Info) ;
+#else
+    amd_2 (n, C->p,  C->i, Len, C->nzmax, cnz, Nv, Next, Perm, Head, Elen,
+	    Degree, Wi, Control, Info) ;
+#endif
+
+    /* LL' flop count.  Need to subtract n for LL' flop count.  Note that this
+     * is a slight upper bound which is often exact (see AMD/Source/amd_2.c for
+     * details).  cholmod_analyze computes an exact flop count and fill-in. */
+    Common->fl = Info [AMD_NDIV] + 2 * Info [AMD_NMULTSUBS_LDL] + n ;
+
+    /* Info [AMD_LNZ] excludes the diagonal */
+    Common->lnz = n + Info [AMD_LNZ] ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free the AMD workspace and clear the persistent workspace in Common */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (IMPLIES (Common->status == CHOLMOD_OK,
+		CHOLMOD(dump_perm) (Perm, n, n, "AMD2 perm", Common))) ;
+    CHOLMOD(free_sparse) (&C, Common) ;
+    for (j = 0 ; j <= n ; j++)
+    {
+	Head [j] = EMPTY ;
+    }
+    return (TRUE) ;
+}
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_analyze.c b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_analyze.c
new file mode 100644
index 0000000..19ce5b4
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_analyze.c
@@ -0,0 +1,896 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_analyze ============================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Order and analyze a matrix (either simplicial or supernodal), in prepartion
+ * for numerical factorization via cholmod_factorize or via the "expert"
+ * routines cholmod_rowfac and cholmod_super_numeric.
+ *
+ * symmetric case:    A or A(p,p)
+ * unsymmetric case:  AA', A(p,:)*A(p,:)', A(:,f)*A(:,f)', or A(p,f)*A(p,f)'
+ *
+ * For the symmetric case, only the upper or lower triangular part of A is
+ * accessed (depending on the type of A).  LL'=A (or permuted A) is analzed.
+ * For the unsymmetric case (LL'=AA' or permuted A).
+ *
+ * There can be no duplicate entries in p or f.  p is of length m if A is
+ * m-by-n.  f can be length 0 to n.
+ *
+ * In both cases, the columns of A need not be sorted.  A can be in packed
+ * or unpacked form.
+ *
+ * Ordering options include:
+ *
+ *	natural:    A is not permuted to reduce fill-in
+ *	given:	    a permutation can be provided to this routine (UserPerm)
+ *	AMD:	    approximate minumum degree (AMD for the symmetric case,
+ *		    COLAMD for the AA' case).
+ *	METIS:	    nested dissection with METIS_NodeND
+ *	NESDIS:	    nested dissection using METIS_NodeComputeSeparator,
+ *		    typically followed by a constrained minimum degree
+ *		    (CAMD for the symmetric case, CCOLAMD for the AA' case).
+ *
+ * Multiple ordering options can be tried (up to 9 of them), and the best one
+ * is selected (the one that gives the smallest number of nonzeros in the
+ * simplicial factor L).  If one method fails, cholmod_analyze keeps going, and
+ * picks the best among the methods that succeeded.  This routine fails (and
+ * returns NULL) if either initial memory allocation fails, all ordering methods
+ * fail, or the supernodal analysis (if requested) fails.  By default, the 9
+ * methods available are:
+ *
+ *	1) given permutation (skipped if UserPerm is NULL)
+ *	2) AMD (symmetric case) or COLAMD (unsymmetric case)
+ *	3) METIS with default parameters
+ *	4) NESDIS with default parameters (stopping the partitioning when
+ *	    the graph is of size nd_small = 200 or less, remove nodes with
+ *	    more than max (16, prune_dense * sqrt (n)) nodes where
+ *	    prune_dense = 10, and follow partitioning with CCOLAMD, a
+ *	    constrained minimum degree ordering).
+ *	5) natural
+ *	6) NESDIS, nd_small = 20000, prune_dense = 10
+ *	7) NESDIS, nd_small =     4, prune_dense = 10, no min degree
+ *	8) NESDIS, nd_small =   200, prune_dense = 0
+ *	9) COLAMD for A*A' or AMD for A
+ *
+ * By default, the first two are tried, and METIS is tried if AMD reports a high
+ * flop count and fill-in.  Let fl denote the flop count for the AMD, ordering,
+ * nnz(L) the # of nonzeros in L, and nnz(tril(A)) (or A*A').  If
+ * fl/nnz(L) >= 500 and nnz(L)/nnz(tril(A)) >= 5, then METIS is attempted.  The
+ * best ordering is used (UserPerm if given, AMD, and METIS if attempted).  If
+ * you do not have METIS, only the first two will be tried (user permutation,
+ * if provided, and AMD/COLAMD).  This default behavior is obtained when
+ * Common->nmethods is zero.  In this case, methods 0, 1, and 2 in
+ * Common->method [..] are reset to User-provided, AMD, and METIS (or NESDIS
+ * if Common->default_nesdis is set to the non-default value of TRUE),
+ * respectively.
+ *
+ * You can modify these 9 methods and the number of methods tried by changing
+ * parameters in the Common argument.  If you know the best ordering for your
+ * matrix, set Common->nmethods to 1 and set Common->method[0].ordering to the
+ * requested ordering method.  Parameters for each method can also be modified
+ * (refer to cholmod.h for details).
+ *
+ * Note that it is possible for METIS to terminate your program if it runs out
+ * of memory.  This is not the case for any CHOLMOD or minimum degree ordering
+ * routine (AMD, COLAMD, CAMD, CCOLAMD, or CSYMAMD).  Since NESDIS relies on
+ * METIS, it too can terminate your program.
+ *
+ * The factor L is returned as simplicial symbolic (L->is_super FALSE) if
+ * Common->supernodal <= CHOLMOD_SIMPLICIAL (0) or as supernodal symbolic if
+ * Common->supernodal >= CHOLMOD_SUPERNODAL (2).  If Common->supernodal is
+ * equal to CHOLMOD_AUTO (1), then L is simplicial if the flop count per
+ * nonzero in L is less than Common->supernodal_switch (default: 40), and
+ * is returned as a supernodal factor otherwise.
+ *
+ * In both cases, L->xtype is CHOLMOD_PATTERN.
+ * A subsequent call to cholmod_factorize will perform a
+ * simplicial or supernodal factorization, depending on the type of L.
+ *
+ * For the simplicial case, L contains the fill-reducing permutation (L->Perm)
+ * and the counts of nonzeros in each column of L (L->ColCount).  For the
+ * supernodal case, L also contains the nonzero pattern of each supernode.
+ *
+ * workspace: Flag (nrow), Head (nrow+1)
+ *	if symmetric:   Iwork (6*nrow)
+ *	if unsymmetric: Iwork (6*nrow+ncol).
+ *	calls various ordering routines, which typically allocate O(nnz(A))
+ *	temporary workspace ((2 to 3)*nnz(A) * sizeof (Int) is typical, but it
+ *	can be much higher if A*A' must be explicitly formed for METIS).  Also
+ *	allocates up to 2 temporary (permuted/transpose) copies of the nonzero
+ *	pattern of A, and up to 3*n*sizeof(Int) additional workspace.
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex)
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+#ifndef NSUPERNODAL
+#include "cholmod_supernodal.h"
+#endif
+
+#ifndef NPARTITION
+#include "cholmod_partition.h"
+#endif
+
+
+/* ========================================================================== */
+/* === cholmod_analyze ====================================================== */
+/* ========================================================================== */
+
+/* Orders and analyzes A, AA', PAP', or PAA'P' and returns a symbolic factor
+ * that can later be passed to cholmod_factorize. */
+
+cholmod_factor *CHOLMOD(analyze)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order and analyze */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    return (CHOLMOD(analyze_p) (A, NULL, NULL, 0, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === permute_matrices ===================================================== */
+/* ========================================================================== */
+
+/* Permute and transpose a matrix.  Allocates the A1 and A2 matrices, if needed,
+ * or returns them as NULL if not needed.
+ */
+
+static int permute_matrices
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to permute */
+    Int ordering,	/* ordering method used */
+    Int *Perm,		/* fill-reducing permutation */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    Int do_rowcolcounts,/* if TRUE, compute both S and F.  If FALSE, only
+			 * S is needed for the symmetric case, and only F for
+			 * the unsymmetric case */
+    /* ---- output --- */
+    cholmod_sparse **A1_handle,	    /* see comments below for A1, A2, S, F */
+    cholmod_sparse **A2_handle,
+    cholmod_sparse **S_handle,
+    cholmod_sparse **F_handle,
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *A1, *A2, *S, *F ;
+
+    *A1_handle = NULL ;
+    *A2_handle = NULL ;
+    *S_handle = NULL ;
+    *F_handle = NULL ;
+    A1 = NULL ;
+    A2 = NULL ;
+
+    if (ordering == CHOLMOD_NATURAL)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* natural ordering of A */
+	/* ------------------------------------------------------------------ */
+
+	if (A->stype < 0)
+	{
+	    /* symmetric lower case: A already in lower form, so S=A' */
+	    /* workspace: Iwork (nrow) */
+	    A2 = CHOLMOD(ptranspose) (A, 0, NULL, NULL, 0, Common) ;
+	    F = A ;
+	    S = A2 ;
+	}
+	else if (A->stype > 0)
+	{
+	    /* symmetric upper case: F = pattern of triu (A)', S = A */
+	    /* workspace: Iwork (nrow) */
+	    if (do_rowcolcounts)
+	    {
+		/* F not needed for symmetric case if do_rowcolcounts FALSE */
+		A1 = CHOLMOD(ptranspose) (A, 0, NULL, fset, fsize, Common) ;
+	    }
+	    F = A1 ;
+	    S = A ;
+	}
+	else
+	{
+	    /* unsymmetric case: F = pattern of A (:,f)',  S = A */
+	    /* workspace: Iwork (nrow if no fset, MAX(nrow,ncol) if fset) */
+	    A1 = CHOLMOD(ptranspose) (A, 0, NULL, fset, fsize, Common) ;
+	    F = A1 ;
+	    S = A ;
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* A is permuted */
+	/* ------------------------------------------------------------------ */
+
+	if (A->stype < 0)
+	{
+	    /* symmetric lower case: S = tril (A (p,p))' and F = S' */
+	    /* workspace: Iwork (2*nrow) */
+	    A2 = CHOLMOD(ptranspose) (A, 0, Perm, NULL, 0, Common) ;
+	    S = A2 ;
+	    /* workspace: Iwork (nrow) */
+	    if (do_rowcolcounts)
+	    {
+		/* F not needed for symmetric case if do_rowcolcounts FALSE */
+		A1 = CHOLMOD(ptranspose) (A2, 0, NULL, NULL, 0, Common) ;
+	    }
+	    F = A1 ;
+	}
+	else if (A->stype > 0)
+	{
+	    /* symmetric upper case: F = triu (A (p,p))' and S = F' */
+	    /* workspace: Iwork (2*nrow) */
+	    A1 = CHOLMOD(ptranspose) (A, 0, Perm, NULL, 0, Common) ;
+	    F = A1 ;
+	    /* workspace: Iwork (nrow) */
+	    A2 = CHOLMOD(ptranspose) (A1, 0, NULL, NULL, 0, Common) ;
+	    S = A2 ;
+	}
+	else
+	{
+	    /* unsymmetric case:     F = A (p,f)'         and S = F' */
+	    /* workspace: Iwork (nrow if no fset, MAX(nrow,ncol) if fset) */
+	    A1 = CHOLMOD(ptranspose) (A, 0, Perm, fset, fsize, Common) ;
+	    F = A1 ;
+	    if (do_rowcolcounts)
+	    {
+		/* S not needed for unsymmetric case if do_rowcolcounts FALSE */
+		/* workspace: Iwork (nrow) */
+		A2 = CHOLMOD(ptranspose) (A1, 0, NULL, NULL, 0, Common) ;
+	    }
+	    S = A2 ;
+	}
+    }
+
+    /* If any cholmod_*transpose fails, one or more matrices will be NULL */
+    *A1_handle = A1 ;
+    *A2_handle = A2 ;
+    *S_handle = S ;
+    *F_handle = F ;
+    return (Common->status == CHOLMOD_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_analyze_ordering ============================================= */
+/* ========================================================================== */
+
+/* Given a matrix A and its fill-reducing permutation, compute the elimination
+ * tree, its (non-weighted) postordering, and the number of nonzeros in each
+ * column of L.  Also computes the flop count, the total nonzeros in L, and
+ * the nonzeros in A (Common->fl, Common->lnz, and Common->anz).
+ *
+ * The column counts of L, flop count, and other statistics from
+ * cholmod_rowcolcounts are not computed if ColCount is NULL.
+ *
+ * workspace: Iwork (2*nrow if symmetric, 2*nrow+ncol if unsymmetric),
+ *	Flag (nrow), Head (nrow+1)
+ */
+
+int CHOLMOD(analyze_ordering)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    int ordering,	/* ordering method used */
+    Int *Perm,		/* size n, fill-reducing permutation to analyze */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- output --- */
+    Int *Parent,	/* size n, elimination tree */
+    Int *Post,		/* size n, postordering of elimination tree */
+    Int *ColCount,	/* size n, nnz in each column of L */
+    /* ---- workspace  */
+    Int *First,		/* size nworkspace for cholmod_postorder */
+    Int *Level,		/* size n workspace for cholmod_postorder */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *A1, *A2, *S, *F ;
+    Int n, ok, do_rowcolcounts ;
+
+    /* check inputs */
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+
+    n = A->nrow ;
+
+    do_rowcolcounts = (ColCount != NULL) ;
+
+    /* permute A according to Perm and fset */
+    ok = permute_matrices (A, ordering, Perm, fset, fsize, do_rowcolcounts,
+	    &A1, &A2, &S, &F, Common) ;
+
+    /* find etree of S (symmetric upper/lower case) or F (unsym case) */
+    /* workspace: symmmetric: Iwork (nrow), unsym: Iwork (nrow+ncol) */
+    ok = ok && CHOLMOD(etree) (A->stype ? S:F, Parent, Common) ;
+
+    /* postorder the etree (required by cholmod_rowcolcounts) */
+    /* workspace: Iwork (2*nrow) */
+    ok = ok && (CHOLMOD(postorder) (Parent, n, NULL, Post, Common) == n) ;
+
+    /* cholmod_postorder doesn't set Common->status if it returns < n */
+    Common->status = (!ok && Common->status == CHOLMOD_OK) ?
+	CHOLMOD_INVALID : Common->status ;
+
+    /* analyze LL'=S or SS' or S(:,f)*S(:,f)' */
+    /* workspace:
+     *	if symmetric:   Flag (nrow), Iwork (2*nrow)
+     *	if unsymmetric: Flag (nrow), Iwork (2*nrow+ncol), Head (nrow+1)
+     */
+    if (do_rowcolcounts)
+    {
+	ok = ok && CHOLMOD(rowcolcounts) (A->stype ? F:S, fset, fsize, Parent,
+	    Post, NULL, ColCount, First, Level, Common) ;
+    }
+
+    /* free temporary matrices and return result */
+    CHOLMOD(free_sparse) (&A1, Common) ;
+    CHOLMOD(free_sparse) (&A2, Common) ;
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === Free workspace and return L ========================================== */
+/* ========================================================================== */
+
+#define FREE_WORKSPACE_AND_RETURN \
+{ \
+    Common->no_workspace_reallocate = FALSE ; \
+    CHOLMOD(free) (n, sizeof (Int), Lparent,  Common) ; \
+    CHOLMOD(free) (n, sizeof (Int), Perm,     Common) ; \
+    CHOLMOD(free) (n, sizeof (Int), ColCount, Common) ; \
+    if (Common->status < CHOLMOD_OK) \
+    { \
+	CHOLMOD(free_factor) (&L, Common) ; \
+    } \
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; \
+    return (L) ; \
+}
+
+
+/* ========================================================================== */
+/* === cholmod_analyze_p ==================================================== */
+/* ========================================================================== */
+
+/* Orders and analyzes A, AA', PAP', PAA'P', FF', or PFF'P and returns a
+ * symbolic factor that can later be passed to cholmod_factorize, where
+ * F = A(:,fset) if fset is not NULL and A->stype is zero.
+ * UserPerm is tried if non-NULL.  */
+
+cholmod_factor *CHOLMOD(analyze_p)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order and analyze */
+    Int *UserPerm,	/* user-provided permutation, size A->nrow */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double lnz_best ;
+    Int *First, *Level, *Work4n, *Cmember, *CParent, *ColCount, *Lperm, *Parent,
+	*Post, *Perm, *Lparent, *Lcolcount ;
+    cholmod_factor *L ;
+    Int k, n, ordering, method, nmethods, status, default_strategy, ncol, uncol,
+	skip_analysis, skip_best ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ;
+    Common->status = CHOLMOD_OK ;
+    status = CHOLMOD_OK ;
+    Common->selected = EMPTY ;
+    Common->called_nd = FALSE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    n = A->nrow ;
+    ncol = A->ncol ;
+    uncol = (A->stype == 0) ? (A->ncol) : 0 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* set the default strategy */
+    /* ---------------------------------------------------------------------- */
+
+    lnz_best = (double) EMPTY ;
+    skip_best = FALSE ;
+    nmethods = MIN (Common->nmethods, CHOLMOD_MAXMETHODS) ;
+    nmethods = MAX (0, nmethods) ;
+    PRINT1 (("nmethods "ID"\n", nmethods)) ;
+
+    default_strategy = (nmethods == 0) ;
+    if (default_strategy)
+    {
+	/* default strategy: try UserPerm, if given.  Try AMD for A, or COLAMD
+	 * to order A*A'.  Try METIS for the symmetric case only if AMD reports
+	 * a high degree of fill-in and flop count.  Always try METIS for the
+	 * unsymmetric case.  METIS is not tried if the Partition Module
+	 * isn't installed.   If Common->default_nesdis is TRUE, then NESDIS
+	 * is used as the 3rd ordering instead. */
+	Common->method [0].ordering = CHOLMOD_GIVEN ;/* skip if UserPerm NULL */
+	Common->method [1].ordering = CHOLMOD_AMD ;
+	Common->method [2].ordering = 
+	    (Common->default_nesdis ? CHOLMOD_NESDIS : CHOLMOD_METIS) ;
+#ifndef NPARTITION
+	nmethods = 3 ;
+#else
+	nmethods = 2 ;
+#endif
+    }
+
+#ifdef NSUPERNODAL
+    /* CHOLMOD Supernodal module not installed, just do simplicial analysis */
+    Common->supernodal = CHOLMOD_SIMPLICIAL ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* Note: enough space needs to be allocated here so that routines called by
+     * cholmod_analyze do not reallocate the space.
+     */
+
+    /* s = 6*n + uncol */
+    s = CHOLMOD(mult_size_t) (n, 6, &ok) ;
+    s = CHOLMOD(add_size_t) (s, uncol, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (NULL) ;
+    }
+
+    CHOLMOD(allocate_work) (n, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ensure that subsequent routines, called by cholmod_analyze, do not
+     * reallocate any workspace.  This is set back to FALSE in the
+     * FREE_WORKSPACE_AND_RETURN macro, which is the only way this function
+     * returns to its caller. */
+    Common->no_workspace_reallocate = TRUE ;
+
+    /* Use the last 4*n Int's in Iwork for Parent, First, Level, and Post, since
+     * other CHOLMOD routines will use the first 2n+uncol space.  The ordering
+     * routines (cholmod_amd, cholmod_colamd, cholmod_ccolamd, cholmod_metis)
+     * are an exception.  They can use all 6n + ncol space, since the contents
+     * of Parent, First, Level, and Post are not needed across calls to those
+     * routines. */
+    Work4n = Common->Iwork ;
+    Work4n += 2*((size_t) n) + uncol ;
+    Parent = Work4n ;
+    First  = Work4n + n ;
+    Level  = Work4n + 2*((size_t) n) ;
+    Post   = Work4n + 3*((size_t) n) ;
+
+    /* note that this assignment means that cholmod_nested_dissection,
+     * cholmod_ccolamd, and cholmod_camd can use only the first 4n+uncol
+     * space in Common->Iwork */
+    Cmember = Post ;
+    CParent = Level ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate more workspace, and an empty simplicial symbolic factor */
+    /* ---------------------------------------------------------------------- */
+
+    L = CHOLMOD(allocate_factor) (n, Common) ;
+    Lparent  = CHOLMOD(malloc) (n, sizeof (Int), Common) ;
+    Perm     = CHOLMOD(malloc) (n, sizeof (Int), Common) ;
+    ColCount = CHOLMOD(malloc) (n, sizeof (Int), Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	FREE_WORKSPACE_AND_RETURN ;
+    }
+    Lperm = L->Perm ;
+    Lcolcount = L->ColCount ;
+    Common->anz = EMPTY ;
+
+    /* ---------------------------------------------------------------------- */
+    /* try all the requested ordering options and backup to AMD if needed */
+    /* ---------------------------------------------------------------------- */
+
+    /* turn off error handling [ */
+    Common->try_catch = TRUE ;
+
+    for (method = 0 ; method <= nmethods ; method++)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* determine the method to try */
+	/* ------------------------------------------------------------------ */
+
+	Common->fl = EMPTY ;
+	Common->lnz = EMPTY ;
+	skip_analysis = FALSE ;
+
+	if (method == nmethods)
+	{
+	    /* All methods failed: backup to AMD */
+	    if (Common->selected == EMPTY && !default_strategy)
+	    {
+		PRINT1 (("All methods requested failed: backup to AMD\n")) ;
+		ordering = CHOLMOD_AMD ;
+	    }
+	    else
+	    {
+		break ;
+	    }
+	}
+	else
+	{
+	    ordering = Common->method [method].ordering ;
+	}
+	Common->current = method ;
+	PRINT1 (("method "ID": Try method: "ID"\n", method, ordering)) ;
+
+	/* ------------------------------------------------------------------ */
+	/* find the fill-reducing permutation */
+	/* ------------------------------------------------------------------ */
+
+	if (ordering == CHOLMOD_NATURAL)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* natural ordering */
+	    /* -------------------------------------------------------------- */
+
+	    for (k = 0 ; k < n ; k++)
+	    {
+		Perm [k] = k ;
+	    }
+
+	}
+	else if (ordering == CHOLMOD_GIVEN)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* use given ordering of A, if provided */
+	    /* -------------------------------------------------------------- */
+
+	    if (UserPerm == NULL)
+	    {
+		/* this is not an error condition */
+		PRINT1 (("skip, no user perm given\n")) ;
+		continue ;
+	    }
+	    for (k = 0 ; k < n ; k++)
+	    {
+		/* UserPerm is checked in cholmod_ptranspose */
+		Perm [k] = UserPerm [k] ;
+	    }
+
+	}
+	else if (ordering == CHOLMOD_AMD)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* AMD ordering of A, A*A', or A(:,f)*A(:,f)' */
+	    /* -------------------------------------------------------------- */
+
+	    CHOLMOD(amd) (A, fset, fsize, Perm, Common) ;
+	    skip_analysis = TRUE ;
+
+	}
+	else if (ordering == CHOLMOD_COLAMD)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* AMD for symmetric case, COLAMD for A*A' or A(:,f)*A(:,f)' */
+	    /* -------------------------------------------------------------- */
+
+	    if (A->stype)
+	    {
+		CHOLMOD(amd) (A, fset, fsize, Perm, Common) ;
+		skip_analysis = TRUE ;
+	    }
+	    else
+	    {
+		/* Alternative:
+		CHOLMOD(ccolamd) (A, fset, fsize, NULL, Perm, Common) ;
+		*/
+		/* do not postorder, it is done later, below */
+		/* workspace: Iwork (4*nrow+uncol), Flag (nrow), Head (nrow+1)*/
+		CHOLMOD(colamd) (A, fset, fsize, FALSE, Perm, Common) ;
+	    }
+
+	}
+	else if (ordering == CHOLMOD_METIS)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* use METIS_NodeND directly (via a CHOLMOD wrapper) */
+	    /* -------------------------------------------------------------- */
+
+#ifndef NPARTITION
+	    /* postorder parameter is false, because it will be later, below */
+	    /* workspace: Iwork (4*nrow+uncol), Flag (nrow), Head (nrow+1) */
+	    Common->called_nd = TRUE ;
+	    CHOLMOD(metis) (A, fset, fsize, FALSE, Perm, Common) ;
+#else
+	    Common->status = CHOLMOD_NOT_INSTALLED ;
+#endif
+
+	}
+	else if (ordering == CHOLMOD_NESDIS)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* use CHOLMOD's nested dissection */
+	    /* -------------------------------------------------------------- */
+
+	    /* this method is based on METIS' node bissection routine
+	     * (METIS_NodeComputeSeparator).  In contrast to METIS_NodeND,
+	     * it calls CAMD or CCOLAMD on the whole graph, instead of MMD
+	     * on just the leaves. */
+#ifndef NPARTITION
+	    /* workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow) */
+	    Common->called_nd = TRUE ;
+	    CHOLMOD(nested_dissection) (A, fset, fsize, Perm, CParent, Cmember,
+		    Common) ;
+#else
+	    Common->status = CHOLMOD_NOT_INSTALLED ;
+#endif
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* invalid ordering method */
+	    /* -------------------------------------------------------------- */
+
+	    Common->status = CHOLMOD_INVALID ;
+	    PRINT1 (("No such ordering: "ID"\n", ordering)) ;
+	}
+
+	ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory, or method failed */
+	    status = MIN (status, Common->status) ;
+	    Common->status = CHOLMOD_OK ;
+	    continue ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* analyze the ordering */
+	/* ------------------------------------------------------------------ */
+
+	if (!skip_analysis)
+	{
+	    if (!CHOLMOD(analyze_ordering) (A, ordering, Perm, fset, fsize,
+		    Parent, Post, ColCount, First, Level, Common))
+	    {
+		/* ordering method failed; clear status and try next method */
+		status = MIN (status, Common->status) ;
+		Common->status = CHOLMOD_OK ;
+		continue ;
+	    }
+	}
+
+	ASSERT (Common->fl >= 0 && Common->lnz >= 0) ;
+	Common->method [method].fl  = Common->fl ;
+	Common->method [method].lnz = Common->lnz ;
+	PRINT1 (("lnz %g fl %g\n", Common->lnz, Common->fl)) ;
+
+	/* ------------------------------------------------------------------ */
+	/* pick the best method */
+	/* ------------------------------------------------------------------ */
+
+	/* fl.pt. compare, but lnz can never be NaN */
+	if (Common->selected == EMPTY || Common->lnz < lnz_best)
+	{
+	    Common->selected = method ;
+	    PRINT1 (("this is best so far, method "ID"\n", method)) ;
+	    L->ordering = ordering ;
+	    lnz_best = Common->lnz ;
+	    for (k = 0 ; k < n ; k++)
+	    {
+		Lperm [k] = Perm [k] ;
+	    }
+	    /* save the results of cholmod_analyze_ordering, if it was called */
+	    skip_best = skip_analysis ;
+	    if (!skip_analysis)
+	    {
+		/* save the column count; becomes permanent part of L */
+		for (k = 0 ; k < n ; k++)
+		{
+		    Lcolcount [k] = ColCount [k] ;
+		}
+		/* Parent is needed for weighted postordering and for supernodal
+		 * analysis.  Does not become a permanent part of L */
+		for (k = 0 ; k < n ; k++)
+		{
+		    Lparent [k] = Parent [k] ;
+		}
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* determine if METIS is to be skipped */
+	/* ------------------------------------------------------------------ */
+
+	if (default_strategy && ordering == CHOLMOD_AMD)
+	{
+	    if ((Common->fl < 500 * Common->lnz) ||
+		(Common->lnz < 5 * Common->anz))
+	    {
+		/* AMD found an ordering with less than 500 flops per nonzero in
+		 * L, or one with a fill-in ratio (nnz(L)/nnz(A)) of less than
+		 * 5.  This is pretty good, and it's unlikely that METIS will do
+		 * better (this heuristic is based on tests on all symmetric
+		 * positive definite matrices in the UF sparse matrix
+		 * collection, and it works well across a wide range of
+		 * problems).  METIS can take much more time and AMD. */
+		break ;
+	    }
+	}
+    }
+
+    /* turn error printing back on ] */
+    Common->try_catch = FALSE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* return if no ordering method succeeded */
+    /* ---------------------------------------------------------------------- */
+
+    if (Common->selected == EMPTY)
+    {
+	/* All methods failed.  
+	 * If two or more methods failed, they may have failed for different
+	 * reasons.  Both would clear Common->status and skip to the next
+	 * method.  Common->status needs to be restored here to the worst error
+	 * obtained in any of the methods.  CHOLMOD_INVALID is worse
+	 * than CHOLMOD_OUT_OF_MEMORY, since the former implies something may
+	 * be wrong with the user's input.  CHOLMOD_OUT_OF_MEMORY is simply an
+	 * indication of lack of resources. */
+	ASSERT (status < CHOLMOD_OK) ;
+	ERROR (status, "all methods failed") ;
+	FREE_WORKSPACE_AND_RETURN ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* do the analysis for AMD, if skipped */
+    /* ---------------------------------------------------------------------- */
+
+    Common->fl  = Common->method [Common->selected].fl  ;
+    Common->lnz = Common->method [Common->selected].lnz ;
+    ASSERT (Common->lnz >= 0) ;
+
+    if (skip_best)
+    {
+	if (!CHOLMOD(analyze_ordering) (A, L->ordering, Lperm, fset, fsize,
+		Lparent, Post, Lcolcount, First, Level, Common))
+	{
+	    /* out of memory, or method failed */
+	    FREE_WORKSPACE_AND_RETURN ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* postorder the etree, weighted by the column counts */
+    /* ---------------------------------------------------------------------- */
+
+    if (Common->postorder)
+    {
+	/* combine the fill-reducing ordering with the weighted postorder */
+	/* workspace: Iwork (2*nrow) */
+	if (CHOLMOD(postorder) (Lparent, n, Lcolcount, Post, Common) == n)
+	{
+	    /* use First and Level as workspace [ */
+	    Int *Wi = First, *InvPost = Level ;
+	    Int newchild, oldchild, newparent, oldparent ;
+
+	    for (k = 0 ; k < n ; k++)
+	    {
+		Wi [k] = Lperm [Post [k]] ;
+	    }
+	    for (k = 0 ; k < n ; k++)
+	    {
+		Lperm [k] = Wi [k] ;
+	    }
+
+	    for (k = 0 ; k < n ; k++)
+	    {
+		Wi [k] = Lcolcount [Post [k]] ;
+	    }
+	    for (k = 0 ; k < n ; k++)
+	    {
+		Lcolcount [k] = Wi [k] ;
+	    }
+	    for (k = 0 ; k < n ; k++)
+	    {
+		InvPost [Post [k]] = k ;
+	    }
+
+	    /* updated Lparent needed only for supernodal case */
+	    for (newchild = 0 ; newchild < n ; newchild++)
+	    {
+		oldchild = Post [newchild] ;
+		oldparent = Lparent [oldchild] ;
+		newparent = (oldparent == EMPTY) ? EMPTY : InvPost [oldparent] ;
+		Wi [newchild] = newparent ;
+	    }
+	    for (k = 0 ; k < n ; k++)
+	    {
+		Lparent [k] = Wi [k] ;
+	    }
+	    /* done using Iwork as workspace ] */
+
+	    /* L is now postordered, no longer in natural ordering */
+	    if (L->ordering == CHOLMOD_NATURAL)
+	    {
+		L->ordering = CHOLMOD_POSTORDERED ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* supernodal analysis, if requested or if selected automatically */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NSUPERNODAL
+    if (Common->supernodal > CHOLMOD_AUTO
+    || (Common->supernodal == CHOLMOD_AUTO &&
+	Common->lnz > 0 &&
+	(Common->fl / Common->lnz) >= Common->supernodal_switch))
+    {
+	cholmod_sparse *S, *F, *A2, *A1 ;
+
+	permute_matrices (A, L->ordering, Lperm, fset, fsize, TRUE,
+		&A1, &A2, &S, &F, Common) ;
+
+	/* workspace: Flag (nrow), Head (nrow), Iwork (5*nrow) */
+	CHOLMOD(super_symbolic) (S, F, Lparent, L, Common) ;
+	PRINT1 (("status %d\n", Common->status)) ;
+
+	CHOLMOD(free_sparse) (&A1, Common) ;
+	CHOLMOD(free_sparse) (&A2, Common) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* free temporary matrices and workspace, and return result L */
+    /* ---------------------------------------------------------------------- */
+
+    FREE_WORKSPACE_AND_RETURN ;
+}
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_colamd.c b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_colamd.c
new file mode 100644
index 0000000..1f20101
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_colamd.c
@@ -0,0 +1,210 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_colamd ============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD interface to the COLAMD ordering routine (version 2.4 or later).
+ * Finds a permutation p such that the Cholesky factorization of PAA'P' is
+ * sparser than AA' using colamd.  If the postorder input parameter is TRUE,
+ * the column etree is found and postordered, and the colamd ordering is then
+ * combined with its postordering.  A must be unsymmetric.
+ *
+ * There can be no duplicate entries in f.
+ * f can be length 0 to n if A is m-by-n.
+ *
+ * workspace: Iwork (4*nrow+ncol), Head (nrow+1), Flag (nrow)
+ *	Allocates a copy of its input matrix, which
+ *	is then used as CCOLAMD's workspace.
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex)
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "colamd.h"
+#include "cholmod_cholesky.h"
+
+#if (!defined (COLAMD_VERSION) || (COLAMD_VERSION < COLAMD_VERSION_CODE (2,5)))
+#error "COLAMD v2.5 or later is required"
+#endif
+
+/* ========================================================================== */
+/* === cholmod_colamd ======================================================= */
+/* ========================================================================== */
+
+int CHOLMOD(colamd)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int postorder,	/* if TRUE, follow with a coletree postorder */
+    /* ---- output --- */
+    Int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double knobs [COLAMD_KNOBS] ;
+    cholmod_sparse *C ;
+    Int *NewPerm, *Parent, *Post, *Work2n ;
+    Int k, nrow, ncol ;
+    size_t s, alen ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (Perm, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (A->stype != 0)
+    {
+	ERROR (CHOLMOD_INVALID, "matrix must be unsymmetric") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* Note: this is less than the space used in cholmod_analyze, so if
+     * cholmod_colamd is being called by that routine, no space will be
+     * allocated.
+     */
+
+    /* s = 4*nrow + ncol */
+    s = CHOLMOD(mult_size_t) (nrow, 4, &ok) ;
+    s = CHOLMOD(add_size_t) (s, ncol, &ok) ;
+
+#ifdef LONG
+    alen = colamd_l_recommended (A->nzmax, ncol, nrow) ;
+    colamd_l_set_defaults (knobs) ;
+#else
+    alen = colamd_recommended (A->nzmax, ncol, nrow) ;
+    colamd_set_defaults (knobs) ;
+#endif
+
+    if (!ok || alen == 0)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "matrix invalid or too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (0, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate COLAMD workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* colamd_printf is only available in colamd v2.4 or later */
+    colamd_printf = Common->print_function ;
+
+    C = CHOLMOD(allocate_sparse) (ncol, nrow, alen, TRUE, TRUE, 0,
+	    CHOLMOD_PATTERN, Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy (and transpose) the input matrix A into the colamd workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* C = A (:,f)', which also packs A if needed. */
+    /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset) */
+    ok = CHOLMOD(transpose_unsym) (A, 0, NULL, fset, fsize, C, Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* order the matrix (destroys the contents of C->i and C->p) */
+    /* ---------------------------------------------------------------------- */
+
+    /* get parameters */
+    if (Common->current < 0 || Common->current >= CHOLMOD_MAXMETHODS)
+    {
+	/* this is the CHOLMOD default, not the COLAMD default */
+	knobs [COLAMD_DENSE_ROW] = -1 ;
+    }
+    else
+    {
+	/* get the knobs from the Common parameters */
+	knobs [COLAMD_DENSE_COL] = Common->method[Common->current].prune_dense ;
+	knobs [COLAMD_DENSE_ROW] = Common->method[Common->current].prune_dense2;
+	knobs [COLAMD_AGGRESSIVE] = Common->method[Common->current].aggressive ;
+    }
+
+    if (ok)
+    {
+	Int *Cp ;
+	Int stats [COLAMD_STATS] ;
+	Cp = C->p ;
+
+#ifdef LONG
+	colamd_l (ncol, nrow, alen, C->i, Cp, knobs, stats) ;
+#else
+	colamd (ncol, nrow, alen, C->i, Cp, knobs, stats) ;
+#endif
+
+	ok = stats [COLAMD_STATUS] ;
+	ok = (ok == COLAMD_OK || ok == COLAMD_OK_BUT_JUMBLED) ;
+	/* permutation returned in C->p, if the ordering succeeded */
+	for (k = 0 ; k < nrow ; k++)
+	{
+	    Perm [k] = Cp [k] ;
+	}
+    }
+
+    CHOLMOD(free_sparse) (&C, Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* column etree postordering */
+    /* ---------------------------------------------------------------------- */
+
+    if (postorder)
+    {
+	/* use the last 2*n space in Iwork for Parent and Post */
+	Work2n = Common->Iwork ;
+	Work2n += 2*((size_t) nrow) + ncol ;
+	Parent = Work2n ;		/* size nrow (i/i/l) */
+	Post   = Work2n + nrow ;	/* size nrow (i/i/l) */
+
+	/* workspace: Iwork (2*nrow+ncol), Flag (nrow), Head (nrow+1) */
+	ok = ok && CHOLMOD(analyze_ordering) (A, CHOLMOD_COLAMD, Perm, fset,
+		fsize, Parent, Post, NULL, NULL, NULL, Common) ;
+
+	/* combine the colamd permutation with its postordering */
+	if (ok)
+	{
+	    NewPerm = Common->Iwork ;		/* size nrow (i/i/l) */
+	    for (k = 0 ; k < nrow ; k++)
+	    {
+		NewPerm [k] = Perm [Post [k]] ;
+	    }
+	    for (k = 0 ; k < nrow ; k++)
+	    {
+		Perm [k] = NewPerm [k] ;
+	    }
+	}
+    }
+
+    return (ok) ;
+}
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_etree.c b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_etree.c
new file mode 100644
index 0000000..592cba8
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_etree.c
@@ -0,0 +1,227 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_etree =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Compute the elimination tree of A or A'*A
+ *
+ * In the symmetric case, the upper triangular part of A is used.  Entries not
+ * in this part of the matrix are ignored.  Computing the etree of a symmetric
+ * matrix from just its lower triangular entries is not supported.
+ *
+ * In the unsymmetric case, all of A is used, and the etree of A'*A is computed.
+ *
+ * References:
+ *
+ * J. Liu, "A compact row storage scheme for Cholesky factors", ACM Trans.
+ * Math. Software, vol 12, 1986, pp. 127-148.
+ *
+ * J. Liu, "The role of elimination trees in sparse factorization", SIAM J.
+ * Matrix Analysis & Applic., vol 11, 1990, pp. 134-172.
+ *
+ * J. Gilbert, X. Li, E. Ng, B. Peyton, "Computing row and column counts for
+ * sparse QR and LU factorization", BIT, vol 41, 2001, pp. 693-710.
+ *
+ * workspace: symmetric: Iwork (nrow), unsymmetric: Iwork (nrow+ncol)
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex)
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+/* ========================================================================== */
+/* === update_etree ========================================================= */
+/* ========================================================================== */
+
+static void update_etree
+(
+    /* inputs, not modified */
+    Int k,		/* process the edge (k,i) in the input graph */
+    Int i,
+    /* inputs, modified on output */
+    Int Parent [ ],	/* Parent [t] = p if p is the parent of t */
+    Int Ancestor [ ]	/* Ancestor [t] is the ancestor of node t in the
+			   partially-constructed etree */
+)
+{
+    Int a ;
+    for ( ; ; )		/* traverse the path from k to the root of the tree */
+    {
+	a = Ancestor [k] ;
+	if (a == i)
+	{
+	    /* final ancestor reached; no change to tree */
+	    return ;
+	}
+	/* perform path compression */
+	Ancestor [k] = i ;
+	if (a == EMPTY)
+	{
+	    /* final ancestor undefined; this is a new edge in the tree */
+	    Parent [k] = i ;
+	    return ;
+	}
+	/* traverse up to the ancestor of k */
+	k = a ;
+    }
+}
+
+/* ========================================================================== */
+/* === cholmod_etree ======================================================== */
+/* ========================================================================== */
+
+/* Find the elimination tree of A or A'*A */
+
+int CHOLMOD(etree)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,
+    /* ---- output --- */
+    Int *Parent,	/* size ncol.  Parent [j] = p if p is the parent of j */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Ap, *Ai, *Anz, *Ancestor, *Prev, *Iwork ;
+    Int i, j, jprev, p, pend, nrow, ncol, packed, stype ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (Parent, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    stype = A->stype ;
+
+    /* s = A->nrow + (stype ? 0 : A->ncol) */
+    s = CHOLMOD(add_size_t) (A->nrow, (stype ? 0 : A->ncol), &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (0, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+
+    ASSERT (CHOLMOD(dump_sparse) (A, "etree", Common) >= 0) ;
+    Iwork = Common->Iwork ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    ncol = A->ncol ;	/* the number of columns of A */
+    nrow = A->nrow ;	/* the number of rows of A */
+    Ap = A->p ;		/* size ncol+1, column pointers for A */
+    Ai = A->i ;		/* the row indices of A */
+    Anz = A->nz ;	/* number of nonzeros in each column of A */
+    packed = A->packed ;
+    Ancestor = Iwork ;	/* size ncol (i/i/l) */
+
+    for (j = 0 ; j < ncol ; j++)
+    {
+	Parent [j] = EMPTY ;
+	Ancestor [j] = EMPTY ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the etree */
+    /* ---------------------------------------------------------------------- */
+
+    if (stype > 0)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* symmetric (upper) case: compute etree (A) */
+	/* ------------------------------------------------------------------ */
+
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    /* for each row i in column j of triu(A), excluding the diagonal */
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		if (i < j)
+		{
+		    update_etree (i, j, Parent, Ancestor) ;
+		}
+	    }
+	}
+
+    }
+    else if (stype == 0)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* unsymmetric case: compute etree (A'*A) */
+	/* ------------------------------------------------------------------ */
+
+	Prev = Iwork + ncol ;	/* size nrow (i/i/l) */
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    Prev [i] = EMPTY ;
+	}
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    /* for each row i in column j of A */
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		/* a graph is constructed dynamically with one path per row
+		 * of A.  If the ith row of A contains column indices
+		 * (j1,j2,j3,j4) then the new graph has edges (j1,j2), (j2,j3),
+		 * and (j3,j4).  When at node i of this path-graph, all edges
+		 * (jprev,j) are considered, where jprev<j */
+		i = Ai [p] ;
+		jprev = Prev [i] ;
+		if (jprev != EMPTY)
+		{
+		    update_etree (jprev, j, Parent, Ancestor) ;
+		}
+		Prev [i] = j ;
+	    }
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* symmetric case with lower triangular part not supported */
+	/* ------------------------------------------------------------------ */
+
+	ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ;
+	return (FALSE) ;
+    }
+
+    ASSERT (CHOLMOD(dump_parent) (Parent, ncol, "Parent", Common)) ;
+    return (TRUE) ;
+}
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_factorize.c b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_factorize.c
new file mode 100644
index 0000000..15544d3
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_factorize.c
@@ -0,0 +1,429 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_factorize =========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Computes the numerical factorization of a symmetric matrix.  The primary
+ * inputs to this routine are a sparse matrix A and the symbolic factor L from
+ * cholmod_analyze or a prior numerical factor L.  If A is symmetric, this
+ * routine factorizes A(p,p)+beta*I (beta can be zero), where p is the
+ * fill-reducing permutation (L->Perm).  If A is unsymmetric, either
+ * A(p,:)*A(p,:)'+beta*I or A(p,f)*A(p,f)'+beta*I is factorized.  The set f and
+ * the nonzero pattern of the matrix A must be the same as the matrix passed to
+ * cholmod_analyze for the supernodal case.  For the simplicial case, it can
+ * be different, but it should be the same for best performance.  beta is real.
+ *
+ * A simplicial factorization or supernodal factorization is chosen, based on
+ * the type of the factor L.  If L->is_super is TRUE, a supernodal LL'
+ * factorization is computed.  Otherwise, a simplicial numeric factorization
+ * is computed, either LL' or LDL', depending on Common->final_ll.
+ *
+ * Once the factorization is complete, it can be left as is or optionally
+ * converted into any simplicial numeric type, depending on the
+ * Common->final_* parameters.  If converted from a supernodal to simplicial
+ * type, and the Common->final_resymbol parameter is true, then numerically
+ * zero entries in L due to relaxed supernodal amalgamation are removed from
+ * the simplicial factor (they are always left in the supernodal form of L).
+ * Entries that are numerically zero but present in the simplicial symbolic
+ * pattern of L are left in place (that is, the graph of L remains chordal).
+ * This is required for the update/downdate/rowadd/rowdel routines to work
+ * properly.
+ *
+ * workspace: Flag (nrow), Head (nrow+1),
+ *	if symmetric:   Iwork (2*nrow+2*nsuper)
+ *	if unsymmetric: Iwork (2*nrow+MAX(2*nsuper,ncol))
+ *	    where nsuper is 0 if simplicial, or the # of relaxed supernodes in
+ *	    L otherwise (nsuper <= nrow).
+ *	if simplicial: W (nrow).
+ *	Allocates up to two temporary copies of its input matrix (including
+ *	both pattern and numerical values).
+ *
+ * If the matrix is not positive definite the routine returns TRUE, but
+ * sets Common->status to CHOLMOD_NOT_POSDEF and L->minor is set to the
+ * column at which the failure occurred.  Columns L->minor to L->n-1 are
+ * set to zero.
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex), except that the
+ * input matrix A cannot be pattern-only.  If L is simplicial, its numeric
+ * xtype matches A on output.  If L is supernodal, its xtype is real if A is
+ * real, or complex if A is complex or zomplex.
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+#ifndef NSUPERNODAL
+#include "cholmod_supernodal.h"
+#endif
+
+
+/* ========================================================================== */
+/* === cholmod_factorize ==================================================== */
+/* ========================================================================== */
+
+/* Factorizes PAP' (or PAA'P' if A->stype is 0), using a factor obtained
+ * from cholmod_analyze.  The analysis can be re-used simply by calling this
+ * routine a second time with another matrix.  A must have the same nonzero
+ * pattern as that passed to cholmod_analyze. */
+
+int CHOLMOD(factorize)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* resulting factorization */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double zero [2] ;
+    zero [0] = 0 ;
+    zero [1] = 0 ;
+    return (CHOLMOD(factorize_p) (A, zero, NULL, 0, L, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_factorize_p ================================================== */
+/* ========================================================================== */
+
+/* Same as cholmod_factorize, but with more options. */
+
+int CHOLMOD(factorize_p)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    double beta [2],	/* factorize beta*I+A or beta*I+A'*A */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* resulting factorization */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *S, *F, *A1, *A2 ;
+    Int nrow, ncol, stype, convert, n, nsuper, grow2, status ;
+    size_t s, t, uncol ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+    n = L->n ;
+    stype = A->stype ;
+    if (L->n != A->nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "A and L dimensions do not match") ;
+	return (FALSE) ;
+    }
+    if (stype != 0 && nrow != ncol)
+    {
+	ERROR (CHOLMOD_INVALID, "matrix invalid") ;
+	return (FALSE) ;
+    }
+    DEBUG (CHOLMOD(dump_sparse) (A, "A for cholmod_factorize", Common)) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    nsuper = (L->is_super ? L->nsuper : 0) ;
+    uncol = ((stype != 0) ? 0 : ncol) ;
+
+    /* s = 2*nrow + MAX (uncol, 2*nsuper) */
+    s = CHOLMOD(mult_size_t) (nsuper, 2, &ok) ;
+    s = MAX (uncol, s) ;
+    t = CHOLMOD(mult_size_t) (nrow, 2, &ok) ;
+    s = CHOLMOD(add_size_t) (s, t, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (nrow, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+
+    S  = NULL ;
+    F  = NULL ;
+    A1 = NULL ;
+    A2 = NULL ;
+
+    /* convert to another form when done, if requested */
+    convert = !(Common->final_asis) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* perform supernodal LL' or simplicial LDL' factorization */
+    /* ---------------------------------------------------------------------- */
+
+    if (L->is_super)
+    {
+
+#ifndef NSUPERNODAL
+
+	/* ------------------------------------------------------------------ */
+	/* supernodal factorization */
+	/* ------------------------------------------------------------------ */
+
+	if (L->ordering == CHOLMOD_NATURAL)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* natural ordering */
+	    /* -------------------------------------------------------------- */
+
+	    if (stype > 0)
+	    {
+		/* S = tril (A'), F not needed */
+		/* workspace: Iwork (nrow) */
+		A1 = CHOLMOD(ptranspose) (A, 2, NULL, NULL, 0, Common) ;
+		S = A1 ;
+	    }
+	    else if (stype < 0)
+	    {
+		/* This is the fastest option for the natural ordering */
+		/* S = A; F not needed */
+		S = A ;
+	    }
+	    else
+	    {
+		/* F = A(:,f)' */
+		/* workspace: Iwork (nrow) */
+		/* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/
+		A1 = CHOLMOD(ptranspose) (A, 2, NULL, fset, fsize, Common) ;
+		F = A1 ;
+		/* S = A */
+		S = A ;
+	    }
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* permute the input matrix before factorization */
+	    /* -------------------------------------------------------------- */
+
+	    if (stype > 0)
+	    {
+		/* This is the fastest option for factoring a permuted matrix */
+		/* S = tril (PAP'); F not needed */
+		/* workspace: Iwork (2*nrow) */
+		A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ;
+		S = A1 ;
+	    }
+	    else if (stype < 0)
+	    {
+		/* A2 = triu (PAP') */
+		/* workspace: Iwork (2*nrow) */
+		A2 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ;
+		/* S = tril (A2'); F not needed */
+		/* workspace: Iwork (nrow) */
+		A1 = CHOLMOD(ptranspose) (A2, 2, NULL, NULL, 0, Common) ;
+		S = A1 ;
+		CHOLMOD(free_sparse) (&A2, Common) ;
+		ASSERT (A2 == NULL) ;
+	    }
+	    else
+	    {
+		/* F = A(p,f)' */
+		/* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/
+		A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, fset, fsize, Common) ;
+		F = A1 ;
+		/* S = F' */
+		/* workspace: Iwork (nrow) */
+		A2 = CHOLMOD(ptranspose) (F, 2, NULL, NULL, 0, Common) ;
+		S = A2 ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* supernodal factorization */
+	/* ------------------------------------------------------------------ */
+
+	/* workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow+2*nsuper) */
+	if (Common->status == CHOLMOD_OK)
+	{
+	    CHOLMOD(super_numeric) (S, F, beta, L, Common) ;
+	}
+	status = Common->status ;
+	ASSERT (IMPLIES (status >= CHOLMOD_OK, L->xtype != CHOLMOD_PATTERN)) ;
+
+	/* ------------------------------------------------------------------ */
+	/* convert to final form, if requested */
+	/* ------------------------------------------------------------------ */
+
+	if (Common->status >= CHOLMOD_OK && convert)
+	{
+	    /* workspace: none */
+	    ok = CHOLMOD(change_factor) (L->xtype, Common->final_ll,
+		    Common->final_super, Common->final_pack,
+		    Common->final_monotonic, L, Common) ;
+	    if (ok && Common->final_resymbol && !(L->is_super))
+	    {
+		/* workspace: Flag (nrow), Head (nrow+1),
+		 *	if symmetric:   Iwork (2*nrow)
+		 *	if unsymmetric: Iwork (2*nrow+ncol) */
+		CHOLMOD(resymbol_noperm) (S, fset, fsize, Common->final_pack,
+		    L, Common) ;
+	    }
+	}
+
+#else
+
+	/* ------------------------------------------------------------------ */
+	/* CHOLMOD Supernodal module not installed */
+	/* ------------------------------------------------------------------ */
+
+	status = CHOLMOD_NOT_INSTALLED ;
+	ERROR (CHOLMOD_NOT_INSTALLED,"Supernodal module not installed") ;
+
+#endif
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* simplicial LDL' factorization */
+	/* ------------------------------------------------------------------ */
+
+	/* Permute the input matrix A if necessary.  cholmod_rowfac requires
+	 * triu(A) in column form for the symmetric case, and A in column form
+	 * for the unsymmetric case (the matrix S).  The unsymmetric case
+	 * requires A in row form, or equivalently A' in column form (the
+	 * matrix F).
+	 */
+
+	if (L->ordering == CHOLMOD_NATURAL)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* natural ordering */
+	    /* -------------------------------------------------------------- */
+
+	    if (stype > 0)
+	    {
+		/* F is not needed, S = A */
+		S = A ;
+	    }
+	    else if (stype < 0)
+	    {
+		/* F is not needed, S = A' */
+		/* workspace: Iwork (nrow) */
+		A2 = CHOLMOD(ptranspose) (A, 2, NULL, NULL, 0, Common) ;
+		S = A2 ;
+	    }
+	    else
+	    {
+		/* F = A (:,f)' */
+		/* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/
+		A1 = CHOLMOD(ptranspose) (A, 2, NULL, fset, fsize, Common) ;
+		F = A1 ;
+		S = A ;
+	    }
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* permute the input matrix before factorization */
+	    /* -------------------------------------------------------------- */
+
+	    if (stype > 0)
+	    {
+		/* F = tril (A (p,p)') */
+		/* workspace: Iwork (2*nrow) */
+		A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ;
+		/* A2 = triu (F') */
+		/* workspace: Iwork (nrow) */
+		A2 = CHOLMOD(ptranspose) (A1, 2, NULL, NULL, 0, Common) ;
+		/* the symmetric case does not need F, free it and set to NULL*/
+		CHOLMOD(free_sparse) (&A1, Common) ;
+	    }
+	    else if (stype < 0)
+	    {
+		/* A2 = triu (A (p,p)'), F not needed.  This is the fastest
+		 * way to factorize a matrix using the simplicial routine
+		 * (cholmod_rowfac). */
+		/* workspace: Iwork (2*nrow) */
+		A2 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ;
+	    }
+	    else
+	    {
+		/* F = A (p,f)' */
+		/* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/
+		A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, fset, fsize, Common) ;
+		F = A1 ;
+		/* A2 = F' */
+		/* workspace: Iwork (nrow) */
+		A2 = CHOLMOD(ptranspose) (F, 2, NULL, NULL, 0, Common) ;
+	    }
+	    S = A2 ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* simplicial LDL' or LL' factorization */
+	/* ------------------------------------------------------------------ */
+
+	/* factorize beta*I+S (symmetric) or beta*I+F*F' (unsymmetric) */
+	/* workspace: Flag (nrow), W (nrow), Iwork (2*nrow) */
+	if (Common->status == CHOLMOD_OK)
+	{
+	    grow2 = Common->grow2 ;
+	    L->is_ll = BOOLEAN (Common->final_ll) ;
+	    if (L->xtype == CHOLMOD_PATTERN && Common->final_pack)
+	    {
+		/* allocate a factor with exactly the space required */
+		Common->grow2 = 0 ;
+	    }
+	    CHOLMOD(rowfac) (S, F, beta, 0, nrow, L, Common) ;
+	    Common->grow2 = grow2 ;
+	}
+	status = Common->status ;
+
+	/* ------------------------------------------------------------------ */
+	/* convert to final form, if requested */
+	/* ------------------------------------------------------------------ */
+
+	if (Common->status >= CHOLMOD_OK && convert)
+	{
+	    /* workspace: none */
+	    CHOLMOD(change_factor) (L->xtype, L->is_ll, FALSE,
+		    Common->final_pack, Common->final_monotonic, L, Common) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* free A1 and A2 if they exist */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(free_sparse) (&A1, Common) ;
+    CHOLMOD(free_sparse) (&A2, Common) ;
+    Common->status = MAX (Common->status, status) ;
+    return (Common->status >= CHOLMOD_OK) ;
+}
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_postorder.c b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_postorder.c
new file mode 100644
index 0000000..d9b44c5
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_postorder.c
@@ -0,0 +1,292 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_postorder =========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Compute the postorder of a tree. */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+
+/* ========================================================================== */
+/* === dfs ================================================================== */
+/* ========================================================================== */
+
+/* The code below includes both a recursive and non-recursive depth-first-search
+ * of a tree.  The recursive code is simpler, but can lead to stack overflow.
+ * It is left here for reference, to understand what the non-recursive code
+ * is computing.  To try the recursive version, uncomment the following
+ * #define, or compile the code with -DRECURSIVE.  Be aware that stack
+ * overflow may occur.
+#define RECURSIVE
+ */
+
+#ifdef RECURSIVE
+
+/* recursive version: a working code for reference only, not actual use */
+
+static Int dfs			/* return the new value of k */
+(
+    Int p,		/* start a DFS at node p */
+    Int k,		/* start the node numbering at k */
+    Int Post [ ],	/* Post ordering, modified on output */
+    Int Head [ ],	/* Head [p] = youngest child of p; EMPTY on output */
+    Int Next [ ],	/* Next [j] = sibling of j; unmodified */
+    Int Pstack [ ]	/* unused */
+)
+{
+    Int j ;
+    /* start a DFS at each child of node p */
+    for (j = Head [p] ; j != EMPTY ; j = Next [j])
+    {
+	/* start a DFS at child node j */
+	k = dfs (j, k, Post, Head, Next, Pstack) ;
+    }
+    Post [k++] = p ;	/* order node p as the kth node */
+    Head [p] = EMPTY ;	/* link list p no longer needed */
+    return (k) ;	/* the next node will be numbered k */
+}
+
+#else
+
+/* non-recursive version for actual use */
+
+static Int dfs		/* return the new value of k */
+(
+    Int p,		/* start the DFS at a root node p */
+    Int k,		/* start the node numbering at k */
+    Int Post [ ],	/* Post ordering, modified on output */
+    Int Head [ ],	/* Head [p] = youngest child of p; EMPTY on output */
+    Int Next [ ],	/* Next [j] = sibling of j; unmodified */
+    Int Pstack [ ]	/* workspace of size n, undefined on input or output */
+)
+{
+    Int j, phead ;
+
+    /* put the root node on the stack */
+    Pstack [0] = p ;
+    phead = 0 ;
+
+    /* while the stack is not empty, do: */
+    while (phead >= 0)
+    {
+	/* grab the node p from top of the stack and get its youngest child j */
+	p = Pstack [phead] ;
+	j = Head [p] ;
+	if (j == EMPTY)
+	{
+	    /* all children of p ordered.  remove p from stack and order it */
+	    phead-- ;
+	    Post [k++] = p ;	/* order node p as the kth node */
+	}
+	else
+	{
+	    /* leave p on the stack.  Start a DFS at child node j by putting
+	     * j on the stack and removing j from the list of children of p. */
+	    Head [p] = Next [j] ;
+	    Pstack [++phead] = j ;
+	}
+    }
+    return (k) ;	/* the next node will be numbered k */
+}
+
+#endif
+
+/* ========================================================================== */
+/* === cholmod_postorder ==================================================== */
+/* ========================================================================== */
+
+/* Postorder a tree.  The tree is either an elimination tree (the output from
+ * from cholmod_etree) or a component tree (from cholmod_nested_dissection).
+ *
+ * An elimination tree is a complete tree of n nodes with Parent [j] > j or
+ * Parent [j] = EMPTY if j is a root.  On output Post [0..n-1] is a complete
+ * permutation vector.
+ *
+ * A component tree is a subset of 0..n-1.  Parent [j] = -2 if node j is not
+ * in the component tree.  Parent [j] = EMPTY if j is a root of the component
+ * tree, and Parent [j] is in the range 0 to n-1 if j is in the component
+ * tree but not a root.  On output, Post [k] is defined only for nodes in
+ * the component tree.  Post [k] = j if node j is the kth node in the
+ * postordered component tree, where k is in the range 0 to the number of
+ * components minus 1.
+ *
+ * Node j is ignored and not included in the postorder if Parent [j] < EMPTY.
+ *
+ * As a result, check_parent (Parent, n,...) may fail on input, since
+ * cholmod_check_parent assumes Parent is an elimination tree.  Similarly,
+ * cholmod_check_perm (Post, ...) may fail on output, since Post is a partial
+ * permutation if Parent is a component tree.
+ *
+ * An optional node weight can be given.  When starting a postorder at node j,
+ * the children of j are ordered in decreasing order of their weight.
+ * If no weights are given (Weight is NULL) then children are ordered in
+ * decreasing order of their node number.  The weight of a node must be in the
+ * range 0 to n-1.  Weights outside that range are silently converted to that
+ * range (weights < 0 are treated as zero, and weights >= n are treated as n-1).
+ *
+ *
+ * workspace: Head (n), Iwork (2*n)
+ */
+
+UF_long CHOLMOD(postorder)	/* return # of nodes postordered */
+(
+    /* ---- input ---- */
+    Int *Parent,	/* size n. Parent [j] = p if p is the parent of j */
+    size_t n,
+    Int *Weight,	/* size n, optional. Weight [j] is weight of node j */
+    /* ---- output --- */
+    Int *Post,		/* size n. Post [k] = j is kth in postordered tree */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Head, *Next, *Pstack, *Iwork ;
+    Int j, p, k, w, nextj ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (EMPTY) ;
+    RETURN_IF_NULL (Parent, EMPTY) ;
+    RETURN_IF_NULL (Post, EMPTY) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* s = 2*n */
+    s = CHOLMOD(mult_size_t) (n, 2, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (EMPTY) ;
+    }
+
+    CHOLMOD(allocate_work) (n, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (EMPTY) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Head  = Common->Head ;	/* size n+1, initially all EMPTY */
+    Iwork = Common->Iwork ;
+    Next  = Iwork ;		/* size n (i/i/l) */
+    Pstack = Iwork + n ;	/* size n (i/i/l) */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct a link list of children for each node */
+    /* ---------------------------------------------------------------------- */
+
+    if (Weight == NULL)
+    {
+
+	/* in reverse order so children are in ascending order in each list */
+	for (j = n-1 ; j >= 0 ; j--)
+	{
+	    p = Parent [j] ;
+	    if (p >= 0 && p < ((Int) n))
+	    {
+		/* add j to the list of children for node p */
+		Next [j] = Head [p] ;
+		Head [p] = j ;
+	    }
+	}
+
+	/* Head [p] = j if j is the youngest (least-numbered) child of p */
+	/* Next [j1] = j2 if j2 is the next-oldest sibling of j1 */
+
+    }
+    else
+    {
+
+	/* First, construct a set of link lists according to Weight.
+	 *
+	 * Whead [w] = j if node j is the first node in bucket w.
+	 * Next [j1] = j2 if node j2 follows j1 in a link list.
+	 */
+
+	Int *Whead = Pstack ;	    /* use Pstack as workspace for Whead [ */
+
+	for (w = 0 ; w < ((Int) n) ; w++)
+	{
+	    Whead [w] = EMPTY ;
+	}
+	/* do in forward order, so nodes that ties are ordered by node index */
+	for (j = 0 ; j < ((Int) n) ; j++)
+	{
+	    p = Parent [j] ;
+	    if (p >= 0 && p < ((Int) n))
+	    {
+		w = Weight [j] ;
+		w = MAX (0, w) ;
+		w = MIN (w, ((Int) n) - 1) ;
+		/* place node j at the head of link list for weight w */
+		Next [j] = Whead [w] ;
+		Whead [w] = j ;
+	    }
+	}
+
+	/* traverse weight buckets, placing each node in its parent's list */
+	for (w = n-1 ; w >= 0 ; w--)
+	{
+	    for (j = Whead [w] ; j != EMPTY ; j = nextj)
+	    {
+		nextj = Next [j] ;
+		/* put node j in the link list of its parent */
+		p = Parent [j] ;
+		ASSERT (p >= 0 && p < ((Int) n)) ;
+		Next [j] = Head [p] ;
+		Head [p] = j ;
+	    }
+	}
+
+	/* Whead no longer needed ] */
+	/* Head [p] = j if j is the lightest child of p */
+	/* Next [j1] = j2 if j2 is the next-heaviest sibling of j1 */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* start a DFS at each root node of the etree */
+    /* ---------------------------------------------------------------------- */
+
+    k = 0 ;
+    for (j = 0 ; j < ((Int) n) ; j++)
+    {
+	if (Parent [j] == EMPTY)
+	{
+	    /* j is the root of a tree; start a DFS here */
+	    k = dfs (j, k, Post, Head, Next, Pstack) ;
+	}
+    }
+
+    /* this would normally be EMPTY already, unless Parent is invalid */
+    for (j = 0 ; j < ((Int) n) ; j++)
+    {
+	Head [j] = EMPTY ;
+    }
+
+    PRINT1 (("postordered "ID" nodes\n", k)) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+    return (k) ;
+}
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_rcond.c b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_rcond.c
new file mode 100644
index 0000000..69f7412
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_rcond.c
@@ -0,0 +1,161 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_rcond =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Return a rough estimate of the reciprocal of the condition number:
+ * the minimum entry on the diagonal of L (or absolute entry of D for an LDL'
+ * factorization) divided by the maximum entry (squared for LL').  L can be
+ * real, complex, or zomplex.  Returns -1 on error, 0 if the matrix is singular
+ * or has a zero entry on the diagonal of L, 1 if the matrix is 0-by-0, or
+ * min(diag(L))/max(diag(L)) otherwise.  Never returns NaN; if L has a NaN on
+ * the diagonal it returns zero instead.
+ *
+ * For an LL' factorization,  (min(diag(L))/max(diag(L)))^2 is returned.
+ * For an LDL' factorization, (min(diag(D))/max(diag(D))) is returned.
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+/* ========================================================================== */
+/* === LMINMAX ============================================================== */
+/* ========================================================================== */
+
+/* Update lmin and lmax for one entry L(j,j) */
+
+#define FIRST_LMINMAX(Ljj,lmin,lmax) \
+{ \
+    double ljj = Ljj ; \
+    if (IS_NAN (ljj)) \
+    { \
+	return (0) ; \
+    } \
+    lmin = ljj ; \
+    lmax = ljj ; \
+}
+
+#define LMINMAX(Ljj,lmin,lmax) \
+{ \
+    double ljj = Ljj ; \
+    if (IS_NAN (ljj)) \
+    { \
+	return (0) ; \
+    } \
+    if (ljj < lmin) \
+    { \
+	lmin = ljj ; \
+    } \
+    else if (ljj > lmax) \
+    { \
+	lmax = ljj ; \
+    } \
+}
+
+/* ========================================================================== */
+/* === cholmod_rcond ======================================================== */
+/* ========================================================================== */
+
+double CHOLMOD(rcond)	    /* return min(diag(L)) / max(diag(L)) */
+(
+    /* ---- input ---- */
+    cholmod_factor *L,
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double lmin, lmax, rcond ;
+    double *Lx ;
+    Int *Lpi, *Lpx, *Super, *Lp ;
+    Int n, e, nsuper, s, k1, k2, psi, psend, psx, nsrow, nscol, jj, j ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (EMPTY) ;
+    RETURN_IF_NULL (L, EMPTY) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, EMPTY) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    n = L->n ;
+    if (n == 0)
+    {
+	return (1) ;
+    }
+    if (L->minor < L->n)
+    {
+	return (0) ;
+    }
+
+    e = (L->xtype == CHOLMOD_COMPLEX) ? 2 : 1 ;
+
+    if (L->is_super)
+    {
+	/* L is supernodal */
+	nsuper = L->nsuper ;	/* number of supernodes in L */
+	Lpi = L->pi ;		/* column pointers for integer pattern */
+	Lpx = L->px ;		/* column pointers for numeric values */
+	Super = L->super ;	/* supernode sizes */
+	Lx = L->x ;		/* numeric values */
+	FIRST_LMINMAX (Lx [0], lmin, lmax) ;	/* first diagonal entry of L */
+	for (s = 0 ; s < nsuper ; s++)
+	{
+	    k1 = Super [s] ;		/* first column in supernode s */
+	    k2 = Super [s+1] ;		/* last column in supernode is k2-1 */
+	    psi = Lpi [s] ;		/* first row index is L->s [psi] */
+	    psend = Lpi [s+1] ;		/* last row index is L->s [psend-1] */
+	    psx = Lpx [s] ;		/* first numeric entry is Lx [psx] */
+	    nsrow = psend - psi ;	/* supernode is nsrow-by-nscol */
+	    nscol = k2 - k1 ;
+	    for (jj = 0 ; jj < nscol ; jj++)
+	    {
+		LMINMAX (Lx [e * (psx + jj + jj*nsrow)], lmin, lmax) ;
+	    }
+	}
+    }
+    else
+    {
+	/* L is simplicial */
+	Lp = L->p ;
+	Lx = L->x ;
+	if (L->is_ll)
+	{
+	    /* LL' factorization */
+	    FIRST_LMINMAX (Lx [Lp [0]], lmin, lmax) ;
+	    for (j = 1 ; j < n ; j++)
+	    {
+		LMINMAX (Lx [e * Lp [j]], lmin, lmax) ;
+	    }
+	}
+	else
+	{
+	    /* LDL' factorization, the diagonal might be negative */
+	    FIRST_LMINMAX (fabs (Lx [Lp [0]]), lmin, lmax) ;
+	    for (j = 1 ; j < n ; j++)
+	    {
+		LMINMAX (fabs (Lx [e * Lp [j]]), lmin, lmax) ;
+	    }
+	}
+    }
+    rcond = lmin / lmax ;
+    if (L->is_ll)
+    {
+	rcond = rcond*rcond ;
+    }
+    return (rcond) ;
+}
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_resymbol.c b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_resymbol.c
new file mode 100644
index 0000000..a25f771
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_resymbol.c
@@ -0,0 +1,604 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_resymbol ============================================ */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Recompute the symbolic pattern of L.  Entries not in the symbolic pattern
+ * are dropped.  L->Perm can be used (or not) to permute the input matrix A.
+ *
+ * These routines are used after a supernodal factorization is converted into
+ * a simplicial one, to remove zero entries that were added due to relaxed
+ * supernode amalgamation.  They can also be used after a series of downdates
+ * to remove entries that would no longer be present if the matrix were
+ * factorized from scratch.  A downdate (cholmod_updown) does not remove any
+ * entries from L.
+ *
+ * workspace: Flag (nrow), Head (nrow+1),
+ *	if symmetric:   Iwork (2*nrow)
+ *	if unsymmetric: Iwork (2*nrow+ncol).
+ *	Allocates up to 2 copies of its input matrix A (pattern only).
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+/* ========================================================================== */
+/* === cholmod_resymbol ===================================================== */
+/* ========================================================================== */
+
+/* Remove entries from L that are not in the factorization of P*A*P', P*A*A'*P',
+ * or P*F*F'*P' (depending on A->stype and whether fset is NULL or not).
+ *
+ * cholmod_resymbol is the same as cholmod_resymbol_noperm, except that it
+ * first permutes A according to L->Perm.  A can be upper/lower/unsymmetric,
+ * in contrast to cholmod_resymbol_noperm (which can be lower or unsym). */
+
+int CHOLMOD(resymbol)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int pack,		/* if TRUE, pack the columns of L */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factorization, entries pruned on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *H, *F, *G ;
+    Int stype, nrow, ncol ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    if (L->is_super)
+    {
+	/* cannot operate on a supernodal factorization */
+	ERROR (CHOLMOD_INVALID, "cannot operate on supernodal L") ;
+	return (FALSE) ;
+    }
+    if (L->n != A->nrow)
+    {
+	/* dimensions must agree */
+	ERROR (CHOLMOD_INVALID, "A and L dimensions do not match") ;
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    stype = A->stype ;
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+
+    /* s = 2*nrow + (stype ? 0 : ncol) */
+    s = CHOLMOD(mult_size_t) (nrow, 2, &ok) ;
+    s = CHOLMOD(add_size_t) (s, (stype ? 0 : ncol), &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (nrow, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* permute the input matrix if necessary */
+    /* ---------------------------------------------------------------------- */
+
+    H = NULL ;
+    G = NULL ;
+
+    if (stype > 0)
+    {
+	if (L->ordering == CHOLMOD_NATURAL)
+	{
+	    /* F = triu(A)' */
+	    /* workspace: Iwork (nrow) */
+	    G = CHOLMOD(ptranspose) (A, 0, NULL, NULL, 0, Common) ;
+	}
+	else
+	{
+	    /* F = triu(A(p,p))' */
+	    /* workspace: Iwork (2*nrow) */
+	    G = CHOLMOD(ptranspose) (A, 0, L->Perm, NULL, 0, Common) ;
+	}
+	F = G ;
+    }
+    else if (stype < 0)
+    {
+	if (L->ordering == CHOLMOD_NATURAL)
+	{
+	    F = A ;
+	}
+	else
+	{
+	    /* G = triu(A(p,p))' */
+	    /* workspace: Iwork (2*nrow) */
+	    G = CHOLMOD(ptranspose) (A, 0, L->Perm, NULL, 0, Common) ;
+	    /* H = G' */
+	    /* workspace: Iwork (nrow) */
+	    H = CHOLMOD(ptranspose) (G, 0, NULL, NULL, 0, Common) ;
+	    F = H ;
+	}
+    }
+    else
+    {
+	if (L->ordering == CHOLMOD_NATURAL)
+	{
+	    F = A ;
+	}
+	else
+	{
+	    /* G = A(p,f)' */
+	    /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/
+	    G = CHOLMOD(ptranspose) (A, 0, L->Perm, fset, fsize, Common) ;
+	    /* H = G' */
+	    /* workspace: Iwork (ncol) */
+	    H = CHOLMOD(ptranspose) (G, 0, NULL, NULL, 0, Common) ;
+	    F = H ;
+	}
+    }
+
+    /* No need to check for failure here.  cholmod_resymbol_noperm will return
+     * FALSE if F is NULL. */
+
+    /* ---------------------------------------------------------------------- */
+    /* resymbol */
+    /* ---------------------------------------------------------------------- */
+
+    ok = CHOLMOD(resymbol_noperm) (F, fset, fsize, pack, L, Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free the temporary matrices, if they exist */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(free_sparse) (&H, Common) ;
+    CHOLMOD(free_sparse) (&G, Common) ;
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_resymbol_noperm ============================================== */
+/* ========================================================================== */
+
+/* Redo symbolic LDL' or LL' factorization of I + F*F' or I+A, where F=A(:,f).
+ *
+ * L already exists, but is a superset of the true dynamic pattern (simple
+ * column downdates and row deletions haven't pruned anything).  Just redo the
+ * symbolic factorization and drop entries that are no longer there.  The
+ * diagonal is not modified.  The number of nonzeros in column j of L
+ * (L->nz[j]) can decrease.  The column pointers (L->p[j]) remain unchanged if
+ * pack is FALSE or if L is not monotonic.  Otherwise, the columns of L are
+ * packed in place.
+ *
+ * For the symmetric case, the columns of the lower triangular part of A
+ * are accessed by column.  NOTE that this the transpose of the general case.
+ *
+ * For the unsymmetric case, F=A(:,f) is accessed by column.
+ *
+ * A need not be sorted, and can be packed or unpacked.  If L->Perm is not
+ * identity, then A must already be permuted according to the permutation used
+ * to factorize L.  The advantage of using this routine is that it does not
+ * need to create permuted copies of A first.
+ *
+ * This routine can be called if L is only partially factored via cholmod_rowfac
+ * since all it does is prune.  If an entry is in F*F' or A, but not in L, it
+ * isn't added to L.
+ *
+ * L must be simplicial LDL' or LL'; it cannot be supernodal or symbolic.
+ *
+ * The set f is held in fset and fsize.
+ *	fset = NULL means ":" in MATLAB. fset is ignored.
+ *	fset != NULL means f = fset [0..fset-1].
+ *	fset != NULL and fsize = 0 means f is the empty set.
+ *	There can be no duplicates in fset.
+ *	Common->status is set to CHOLMOD_INVALID if fset is invalid.
+ *
+ * workspace: Flag (nrow), Head (nrow+1),
+ *	if symmetric:   Iwork (2*nrow)
+ *	if unsymmetric: Iwork (2*nrow+ncol).
+ *	Unlike cholmod_resymbol, this routine does not allocate any temporary
+ *	copies of its input matrix.
+ */
+
+int CHOLMOD(resymbol_noperm)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int pack,		/* if TRUE, pack the columns of L */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factorization, entries pruned on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Lx, *Lz ;
+    Int i, j, k, row, parent, p, pend, pdest, ncol, apacked, sorted, nrow, nf,
+	use_fset, mark, jj, stype, xtype ;
+    Int *Ap, *Ai, *Anz, *Li, *Lp, *Lnz, *Flag, *Head, *Link, *Anext, *Iwork ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    ncol = A->ncol ;
+    nrow = A->nrow ;
+    stype = A->stype ;
+    ASSERT (IMPLIES (stype != 0, nrow == ncol)) ;
+    if (stype > 0)
+    {
+	/* symmetric, with upper triangular part, not supported */
+	ERROR (CHOLMOD_INVALID, "symmetric upper not supported ") ;
+	return (FALSE) ;
+    }
+    if (L->is_super)
+    {
+	/* cannot operate on a supernodal or symbolic factorization */
+	ERROR (CHOLMOD_INVALID, "cannot operate on supernodal L") ;
+	return (FALSE) ;
+    }
+    if (L->n != A->nrow)
+    {
+	/* dimensions must agree */
+	ERROR (CHOLMOD_INVALID, "A and L dimensions do not match") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* s = 2*nrow + (stype ? 0 : ncol) */
+    s = CHOLMOD(mult_size_t) (nrow, 2, &ok) ;
+    if (stype != 0)
+    {
+	s = CHOLMOD(add_size_t) (s, ncol, &ok) ;
+    }
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (nrow, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Ai = A->i ;
+    Ap = A->p ;
+    Anz = A->nz ;
+    apacked = A->packed ;
+    sorted = A->sorted ;
+
+    Li = L->i ;
+    Lx = L->x ;
+    Lz = L->z ;
+    Lp = L->p ;
+    Lnz = L->nz ;
+    xtype = L->xtype ;
+
+    /* If L is monotonic on input, then it can be packed or
+     * unpacked on output, depending on the pack input parameter. */
+
+    /* cannot pack a non-monotonic matrix */
+    if (!(L->is_monotonic))
+    {
+	pack = FALSE ;
+    }
+
+    ASSERT (L->nzmax >= (size_t) (Lp [L->n])) ;
+
+    pdest = 0 ;
+
+    PRINT1 (("\n\n===================== Resymbol pack %d Apacked %d\n",
+	pack, A->packed)) ;
+    ASSERT (CHOLMOD(dump_sparse) (A, "ReSymbol A:", Common) >= 0) ;
+    DEBUG (CHOLMOD(dump_factor) (L, "ReSymbol initial L (i, x):", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Flag  = Common->Flag ;	/* size nrow */
+    Head  = Common->Head ;	/* size nrow+1 */
+    Iwork = Common->Iwork ;
+    Link  = Iwork ;		/* size nrow (i/i/l) [ */
+    Lnz   = Iwork + nrow ;	/* size nrow (i/i/l), if L not packed */
+    Anext = Iwork + 2*((size_t) nrow) ;	/* size ncol (i/i/l), unsym. only */
+    for (j = 0 ; j < nrow ; j++)
+    {
+	Link [j] = EMPTY ;
+    }
+
+    /* use Lnz in L itself */
+    Lnz = L->nz ;
+    ASSERT (Lnz != NULL) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* for the unsymmetric case, queue each column of A (:,f) */
+    /* ---------------------------------------------------------------------- */
+
+    /* place each column of the basis set on the link list corresponding to */
+    /* the smallest row index in that column */
+
+    if (stype == 0)
+    {
+	use_fset = (fset != NULL) ;
+	if (use_fset)
+	{
+	    nf = fsize ;
+	    /* This is the only O(ncol) loop in cholmod_resymbol.
+	     * It is required only to check the fset. */
+	    for (j = 0 ; j < ncol ; j++)
+	    {
+		Anext [j] = -2 ;
+	    }
+	    for (jj = 0 ; jj < nf ; jj++)
+	    {
+		j = fset [jj] ;
+		if (j < 0 || j > ncol || Anext [j] != -2)
+		{
+		    /* out-of-range or duplicate entry in fset */
+		    ERROR (CHOLMOD_INVALID, "fset invalid") ;
+		    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+		    return (FALSE) ;
+		}
+		/* flag column j as having been seen */
+		Anext [j] = EMPTY ;
+	    }
+	    /* the fset is now valid */
+	    ASSERT (CHOLMOD(dump_perm) (fset, nf, ncol, "fset", Common)) ;
+	}
+	else
+	{
+	    nf = ncol ;
+	}
+	for (jj = 0 ; jj < nf ; jj++)
+	{
+	    j = (use_fset) ? (fset [jj]) : jj ;
+	    /* column j is the fset; find the smallest row (if any) */
+	    p = Ap [j] ;
+	    pend = (apacked) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    if (pend > p)
+	    {
+		k = Ai [p] ;
+		if (!sorted)
+		{
+		    for ( ; p < pend ; p++)
+		    {
+			k = MIN (k, Ai [p]) ;
+		    }
+		}
+		/* place column j on link list k */
+		ASSERT (k >= 0 && k < nrow) ;
+		Anext [j] = Head [k] ;
+		Head [k] = j ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* recompute symbolic LDL' factorization */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < nrow ; k++)
+    {
+
+#ifndef NDEBUG
+	PRINT1 (("\n\n================== Initial column k = "ID"\n", k)) ;
+	for (p = Lp [k] ; p < Lp [k] + Lnz [k] ; p++)
+	{
+	    PRINT1 ((" row: "ID"  value: ", Li [p])) ;
+	    PRINT1 (("\n")) ;
+	}
+	PRINT1 (("Recomputing LDL, column k = "ID"\n", k)) ;
+#endif
+
+	/* ------------------------------------------------------------------ */
+	/* compute column k of I+F*F' or I+A */
+	/* ------------------------------------------------------------------ */
+
+	/* flag the diagonal entry */
+	mark = CHOLMOD(clear_flag) (Common) ;
+	Flag [k] = mark ;
+	PRINT1 (("	row: "ID" (diagonal)\n", k)) ;
+
+	if (stype != 0)
+	{
+	    /* merge column k of A into Flag (lower triangular part only) */
+	    p = Ap [k] ;
+	    pend = (apacked) ? (Ap [k+1]) : (p + Anz [k]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		if (i > k)
+		{
+		    Flag [i] = mark ;
+		}
+	    }
+	}
+	else
+	{
+	    /* for each column j whos first row index is in row k */
+	    for (j = Head [k] ; j != EMPTY ; j = Anext [j])
+	    {
+		/* merge column j of A into Flag */
+		PRINT1 (("	---- A column "ID"\n", j)) ;
+		p = Ap [j] ;
+		pend = (apacked) ? (Ap [j+1]) : (p + Anz [j]) ;
+		PRINT1 (("  length "ID"  adding\n", pend-p)) ;
+		for ( ; p < pend ; p++)
+		{
+#ifndef NDEBUG
+		    ASSERT (Ai [p] >= k && Ai [p] < nrow) ;
+		    if (Flag [Ai [p]] < mark) PRINT1 ((" row "ID"\n", Ai [p])) ;
+#endif
+		    Flag [Ai [p]] = mark ;
+		}
+	    }
+	    /* clear the kth link list */
+	    Head [k] = EMPTY ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* compute pruned pattern of kth column of L = union of children */
+	/* ------------------------------------------------------------------ */
+
+	/* for each column j of L whose parent is k */
+	for (j = Link [k] ; j != EMPTY ; j = Link [j])
+	{
+	    /* merge column j of L into Flag */
+	    PRINT1 (("	---- L column "ID"\n", k)) ;
+	    ASSERT (j < k) ;
+	    ASSERT (Lnz [j] > 0) ;
+	    p = Lp [j] ;
+	    pend = p + Lnz [j] ;
+	    ASSERT (Li [p] == j && Li [p+1] == k) ;
+	    p++ ;	    /* skip past the diagonal entry */
+	    for ( ; p < pend ; p++)
+	    {
+		/* add to pattern */
+		ASSERT (Li [p] >= k && Li [p] < nrow) ;
+		Flag [Li [p]] = mark ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* prune the kth column of L */
+	/* ------------------------------------------------------------------ */
+
+	PRINT1 (("Final column of L:\n")) ;
+	p = Lp [k] ;
+	pend = p + Lnz [k] ;
+
+	if (pack)
+	{
+	    /* shift column k upwards */
+	    Lp [k] = pdest ;
+	}
+	else
+	{
+	    /* leave column k in place, just reduce Lnz [k] */
+	    pdest = p ;
+	}
+
+	for ( ; p < pend ; p++)
+	{
+	    ASSERT (pdest < pend) ;
+	    ASSERT (pdest <= p) ;
+	    row = Li [p] ;
+	    ASSERT (row >= k && row < nrow) ;
+	    if (Flag [row] == mark)
+	    {
+		/* keep this entry */
+		Li [pdest] = row ;
+		if (xtype == CHOLMOD_REAL)
+		{
+		    Lx [pdest] = Lx [p] ;
+		}
+		else if (xtype == CHOLMOD_COMPLEX)
+		{
+		    Lx [2*pdest  ] = Lx [2*p  ] ;
+		    Lx [2*pdest+1] = Lx [2*p+1] ;
+		}
+		else if (xtype == CHOLMOD_ZOMPLEX)
+		{
+		    Lx [pdest] = Lx [p] ;
+		    Lz [pdest] = Lz [p] ;
+		}
+		pdest++ ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* prepare this column for its parent */
+	/* ------------------------------------------------------------------ */
+
+	Lnz [k] = pdest - Lp [k] ;
+
+	PRINT1 ((" L("ID") length "ID"\n", k, Lnz [k])) ;
+	ASSERT (Lnz [k] > 0) ;
+
+	/* parent is the first entry in the column after the diagonal */
+	parent = (Lnz [k] > 1) ? (Li [Lp [k] + 1]) : EMPTY ;
+
+	PRINT1 (("parent ("ID") = "ID"\n", k, parent)) ;
+	ASSERT ((parent > k && parent < nrow) || (parent == EMPTY)) ;
+
+	if (parent != EMPTY)
+	{
+	    Link [k] = Link [parent] ;
+	    Link [parent] = k ;
+	}
+    }
+
+    /* done using Iwork for Link, Lnz (if needed), and Anext ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* convert L to packed, if requested */
+    /* ---------------------------------------------------------------------- */
+
+    if (pack)
+    {
+	/* finalize Lp */
+	Lp [nrow] = pdest ;
+	/* Shrink L to be just large enough.  It cannot fail. */
+	/* workspace: none */
+	ASSERT ((size_t) (Lp [nrow]) <= L->nzmax) ;
+	CHOLMOD(reallocate_factor) (Lp [nrow], L, Common) ;
+	ASSERT (Common->status >= CHOLMOD_OK) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* clear workspace */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(clear_flag) (Common) ;
+    DEBUG (CHOLMOD(dump_factor) (L, "ReSymbol final L (i, x):", Common)) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+    return (TRUE) ;
+}
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_rowcolcounts.c b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_rowcolcounts.c
new file mode 100644
index 0000000..7965868
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_rowcolcounts.c
@@ -0,0 +1,535 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_rowcolcounts ======================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Compute the row and column counts of the Cholesky factor L of the matrix
+ * A or A*A'.  The etree and its postordering must already be computed (see
+ * cholmod_etree and cholmod_postorder) and given as inputs to this routine.
+ *
+ * For the symmetric case (LL'=A), A is accessed by column.  Only the lower
+ * triangular part of A is used.  Entries not in this part of the matrix are
+ * ignored.  This is the same as storing the upper triangular part of A by
+ * rows, with entries in the lower triangular part being ignored.  NOTE: this
+ * representation is the TRANSPOSE of the input to cholmod_etree.
+ *
+ * For the unsymmetric case (LL'=AA'), A is accessed by column.  Equivalently,
+ * if A is viewed as a matrix in compressed-row form, this routine computes
+ * the row and column counts for L where LL'=A'A.  If the input vector f is
+ * present, then F*F' is analyzed instead, where F = A(:,f).
+ *
+ * The set f is held in fset and fsize.
+ *	fset = NULL means ":" in MATLAB. fset is ignored.
+ *	fset != NULL means f = fset [0..fset-1].
+ *	fset != NULL and fsize = 0 means f is the empty set.
+ *	Common->status is set to CHOLMOD_INVALID if fset is invalid.
+ *
+ * In both cases, the columns of A need not be sorted.
+ * A can be packed or unpacked.
+ *
+ * References:
+ * J. Gilbert, E. Ng, B. Peyton, "An efficient algorithm to compute row and
+ * column counts for sparse Cholesky factorization", SIAM J. Matrix Analysis &
+ * Applic., vol 15, 1994, pp. 1075-1091.
+ *
+ * J. Gilbert, X. Li, E. Ng, B. Peyton, "Computing row and column counts for
+ * sparse QR and LU factorization", BIT, vol 41, 2001, pp. 693-710.
+ *
+ * workspace:
+ *	if symmetric:   Flag (nrow), Iwork (2*nrow)
+ *	if unsymmetric: Flag (nrow), Iwork (2*nrow+ncol), Head (nrow+1)
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex).
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+/* ========================================================================== */
+/* === initialize_node ====================================================== */
+/* ========================================================================== */
+
+static int initialize_node  /* initial work for kth node in postordered etree */
+(
+    Int k,		/* at the kth step of the algorithm (and kth node) */
+    Int Post [ ],	/* Post [k] = i, the kth node in postordered etree */
+    Int Parent [ ],	/* Parent [i] is the parent of i in the etree */
+    Int ColCount [ ],	/* ColCount [c] is the current weight of node c */
+    Int PrevNbr [ ]	/* PrevNbr [u] = k if u was last considered at step k */
+)
+{
+    Int p, parent ;
+    /* determine p, the kth node in the postordered etree */
+    p = Post [k] ;
+    /* adjust the weight if p is not a root of the etree */
+    parent = Parent [p] ;
+    if (parent != EMPTY)
+    {
+	ColCount [parent]-- ;
+    }
+    /* flag node p to exclude self edges (p,p) */
+    PrevNbr [p] = k ;
+    return (p) ;
+}
+
+
+/* ========================================================================== */
+/* === process_edge ========================================================= */
+/* ========================================================================== */
+
+/* edge (p,u) is being processed.  p < u is a descendant of its ancestor u in
+ * the etree.  node p is the kth node in the postordered etree.  */
+
+static void process_edge
+(
+    Int p,		/* process edge (p,u) of the matrix */
+    Int u,
+    Int k,		/* we are at the kth node in the postordered etree */
+    Int First [ ],	/* First [i] = k if the postordering of first
+			 * descendent of node i is k */
+    Int PrevNbr [ ],	/* u was last considered at step k = PrevNbr [u] */
+    Int ColCount [ ],	/* ColCount [c] is the current weight of node c */
+    Int PrevLeaf [ ],	/* s = PrevLeaf [u] means that s was the last leaf
+			 * seen in the subtree rooted at u.  */
+    Int RowCount [ ],	/* RowCount [i] is # of nonzeros in row i of L,
+			 * including the diagonal.  Not computed if NULL. */
+    Int SetParent [ ],	/* the FIND/UNION data structure, which forms a set
+			 * of trees.  A root i has i = SetParent [i].  Following
+			 * a path from i to the root q of the subtree containing
+			 * i means that q is the SetParent representative of i.
+			 * All nodes in the tree could have their SetParent
+			 * equal to the root q; the tree representation is used
+			 * to save time.  When a path is traced from i to its
+			 * root q, the path is re-traversed to set the SetParent
+			 * of the whole path to be the root q. */
+    Int Level [ ]	 /* Level [i] = length of path from node i to root */
+)
+{
+    Int prevleaf, q, s, sparent ;
+    if (First [p] > PrevNbr [u])
+    {
+	/* p is a leaf of the subtree of u */
+	ColCount [p]++ ;
+	prevleaf = PrevLeaf [u] ;
+	if (prevleaf == EMPTY)
+	{
+	    /* p is the first leaf of subtree of u; RowCount will be incremented
+	     * by the length of the path in the etree from p up to u. */
+	    q = u ;
+	}
+	else
+	{
+	    /* q = FIND (prevleaf): find the root q of the
+	     * SetParent tree containing prevleaf */
+	    for (q = prevleaf ; q != SetParent [q] ; q = SetParent [q])
+	    {
+		;
+	    }
+	    /* the root q has been found; re-traverse the path and
+	     * perform path compression */
+	    s = prevleaf ;
+	    for (s = prevleaf ; s != q ; s = sparent)
+	    {
+		sparent = SetParent [s] ;
+		SetParent [s] = q ;
+	    }
+	    /* adjust the RowCount and ColCount; RowCount will be incremented by
+	     * the length of the path from p to the SetParent root q, and
+	     * decrement the ColCount of q by one. */
+	    ColCount [q]-- ;
+	}
+	if (RowCount != NULL)
+	{
+	    /* if RowCount is being computed, increment it by the length of
+	     * the path from p to q */
+	    RowCount [u] += (Level [p] - Level [q]) ;
+	}
+	/* p is a leaf of the subtree of u, so mark PrevLeaf [u] to be p */
+	PrevLeaf [u] = p ;
+    }
+    /* flag u has having been processed at step k */
+    PrevNbr [u] = k ;
+}
+
+
+/* ========================================================================== */
+/* === finalize_node ======================================================== */
+/* ========================================================================== */
+
+static void finalize_node    /* compute UNION (p, Parent [p]) */
+(
+    Int p,
+    Int Parent [ ],	/* Parent [p] is the parent of p in the etree */
+    Int SetParent [ ]	/* see process_edge, above */
+)
+{
+    /* all nodes in the SetParent tree rooted at p now have as their final
+     * root the node Parent [p].  This computes UNION (p, Parent [p]) */
+    if (Parent [p] != EMPTY)
+    {
+	SetParent [p] = Parent [p] ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === cholmod_rowcolcounts ================================================= */
+/* ========================================================================== */
+
+int CHOLMOD(rowcolcounts)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    Int *Parent,	/* size nrow.  Parent [i] = p if p is the parent of i */
+    Int *Post,		/* size nrow.  Post [k] = i if i is the kth node in
+			 * the postordered etree. */
+    /* ---- output --- */
+    Int *RowCount,	/* size nrow. RowCount [i] = # entries in the ith row of
+			 * L, including the diagonal. */
+    Int *ColCount,	/* size nrow. ColCount [i] = # entries in the ith
+			 * column of L, including the diagonal. */
+    Int *First,		/* size nrow.  First [i] = k is the least postordering
+			 * of any descendant of i. */
+    Int *Level,		/* size nrow.  Level [i] is the length of the path from
+			 * i to the root, with Level [root] = 0. */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double fl, ff ;
+    Int *Ap, *Ai, *Anz, *PrevNbr, *SetParent, *Head, *PrevLeaf, *Anext, *Ipost,
+	*Iwork ;
+    Int i, j, r, k, len, s, p, pend, inew, stype, nf, anz, inode, parent,
+	nrow, ncol, packed, use_fset, jj ;
+    size_t w ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (Parent, FALSE) ;
+    RETURN_IF_NULL (Post, FALSE) ;
+    RETURN_IF_NULL (ColCount, FALSE) ;
+    RETURN_IF_NULL (First, FALSE) ;
+    RETURN_IF_NULL (Level, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    stype = A->stype ;
+    if (stype > 0)
+    {
+	/* symmetric with upper triangular part not supported */
+	ERROR (CHOLMOD_INVALID, "symmetric upper not supported") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = A->nrow ;	/* the number of rows of A */
+    ncol = A->ncol ;	/* the number of columns of A */
+
+    /* w = 2*nrow + (stype ? 0 : ncol) */
+    w = CHOLMOD(mult_size_t) (nrow, 2, &ok) ;
+    w = CHOLMOD(add_size_t) (w, (stype ? 0 : ncol), &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (nrow, w, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+
+    ASSERT (CHOLMOD(dump_perm) (Post, nrow, nrow, "Post", Common)) ;
+    ASSERT (CHOLMOD(dump_parent) (Parent, nrow, "Parent", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;	/* size ncol+1, column pointers for A */
+    Ai = A->i ;	/* the row indices of A, of size nz=Ap[ncol+1] */
+    Anz = A->nz ;
+    packed = A->packed ;
+    ASSERT (IMPLIES (!packed, Anz != NULL)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Iwork = Common->Iwork ;
+    SetParent = Iwork ;		    /* size nrow (i/i/l) */
+    PrevNbr   = Iwork + nrow ;	    /* size nrow (i/i/l) */
+    Anext     = Iwork + 2*((size_t) nrow) ;    /* size ncol (i/i/l) (unsym only) */
+    PrevLeaf  = Common->Flag ;	    /* size nrow */
+    Head      = Common->Head ;	    /* size nrow+1 (unsym only)*/
+
+    /* ---------------------------------------------------------------------- */
+    /* find the first descendant and level of each node in the tree */
+    /* ---------------------------------------------------------------------- */
+
+    /* First [i] = k if the postordering of first descendent of node i is k */
+    /* Level [i] = length of path from node i to the root (Level [root] = 0) */
+
+    for (i = 0 ; i < nrow ; i++)
+    {
+	First [i] = EMPTY ;
+    }
+
+    /* postorder traversal of the etree */
+    for (k = 0 ; k < nrow ; k++)
+    {
+	/* node i of the etree is the kth node in the postordered etree */
+	i = Post [k] ;
+
+	/* i is a leaf if First [i] is still EMPTY */
+	/* ColCount [i] starts at 1 if i is a leaf, zero otherwise */
+	ColCount [i] = (First [i] == EMPTY) ? 1 : 0 ;
+
+	/* traverse the path from node i to the root, stopping if we find a
+	 * node r whose First [r] is already defined. */
+	len = 0 ;
+	for (r = i ; (r != EMPTY) && (First [r] == EMPTY) ; r = Parent [r])
+	{
+	    First [r] = k ;
+	    len++ ;
+	}
+	if (r == EMPTY)
+	{
+	    /* we hit a root node, the level of which is zero */
+	    len-- ;
+	}
+	else
+	{
+	    /* we stopped at node r, where Level [r] is already defined */
+	    len += Level [r] ;
+	}
+	/* re-traverse the path from node i to r; set the level of each node */
+	for (s = i ; s != r ; s = Parent [s])
+	{
+	    Level [s] = len-- ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* AA' case: sort columns of A according to first postordered row index */
+    /* ---------------------------------------------------------------------- */
+
+    fl = 0.0 ;
+    if (stype == 0)
+    {
+	/* [ use PrevNbr [0..nrow-1] as workspace for Ipost */
+	Ipost = PrevNbr ;
+	/* Ipost [i] = k if i is the kth node in the postordered etree. */
+	for (k = 0 ; k < nrow ; k++)
+	{
+	    Ipost [Post [k]] = k ;
+	}
+	use_fset = (fset != NULL) ;
+	if (use_fset)
+	{
+	    nf = fsize ;
+	    /* clear Anext to check fset */
+	    for (j = 0 ; j < ncol ; j++)
+	    {
+		Anext [j] = -2 ;
+	    }
+	    /* find the first postordered row in each column of A (post,f)
+	     * and place the column in the corresponding link list */
+	    for (jj = 0 ; jj < nf ; jj++)
+	    {
+		j = fset [jj] ;
+		if (j < 0 || j > ncol || Anext [j] != -2)
+		{
+		    /* out-of-range or duplicate entry in fset */
+		    ERROR (CHOLMOD_INVALID, "fset invalid") ;
+		    return (FALSE) ;
+		}
+		/* flag column j as having been seen */
+		Anext [j] = EMPTY ;
+	    }
+	    /* fset is now valid */
+	    ASSERT (CHOLMOD(dump_perm) (fset, nf, ncol, "fset", Common)) ;
+	}
+	else
+	{
+	    nf = ncol ;
+	}
+	for (jj = 0 ; jj < nf ; jj++)
+	{
+	    j = (use_fset) ? (fset [jj]) : jj ;
+	    /* column j is in the fset; find the smallest row (if any) */
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    ff = (double) MAX (0, pend - p) ;
+	    fl += ff*ff + ff ;
+	    if (pend > p)
+	    {
+		k = Ipost [Ai [p]] ;
+		for ( ; p < pend ; p++)
+		{
+		    inew = Ipost [Ai [p]] ;
+		    k = MIN (k, inew) ;
+		}
+		/* place column j in link list k */
+		ASSERT (k >= 0 && k < nrow) ;
+		Anext [j] = Head [k] ;
+		Head [k] = j ;
+	    }
+	}
+	/* Ipost no longer needed for inverse postordering ]
+	 * Head [k] contains a link list of all columns whose first
+	 * postordered row index is equal to k, for k = 0 to nrow-1. */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the row counts and node weights */
+    /* ---------------------------------------------------------------------- */
+
+    if (RowCount != NULL)
+    {
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    RowCount [i] = 1 ;
+	}
+    }
+    for (i = 0 ; i < nrow ; i++)
+    {
+	PrevLeaf [i] = EMPTY ;
+	PrevNbr [i] = EMPTY ;
+	SetParent [i] = i ;	/* every node is in its own set, by itself */
+    }
+
+    if (stype != 0)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* symmetric case: LL' = A */
+	/* ------------------------------------------------------------------ */
+
+	/* also determine the number of entries in triu(A) */
+	anz = nrow ;
+	for (k = 0 ; k < nrow ; k++)
+	{
+	    /* j is the kth node in the postordered etree */
+	    j = initialize_node (k, Post, Parent, ColCount, PrevNbr) ;
+
+	    /* for all nonzeros A(i,j) below the diagonal, in column j of A */
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		if (i > j)
+		{
+		    /* j is a descendant of i in etree(A) */
+		    anz++ ;
+		    process_edge (j, i, k, First, PrevNbr, ColCount,
+			    PrevLeaf, RowCount, SetParent, Level) ;
+		}
+	    }
+	    /* update SetParent: UNION (j, Parent [j]) */
+	    finalize_node (j, Parent, SetParent) ;
+	}
+	Common->anz = anz ;
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* unsymmetric case: LL' = AA' */
+	/* ------------------------------------------------------------------ */
+
+	for (k = 0 ; k < nrow ; k++)
+	{
+	    /* inode is the kth node in the postordered etree */
+	    inode = initialize_node (k, Post, Parent, ColCount, PrevNbr) ;
+
+	    /* for all cols j whose first postordered row is k: */
+	    for (j = Head [k] ; j != EMPTY ; j = Anext [j])
+	    {
+		/* k is the first postordered row in column j of A */
+		/* for all rows i in column j: */
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    /* has i already been considered at this step k */
+		    if (PrevNbr [i] < k)
+		    {
+			/* inode is a descendant of i in etree(AA') */
+			/* process edge (inode,i) and set PrevNbr[i] to k */
+			process_edge (inode, i, k, First, PrevNbr, ColCount,
+				PrevLeaf, RowCount, SetParent, Level) ;
+		    }
+		}
+	    }
+	    /* clear link list k */
+	    Head [k] = EMPTY ;
+	    /* update SetParent: UNION (inode, Parent [inode]) */
+	    finalize_node (inode, Parent, SetParent) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* finish computing the column counts */
+    /* ---------------------------------------------------------------------- */
+
+    for (j = 0 ; j < nrow ; j++)
+    {
+	parent = Parent [j] ;
+	if (parent != EMPTY)
+	{
+	    /* add the ColCount of j to its parent */
+	    ColCount [parent] += ColCount [j] ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* clear workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Common->mark = EMPTY ;
+    CHOLMOD(clear_flag) (Common) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* flop count and nnz(L) for subsequent LL' numerical factorization */
+    /* ---------------------------------------------------------------------- */
+
+    /* use double to avoid integer overflow.  lnz cannot be NaN. */
+    Common->aatfl = fl ;
+    Common->lnz = 0. ;
+    fl = 0 ;
+    for (j = 0 ; j < nrow ; j++)
+    {
+	ff = (double) (ColCount [j]) ;
+	Common->lnz += ff ;
+	fl += ff*ff ;
+    }
+
+    Common->fl = fl ;
+    PRINT1 (("rowcol fl %g lnz %g\n", Common->fl, Common->lnz)) ;
+
+    return (TRUE) ;
+}
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_rowfac.c b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_rowfac.c
new file mode 100644
index 0000000..f0be0e9
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_rowfac.c
@@ -0,0 +1,677 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_rowfac ============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Full or incremental numerical LDL' or LL' factorization (simplicial, not
+ * supernodal) cholmod_factorize is the "easy" wrapper for this code, but it
+ * does not provide access to incremental factorization.
+ *
+ * cholmod_rowfac computes the full or incremental LDL' or LL' factorization of
+ * A+beta*I (where A is symmetric) or A*F+beta*I (where A and F are unsymmetric
+ * and only the upper triangular part of A*F+beta*I is used).  It computes
+ * L (and D, for LDL') one row at a time.  beta is real.
+ *
+ * A is nrow-by-ncol or nrow-by-nrow.  In "packed" form it is a conventional
+ * column-oriented sparse matrix.  Row indices of column j are in
+ * Ai [Ap [j] ... Ap [j+1]-1] and values in the same locations of Ax.
+ * will be faster if A has sorted columns.  In "unpacked" form the column
+ * of A ends at Ap [j] + Anz [j] - 1 instead of Ap [j+1] - 1.
+ *
+ * Row indices in each column of A can be sorted or unsorted, but the routine
+ * routine works fastest if A is sorted, or if only triu(A) is provided
+ * for the symmetric case.
+ *
+ * The unit-diagonal nrow-by-nrow output matrix L is returned in "unpacked"
+ * column form, with row indices of column j in Li [Lp [j] ...
+ * Lp [j] + Lnz [j] - 1] and values in the same location in Lx.  The row
+ * indices in each column of L are in sorted order.  The unit diagonal of L
+ * is not stored.
+ *
+ * L can be a simplicial symbolic or numeric (L->is_super must be FALSE).
+ * A symbolic factor is converted immediately into a numeric factor containing
+ * the identity matrix.
+ *
+ * For a full factorization, kstart = 0 and kend = nrow.  The existing nonzero
+ * entries (numerical values in L->x and L->z for the zomplex case, and indices
+ * in L->i), if any, are overwritten.
+ *
+ * To compute an incremental factorization, select kstart and kend as the range
+ * of rows of L you wish to compute.  A correct factorization will be computed
+ * only if all descendants of all nodes k = kstart to kend-1 in the etree have
+ * been factorized by a prior call to this routine, and if rows kstart to kend-1
+ * have not been factorized.  This condition is NOT checked on input.
+ *
+ * ---------------
+ * Symmetric case:
+ * ---------------
+ *
+ *	The factorization (in MATLAB notation) is:
+ *
+ *	S = beta*I + A
+ *	S = triu (S) + triu (S,1)'
+ *	L*D*L' = S, or L*L' = S
+ *
+ *	A is a conventional sparse matrix in compressed column form.  Only the
+ *	diagonal and upper triangular part of A is accessed; the lower
+ *	triangular part is ignored and assumed to be equal to the upper
+ *	triangular part.  For an incremental factorization, only columns kstart
+ *	to kend-1 of A are accessed.  F is not used.
+ *
+ * ---------------
+ * Unsymmetric case:
+ * ---------------
+ *
+ *	The factorization (in MATLAB notation) is:
+ *
+ *	S = beta*I + A*F
+ *	S = triu (S) + triu (S,1)'
+ *	L*D*L' = S, or L*L' = S
+ *
+ *	The typical case is F=A'.  Alternatively, if F=A(:,f)', then this
+ *	routine factorizes S = beta*I + A(:,f)*A(:,f)'.
+ *
+ *	All of A and F are accessed, but only the upper triangular part of A*F
+ *	is used.  F must be of size A->ncol by A->nrow.  F is used for the
+ *	unsymmetric case only.  F can be packed or unpacked and it need not be
+ *	sorted.
+ *
+ *	For a complete factorization of beta*I + A*A',
+ *	this routine performs a number of flops exactly equal to:
+ *
+ *	sum (for each column j of A) of (Anz (j)^2 + Anz (j)), to form S
+ *	+
+ *	sum (for each column j of L) of (Lnz (j)^2 + 3*Lnz (j)), to factorize S
+ *
+ *	where Anz (j) is the number of nonzeros in column j of A, and Lnz (j)
+ *	is the number of nonzero in column j of L below the diagonal.
+ *
+ *
+ * workspace: Flag (nrow), W (nrow if real, 2*nrow if complex/zomplex),
+ * Iwork (nrow)
+ *
+ * Supports any xtype, except a pattern-only input matrix A cannot be
+ * factorized.
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+/* ========================================================================== */
+/* === subtree ============================================================== */
+/* ========================================================================== */
+
+/* Compute the nonzero pattern of the sparse triangular solve Lx=b, where L in
+ * this case is L(0:k-1,0:k-1), and b is a column of A.  This is done by
+ * traversing the kth row-subtree of the elimination tree of L, starting from
+ * each nonzero entry in b.  The pattern is returned postordered, and is valid
+ * for a subsequent numerical triangular solve of Lx=b.  The elimination tree
+ * can be provided in a Parent array, or extracted from the pattern of L itself.
+ *
+ * The pattern of x = inv(L)*b is returned in Stack [top...].
+ * Also scatters b, or a multiple of b, into the work vector W.
+ *
+ * The SCATTER macro is defines how the numerical values of A or A*A' are to be
+ * scattered.
+ *
+ * PARENT(i) is a macro the defines how the etree is accessed.  It is either:
+ *	#define PARENT(i) Parent [i]
+ *	#define PARENT(i) (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY
+ */
+
+#define SUBTREE \
+    for ( ; p < pend ; p++) \
+    { \
+	i = Ai [p] ; \
+	if (i <= k) \
+	{ \
+	    /* scatter the column of A, or A*A' into Wx and Wz */ \
+	    SCATTER ; \
+	    /* start at node i and traverse up the subtree, stop at node k */ \
+	    for (len = 0 ; i < k && i != EMPTY && Flag [i] < mark ; i = parent) \
+	    { \
+		/* L(k,i) is nonzero, and seen for the first time */ \
+		Stack [len++] = i ;	    /* place i on the stack */ \
+		Flag [i] = mark ;	    /* mark i as visited */ \
+		parent = PARENT (i) ;   /* traverse up the etree to the parent */ \
+	    } \
+	    /* move the path down to the bottom of the stack */ \
+	    while (len > 0) \
+	    { \
+		Stack [--top] = Stack [--len] ; \
+	    } \
+	} \
+	else if (sorted) \
+	{ \
+	    break ; \
+	} \
+    }
+
+
+/* ========================================================================== */
+/* === TEMPLATE ============================================================= */
+/* ========================================================================== */
+
+#define REAL
+#include "t_cholmod_rowfac.c"
+#define COMPLEX
+#include "t_cholmod_rowfac.c"
+#define ZOMPLEX
+#include "t_cholmod_rowfac.c"
+
+#define MASK
+#define REAL
+#include "t_cholmod_rowfac.c"
+#define COMPLEX
+#include "t_cholmod_rowfac.c"
+#define ZOMPLEX
+#include "t_cholmod_rowfac.c"
+#undef MASK
+
+
+/* ========================================================================== */
+/* === cholmod_row_subtree ================================================== */
+/* ========================================================================== */
+
+/* Compute the nonzero pattern of the solution to the lower triangular system
+ * L(0:k-1,0:k-1) * x = A (0:k-1,k) if A is symmetric, or
+ * L(0:k-1,0:k-1) * x = A (0:k-1,:) * A (:,k)' if A is unsymmetric.
+ * This gives the nonzero pattern of row k of L (excluding the diagonal).
+ * The pattern is returned postordered.
+ *
+ * The symmetric case requires A to be in symmetric-upper form.
+ *
+ * The result is returned in R, a pre-allocated sparse matrix of size nrow-by-1,
+ * with R->nzmax >= nrow.  R is assumed to be packed (Rnz [0] is not updated);
+ * the number of entries in R is given by Rp [0].
+ *
+ * FUTURE WORK:  a very minor change to this routine could allow it to compute
+ * the nonzero pattern of x for any system Lx=b.  The SUBTREE macro would need
+ * to change, to eliminate its dependence on k.
+ *
+ * workspace: Flag (nrow)
+ */
+
+int CHOLMOD(row_subtree)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    cholmod_sparse *F,	/* used for A*A' case only. F=A' or A(:,f)' */
+    size_t krow,	/* row k of L */
+    Int *Parent,	/* elimination tree */
+    /* ---- output --- */
+    cholmod_sparse *R,	/* pattern of L(k,:), 1-by-n with R->nzmax >= n */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Rp, *Stack, *Flag, *Ap, *Ai, *Anz, *Fp, *Fi, *Fnz ;
+    Int p, pend, parent, t, stype, nrow, k, pf, pfend, Fpacked, packed,
+	sorted, top, len, i, mark ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (R, FALSE) ;
+    RETURN_IF_NULL (Parent, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (R, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    stype = A->stype ;
+    if (stype == 0)
+    {
+	RETURN_IF_NULL (F, FALSE) ;
+	RETURN_IF_XTYPE_INVALID (F, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    }
+    if (krow >= A->nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "subtree: k invalid") ;
+	return (FALSE) ;
+    }
+    if (R->ncol != 1 || A->nrow != R->nrow || A->nrow > R->nzmax)
+    {
+	ERROR (CHOLMOD_INVALID, "subtree: R invalid") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = A->nrow ;
+    CHOLMOD(allocate_work) (nrow, 0, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    if (stype > 0)
+    {
+	/* symmetric upper case: F is not needed.  It may be NULL */
+	Fp = NULL ;
+	Fi = NULL ;
+	Fnz = NULL ;
+	Fpacked = TRUE ;
+    }
+    else if (stype == 0)
+    {
+	/* unsymmetric case: F is required. */
+	Fp = F->p ;
+	Fi = F->i ;
+	Fnz = F->nz ;
+	Fpacked = F->packed ;
+    }
+    else
+    {
+	/* symmetric lower triangular form not supported */
+	ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ;
+	return (FALSE) ;
+    }
+
+    Ap = A->p ;
+    Ai = A->i ;
+    Anz = A->nz ;
+    packed = A->packed ;
+    sorted = A->sorted ;
+
+    k = krow ;
+    Stack = R->i ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Flag = Common->Flag ;	/* size nrow, Flag [i] < mark must hold */
+    mark = CHOLMOD(clear_flag) (Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the pattern of L(k,:) */
+    /* ---------------------------------------------------------------------- */
+
+    top = nrow ;		/* Stack is empty */
+    Flag [k] = mark ;		/* do not include diagonal entry in Stack */
+
+#define SCATTER			/* do not scatter numerical values */
+#define PARENT(i) Parent [i]	/* use Parent for etree */
+
+    if (stype != 0)
+    {
+	/* scatter kth col of triu (A), get pattern L(k,:) */
+	p = Ap [k] ;
+	pend = (packed) ? (Ap [k+1]) : (p + Anz [k]) ;
+	SUBTREE ;
+    }
+    else
+    {
+	/* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */
+	pf = Fp [k] ;
+	pfend = (Fpacked) ? (Fp [k+1]) : (pf + Fnz [k]) ;
+	for ( ; pf < pfend ; pf++)
+	{
+	    /* get nonzero entry F (t,k) */
+	    t = Fi [pf] ;
+	    p = Ap [t] ;
+	    pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ;
+	    SUBTREE ;
+	}
+    }
+
+#undef SCATTER
+#undef PARENT
+
+    /* shift the stack upwards, to the first part of R */
+    len = nrow - top ;
+    for (i = 0 ; i < len ; i++)
+    {
+	Stack [i] = Stack [top + i] ;
+    }
+
+    Rp = R->p ;
+    Rp [0] = 0 ;
+    Rp [1] = len ;
+    R->sorted = FALSE ;
+
+    CHOLMOD(clear_flag) (Common) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_row_lsubtree ================================================= */
+/* ========================================================================== */
+
+/* Identical to cholmod_row_subtree, except that the elimination tree is
+ * obtained from L itself, as the first off-diagonal entry in each column.
+ * L must be simplicial, not supernodal */
+
+int CHOLMOD(row_lsubtree)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    Int *Fi, size_t fnz,    /* nonzero pattern of kth row of A', not required
+			     * for the symmetric case.  Need not be sorted. */
+    size_t krow,	/* row k of L */
+    cholmod_factor *L,	/* the factor L from which parent(i) is derived */
+    /* ---- output --- */
+    cholmod_sparse *R,	/* pattern of L(k,:), 1-by-n with R->nzmax >= n */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Rp, *Stack, *Flag, *Ap, *Ai, *Anz, *Lp, *Li, *Lnz ;
+    Int p, pend, parent, t, stype, nrow, k, pf, packed, sorted, top, len, i,
+	mark ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (R, FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (R, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    stype = A->stype ;
+    if (stype == 0)
+    {
+	RETURN_IF_NULL (Fi, FALSE) ;
+    }
+    if (krow >= A->nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "lsubtree: k invalid") ;
+	return (FALSE) ;
+    }
+    if (R->ncol != 1 || A->nrow != R->nrow || A->nrow > R->nzmax)
+    {
+	ERROR (CHOLMOD_INVALID, "lsubtree: R invalid") ;
+	return (FALSE) ;
+    }
+    if (L->is_super)
+    {
+	ERROR (CHOLMOD_INVALID, "lsubtree: L invalid (cannot be supernodal)") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = A->nrow ;
+    CHOLMOD(allocate_work) (nrow, 0, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    if (stype < 0)
+    {
+	/* symmetric lower triangular form not supported */
+	ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ;
+	return (FALSE) ;
+    }
+
+    Ap = A->p ;
+    Ai = A->i ;
+    Anz = A->nz ;
+    packed = A->packed ;
+    sorted = A->sorted ;
+
+    k = krow ;
+    Stack = R->i ;
+
+    Lp = L->p ;
+    Li = L->i ;
+    Lnz = L->nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Flag = Common->Flag ;	/* size nrow, Flag [i] < mark must hold */
+    mark = CHOLMOD(clear_flag) (Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the pattern of L(k,:) */
+    /* ---------------------------------------------------------------------- */
+
+    top = nrow ;		/* Stack is empty */
+    Flag [k] = mark ;		/* do not include diagonal entry in Stack */
+
+#define SCATTER			/* do not scatter numerical values */
+#define PARENT(i) (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY
+
+    if (stype != 0)
+    {
+	/* scatter kth col of triu (A), get pattern L(k,:) */
+	p = Ap [k] ;
+	pend = (packed) ? (Ap [k+1]) : (p + Anz [k]) ;
+	SUBTREE ;
+    }
+    else
+    {
+	/* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */
+	for (pf = 0 ; pf < (Int) fnz ; pf++)
+	{
+	    /* get nonzero entry F (t,k) */
+	    t = Fi [pf] ;
+	    p = Ap [t] ;
+	    pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ;
+	    SUBTREE ;
+	}
+    }
+
+#undef SCATTER
+#undef PARENT
+
+    /* shift the stack upwards, to the first part of R */
+    len = nrow - top ;
+    for (i = 0 ; i < len ; i++)
+    {
+	Stack [i] = Stack [top + i] ;
+    }
+
+    Rp = R->p ;
+    Rp [0] = 0 ;
+    Rp [1] = len ;
+    R->sorted = FALSE ;
+
+    CHOLMOD(clear_flag) (Common) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_rowfac ======================================================= */
+/* ========================================================================== */
+
+/* This is the incremental factorization for general purpose usage. */
+
+int CHOLMOD(rowfac)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    cholmod_sparse *F,	/* used for A*A' case only. F=A' or A(:,f)' */
+    double beta [2],	/* factorize beta*I+A or beta*I+AA' */
+    size_t kstart,	/* first row to factorize */
+    size_t kend,	/* last row to factorize is kend-1 */
+    /* ---- in/out --- */
+    cholmod_factor *L,
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    return (CHOLMOD(rowfac_mask) (A, F, beta, kstart, kend, NULL, NULL, L,
+	Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_rowfac_mask ================================================== */
+/* ========================================================================== */
+
+/* This is meant for use in LPDASA only. */
+
+int CHOLMOD(rowfac_mask)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    cholmod_sparse *F,	/* used for A*A' case only. F=A' or A(:,f)' */
+    double beta [2],	/* factorize beta*I+A or beta*I+AA' */
+    size_t kstart,	/* first row to factorize */
+    size_t kend,	/* last row to factorize is kend-1 */
+    Int *mask,		/* size A->nrow. if mask[i] >= 0 row i is set to zero */
+    Int *RLinkUp,	/* size A->nrow. link list of rows to compute */
+    /* ---- in/out --- */
+    cholmod_factor *L,
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int n ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (L->xtype != CHOLMOD_PATTERN && A->xtype != L->xtype)
+    {
+	ERROR (CHOLMOD_INVALID, "xtype of A and L do not match") ;
+	return (FALSE) ;
+    }
+    if (L->is_super)
+    {
+	ERROR (CHOLMOD_INVALID, "can only do simplicial factorization");
+	return (FALSE) ;
+    }
+    if (A->stype == 0)
+    {
+	RETURN_IF_NULL (F, FALSE) ;
+	if (A->xtype != F->xtype)
+	{
+	    ERROR (CHOLMOD_INVALID, "xtype of A and F do not match") ;
+	    return (FALSE) ;
+	}
+    }
+    if (A->stype < 0)
+    {
+	/* symmetric lower triangular form not supported */
+	ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ;
+	return (FALSE) ;
+    }
+    if (kend > L->n)
+    {
+	ERROR (CHOLMOD_INVALID, "kend invalid") ;
+	return (FALSE) ;
+    }
+    if (A->nrow != L->n)
+    {
+	ERROR (CHOLMOD_INVALID, "dimensions of A and L do not match") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+    Common->rowfacfl = 0 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* Xwork is of size n for the real case, 2*n for complex/zomplex */
+    n = L->n  ;
+
+    /* s = ((A->xtype != CHOLMOD_REAL) ? 2:1)*n */
+    s = CHOLMOD(mult_size_t) (n, ((A->xtype != CHOLMOD_REAL) ? 2:1), &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (n, n, s, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, A->nrow, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* factorize the matrix, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    if (RLinkUp == NULL)
+    {
+
+	switch (A->xtype)
+	{
+	    case CHOLMOD_REAL:
+		ok = r_cholmod_rowfac (A, F, beta, kstart, kend, L, Common) ;
+		break ;
+
+	    case CHOLMOD_COMPLEX:
+		ok = c_cholmod_rowfac (A, F, beta, kstart, kend, L, Common) ;
+		break ;
+
+	    case CHOLMOD_ZOMPLEX:
+		ok = z_cholmod_rowfac (A, F, beta, kstart, kend, L, Common) ;
+		break ;
+	}
+
+    }
+    else
+    {
+
+	switch (A->xtype)
+	{
+	    case CHOLMOD_REAL:
+		ok = r_cholmod_rowfac_mask (A, F, beta, kstart, kend,
+		    mask, RLinkUp, L, Common) ;
+		break ;
+
+	    case CHOLMOD_COMPLEX:
+		ok = c_cholmod_rowfac_mask (A, F, beta, kstart, kend,
+		    mask, RLinkUp, L, Common) ;
+		break ;
+
+	    case CHOLMOD_ZOMPLEX:
+		ok = z_cholmod_rowfac_mask (A, F, beta, kstart, kend,
+		    mask, RLinkUp, L, Common) ;
+		break ;
+	}
+    }
+
+    return (ok) ;
+}
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_solve.c b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_solve.c
new file mode 100644
index 0000000..f8ab992
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_solve.c
@@ -0,0 +1,1195 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_solve =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Solve one of the following systems:
+ *
+ *	Ax=b	    0: CHOLMOD_A	also applies the permutation L->Perm
+ *	LDL'x=b	    1: CHOLMOD_LDLt	does not apply L->Perm
+ *	LDx=b	    2: CHOLMOD_LD
+ *	DL'x=b	    3: CHOLMOD_DLt
+ *	Lx=b	    4: CHOLMOD_L
+ *	L'x=b	    5: CHOLMOD_Lt
+ *	Dx=b	    6: CHOLMOD_D
+ *	x=Pb	    7: CHOLMOD_P	apply a permutation (P is L->Perm)
+ *	x=P'b	    8: CHOLMOD_Pt	apply an inverse permutation
+ *
+ * The factorization can be simplicial LDL', simplicial LL', or supernodal LL'.
+ * For an LL' factorization, D is the identity matrix.  Thus CHOLMOD_LD and
+ * CHOLMOD_L solve the same system if an LL' factorization was performed,
+ * for example.
+ *
+ * The supernodal solver uses BLAS routines dtrsv, dgemv, dtrsm, and dgemm,
+ * or their complex counterparts ztrsv, zgemv, ztrsm, and zgemm.
+ *
+ * If both L and B are real, then X is returned real.  If either is complex
+ * or zomplex, X is returned as either complex or zomplex, depending on the
+ * Common->prefer_zomplex parameter.
+ *
+ * Supports any numeric xtype (pattern-only matrices not supported).
+ *
+ * This routine does not check to see if the diagonal of L or D is zero,
+ * because sometimes a partial solve can be done with indefinite or singular
+ * matrix.  If you wish to check in your own code, test L->minor.  If
+ * L->minor == L->n, then the matrix has no zero diagonal entries.
+ * If k = L->minor < L->n, then L(k,k) is zero for an LL' factorization, or
+ * D(k,k) is zero for an LDL' factorization.
+ *
+ * This routine returns X as NULL only if it runs out of memory.  If L is
+ * indefinite or singular, then X may contain Inf's or NaN's, but it will
+ * exist on output.
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+#ifndef NSUPERNODAL
+#include "cholmod_supernodal.h"
+#endif
+
+
+/* ========================================================================== */
+/* === TEMPLATE ============================================================= */
+/* ========================================================================== */
+
+#define REAL
+#include "t_cholmod_solve.c"
+
+#define COMPLEX
+#include "t_cholmod_solve.c"
+
+#define ZOMPLEX
+#include "t_cholmod_solve.c"
+
+/* ========================================================================== */
+/* === Permutation macro ==================================================== */
+/* ========================================================================== */
+
+/* If Perm is NULL, it is interpretted as the identity permutation */
+
+#define P(k) ((Perm == NULL) ? (k) : Perm [k])
+
+
+/* ========================================================================== */
+/* === perm ================================================================= */
+/* ========================================================================== */
+
+/* Y = B (P (1:nrow), k1 : min (k1+ncols,ncol)-1) where B is nrow-by-ncol.
+ *
+ * Creates a permuted copy of a contiguous set of columns of B.
+ * Y is already allocated on input.  Y must be of sufficient size.  Let nk be
+ * the number of columns accessed in B.  Y->xtype determines the complexity of
+ * the result.
+ *
+ * If B is real and Y is complex (or zomplex), only the real part of B is
+ * copied into Y.  The imaginary part of Y is set to zero.
+ *
+ * If B is complex (or zomplex) and Y is real, both the real and imaginary and
+ * parts of B are returned in Y.  Y is returned as nrow-by-2*nk. The even
+ * columns of Y contain the real part of B and the odd columns contain the
+ * imaginary part of B.  Y->nzmax must be >= 2*nrow*nk.  Otherise, Y is
+ * returned as nrow-by-nk with leading dimension nrow.  Y->nzmax must be >=
+ * nrow*nk.
+ *
+ * The case where the input (B) is real and the output (Y) is zomplex is
+ * not used.
+ */
+
+static void perm
+(
+    /* ---- input ---- */
+    cholmod_dense *B,	/* input matrix B */
+    Int *Perm,		/* optional input permutation (can be NULL) */
+    Int k1,		/* first column of B to copy */
+    Int ncols,		/* last column to copy is min(k1+ncols,B->ncol)-1 */
+    /* ---- in/out --- */
+    cholmod_dense *Y	/* output matrix Y, already allocated */
+)
+{
+    double *Yx, *Yz, *Bx, *Bz ;
+    Int k2, nk, p, k, j, nrow, ncol, d, dual, dj, j2 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    ncol = B->ncol ;
+    nrow = B->nrow ;
+    k2 = MIN (k1+ncols, ncol) ;
+    nk = MAX (k2 - k1, 0) ;
+    dual = (Y->xtype == CHOLMOD_REAL && B->xtype != CHOLMOD_REAL) ? 2 : 1 ;
+    d = B->d ;
+    Bx = B->x ;
+    Bz = B->z ;
+    Yx = Y->x ;
+    Yz = Y->z ;
+    Y->nrow = nrow ;
+    Y->ncol = dual*nk ;
+    Y->d = nrow ;
+    ASSERT (((Int) Y->nzmax) >= nrow*nk*dual) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* Y = B (P (1:nrow), k1:k2-1) */
+    /* ---------------------------------------------------------------------- */
+
+    switch (Y->xtype)
+    {
+
+	case CHOLMOD_REAL:
+
+	    switch (B->xtype)
+	    {
+
+		case CHOLMOD_REAL:
+		    /* Y real, B real */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [k + j2] = Bx [p] ;		/* real */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    /* Y real, B complex. Y is nrow-by-2*nk */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [k + j2       ] = Bx [2*p  ] ;	/* real */
+			    Yx [k + j2 + nrow] = Bx [2*p+1] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y real, B zomplex. Y is nrow-by-2*nk */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [k + j2       ] = Bx [p] ;	/* real */
+			    Yx [k + j2 + nrow] = Bz [p] ;	/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+
+	    switch (B->xtype)
+	    {
+
+		case CHOLMOD_REAL:
+		    /* Y complex, B real */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [2*k   + j2] = Bx [p] ;		/* real */
+			    Yx [2*k+1 + j2] = 0 ;		/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    /* Y complex, B complex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [2*k   + j2] = Bx [2*p  ] ;	/* real */
+			    Yx [2*k+1 + j2] = Bx [2*p+1] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y complex, B zomplex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [2*k   + j2] = Bx [p] ;		/* real */
+			    Yx [2*k+1 + j2] = Bz [p] ;		/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+
+	    switch (B->xtype)
+	    {
+
+#if 0
+		case CHOLMOD_REAL:
+		    /* this case is not used */
+		    break ;
+#endif
+
+		case CHOLMOD_COMPLEX:
+		    /* Y zomplex, B complex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [k + j2] = Bx [2*p  ] ;		/* real */
+			    Yz [k + j2] = Bx [2*p+1] ;		/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y zomplex, B zomplex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [k + j2] = Bx [p] ;		/* real */
+			    Yz [k + j2] = Bz [p] ;		/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+    }
+}
+
+
+/* ========================================================================== */
+/* === iperm ================================================================ */
+/* ========================================================================== */
+
+/* X (P (1:nrow), k1 : min (k1+ncols,ncol)-1) = Y where X is nrow-by-ncol.
+ *
+ * Copies and permutes Y into a contiguous set of columns of X.  X is already
+ * allocated on input.  Y must be of sufficient size.  Let nk be the number
+ * of columns accessed in X.  X->xtype determines the complexity of the result.
+ *
+ * If X is real and Y is complex (or zomplex), only the real part of B is
+ * copied into X.  The imaginary part of Y is ignored.
+ *
+ * If X is complex (or zomplex) and Y is real, both the real and imaginary and
+ * parts of Y are returned in X.  Y is nrow-by-2*nk. The even
+ * columns of Y contain the real part of B and the odd columns contain the
+ * imaginary part of B.  Y->nzmax must be >= 2*nrow*nk.  Otherise, Y is
+ * nrow-by-nk with leading dimension nrow.  Y->nzmax must be >= nrow*nk.
+ *
+ * The case where the input (Y) is complex and the output (X) is real,
+ * and the case where the input (Y) is zomplex and the output (X) is real,
+ * are not used.
+ */
+
+static void iperm
+(
+    /* ---- input ---- */
+    cholmod_dense *Y,	/* input matrix Y */
+    Int *Perm,		/* optional input permutation (can be NULL) */
+    Int k1,		/* first column of B to copy */
+    Int ncols,		/* last column to copy is min(k1+ncols,B->ncol)-1 */
+    /* ---- in/out --- */
+    cholmod_dense *X	/* output matrix X, already allocated */
+)
+{
+    double *Yx, *Yz, *Xx, *Xz ;
+    Int k2, nk, p, k, j, nrow, ncol, d, dj, j2 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    ncol = X->ncol ;
+    nrow = X->nrow ;
+    k2 = MIN (k1+ncols, ncol) ;
+    nk = MAX (k2 - k1, 0) ;
+    d = X->d ;
+    Xx = X->x ;
+    Xz = X->z ;
+    Yx = Y->x ;
+    Yz = Y->z ;
+    ASSERT (((Int) Y->nzmax) >= nrow*nk*
+	    ((X->xtype != CHOLMOD_REAL && Y->xtype == CHOLMOD_REAL) ? 2:1)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* X (P (1:nrow), k1:k2-1) = Y */
+    /* ---------------------------------------------------------------------- */
+
+    switch (Y->xtype)
+    {
+
+	case CHOLMOD_REAL:
+
+	    switch (X->xtype)
+	    {
+
+		case CHOLMOD_REAL:
+		    /* Y real, X real */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [p] = Yx [k + j2] ;		/* real */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    /* Y real, X complex. Y is nrow-by-2*nk */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [2*p  ] = Yx [k + j2       ] ;	/* real */
+			    Xx [2*p+1] = Yx [k + j2 + nrow] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y real, X zomplex. Y is nrow-by-2*nk */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [p] = Yx [k + j2       ] ;	/* real */
+			    Xz [p] = Yx [k + j2 + nrow] ;	/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+
+	    switch (X->xtype)
+	    {
+
+#if 0
+		case CHOLMOD_REAL:
+		    /* this case is not used */
+		    break ;
+#endif
+
+		case CHOLMOD_COMPLEX:
+		    /* Y complex, X complex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [2*p  ] = Yx [2*k   + j2] ;	/* real */
+			    Xx [2*p+1] = Yx [2*k+1 + j2] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y complex, X zomplex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [p] = Yx [2*k   + j2] ;		/* real */
+			    Xz [p] = Yx [2*k+1 + j2] ;		/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+
+	    switch (X->xtype)
+	    {
+
+#if 0
+		case CHOLMOD_REAL:
+		    /* this case is not used */
+		    break ;
+#endif
+
+		case CHOLMOD_COMPLEX:
+		    /* Y zomplex, X complex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [2*p  ] = Yx [k + j2] ;		/* real */
+			    Xx [2*p+1] = Yz [k + j2] ;		/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y zomplex, X zomplex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [p] = Yx [k + j2] ;		/* real */
+			    Xz [p] = Yz [k + j2] ;		/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+    }
+}
+
+
+/* ========================================================================== */
+/* === ptrans =============================================================== */
+/* ========================================================================== */
+
+/* Y = B (P (1:nrow), k1 : min (k1+ncols,ncol)-1)' where B is nrow-by-ncol.
+ *
+ * Creates a permuted and transposed copy of a contiguous set of columns of B.
+ * Y is already allocated on input.  Y must be of sufficient size.  Let nk be
+ * the number of columns accessed in B.  Y->xtype determines the complexity of
+ * the result.
+ *
+ * If B is real and Y is complex (or zomplex), only the real part of B is
+ * copied into Y.  The imaginary part of Y is set to zero.
+ *
+ * If B is complex (or zomplex) and Y is real, both the real and imaginary and
+ * parts of B are returned in Y.  Y is returned as 2*nk-by-nrow. The even
+ * rows of Y contain the real part of B and the odd rows contain the
+ * imaginary part of B.  Y->nzmax must be >= 2*nrow*nk.  Otherise, Y is
+ * returned as nk-by-nrow with leading dimension nk.  Y->nzmax must be >=
+ * nrow*nk.
+ *
+ * The array transpose is performed, not the complex conjugate transpose.
+ */
+
+static void ptrans
+(
+    /* ---- input ---- */
+    cholmod_dense *B,	/* input matrix B */
+    Int *Perm,		/* optional input permutation (can be NULL) */
+    Int k1,		/* first column of B to copy */
+    Int ncols,		/* last column to copy is min(k1+ncols,B->ncol)-1 */
+    /* ---- in/out --- */
+    cholmod_dense *Y	/* output matrix Y, already allocated */
+)
+{
+    double *Yx, *Yz, *Bx, *Bz ;
+    Int k2, nk, p, k, j, nrow, ncol, d, dual, dj, j2 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    ncol = B->ncol ;
+    nrow = B->nrow ;
+    k2 = MIN (k1+ncols, ncol) ;
+    nk = MAX (k2 - k1, 0) ;
+    dual = (Y->xtype == CHOLMOD_REAL && B->xtype != CHOLMOD_REAL) ? 2 : 1 ;
+    d = B->d ;
+    Bx = B->x ;
+    Bz = B->z ;
+    Yx = Y->x ;
+    Yz = Y->z ;
+    Y->nrow = dual*nk ;
+    Y->ncol = nrow ;
+    Y->d = dual*nk ;
+    ASSERT (((Int) Y->nzmax) >= nrow*nk*dual) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* Y = B (P (1:nrow), k1:k2-1)' */
+    /* ---------------------------------------------------------------------- */
+
+    switch (Y->xtype)
+    {
+
+	case CHOLMOD_REAL:
+
+	    switch (B->xtype)
+	    {
+
+		case CHOLMOD_REAL:
+		    /* Y real, B real  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = j-k1 ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2 + k*nk] = Bx [p] ;		/* real */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    /* Y real, B complex. Y is 2*nk-by-nrow */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2   + k*2*nk] = Bx [2*p  ] ;	/* real */
+			    Yx [j2+1 + k*2*nk] = Bx [2*p+1] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y real, B zomplex. Y is 2*nk-by-nrow */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2   + k*2*nk] = Bx [p] ;	/* real */
+			    Yx [j2+1 + k*2*nk] = Bz [p] ;	/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+
+	    switch (B->xtype)
+	    {
+
+		case CHOLMOD_REAL:
+		    /* Y complex, B real  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2   + k*2*nk] = Bx [p] ;	/* real */
+			    Yx [j2+1 + k*2*nk] = 0 ;		/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    /* Y complex, B complex  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2   + k*2*nk] = Bx [2*p  ] ;	/* real */
+			    Yx [j2+1 + k*2*nk] = Bx [2*p+1] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y complex, B zomplex  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2   + k*2*nk] = Bx [p] ;	/* real */
+			    Yx [j2+1 + k*2*nk] = Bz [p] ;	/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+
+	    switch (B->xtype)
+	    {
+
+		case CHOLMOD_REAL:
+		    /* Y zomplex, B real  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = j-k1 ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2 + k*nk] = Bx [p] ;		/* real */
+			    Yz [j2 + k*nk] = 0 ;		/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    /* Y zomplex, B complex  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = j-k1 ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2 + k*nk] = Bx [2*p  ] ;	/* real */
+			    Yz [j2 + k*nk] = Bx [2*p+1] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y zomplex, B zomplex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = j-k1 ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2 + k*nk] = Bx [p] ;		/* real */
+			    Yz [j2 + k*nk] = Bz [p] ;		/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+    }
+}
+
+
+/* ========================================================================== */
+/* === iptrans ============================================================== */
+/* ========================================================================== */
+
+/* X (P (1:nrow), k1 : min (k1+ncols,ncol)-1) = Y' where X is nrow-by-ncol.
+ *
+ * Copies into a permuted and transposed contiguous set of columns of X.
+ * X is already allocated on input.  Y must be of sufficient size.  Let nk be
+ * the number of columns accessed in X.  X->xtype determines the complexity of
+ * the result.
+ *
+ * If X is real and Y is complex (or zomplex), only the real part of Y is
+ * copied into X.  The imaginary part of Y is ignored.
+ *
+ * If X is complex (or zomplex) and Y is real, both the real and imaginary and
+ * parts of X are returned in Y.  Y is 2*nk-by-nrow. The even
+ * rows of Y contain the real part of X and the odd rows contain the
+ * imaginary part of X.  Y->nzmax must be >= 2*nrow*nk.  Otherise, Y is
+ * nk-by-nrow with leading dimension nk.  Y->nzmax must be >= nrow*nk.
+ *
+ * The case where Y is complex or zomplex, and X is real, is not used.
+ *
+ * The array transpose is performed, not the complex conjugate transpose.
+ */
+
+static void iptrans
+(
+    /* ---- input ---- */
+    cholmod_dense *Y,	/* input matrix Y */
+    Int *Perm,		/* optional input permutation (can be NULL) */
+    Int k1,		/* first column of X to copy into */
+    Int ncols,		/* last column to copy is min(k1+ncols,X->ncol)-1 */
+    /* ---- in/out --- */
+    cholmod_dense *X	/* output matrix X, already allocated */
+)
+{
+    double *Yx, *Yz, *Xx, *Xz ;
+    Int k2, nk, p, k, j, nrow, ncol, d, dj, j2 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    ncol = X->ncol ;
+    nrow = X->nrow ;
+    k2 = MIN (k1+ncols, ncol) ;
+    nk = MAX (k2 - k1, 0) ;
+    d = X->d ;
+    Xx = X->x ;
+    Xz = X->z ;
+    Yx = Y->x ;
+    Yz = Y->z ;
+    ASSERT (((Int) Y->nzmax) >= nrow*nk*
+	    ((X->xtype != CHOLMOD_REAL && Y->xtype == CHOLMOD_REAL) ? 2:1)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* X (P (1:nrow), k1:k2-1) = Y' */
+    /* ---------------------------------------------------------------------- */
+
+    switch (Y->xtype)
+    {
+
+	case CHOLMOD_REAL:
+
+	    switch (X->xtype)
+	    {
+
+		case CHOLMOD_REAL:
+		    /* Y real, X real  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = j-k1 ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [p] = Yx [j2 + k*nk] ;		/* real */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    /* Y real, X complex. Y is 2*nk-by-nrow */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [2*p  ] = Yx [j2   + k*2*nk] ;	/* real */
+			    Xx [2*p+1] = Yx [j2+1 + k*2*nk] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y real, X zomplex. Y is 2*nk-by-nrow */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [p] = Yx [j2   + k*2*nk] ;	/* real */
+			    Xz [p] = Yx [j2+1 + k*2*nk] ;	/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+
+	    switch (X->xtype)
+	    {
+
+#if 0
+		case CHOLMOD_REAL:
+		    /* this case is not used */
+		    break ;
+#endif
+
+		case CHOLMOD_COMPLEX:
+		    /* Y complex, X complex  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [2*p  ] = Yx [j2   + k*2*nk] ;	/* real */
+			    Xx [2*p+1] = Yx [j2+1 + k*2*nk] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y complex, X zomplex  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [p] = Yx [j2   + k*2*nk] ;	/* real */
+			    Xz [p] = Yx [j2+1 + k*2*nk] ;	/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+
+	    switch (X->xtype)
+	    {
+
+#if 0
+		case CHOLMOD_REAL:
+		    /* this case is not used */
+		    break ;
+#endif
+
+		case CHOLMOD_COMPLEX:
+		    /* Y zomplex, X complex  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = j-k1 ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [2*p  ] = Yx [j2 + k*nk] ;	/* real */
+			    Xx [2*p+1] = Yz [j2 + k*nk] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y zomplex, X zomplex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = j-k1 ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [p] = Yx [j2 + k*nk] ;		/* real */
+			    Xz [p] = Yz [j2 + k*nk] ;		/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+    }
+}
+
+
+/* ========================================================================== */
+/* === cholmod_solve ======================================================== */
+/* ========================================================================== */
+
+/* Solve a linear system.
+ *
+ * The factorization can be simplicial LDL', simplicial LL', or supernodal LL'.
+ * The Dx=b solve returns silently for the LL' factorizations (it is implicitly
+ * identity).
+ */
+
+cholmod_dense *CHOLMOD(solve)
+(
+    /* ---- input ---- */
+    int sys,		/* system to solve */
+    cholmod_factor *L,	/* factorization to use */
+    cholmod_dense *B,	/* right-hand-side */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *Y = NULL, *X = NULL ;
+    Int *Perm ;
+    Int n, nrhs, ncols, ctype, xtype, k1, nr, ytype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (L, NULL) ;
+    RETURN_IF_NULL (B, NULL) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ;
+    RETURN_IF_XTYPE_INVALID (B, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ;
+    if (sys < CHOLMOD_A || sys > CHOLMOD_Pt)
+    {
+	ERROR (CHOLMOD_INVALID, "invalid system") ;
+	return (NULL) ;
+    }
+    if (B->d < L->n || B->nrow != L->n)
+    {
+	ERROR (CHOLMOD_INVALID, "dimensions of L and B do not match") ;
+	return (NULL) ;
+    }
+    DEBUG (CHOLMOD(dump_factor) (L, "L", Common)) ;
+    DEBUG (CHOLMOD(dump_dense) (B, "B", Common)) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    if ((sys == CHOLMOD_P || sys == CHOLMOD_Pt || sys == CHOLMOD_A)
+	    && L->ordering != CHOLMOD_NATURAL)
+    {
+	Perm = L->Perm ;
+    }
+    else
+    {
+	/* do not use L->Perm; use the identity permutation instead */
+	Perm = NULL ;
+    }
+
+    nrhs = B->ncol ;
+    n = L->n ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the result X */
+    /* ---------------------------------------------------------------------- */
+
+    ctype = (Common->prefer_zomplex) ? CHOLMOD_ZOMPLEX : CHOLMOD_COMPLEX ;
+
+    if (sys == CHOLMOD_P || sys == CHOLMOD_Pt)
+    {
+	/* x=Pb and x=P'b return X real if B is real; X is the preferred
+	 * complex/zcomplex type if B is complex or zomplex */
+	xtype = (B->xtype == CHOLMOD_REAL) ? CHOLMOD_REAL : ctype ;
+    }
+    else if (L->xtype == CHOLMOD_REAL && B->xtype == CHOLMOD_REAL)
+    {
+	/* X is real if both L and B are real */
+	xtype = CHOLMOD_REAL ;
+    }
+    else
+    {
+	/* X is complex, use the preferred complex/zomplex type */
+	xtype = ctype ;
+    }
+
+    X = CHOLMOD(allocate_dense) (n, nrhs, n, xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* solve using L, D, L', P, or some combination */
+    /* ---------------------------------------------------------------------- */
+
+    if (sys == CHOLMOD_P)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* x = P*b */
+	/* ------------------------------------------------------------------ */
+
+	perm (B, Perm, 0, nrhs, X) ;
+
+    }
+    else if (sys == CHOLMOD_Pt)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* x = P'*b */
+	/* ------------------------------------------------------------------ */
+
+	iperm (B, Perm, 0, nrhs, X) ;
+
+    }
+    else if (L->is_super)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* solve using a supernodal LL' factorization */
+	/* ------------------------------------------------------------------ */
+
+#ifndef NSUPERNODAL
+	Int ok ;
+
+	/* allocate workspace */
+	cholmod_dense *E ;
+	Int dual ;
+	dual = (L->xtype == CHOLMOD_REAL && B->xtype != CHOLMOD_REAL) ? 2 : 1 ;
+	Y = CHOLMOD(allocate_dense) (n, dual*nrhs, n, L->xtype, Common) ;
+	E = CHOLMOD(allocate_dense) (dual*nrhs, L->maxesize, dual*nrhs,
+		L->xtype, Common) ;
+
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+	    CHOLMOD(free_dense) (&X, Common) ;
+	    CHOLMOD(free_dense) (&Y, Common) ;
+	    CHOLMOD(free_dense) (&E, Common) ;
+	    return (NULL) ;
+	}
+
+	perm (B, Perm, 0, nrhs, Y) ;			    /* Y = P*B */
+
+	if (sys == CHOLMOD_A || sys == CHOLMOD_LDLt)
+	{
+	    ok = CHOLMOD(super_lsolve) (L, Y, E, Common) ;	   /* Y = L\Y */
+	    ok = ok && CHOLMOD(super_ltsolve) (L, Y, E, Common) ;  /* Y = L'\Y*/
+	}
+	else if (sys == CHOLMOD_L || sys == CHOLMOD_LD)
+	{
+	    ok = CHOLMOD(super_lsolve) (L, Y, E, Common) ;	   /* Y = L\Y */
+	}
+	else if (sys == CHOLMOD_Lt || sys == CHOLMOD_DLt)
+	{
+	    ok = CHOLMOD(super_ltsolve) (L, Y, E, Common) ;	   /* Y = L'\Y*/
+	}
+	CHOLMOD(free_dense) (&E, Common) ;
+
+	iperm (Y, Perm, 0, nrhs, X) ;			    /* X = P'*Y */
+
+	if (CHECK_BLAS_INT && !ok)
+	{
+	    /* integer overflow in the BLAS */
+	    CHOLMOD(free_dense) (&X, Common) ;
+	}
+
+#else
+	/* CHOLMOD Supernodal module not installed */
+	ERROR (CHOLMOD_NOT_INSTALLED,"Supernodal module not installed") ;
+#endif
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* solve using a simplicial LL' or LDL' factorization */
+	/* ------------------------------------------------------------------ */
+
+	if (L->xtype == CHOLMOD_REAL && B->xtype == CHOLMOD_REAL)
+	{
+	    /* L, B, and Y are all real */
+	    /* solve with up to 4 columns of B at a time */
+	    ncols = 4 ;
+	    nr = MAX (4, nrhs) ;
+	    ytype = CHOLMOD_REAL ;
+	}
+	else if (L->xtype == CHOLMOD_REAL)
+	{
+	    /* solve with one column of B (real/imag), at a time */
+	    ncols = 1 ;
+	    nr = 2 ;
+	    ytype = CHOLMOD_REAL ;
+	}
+	else
+	{
+	    /* L is complex or zomplex, B is real/complex/zomplex, Y has the
+	     * same complexity as L.  Solve with one column of B at a time. */
+	    ncols = 1 ;
+	    nr = 1 ;
+	    ytype = L->xtype ;
+	}
+
+	Y = CHOLMOD(allocate_dense) (nr, n, nr, ytype, Common) ;
+
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+	    CHOLMOD(free_dense) (&X, Common) ;
+	    CHOLMOD(free_dense) (&Y, Common) ;
+	    return (NULL) ;
+	}
+
+	for (k1 = 0 ; k1 < nrhs ; k1 += ncols)
+	{
+	    /* -------------------------------------------------------------- */
+	    /* Y = B (P, k1:k1+ncols-1)' = (P * B (:,...))' */
+	    /* -------------------------------------------------------------- */
+
+	    ptrans (B, Perm, k1, ncols, Y) ;
+
+	    /* -------------------------------------------------------------- */
+	    /* solve Y = (L' \ (L \ Y'))', or other system, with template */
+	    /* -------------------------------------------------------------- */
+
+	    switch (L->xtype)
+	    {
+		case CHOLMOD_REAL:
+		    r_simplicial_solver (sys, L, Y) ;
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    c_simplicial_solver (sys, L, Y) ;
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    z_simplicial_solver (sys, L, Y) ;
+		    break ;
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* X (P, k1:k2+ncols-1) = Y' */
+	    /* -------------------------------------------------------------- */
+
+	    iptrans (Y, Perm, k1, ncols, X) ;
+	}
+    }
+
+    CHOLMOD(free_dense) (&Y, Common) ;
+    DEBUG (CHOLMOD(dump_dense) (X, "X result", Common)) ;
+    return (X) ;
+}
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_spsolve.c b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_spsolve.c
new file mode 100644
index 0000000..9ae0a93
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_spsolve.c
@@ -0,0 +1,397 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_spsolve ============================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Given an LL' or LDL' factorization of A, solve one of the following systems:
+ *
+ *	Ax=b	    0: CHOLMOD_A	also applies the permutation L->Perm
+ *	LDL'x=b	    1: CHOLMOD_LDLt	does not apply L->Perm
+ *	LDx=b	    2: CHOLMOD_LD
+ *	DL'x=b	    3: CHOLMOD_DLt
+ *	Lx=b	    4: CHOLMOD_L
+ *	L'x=b	    5: CHOLMOD_Lt
+ *	Dx=b	    6: CHOLMOD_D
+ *	x=Pb	    7: CHOLMOD_P	apply a permutation (P is L->Perm)
+ *	x=P'b	    8: CHOLMOD_Pt	apply an inverse permutation
+ *
+ * where b and x are sparse.  If L and b are real, then x is real.  Otherwise,
+ * x is complex or zomplex, depending on the Common->prefer_zomplex parameter.
+ * All xtypes of x and b are supported (real, complex, and zomplex).
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+/* ========================================================================== */
+/* === EXPAND_AS_NEEDED ===================================================== */
+/* ========================================================================== */
+
+/* Double the size of the sparse matrix X, if we have run out of space. */ 
+
+#define EXPAND_AS_NEEDED \
+if (xnz >= nzmax) \
+{ \
+    nzmax *= 2 ; \
+    CHOLMOD(reallocate_sparse) (nzmax, X, Common) ; \
+    if (Common->status < CHOLMOD_OK) \
+    { \
+	CHOLMOD(free_sparse) (&X, Common) ; \
+	CHOLMOD(free_dense) (&X4, Common) ; \
+	CHOLMOD(free_dense) (&B4, Common) ; \
+	return (NULL) ; \
+    } \
+    Xi = X->i ; \
+    Xx = X->x ; \
+    Xz = X->z ; \
+}
+
+
+/* ========================================================================== */
+/* === cholmod_spolve ======================================================= */
+/* ========================================================================== */
+
+cholmod_sparse *CHOLMOD(spsolve)	    /* returns the sparse solution X */
+(
+    /* ---- input ---- */
+    int sys,		/* system to solve */
+    cholmod_factor *L,	/* factorization to use */
+    cholmod_sparse *B,	/* right-hand-side */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double x, z ;
+    cholmod_dense *X4, *B4 ;
+    cholmod_sparse *X ;
+    double *Bx, *Bz, *Xx, *Xz, *B4x, *B4z, *X4x, *X4z ;
+    Int *Bi, *Bp, *Xp, *Xi, *Bnz ;
+    Int n, nrhs, q, p, i, j, j1, j2, packed, block, pend, jn, xtype ;
+    size_t xnz, nzmax ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (L, NULL) ;
+    RETURN_IF_NULL (B, NULL) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ;
+    RETURN_IF_XTYPE_INVALID (B, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ;
+    if (L->n != B->nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "dimensions of L and B do not match") ;
+	return (NULL) ;
+    }
+    if (B->stype)
+    {
+	ERROR (CHOLMOD_INVALID, "B cannot be stored in symmetric mode") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace B4 and initial result X */
+    /* ---------------------------------------------------------------------- */
+
+    n = L->n ;
+    nrhs = B->ncol ;
+
+    /* X is real if both L and B are real, complex/zomplex otherwise */
+    xtype = (L->xtype == CHOLMOD_REAL && B->xtype == CHOLMOD_REAL) ?
+	CHOLMOD_REAL :
+	(Common->prefer_zomplex ? CHOLMOD_ZOMPLEX : CHOLMOD_COMPLEX) ;
+
+    /* solve up to 4 columns at a time */
+    block = MIN (nrhs, 4) ;
+
+    /* initial size of X is at most 4*n */
+    nzmax = n*block ;
+
+    X = CHOLMOD(spzeros) (n, nrhs, nzmax, xtype, Common) ;
+    B4 = CHOLMOD(zeros) (n, block, B->xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free_sparse) (&X, Common) ;
+	CHOLMOD(free_dense) (&B4, Common) ;
+	return (NULL) ;
+    }
+
+    Bp = B->p ;
+    Bi = B->i ;
+    Bx = B->x ;
+    Bz = B->z ;
+    Bnz = B->nz ;
+    packed = B->packed ;
+
+    Xp = X->p ;
+    Xi = X->i ;
+    Xx = X->x ;
+    Xz = X->z ;
+
+    xnz = 0 ;
+
+    B4x = B4->x ;
+    B4z = B4->z ;
+
+    /* ---------------------------------------------------------------------- */
+    /* solve in chunks of 4 columns at a time */
+    /* ---------------------------------------------------------------------- */
+
+    for (j1 = 0 ; j1 < nrhs ; j1 += block)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* adjust the number of columns of B4 */
+	/* ------------------------------------------------------------------ */
+
+	j2 = MIN (nrhs, j1 + block) ;
+	B4->ncol = j2 - j1 ;
+
+	/* ------------------------------------------------------------------ */
+	/* scatter B(j1:j2-1) into B4 */
+	/* ------------------------------------------------------------------ */
+
+	for (j = j1 ; j < j2 ; j++)
+	{
+	    p = Bp [j] ;
+	    pend = (packed) ? (Bp [j+1]) : (p + Bnz [j]) ;
+	    jn = (j-j1)*n ;
+
+	    switch (B->xtype)
+	    {
+
+		case CHOLMOD_REAL:
+		    for ( ; p < pend ; p++)
+		    {
+			B4x [Bi [p] + jn] = Bx [p] ;
+		    }
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    for ( ; p < pend ; p++)
+		    {
+			q = Bi [p] + jn ;
+			B4x [2*q  ] = Bx [2*p  ] ;
+			B4x [2*q+1] = Bx [2*p+1] ;
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    for ( ; p < pend ; p++)
+		    {
+			q = Bi [p] + jn ;
+			B4x [q] = Bx [p] ;
+			B4z [q] = Bz [p] ;
+		    }
+		    break ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* solve the system (X4 = A\B4 or other system) */
+	/* ------------------------------------------------------------------ */
+
+	X4 = CHOLMOD(solve) (sys, L, B4, Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    CHOLMOD(free_sparse) (&X, Common) ;
+	    CHOLMOD(free_dense) (&B4, Common) ;
+	    CHOLMOD(free_dense) (&X4, Common) ;
+	    return (NULL) ;
+	}
+	ASSERT (X4->xtype == xtype) ;
+	X4x = X4->x ;
+	X4z = X4->z ;
+
+	/* ------------------------------------------------------------------ */
+	/* append the solution onto X */
+	/* ------------------------------------------------------------------ */
+
+	for (j = j1 ; j < j2 ; j++)
+	{
+	    Xp [j] = xnz ;
+	    jn = (j-j1)*n ;
+	    if ( xnz + n <= nzmax)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* X is guaranteed to be large enough */
+		/* ---------------------------------------------------------- */
+
+		switch (xtype)
+		{
+
+		    case CHOLMOD_REAL:
+			for (i = 0 ; i < n ; i++)
+			{
+			    x = X4x [i + jn] ;
+			    if (IS_NONZERO (x))
+			    {
+				Xi [xnz] = i ;
+				Xx [xnz] = x ;
+				xnz++ ;
+			    }
+			}
+			break ;
+
+		    case CHOLMOD_COMPLEX:
+			for (i = 0 ; i < n ; i++)
+			{
+			    x = X4x [2*(i + jn)  ] ;
+			    z = X4x [2*(i + jn)+1] ;
+			    if (IS_NONZERO (x) || IS_NONZERO (z))
+			    {
+				Xi [xnz] = i ;
+				Xx [2*xnz  ] = x ;
+				Xx [2*xnz+1] = z ;
+				xnz++ ;
+			    }
+			}
+			break ;
+
+		    case CHOLMOD_ZOMPLEX:
+			for (i = 0 ; i < n ; i++)
+			{
+			    x = X4x [i + jn] ;
+			    z = X4z [i + jn] ;
+			    if (IS_NONZERO (x) || IS_NONZERO (z))
+			    {
+				Xi [xnz] = i ;
+				Xx [xnz] = x ;
+				Xz [xnz] = z ;
+				xnz++ ;
+			    }
+			}
+			break ;
+		}
+
+	    }
+	    else
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* X may need to increase in size */
+		/* ---------------------------------------------------------- */
+
+		switch (xtype)
+		{
+
+		    case CHOLMOD_REAL:
+			for (i = 0 ; i < n ; i++)
+			{
+			    x = X4x [i + jn] ;
+			    if (IS_NONZERO (x))
+			    {
+				EXPAND_AS_NEEDED ;
+				Xi [xnz] = i ;
+				Xx [xnz] = x ;
+				xnz++ ;
+			    }
+			}
+			break ;
+
+		    case CHOLMOD_COMPLEX:
+			for (i = 0 ; i < n ; i++)
+			{
+			    x = X4x [2*(i + jn)  ] ;
+			    z = X4x [2*(i + jn)+1] ;
+			    if (IS_NONZERO (x) || IS_NONZERO (z))
+			    {
+				EXPAND_AS_NEEDED ;
+				Xi [xnz] = i ;
+				Xx [2*xnz  ] = x ;
+				Xx [2*xnz+1] = z ;
+				xnz++ ;
+			    }
+			}
+			break ;
+
+		    case CHOLMOD_ZOMPLEX:
+			for (i = 0 ; i < n ; i++)
+			{
+			    x = X4x [i + jn] ;
+			    z = X4z [i + jn] ;
+			    if (IS_NONZERO (x) || IS_NONZERO (z))
+			    {
+				EXPAND_AS_NEEDED ;
+				Xi [xnz] = i ;
+				Xx [xnz] = x ;
+				Xz [xnz] = z ;
+				xnz++ ;
+			    }
+			}
+			break ;
+		}
+
+	    }
+	}
+	CHOLMOD(free_dense) (&X4, Common) ;
+
+	/* ------------------------------------------------------------------ */
+	/* clear B4 for next iteration */
+	/* ------------------------------------------------------------------ */
+
+	if (j2 < nrhs)
+	{
+
+	    for (j = j1 ; j < j2 ; j++)
+	    {
+		p = Bp [j] ;
+		pend = (packed) ? (Bp [j+1]) : (p + Bnz [j]) ;
+		jn = (j-j1)*n ;
+
+		switch (B->xtype)
+		{
+
+		    case CHOLMOD_REAL:
+			for ( ; p < pend ; p++)
+			{
+			    B4x [Bi [p] + jn] = 0 ;
+			}
+			break ;
+
+		    case CHOLMOD_COMPLEX:
+			for ( ; p < pend ; p++)
+			{
+			    q = Bi [p] + jn ;
+			    B4x [2*q  ] = 0 ;
+			    B4x [2*q+1] = 0 ;
+			}
+			break ;
+
+		    case CHOLMOD_ZOMPLEX:
+			for ( ; p < pend ; p++)
+			{
+			    q = Bi [p] + jn ;
+			    B4x [q] = 0 ;
+			    B4z [q] = 0 ;
+			}
+			break ;
+		}
+	    }
+	}
+    }
+
+    Xp [nrhs] = xnz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* reduce X in size, free workspace, and return result */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (xnz <= X->nzmax) ;
+    CHOLMOD(reallocate_sparse) (xnz, X, Common) ;
+    ASSERT (Common->status == CHOLMOD_OK) ;
+    CHOLMOD(free_dense) (&B4, Common) ;
+    return (X) ;
+}
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/lesser.txt b/src/C/SuiteSparse/CHOLMOD/Cholesky/lesser.txt
new file mode 100644
index 0000000..8add30a
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/lesser.txt
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+

+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+

+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+

+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+

+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+

+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+

+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+

+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+

+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/t_cholmod_lsolve.c b/src/C/SuiteSparse/CHOLMOD/Cholesky/t_cholmod_lsolve.c
new file mode 100644
index 0000000..1ab79b9
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/t_cholmod_lsolve.c
@@ -0,0 +1,843 @@
+/* ========================================================================== */
+/* === Cholesky/t_cholmod_lsolve ============================================ */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Template routine to solve Lx=b with unit or non-unit diagonal, or
+ * solve LDx=b.
+ *
+ * The numeric xtype of L and Y must match.  Y contains b on input and x on
+ * output, stored in row-form.  Y is nrow-by-n, where nrow must equal 1 for the 
+ * complex or zomplex cases, and nrow <= 4 for the real case.
+ *
+ * This file is not compiled separately.  It is included in t_cholmod_solve.c
+ * instead.  It contains no user-callable routines.
+ *
+ * workspace: none
+ *
+ * Supports real, complex, and zomplex factors.
+ */
+
+/* undefine all prior definitions */
+#undef FORM_NAME
+#undef LSOLVE
+
+/* -------------------------------------------------------------------------- */
+/* define the method */
+/* -------------------------------------------------------------------------- */
+
+#ifdef LL
+/* LL': solve Lx=b with non-unit diagonal */
+#define FORM_NAME(prefix,rank) prefix ## ll_lsolve_ ## rank
+
+#elif defined (LD)
+/* LDL': solve LDx=b */
+#define FORM_NAME(prefix,rank) prefix ## ldl_ldsolve_ ## rank
+
+#else
+/* LDL': solve Lx=b with unit diagonal */
+#define FORM_NAME(prefix,rank) prefix ## ldl_lsolve_ ## rank
+
+#endif
+
+/* LSOLVE(k) defines the name of a routine for an n-by-k right-hand-side. */
+
+#define LSOLVE(prefix,rank) FORM_NAME(prefix,rank)
+
+#ifdef REAL
+
+/* ========================================================================== */
+/* === LSOLVE (1) =========================================================== */
+/* ========================================================================== */
+
+/* Solve Lx=b, where b has 1 column  */
+
+static void LSOLVE (PREFIX,1)
+(
+    cholmod_factor *L,
+    double X [ ]			/* n-by-1 in row form */
+)
+{
+    double *Lx = L->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int j, n = L->n ;
+
+    for (j = 0 ; j < n ; )
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* find a chain of supernodes (up to j, j+1, and j+2) */
+	if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a single column of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y = X [j] ;
+#ifdef LL
+	    y /= Lx [p] ;
+	    X [j] = y ;
+#elif defined (LD)
+	    X [j] = y / Lx [p] ;
+#endif
+	    for (p++ ; p < pend ; p++)
+	    {
+		X [Li [p]] -= Lx [p] * y ;
+	    }
+	    j++ ;	/* advance to next column of L */
+
+	}
+	else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of two columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2] ;
+	    Int q = Lp [j+1] ;
+#ifdef LL
+	    y [0] = X [j] / Lx [p] ;
+	    y [1] = (X [j+1] - Lx [p+1] * y [0]) / Lx [q] ;
+	    X [j  ] = y [0] ;
+	    X [j+1] = y [1] ;
+#elif defined (LD)
+	    y [0] = X [j] ;
+	    y [1] = X [j+1] - Lx [p+1] * y [0] ;
+	    X [j  ] = y [0] / Lx [p] ;
+	    X [j+1] = y [1] / Lx [q] ;
+#else
+	    y [0] = X [j] ;
+	    y [1] = X [j+1] - Lx [p+1] * y [0] ;
+	    X [j+1] = y [1] ;
+#endif
+	    for (p += 2, q++ ; p < pend ; p++, q++)
+	    {
+		X [Li [p]] -= Lx [p] * y [0] + Lx [q] * y [1] ;
+	    }
+	    j += 2 ;	    /* advance to next column of L */
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of three columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3] ;
+	    Int q = Lp [j+1] ;
+	    Int r = Lp [j+2] ;
+#ifdef LL
+	    y [0] = X [j] / Lx [p] ;
+	    y [1] = (X [j+1] - Lx [p+1] * y [0]) / Lx [q] ;
+	    y [2] = (X [j+2] - Lx [p+2] * y [0] - Lx [q+1] * y [1]) / Lx [r] ;
+	    X [j  ] = y [0] ;
+	    X [j+1] = y [1] ;
+	    X [j+2] = y [2] ;
+#elif defined (LD)
+	    y [0] = X [j] ;
+	    y [1] = X [j+1] - Lx [p+1] * y [0] ;
+	    y [2] = X [j+2] - Lx [p+2] * y [0] - Lx [q+1] * y [1] ;
+	    X [j  ] = y [0] / Lx [p] ;
+	    X [j+1] = y [1] / Lx [q] ;
+	    X [j+2] = y [2] / Lx [r] ;
+#else
+	    y [0] = X [j] ;
+	    y [1] = X [j+1] - Lx [p+1] * y [0] ;
+	    y [2] = X [j+2] - Lx [p+2] * y [0] - Lx [q+1] * y [1] ;
+	    X [j+1] = y [1] ;
+	    X [j+2] = y [2] ;
+#endif
+	    for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++)
+	    {
+		X [Li [p]] -= Lx [p] * y [0] + Lx [q] * y [1] + Lx [r] * y [2] ;
+	    }
+	    j += 3 ;	    /* advance to next column of L */
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === LSOLVE (2) =========================================================== */
+/* ========================================================================== */
+
+/* Solve Lx=b, where b has 2 columns */
+
+static void LSOLVE (PREFIX,2)
+(
+    cholmod_factor *L,
+    double X [ ][2]		/* n-by-2 in row form */
+)
+{
+    double *Lx = L->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int j, n = L->n ;
+
+    for (j = 0 ; j < n ; )
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* find a chain of supernodes (up to j, j+1, and j+2) */
+	if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a single column of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2] ;
+	    y [0] = X [j][0] ;
+	    y [1] = X [j][1] ;
+#ifdef LL
+	    y [0] /= Lx [p] ;
+	    y [1] /= Lx [p] ;
+	    X [j][0] = y [0] ;
+	    X [j][1] = y [1] ;
+#elif defined (LD)
+	    X [j][0] = y [0] / Lx [p] ;
+	    X [j][1] = y [1] / Lx [p] ;
+#endif
+	    for (p++ ; p < pend ; p++)
+	    {
+		Int i = Li [p] ;
+		X [i][0] -= Lx [p] * y [0] ;
+		X [i][1] -= Lx [p] * y [1] ;
+	    }
+	    j++ ;	/* advance to next column of L */
+
+	}
+	else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of two columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2][2] ;
+	    Int q = Lp [j+1] ;
+	    y [0][0] = X [j][0] ;
+	    y [0][1] = X [j][1] ;
+#ifdef LL
+	    y [0][0] /= Lx [p] ;
+	    y [0][1] /= Lx [p] ;
+	    y [1][0] = (X [j+1][0] - Lx [p+1] * y [0][0]) / Lx [q] ;
+	    y [1][1] = (X [j+1][1] - Lx [p+1] * y [0][1]) / Lx [q] ;
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+#elif defined (LD)
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    X [j  ][0] = y [0][0] / Lx [p] ;
+	    X [j  ][1] = y [0][1] / Lx [p] ;
+	    X [j+1][0] = y [1][0] / Lx [q] ;
+	    X [j+1][1] = y [1][1] / Lx [q] ;
+#else
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+#endif
+	    for (p += 2, q++ ; p < pend ; p++, q++)
+	    {
+		Int i = Li [p] ;
+		X [i][0] -= Lx [p] * y [0][0] + Lx [q] * y [1][0] ;
+		X [i][1] -= Lx [p] * y [0][1] + Lx [q] * y [1][1] ;
+	    }
+	    j += 2 ;	    /* advance to next column of L */
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of three columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3][2] ;
+	    Int q = Lp [j+1] ;
+	    Int r = Lp [j+2] ;
+	    y [0][0] = X [j][0] ;
+	    y [0][1] = X [j][1] ;
+#ifdef LL
+	    y [0][0] /= Lx [p] ;
+	    y [0][1] /= Lx [p] ;
+	    y [1][0] = (X [j+1][0] - Lx[p+1] * y[0][0]) / Lx [q] ;
+	    y [1][1] = (X [j+1][1] - Lx[p+1] * y[0][1]) / Lx [q] ;
+	    y [2][0] = (X [j+2][0] - Lx[p+2] * y[0][0] - Lx[q+1]*y[1][0])/Lx[r];
+	    y [2][1] = (X [j+2][1] - Lx[p+2] * y[0][1] - Lx[q+1]*y[1][1])/Lx[r];
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+2][0] = y [2][0] ;
+	    X [j+2][1] = y [2][1] ;
+#elif defined (LD)
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ;
+	    y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ;
+	    X [j  ][0] = y [0][0] / Lx [p] ;
+	    X [j  ][1] = y [0][1] / Lx [p] ;
+	    X [j+1][0] = y [1][0] / Lx [q] ;
+	    X [j+1][1] = y [1][1] / Lx [q] ;
+	    X [j+2][0] = y [2][0] / Lx [r] ;
+	    X [j+2][1] = y [2][1] / Lx [r] ;
+#else
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ;
+	    y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+2][0] = y [2][0] ;
+	    X [j+2][1] = y [2][1] ;
+#endif
+	    for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++)
+	    {
+		Int i = Li [p] ;
+		X[i][0] -= Lx[p] * y[0][0] + Lx[q] * y[1][0] + Lx[r] * y[2][0] ;
+		X[i][1] -= Lx[p] * y[0][1] + Lx[q] * y[1][1] + Lx[r] * y[2][1] ;
+	    }
+	    j += 3 ;	    /* advance to next column of L */
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === LSOLVE (3) =========================================================== */
+/* ========================================================================== */
+
+/* Solve Lx=b, where b has 3 columns */
+
+static void LSOLVE (PREFIX,3)
+(
+    cholmod_factor *L,
+    double X [ ][3]			/* n-by-3 in row form */
+)
+{
+    double *Lx = L->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int j, n = L->n ;
+
+    for (j = 0 ; j < n ; )
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* find a chain of supernodes (up to j, j+1, and j+2) */
+	if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a single column of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3] ;
+	    y [0] = X [j][0] ;
+	    y [1] = X [j][1] ;
+	    y [2] = X [j][2] ;
+#ifdef LL
+	    y [0] /= Lx [p] ;
+	    y [1] /= Lx [p] ;
+	    y [2] /= Lx [p] ;
+	    X [j][0] = y [0] ;
+	    X [j][1] = y [1] ;
+	    X [j][2] = y [2] ;
+#elif defined (LD)
+	    X [j][0] = y [0] / Lx [p] ;
+	    X [j][1] = y [1] / Lx [p] ;
+	    X [j][2] = y [2] / Lx [p] ;
+#endif
+	    for (p++ ; p < pend ; p++)
+	    {
+		Int i = Li [p] ;
+		double lx = Lx [p] ;
+		X [i][0] -= lx * y [0] ;
+		X [i][1] -= lx * y [1] ;
+		X [i][2] -= lx * y [2] ;
+	    }
+	    j++ ;	/* advance to next column of L */
+
+	}
+	else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of two columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2][3] ;
+	    Int q = Lp [j+1] ;
+	    y [0][0] = X [j][0] ;
+	    y [0][1] = X [j][1] ;
+	    y [0][2] = X [j][2] ;
+#ifdef LL
+	    y [0][0] /= Lx [p] ;
+	    y [0][1] /= Lx [p] ;
+	    y [0][2] /= Lx [p] ;
+	    y [1][0] = (X [j+1][0] - Lx [p+1] * y [0][0]) / Lx [q] ;
+	    y [1][1] = (X [j+1][1] - Lx [p+1] * y [0][1]) / Lx [q] ;
+	    y [1][2] = (X [j+1][2] - Lx [p+1] * y [0][2]) / Lx [q] ;
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j  ][2] = y [0][2] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+1][2] = y [1][2] ;
+#elif defined (LD)
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ;
+	    X [j  ][0] = y [0][0] / Lx [p] ;
+	    X [j  ][1] = y [0][1] / Lx [p] ;
+	    X [j  ][2] = y [0][2] / Lx [p] ;
+	    X [j+1][0] = y [1][0] / Lx [q] ;
+	    X [j+1][1] = y [1][1] / Lx [q] ;
+	    X [j+1][2] = y [1][2] / Lx [q] ;
+#else
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+1][2] = y [1][2] ;
+#endif
+	    for (p += 2, q++ ; p < pend ; p++, q++)
+	    {
+		Int i = Li [p] ;
+		double lx [2] ;
+		lx [0] = Lx [p] ;
+		lx [1] = Lx [q] ;
+		X [i][0] -= lx [0] * y [0][0] + lx [1] * y [1][0] ;
+		X [i][1] -= lx [0] * y [0][1] + lx [1] * y [1][1] ;
+		X [i][2] -= lx [0] * y [0][2] + lx [1] * y [1][2] ;
+	    }
+	    j += 2 ;	    /* advance to next column of L */
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of three columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3][3] ;
+	    Int q = Lp [j+1] ;
+	    Int r = Lp [j+2] ;
+	    y [0][0] = X [j][0] ;
+	    y [0][1] = X [j][1] ;
+	    y [0][2] = X [j][2] ;
+#ifdef LL
+	    y [0][0] /= Lx [p] ;
+	    y [0][1] /= Lx [p] ;
+	    y [0][2] /= Lx [p] ;
+	    y [1][0] = (X [j+1][0] - Lx[p+1] * y[0][0]) / Lx [q] ;
+	    y [1][1] = (X [j+1][1] - Lx[p+1] * y[0][1]) / Lx [q] ;
+	    y [1][2] = (X [j+1][2] - Lx[p+1] * y[0][2]) / Lx [q] ;
+	    y [2][0] = (X [j+2][0] - Lx[p+2] * y[0][0] - Lx[q+1]*y[1][0])/Lx[r];
+	    y [2][1] = (X [j+2][1] - Lx[p+2] * y[0][1] - Lx[q+1]*y[1][1])/Lx[r];
+	    y [2][2] = (X [j+2][2] - Lx[p+2] * y[0][2] - Lx[q+1]*y[1][2])/Lx[r];
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j  ][2] = y [0][2] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+1][2] = y [1][2] ;
+	    X [j+2][0] = y [2][0] ;
+	    X [j+2][1] = y [2][1] ;
+	    X [j+2][2] = y [2][2] ;
+#elif defined (LD)
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ;
+	    y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ;
+	    y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ;
+	    y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ;
+	    X [j  ][0] = y [0][0] / Lx [p] ;
+	    X [j  ][1] = y [0][1] / Lx [p] ;
+	    X [j  ][2] = y [0][2] / Lx [p] ;
+	    X [j+1][0] = y [1][0] / Lx [q] ;
+	    X [j+1][1] = y [1][1] / Lx [q] ;
+	    X [j+1][2] = y [1][2] / Lx [q] ;
+	    X [j+2][0] = y [2][0] / Lx [r] ;
+	    X [j+2][1] = y [2][1] / Lx [r] ;
+	    X [j+2][2] = y [2][2] / Lx [r] ;
+#else
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ;
+	    y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ;
+	    y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ;
+	    y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+1][2] = y [1][2] ;
+	    X [j+2][0] = y [2][0] ;
+	    X [j+2][1] = y [2][1] ;
+	    X [j+2][2] = y [2][2] ;
+#endif
+	    for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++)
+	    {
+		Int i = Li [p] ;
+		double lx [3] ;
+		lx [0] = Lx [p] ;
+		lx [1] = Lx [q] ;
+		lx [2] = Lx [r] ;
+		X [i][0] -= lx[0] * y[0][0] + lx[1] * y[1][0] + lx[2] * y[2][0];
+		X [i][1] -= lx[0] * y[0][1] + lx[1] * y[1][1] + lx[2] * y[2][1];
+		X [i][2] -= lx[0] * y[0][2] + lx[1] * y[1][2] + lx[2] * y[2][2];
+	    }
+	    j += 3 ;	    /* advance to next column of L */
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === LSOLVE (4) =========================================================== */
+/* ========================================================================== */
+
+/* Solve Lx=b, where b has 4 columns */
+
+static void LSOLVE (PREFIX,4)
+(
+    cholmod_factor *L,
+    double X [ ][4]			    /* n-by-4 in row form */
+)
+{
+    double *Lx = L->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int j, n = L->n ;
+
+    for (j = 0 ; j < n ; )
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* find a chain of supernodes (up to j, j+1, and j+2) */
+	if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a single column of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [4] ;
+	    y [0] = X [j][0] ;
+	    y [1] = X [j][1] ;
+	    y [2] = X [j][2] ;
+	    y [3] = X [j][3] ;
+#ifdef LL
+	    y [0] /= Lx [p] ;
+	    y [1] /= Lx [p] ;
+	    y [2] /= Lx [p] ;
+	    y [3] /= Lx [p] ;
+	    X [j][0] = y [0] ;
+	    X [j][1] = y [1] ;
+	    X [j][2] = y [2] ;
+	    X [j][3] = y [3] ;
+#elif defined (LD)
+	    X [j][0] = y [0] / Lx [p] ;
+	    X [j][1] = y [1] / Lx [p] ;
+	    X [j][2] = y [2] / Lx [p] ;
+	    X [j][3] = y [3] / Lx [p] ;
+#endif
+	    for (p++ ; p < pend ; p++)
+	    {
+		Int i = Li [p] ;
+		double lx = Lx [p] ;
+		X [i][0] -= lx * y [0] ;
+		X [i][1] -= lx * y [1] ;
+		X [i][2] -= lx * y [2] ;
+		X [i][3] -= lx * y [3] ;
+	    }
+	    j++ ;	/* advance to next column of L */
+
+	}
+	else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of two columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2][4] ;
+	    Int q = Lp [j+1] ;
+	    y [0][0] = X [j][0] ;
+	    y [0][1] = X [j][1] ;
+	    y [0][2] = X [j][2] ;
+	    y [0][3] = X [j][3] ;
+#ifdef LL
+	    y [0][0] /= Lx [p] ;
+	    y [0][1] /= Lx [p] ;
+	    y [0][2] /= Lx [p] ;
+	    y [0][3] /= Lx [p] ;
+	    y [1][0] = (X [j+1][0] - Lx [p+1] * y [0][0]) / Lx [q] ;
+	    y [1][1] = (X [j+1][1] - Lx [p+1] * y [0][1]) / Lx [q] ;
+	    y [1][2] = (X [j+1][2] - Lx [p+1] * y [0][2]) / Lx [q] ;
+	    y [1][3] = (X [j+1][3] - Lx [p+1] * y [0][3]) / Lx [q] ;
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j  ][2] = y [0][2] ;
+	    X [j  ][3] = y [0][3] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+1][2] = y [1][2] ;
+	    X [j+1][3] = y [1][3] ;
+#elif defined (LD)
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ;
+	    y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ;
+	    X [j  ][0] = y [0][0] / Lx [p] ;
+	    X [j  ][1] = y [0][1] / Lx [p] ;
+	    X [j  ][2] = y [0][2] / Lx [p] ;
+	    X [j  ][3] = y [0][3] / Lx [p] ;
+	    X [j+1][0] = y [1][0] / Lx [q] ;
+	    X [j+1][1] = y [1][1] / Lx [q] ;
+	    X [j+1][2] = y [1][2] / Lx [q] ;
+	    X [j+1][3] = y [1][3] / Lx [q] ;
+#else
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ;
+	    y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+1][2] = y [1][2] ;
+	    X [j+1][3] = y [1][3] ;
+#endif
+	    for (p += 2, q++ ; p < pend ; p++, q++)
+	    {
+		Int i = Li [p] ;
+		double lx [2] ;
+		lx [0] = Lx [p] ;
+		lx [1] = Lx [q] ;
+		X [i][0] -= lx [0] * y [0][0] + lx [1] * y [1][0] ;
+		X [i][1] -= lx [0] * y [0][1] + lx [1] * y [1][1] ;
+		X [i][2] -= lx [0] * y [0][2] + lx [1] * y [1][2] ;
+		X [i][3] -= lx [0] * y [0][3] + lx [1] * y [1][3] ;
+	    }
+	    j += 2 ;	    /* advance to next column of L */
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of three columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3][4] ;
+	    Int q = Lp [j+1] ;
+	    Int r = Lp [j+2] ;
+	    y [0][0] = X [j][0] ;
+	    y [0][1] = X [j][1] ;
+	    y [0][2] = X [j][2] ;
+	    y [0][3] = X [j][3] ;
+#ifdef LL
+	    y [0][0] /= Lx [p] ;
+	    y [0][1] /= Lx [p] ;
+	    y [0][2] /= Lx [p] ;
+	    y [0][3] /= Lx [p] ;
+	    y [1][0] = (X [j+1][0] - Lx[p+1] * y[0][0]) / Lx [q] ;
+	    y [1][1] = (X [j+1][1] - Lx[p+1] * y[0][1]) / Lx [q] ;
+	    y [1][2] = (X [j+1][2] - Lx[p+1] * y[0][2]) / Lx [q] ;
+	    y [1][3] = (X [j+1][3] - Lx[p+1] * y[0][3]) / Lx [q] ;
+	    y [2][0] = (X [j+2][0] - Lx[p+2] * y[0][0] - Lx[q+1]*y[1][0])/Lx[r];
+	    y [2][1] = (X [j+2][1] - Lx[p+2] * y[0][1] - Lx[q+1]*y[1][1])/Lx[r];
+	    y [2][2] = (X [j+2][2] - Lx[p+2] * y[0][2] - Lx[q+1]*y[1][2])/Lx[r];
+	    y [2][3] = (X [j+2][3] - Lx[p+2] * y[0][3] - Lx[q+1]*y[1][3])/Lx[r];
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j  ][2] = y [0][2] ;
+	    X [j  ][3] = y [0][3] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+1][2] = y [1][2] ;
+	    X [j+1][3] = y [1][3] ;
+	    X [j+2][0] = y [2][0] ;
+	    X [j+2][1] = y [2][1] ;
+	    X [j+2][2] = y [2][2] ;
+	    X [j+2][3] = y [2][3] ;
+#elif defined (LD)
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ;
+	    y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ;
+	    y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ;
+	    y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ;
+	    y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ;
+	    y [2][3] = X [j+2][3] - Lx [p+2] * y [0][3] - Lx [q+1] * y [1][3] ;
+	    X [j  ][0] = y [0][0] / Lx [p] ;
+	    X [j  ][1] = y [0][1] / Lx [p] ;
+	    X [j  ][2] = y [0][2] / Lx [p] ;
+	    X [j  ][3] = y [0][3] / Lx [p] ;
+	    X [j+1][0] = y [1][0] / Lx [q] ;
+	    X [j+1][1] = y [1][1] / Lx [q] ;
+	    X [j+1][2] = y [1][2] / Lx [q] ;
+	    X [j+1][3] = y [1][3] / Lx [q] ;
+	    X [j+2][0] = y [2][0] / Lx [r] ;
+	    X [j+2][1] = y [2][1] / Lx [r] ;
+	    X [j+2][2] = y [2][2] / Lx [r] ;
+	    X [j+2][3] = y [2][3] / Lx [r] ;
+#else
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ;
+	    y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ;
+	    y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ;
+	    y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ;
+	    y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ;
+	    y [2][3] = X [j+2][3] - Lx [p+2] * y [0][3] - Lx [q+1] * y [1][3] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+1][2] = y [1][2] ;
+	    X [j+1][3] = y [1][3] ;
+	    X [j+2][0] = y [2][0] ;
+	    X [j+2][1] = y [2][1] ;
+	    X [j+2][2] = y [2][2] ;
+	    X [j+2][3] = y [2][3] ;
+#endif
+	    for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++)
+	    {
+		Int i = Li [p] ;
+		double lx [3] ;
+		lx [0] = Lx [p] ;
+		lx [1] = Lx [q] ;
+		lx [2] = Lx [r] ;
+		X [i][0] -= lx[0] * y[0][0] + lx[1] * y[1][0] + lx[2] * y[2][0];
+		X [i][1] -= lx[0] * y[0][1] + lx[1] * y[1][1] + lx[2] * y[2][1];
+		X [i][2] -= lx[0] * y[0][2] + lx[1] * y[1][2] + lx[2] * y[2][2];
+		X [i][3] -= lx[0] * y[0][3] + lx[1] * y[1][3] + lx[2] * y[2][3];
+	    }
+	    j += 3 ;	    /* advance to next column of L */
+	}
+    }
+}
+
+#endif
+
+
+/* ========================================================================== */
+/* === LSOLVE (k) =========================================================== */
+/* ========================================================================== */
+
+static void LSOLVE (PREFIX,k)
+(
+    cholmod_factor *L,
+    cholmod_dense *Y		    /* nr-by-n where nr is 1 to 4 */
+)
+{
+
+#ifndef REAL
+    double yx [2] ;
+#ifdef ZOMPLEX
+    double yz [1] ;
+    double *Lz = L->z ;
+    double *Xz = Y->z ;
+#endif
+    double *Lx = L->x ;
+    double *Xx = Y->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int i, j, n = L->n ;
+#endif
+
+    ASSERT (L->xtype == Y->xtype) ; /* L and Y must have the same xtype */
+    ASSERT (L->n == Y->ncol) ;	    /* dimensions must match */
+    ASSERT (Y->nrow == Y->d) ;	    /* leading dimension of Y = # rows of Y */
+    ASSERT (L->xtype != CHOLMOD_PATTERN) ;  /* L is not symbolic */
+    ASSERT (!(L->is_super)) ;	    /* L is simplicial LL' or LDL' */
+
+#ifdef REAL
+
+    /* ---------------------------------------------------------------------- */
+    /* solve a real linear system, with 1 to 4 RHS's and dynamic supernodes */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (Y->nrow <= 4) ;
+
+    switch (Y->nrow)
+    {
+	case 1: LSOLVE (PREFIX,1) (L, Y->x) ; break ;
+	case 2: LSOLVE (PREFIX,2) (L, Y->x) ; break ;
+	case 3: LSOLVE (PREFIX,3) (L, Y->x) ; break ;
+	case 4: LSOLVE (PREFIX,4) (L, Y->x) ; break ;
+    }
+
+#else
+
+    /* ---------------------------------------------------------------------- */
+    /* solve a complex linear system, with just one right-hand-side */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (Y->nrow == 1) ;
+
+    for (j = 0 ; j < n ; j++)
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* y = X [j] ; */
+	ASSIGN (yx,yz,0, Xx,Xz,j) ;
+
+#ifdef LL
+	/* y /= Lx [p] ; */
+	/* X [j] = y ; */
+	DIV_REAL (yx,yz,0, yx,yz,0, Lx,p) ;
+	ASSIGN (Xx,Xz,j, yx,yz,0) ;
+#elif defined (LD)
+	/* X [j] = y / Lx [p] ; */
+	DIV_REAL (Xx,Xz,j, yx,yz,0, Lx,p) ;
+#endif
+
+	for (p++ ; p < pend ; p++)
+	{
+	    /* X [Li [p]] -= Lx [p] * y ; */
+	    i = Li [p] ;
+	    MULTSUB (Xx,Xz,i, Lx,Lz,p, yx,yz,0) ;
+	}
+    }
+
+#endif
+}
+
+/* prepare for the next inclusion of this file in cholmod_solve.c */
+#undef LL
+#undef LD
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/t_cholmod_ltsolve.c b/src/C/SuiteSparse/CHOLMOD/Cholesky/t_cholmod_ltsolve.c
new file mode 100644
index 0000000..e58d1cd
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/t_cholmod_ltsolve.c
@@ -0,0 +1,841 @@
+/* ========================================================================== */
+/* === Cholesky/t_cholmod_ltsolve =========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Template routine to solve L'x=b with unit or non-unit diagonal, or
+ * solve DL'x=b.
+ *
+ * The numeric xtype of L and Y must match.  Y contains b on input and x on
+ * output, stored in row-form.  Y is nrow-by-n, where nrow must equal 1 for the 
+ * complex or zomplex cases, and nrow <= 4 for the real case.
+ *
+ * This file is not compiled separately.  It is included in t_cholmod_solve.c
+ * instead.  It contains no user-callable routines.
+ *
+ * workspace: none
+ *
+ * Supports real, complex, and zomplex factors.
+ */
+
+/* undefine all prior definitions */
+#undef FORM_NAME
+#undef LSOLVE
+#undef DIAG
+
+/* -------------------------------------------------------------------------- */
+/* define the method */
+/* -------------------------------------------------------------------------- */
+
+#ifdef LL
+/* LL': solve Lx=b with non-unit diagonal */
+#define FORM_NAME(prefix,rank) prefix ## ll_ltsolve_ ## rank
+#define DIAG
+
+#elif defined (LD)
+/* LDL': solve LDx=b */
+#define FORM_NAME(prefix,rank) prefix ## ldl_dltsolve_ ## rank
+#define DIAG
+
+#else
+/* LDL': solve Lx=b with unit diagonal */
+#define FORM_NAME(prefix,rank) prefix ## ldl_ltsolve_ ## rank
+
+#endif
+
+/* LSOLVE(k) defines the name of a routine for an n-by-k right-hand-side. */
+#define LSOLVE(prefix,rank) FORM_NAME(prefix,rank)
+
+#ifdef REAL
+
+/* ========================================================================== */
+/* === LSOLVE (1) =========================================================== */
+/* ========================================================================== */
+
+/* Solve L'x=b, where b has 1 column  */
+
+static void LSOLVE (PREFIX,1)
+(
+    cholmod_factor *L,
+    double X [ ]		    /* n-by-1 in row form */
+)
+{
+    double *Lx = L->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int j, n = L->n ;
+
+    for (j = n-1 ; j >= 0 ; )
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* find a chain of supernodes (up to j, j-1, and j-2) */
+	if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a single column of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y = X [j] ;
+#ifdef DIAG
+	    double d = Lx [p] ;
+#endif
+#ifdef LD
+	    y /= d ;
+#endif
+	    for (p++ ; p < pend ; p++)
+	    {
+		y -= Lx [p] * X [Li [p]] ;
+	    }
+#ifdef LL
+	    X [j] = y / d ;
+#else
+	    X [j] = y ;
+#endif
+	    j-- ;	/* advance to the next column of L */
+
+	}
+	else if (lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of two columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2], t ;
+	    Int q = Lp [j-1] ;
+#ifdef DIAG
+	    double d [2] ;
+	    d [0] = Lx [p] ;
+	    d [1] = Lx [q] ;
+#endif
+	    t = Lx [q+1] ;
+#ifdef LD
+	    y [0] = X [j  ] / d [0] ;
+	    y [1] = X [j-1] / d [1] ;
+#else
+	    y [0] = X [j  ] ;
+	    y [1] = X [j-1] ;
+#endif
+	    for (p++, q += 2 ; p < pend ; p++, q++)
+	    {
+		Int i = Li [p] ;
+		y [0] -= Lx [p] * X [i] ;
+		y [1] -= Lx [q] * X [i] ;
+	    }
+#ifdef LL
+	    y [0] /= d [0] ;
+	    y [1] = (y [1] - t * y [0]) / d [1] ;
+#else
+	    y [1] -= t * y [0] ;
+#endif
+	    X [j  ] = y [0] ;
+	    X [j-1] = y [1] ;
+	    j -= 2 ;	    /* advance to the next column of L */
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of three columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3], t [3] ;
+	    Int q = Lp [j-1] ;
+	    Int r = Lp [j-2] ;
+#ifdef DIAG
+	    double d [3] ;
+	    d [0] = Lx [p] ;
+	    d [1] = Lx [q] ;
+	    d [2] = Lx [r] ;
+#endif
+	    t [0] = Lx [q+1] ;
+	    t [1] = Lx [r+1] ;
+	    t [2] = Lx [r+2] ;
+#ifdef LD
+	    y [0] = X [j]   / d [0] ;
+	    y [1] = X [j-1] / d [1] ;
+	    y [2] = X [j-2] / d [2] ;
+#else
+	    y [0] = X [j] ;
+	    y [1] = X [j-1] ;
+	    y [2] = X [j-2] ;
+#endif
+	    for (p++, q += 2, r += 3 ; p < pend ; p++, q++, r++)
+	    {
+		Int i = Li [p] ;
+		y [0] -= Lx [p] * X [i] ;
+		y [1] -= Lx [q] * X [i] ;
+		y [2] -= Lx [r] * X [i] ;
+	    }
+#ifdef LL
+	    y [0] /= d [0] ;
+	    y [1] = (y [1] - t [0] * y [0]) / d [1] ;
+	    y [2] = (y [2] - t [2] * y [0] - t [1] * y [1]) / d [2] ;
+#else
+	    y [1] -= t [0] * y [0] ;
+	    y [2] -= t [2] * y [0] + t [1] * y [1] ;
+#endif
+	    X [j-2] = y [2] ;
+	    X [j-1] = y [1] ;
+	    X [j  ] = y [0] ;
+	    j -= 3 ;	    /* advance to the next column of L */
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === LSOLVE (2) =========================================================== */
+/* ========================================================================== */
+
+/* Solve L'x=b, where b has 2 columns */
+
+static void LSOLVE (PREFIX,2)
+(
+    cholmod_factor *L,
+    double X [ ][2]		    /* n-by-2 in row form */
+)
+{
+    double *Lx = L->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int j, n = L->n ;
+
+    for (j = n-1 ; j >= 0 ; )
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* find a chain of supernodes (up to j, j-1, and j-2) */
+	if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a single column of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2] ;
+#ifdef DIAG
+	    double d = Lx [p] ;
+#endif
+#ifdef LD
+	    y [0] = X [j][0] / d ;
+	    y [1] = X [j][1] / d ;
+#else
+	    y [0] = X [j][0] ;
+	    y [1] = X [j][1] ;
+#endif
+	    for (p++ ; p < pend ; p++)
+	    {
+		Int i = Li [p] ;
+		y [0] -= Lx [p] * X [i][0] ;
+		y [1] -= Lx [p] * X [i][1] ;
+	    }
+#ifdef LL
+	    X [j][0] = y [0] / d ;
+	    X [j][1] = y [1] / d ;
+#else
+	    X [j][0] = y [0] ;
+	    X [j][1] = y [1] ;
+#endif
+	    j-- ;	/* advance to the next column of L */
+
+	}
+	else if (lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of two columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2][2], t ;
+	    Int q = Lp [j-1] ;
+#ifdef DIAG
+	    double d [2] ;
+	    d [0] = Lx [p] ;
+	    d [1] = Lx [q] ;
+#endif
+	    t = Lx [q+1] ;
+#ifdef LD
+	    y [0][0] = X [j  ][0] / d [0] ;
+	    y [0][1] = X [j  ][1] / d [0] ;
+	    y [1][0] = X [j-1][0] / d [1] ;
+	    y [1][1] = X [j-1][1] / d [1] ;
+#else
+	    y [0][0] = X [j  ][0] ;
+	    y [0][1] = X [j  ][1] ;
+	    y [1][0] = X [j-1][0] ;
+	    y [1][1] = X [j-1][1] ;
+#endif
+	    for (p++, q += 2 ; p < pend ; p++, q++)
+	    {
+		Int i = Li [p] ;
+		y [0][0] -= Lx [p] * X [i][0] ;
+		y [0][1] -= Lx [p] * X [i][1] ;
+		y [1][0] -= Lx [q] * X [i][0] ;
+		y [1][1] -= Lx [q] * X [i][1] ;
+	    }
+#ifdef LL
+	    y [0][0] /= d [0] ;
+	    y [0][1] /= d [0] ;
+	    y [1][0] = (y [1][0] - t * y [0][0]) / d [1] ;
+	    y [1][1] = (y [1][1] - t * y [0][1]) / d [1] ;
+#else
+	    y [1][0] -= t * y [0][0] ;
+	    y [1][1] -= t * y [0][1] ;
+#endif
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j-1][0] = y [1][0] ;
+	    X [j-1][1] = y [1][1] ;
+	    j -= 2 ;	    /* advance to the next column of L */
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of three columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3][2], t [3] ;
+	    Int q = Lp [j-1] ;
+	    Int r = Lp [j-2] ;
+#ifdef DIAG
+	    double d [3] ; 
+	    d [0] = Lx [p] ;
+	    d [1] = Lx [q] ;
+	    d [2] = Lx [r] ;
+#endif
+	    t [0] = Lx [q+1] ;
+	    t [1] = Lx [r+1] ;
+	    t [2] = Lx [r+2] ;
+#ifdef LD
+	    y [0][0] = X [j  ][0] / d [0] ;
+	    y [0][1] = X [j  ][1] / d [0] ;
+	    y [1][0] = X [j-1][0] / d [1] ;
+	    y [1][1] = X [j-1][1] / d [1] ;
+	    y [2][0] = X [j-2][0] / d [2] ;
+	    y [2][1] = X [j-2][1] / d [2] ;
+#else
+	    y [0][0] = X [j  ][0] ;
+	    y [0][1] = X [j  ][1] ;
+	    y [1][0] = X [j-1][0] ;
+	    y [1][1] = X [j-1][1] ;
+	    y [2][0] = X [j-2][0] ;
+	    y [2][1] = X [j-2][1] ;
+#endif
+	    for (p++, q += 2, r += 3 ; p < pend ; p++, q++, r++)
+	    {
+		Int i = Li [p] ;
+		y [0][0] -= Lx [p] * X [i][0] ;
+		y [0][1] -= Lx [p] * X [i][1] ;
+		y [1][0] -= Lx [q] * X [i][0] ;
+		y [1][1] -= Lx [q] * X [i][1] ;
+		y [2][0] -= Lx [r] * X [i][0] ;
+		y [2][1] -= Lx [r] * X [i][1] ;
+	    }
+#ifdef LL
+	    y [0][0] /= d [0] ;
+	    y [0][1] /= d [0] ;
+	    y [1][0] = (y [1][0] - t [0] * y [0][0]) / d [1] ;
+	    y [1][1] = (y [1][1] - t [0] * y [0][1]) / d [1] ;
+	    y [2][0] = (y [2][0] - t [2] * y [0][0] - t [1] * y [1][0]) / d [2];
+	    y [2][1] = (y [2][1] - t [2] * y [0][1] - t [1] * y [1][1]) / d [2];
+#else
+	    y [1][0] -= t [0] * y [0][0] ;
+	    y [1][1] -= t [0] * y [0][1] ;
+	    y [2][0] -= t [2] * y [0][0] + t [1] * y [1][0] ;
+	    y [2][1] -= t [2] * y [0][1] + t [1] * y [1][1] ;
+#endif
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j-1][0] = y [1][0] ;
+	    X [j-1][1] = y [1][1] ;
+	    X [j-2][0] = y [2][0] ;
+	    X [j-2][1] = y [2][1] ;
+	    j -= 3 ;	    /* advance to the next column of L */
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === LSOLVE (3) =========================================================== */
+/* ========================================================================== */
+
+/* Solve L'x=b, where b has 3 columns */
+
+static void LSOLVE (PREFIX,3)
+(
+    cholmod_factor *L,
+    double X [ ][3]		    /* n-by-3 in row form */
+)
+{
+    double *Lx = L->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int j, n = L->n ;
+
+    for (j = n-1 ; j >= 0 ; )
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* find a chain of supernodes (up to j, j-1, and j-2) */
+	if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a single column of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3] ;
+#ifdef DIAG
+	    double d = Lx [p] ;
+#endif
+#ifdef LD
+	    y [0] = X [j][0] / d ;
+	    y [1] = X [j][1] / d ;
+	    y [2] = X [j][2] / d ;
+#else
+	    y [0] = X [j][0] ;
+	    y [1] = X [j][1] ;
+	    y [2] = X [j][2] ;
+#endif
+	    for (p++ ; p < pend ; p++)
+	    {
+		Int i = Li [p] ;
+		y [0] -= Lx [p] * X [i][0] ;
+		y [1] -= Lx [p] * X [i][1] ;
+		y [2] -= Lx [p] * X [i][2] ;
+	    }
+#ifdef LL
+	    X [j][0] = y [0] / d ;
+	    X [j][1] = y [1] / d ;
+	    X [j][2] = y [2] / d ;
+#else
+	    X [j][0] = y [0] ;
+	    X [j][1] = y [1] ;
+	    X [j][2] = y [2] ;
+#endif
+	    j-- ;	/* advance to the next column of L */
+
+	}
+	else if (lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of two columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2][3], t ;
+	    Int q = Lp [j-1] ;
+#ifdef DIAG
+	    double d [2] ;
+	    d [0] = Lx [p] ;
+	    d [1] = Lx [q] ;
+#endif
+	    t = Lx [q+1] ;
+#ifdef LD
+	    y [0][0] = X [j  ][0] / d [0] ;
+	    y [0][1] = X [j  ][1] / d [0] ;
+	    y [0][2] = X [j  ][2] / d [0] ;
+	    y [1][0] = X [j-1][0] / d [1] ;
+	    y [1][1] = X [j-1][1] / d [1] ;
+	    y [1][2] = X [j-1][2] / d [1] ;
+#else
+	    y [0][0] = X [j  ][0] ;
+	    y [0][1] = X [j  ][1] ;
+	    y [0][2] = X [j  ][2] ;
+	    y [1][0] = X [j-1][0] ;
+	    y [1][1] = X [j-1][1] ;
+	    y [1][2] = X [j-1][2] ;
+#endif
+	    for (p++, q += 2 ; p < pend ; p++, q++)
+	    {
+		Int i = Li [p] ;
+		y [0][0] -= Lx [p] * X [i][0] ;
+		y [0][1] -= Lx [p] * X [i][1] ;
+		y [0][2] -= Lx [p] * X [i][2] ;
+		y [1][0] -= Lx [q] * X [i][0] ;
+		y [1][1] -= Lx [q] * X [i][1] ;
+		y [1][2] -= Lx [q] * X [i][2] ;
+	    }
+#ifdef LL
+	    y [0][0] /= d [0] ;
+	    y [0][1] /= d [0] ;
+	    y [0][2] /= d [0] ;
+	    y [1][0] = (y [1][0] - t * y [0][0]) / d [1] ;
+	    y [1][1] = (y [1][1] - t * y [0][1]) / d [1] ;
+	    y [1][2] = (y [1][2] - t * y [0][2]) / d [1] ;
+#else
+	    y [1][0] -= t * y [0][0] ;
+	    y [1][1] -= t * y [0][1] ;
+	    y [1][2] -= t * y [0][2] ;
+#endif
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j  ][2] = y [0][2] ;
+	    X [j-1][0] = y [1][0] ;
+	    X [j-1][1] = y [1][1] ;
+	    X [j-1][2] = y [1][2] ;
+	    j -= 2 ;	    /* advance to the next column of L */
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of three columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3][3], t [3] ;
+	    Int q = Lp [j-1] ;
+	    Int r = Lp [j-2] ;
+#ifdef DIAG
+	    double d [3] ;
+	    d [0] = Lx [p] ;
+	    d [1] = Lx [q] ;
+	    d [2] = Lx [r] ;
+#endif
+	    t [0] = Lx [q+1] ;
+	    t [1] = Lx [r+1] ;
+	    t [2] = Lx [r+2] ;
+#ifdef LD
+	    y [0][0] = X [j  ][0] / d [0] ;
+	    y [0][1] = X [j  ][1] / d [0] ;
+	    y [0][2] = X [j  ][2] / d [0] ;
+	    y [1][0] = X [j-1][0] / d [1] ;
+	    y [1][1] = X [j-1][1] / d [1] ;
+	    y [1][2] = X [j-1][2] / d [1] ;
+	    y [2][0] = X [j-2][0] / d [2] ;
+	    y [2][1] = X [j-2][1] / d [2] ;
+	    y [2][2] = X [j-2][2] / d [2] ;
+#else
+	    y [0][0] = X [j  ][0] ;
+	    y [0][1] = X [j  ][1] ;
+	    y [0][2] = X [j  ][2] ;
+	    y [1][0] = X [j-1][0] ;
+	    y [1][1] = X [j-1][1] ;
+	    y [1][2] = X [j-1][2] ;
+	    y [2][0] = X [j-2][0] ;
+	    y [2][1] = X [j-2][1] ;
+	    y [2][2] = X [j-2][2] ;
+#endif
+	    for (p++, q += 2, r += 3 ; p < pend ; p++, q++, r++)
+	    {
+		Int i = Li [p] ;
+		y [0][0] -= Lx [p] * X [i][0] ;
+		y [0][1] -= Lx [p] * X [i][1] ;
+		y [0][2] -= Lx [p] * X [i][2] ;
+		y [1][0] -= Lx [q] * X [i][0] ;
+		y [1][1] -= Lx [q] * X [i][1] ;
+		y [1][2] -= Lx [q] * X [i][2] ;
+		y [2][0] -= Lx [r] * X [i][0] ;
+		y [2][1] -= Lx [r] * X [i][1] ;
+		y [2][2] -= Lx [r] * X [i][2] ;
+	    }
+#ifdef LL
+	    y [0][0] /= d [0] ;
+	    y [0][1] /= d [0] ;
+	    y [0][2] /= d [0] ;
+	    y [1][0] = (y [1][0] - t [0] * y [0][0]) / d [1] ;
+	    y [1][1] = (y [1][1] - t [0] * y [0][1]) / d [1] ;
+	    y [1][2] = (y [1][2] - t [0] * y [0][2]) / d [1] ;
+	    y [2][0] = (y [2][0] - t [2] * y [0][0] - t [1] * y [1][0]) / d [2];
+	    y [2][1] = (y [2][1] - t [2] * y [0][1] - t [1] * y [1][1]) / d [2];
+	    y [2][2] = (y [2][2] - t [2] * y [0][2] - t [1] * y [1][2]) / d [2];
+#else
+	    y [1][0] -= t [0] * y [0][0] ;
+	    y [1][1] -= t [0] * y [0][1] ;
+	    y [1][2] -= t [0] * y [0][2] ;
+	    y [2][0] -= t [2] * y [0][0] + t [1] * y [1][0] ;
+	    y [2][1] -= t [2] * y [0][1] + t [1] * y [1][1] ;
+	    y [2][2] -= t [2] * y [0][2] + t [1] * y [1][2] ;
+#endif
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j  ][2] = y [0][2] ;
+	    X [j-1][0] = y [1][0] ;
+	    X [j-1][1] = y [1][1] ;
+	    X [j-1][2] = y [1][2] ;
+	    X [j-2][0] = y [2][0] ;
+	    X [j-2][1] = y [2][1] ;
+	    X [j-2][2] = y [2][2] ;
+	    j -= 3 ;	    /* advance to the next column of L */
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === LSOLVE (4) =========================================================== */
+/* ========================================================================== */
+
+/* Solve L'x=b, where b has 4 columns */
+
+static void LSOLVE (PREFIX,4)
+(
+    cholmod_factor *L,
+    double X [ ][4]		    /* n-by-4 in row form */
+)
+{
+    double *Lx = L->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int j, n = L->n ;
+
+    for (j = n-1 ; j >= 0 ; )
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* find a chain of supernodes (up to j, j-1, and j-2) */
+	if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a single column of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [4] ;
+#ifdef DIAG
+	    double d = Lx [p] ;
+#endif
+#ifdef LD
+	    y [0] = X [j][0] / d ;
+	    y [1] = X [j][1] / d ;
+	    y [2] = X [j][2] / d ;
+	    y [3] = X [j][3] / d ;
+#else
+	    y [0] = X [j][0] ;
+	    y [1] = X [j][1] ;
+	    y [2] = X [j][2] ;
+	    y [3] = X [j][3] ;
+#endif
+	    for (p++ ; p < pend ; p++)
+	    {
+		Int i = Li [p] ;
+		y [0] -= Lx [p] * X [i][0] ;
+		y [1] -= Lx [p] * X [i][1] ;
+		y [2] -= Lx [p] * X [i][2] ;
+		y [3] -= Lx [p] * X [i][3] ;
+	    }
+#ifdef LL
+	    X [j][0] = y [0] / d ;
+	    X [j][1] = y [1] / d ;
+	    X [j][2] = y [2] / d ;
+	    X [j][3] = y [3] / d ;
+#else
+	    X [j][0] = y [0] ;
+	    X [j][1] = y [1] ;
+	    X [j][2] = y [2] ;
+	    X [j][3] = y [3] ;
+#endif
+	    j-- ;	/* advance to the next column of L */
+
+	}
+	else /* if (j == 1 || lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j) */
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of two columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2][4], t ;
+	    Int q = Lp [j-1] ;
+#ifdef DIAG
+	    double d [2] ;
+	    d [0] = Lx [p] ;
+	    d [1] = Lx [q] ;
+#endif
+	    t = Lx [q+1] ;
+#ifdef LD
+	    y [0][0] = X [j  ][0] / d [0] ;
+	    y [0][1] = X [j  ][1] / d [0] ;
+	    y [0][2] = X [j  ][2] / d [0] ;
+	    y [0][3] = X [j  ][3] / d [0] ;
+	    y [1][0] = X [j-1][0] / d [1] ;
+	    y [1][1] = X [j-1][1] / d [1] ;
+	    y [1][2] = X [j-1][2] / d [1] ;
+	    y [1][3] = X [j-1][3] / d [1] ;
+#else
+	    y [0][0] = X [j  ][0] ;
+	    y [0][1] = X [j  ][1] ;
+	    y [0][2] = X [j  ][2] ;
+	    y [0][3] = X [j  ][3] ;
+	    y [1][0] = X [j-1][0] ;
+	    y [1][1] = X [j-1][1] ;
+	    y [1][2] = X [j-1][2] ;
+	    y [1][3] = X [j-1][3] ;
+#endif
+	    for (p++, q += 2 ; p < pend ; p++, q++)
+	    {
+		Int i = Li [p] ;
+		y [0][0] -= Lx [p] * X [i][0] ;
+		y [0][1] -= Lx [p] * X [i][1] ;
+		y [0][2] -= Lx [p] * X [i][2] ;
+		y [0][3] -= Lx [p] * X [i][3] ;
+		y [1][0] -= Lx [q] * X [i][0] ;
+		y [1][1] -= Lx [q] * X [i][1] ;
+		y [1][2] -= Lx [q] * X [i][2] ;
+		y [1][3] -= Lx [q] * X [i][3] ;
+	    }
+#ifdef LL
+	    y [0][0] /= d [0] ;
+	    y [0][1] /= d [0] ;
+	    y [0][2] /= d [0] ;
+	    y [0][3] /= d [0] ;
+	    y [1][0] = (y [1][0] - t * y [0][0]) / d [1] ;
+	    y [1][1] = (y [1][1] - t * y [0][1]) / d [1] ;
+	    y [1][2] = (y [1][2] - t * y [0][2]) / d [1] ;
+	    y [1][3] = (y [1][3] - t * y [0][3]) / d [1] ;
+#else
+	    y [1][0] -= t * y [0][0] ;
+	    y [1][1] -= t * y [0][1] ;
+	    y [1][2] -= t * y [0][2] ;
+	    y [1][3] -= t * y [0][3] ;
+#endif
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j  ][2] = y [0][2] ;
+	    X [j  ][3] = y [0][3] ;
+	    X [j-1][0] = y [1][0] ;
+	    X [j-1][1] = y [1][1] ;
+	    X [j-1][2] = y [1][2] ;
+	    X [j-1][3] = y [1][3] ;
+	    j -= 2 ;	    /* advance to the next column of L */
+	}
+
+	/* NOTE: with 4 right-hand-sides, it suffices to exploit dynamic
+	 * supernodes of just size 1 and 2.  3-column supernodes are not
+	 * needed. */
+    }
+}
+
+#endif
+
+/* ========================================================================== */
+/* === LSOLVE (k) =========================================================== */
+/* ========================================================================== */
+
+static void LSOLVE (PREFIX,k)
+(
+    cholmod_factor *L,
+    cholmod_dense *Y		    /* nr-by-n where nr is 1 to 4 */
+)
+{
+
+#ifndef REAL
+#ifdef DIAG
+    double d [1] ;
+#endif
+    double yx [2] ;
+#ifdef ZOMPLEX
+    double yz [1] ;
+    double *Lz = L->z ;
+    double *Xz = Y->z ;
+#endif
+    double *Lx = L->x ;
+    double *Xx = Y->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int i, j, n = L->n ;
+#endif
+
+    ASSERT (L->xtype == Y->xtype) ; /* L and Y must have the same xtype */
+    ASSERT (L->n == Y->ncol) ;	    /* dimensions must match */
+    ASSERT (Y->nrow == Y->d) ;	    /* leading dimension of Y = # rows of Y */
+    ASSERT (L->xtype != CHOLMOD_PATTERN) ;  /* L is not symbolic */
+    ASSERT (!(L->is_super)) ;	    /* L is simplicial LL' or LDL' */
+
+#ifdef REAL
+
+    /* ---------------------------------------------------------------------- */
+    /* solve a real linear system, with 1 to 4 RHS's and dynamic supernodes */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (Y->nrow <= 4) ;
+    switch (Y->nrow)
+    {
+	case 1: LSOLVE (PREFIX,1) (L, Y->x) ; break ;
+	case 2: LSOLVE (PREFIX,2) (L, Y->x) ; break ;
+	case 3: LSOLVE (PREFIX,3) (L, Y->x) ; break ;
+	case 4: LSOLVE (PREFIX,4) (L, Y->x) ; break ;
+    }
+
+#else
+
+    /* ---------------------------------------------------------------------- */
+    /* solve a complex linear system, with just one right-hand-side */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (Y->nrow == 1) ;
+
+    for (j = n-1 ; j >= 0 ; j--)
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* y = X [j] ; */
+	ASSIGN (yx,yz,0, Xx,Xz,j) ;
+
+#ifdef DIAG
+	/* d = Lx [p] ; */
+	ASSIGN_REAL (d,0, Lx,p) ;
+#endif
+#ifdef LD
+	/* y /= d ; */
+	DIV_REAL (yx,yz,0, yx,yz,0, d,0) ;
+#endif
+
+	for (p++ ; p < pend ; p++)
+	{
+	    /* y -= conj (Lx [p]) * X [Li [p]] ; */
+	    i = Li [p] ;
+	    MULTSUBCONJ (yx,yz,0, Lx,Lz,p, Xx,Xz,i) ;
+	}
+
+#ifdef LL
+	/* X [j] = y / d ; */
+	DIV_REAL (Xx,Xz,j, yx,yz,0, d,0) ;
+#else
+	/* X [j] = y ; */
+	ASSIGN (Xx,Xz,j, yx,yz,0) ;
+#endif
+
+    }
+
+#endif
+}
+
+/* prepare for the next inclusion of this file in cholmod_solve.c */
+#undef LL
+#undef LD
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/t_cholmod_rowfac.c b/src/C/SuiteSparse/CHOLMOD/Cholesky/t_cholmod_rowfac.c
new file mode 100644
index 0000000..57f0f33
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/t_cholmod_rowfac.c
@@ -0,0 +1,456 @@
+/* ========================================================================== */
+/* === Cholesky/t_cholmod_rowfac ============================================ */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Template routine for cholmod_rowfac.  Supports any numeric xtype
+ * (real, complex, or zomplex).
+ *
+ * workspace: Iwork (n), Flag (n), Xwork (n if real, 2*n if complex)
+ */
+
+#include "cholmod_template.h"
+
+#ifdef MASK
+static int TEMPLATE (cholmod_rowfac_mask)
+#else
+static int TEMPLATE (cholmod_rowfac)
+#endif
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    cholmod_sparse *F,	/* used for A*A' case only. F=A' or A(:,f)' */
+    double beta [2],	/* factorize beta*I+A or beta*I+AA' (beta [0] only) */
+    size_t kstart,	/* first row to factorize */
+    size_t kend,	/* last row to factorize is kend-1 */
+#ifdef MASK
+    /* These inputs are used for cholmod_rowfac_mask only */
+    Int *mask,		/* size A->nrow. if mask[i] then W(i) is set to zero */
+    Int *RLinkUp,	/* size A->nrow. link list of rows to compute */
+#endif
+    /* ---- in/out --- */
+    cholmod_factor *L,
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double yx [2], lx [2], fx [2], dk [1], di [1], fl = 0 ;
+#ifdef ZOMPLEX
+    double yz [1], lz [1], fz [1] ;
+#endif
+    double *Ax, *Az, *Lx, *Lz, *Wx, *Wz, *Fx, *Fz ;
+    Int *Ap, *Anz, *Ai, *Lp, *Lnz, *Li, *Lnext, *Flag, *Stack, *Fp, *Fi, *Fnz,
+	*Iwork ;
+    Int i, p, k, t, pf, pfend, top, s, mark, pend, n, lnz, is_ll, multadds,
+	use_dbound, packed, stype, Fpacked, sorted, nzmax, len, parent ;
+#ifndef REAL
+    Int dk_imaginary ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    PRINT1 (("\nin cholmod_rowfac, kstart %d kend %d stype %d\n",
+		kstart, kend, A->stype)) ;
+    DEBUG (CHOLMOD(dump_factor) (L, "Initial L", Common)) ;
+
+    n = A->nrow ;
+    stype = A->stype ;
+
+    if (stype > 0)
+    {
+	/* symmetric upper case: F is not needed.  It may be NULL */
+	Fp = NULL ;
+	Fi = NULL ;
+	Fx = NULL ;
+	Fz = NULL ;
+	Fnz = NULL ;
+	Fpacked = TRUE ;
+    }
+    else
+    {
+	/* unsymmetric case: F is required. */
+	Fp = F->p ;
+	Fi = F->i ;
+	Fx = F->x ;
+	Fz = F->z ;
+	Fnz = F->nz ;
+	Fpacked = F->packed ;
+    }
+
+    Ap = A->p ;		/* size A->ncol+1, column pointers of A */
+    Ai = A->i ;		/* size nz = Ap [A->ncol], row indices of A */
+    Ax = A->x ;		/* size nz, numeric values of A */
+    Az = A->z ;
+    Anz = A->nz ;
+    packed = A->packed ;
+    sorted = A->sorted ;
+
+    use_dbound = IS_GT_ZERO (Common->dbound) ;
+
+    /* get the current factors L (and D for LDL'); allocate space if needed */
+    is_ll = L->is_ll ;
+    if (L->xtype == CHOLMOD_PATTERN)
+    {
+	/* ------------------------------------------------------------------ */
+	/* L is symbolic only; allocate and initialize L (and D for LDL') */
+	/* ------------------------------------------------------------------ */
+
+	/* workspace: none */
+	CHOLMOD(change_factor) (A->xtype, is_ll, FALSE, FALSE, TRUE, L, Common);
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+	    return (FALSE) ;
+	}
+	ASSERT (L->minor == (size_t) n) ;
+    }
+    else if (kstart == 0 && kend == (size_t) n)
+    {
+	/* ------------------------------------------------------------------ */
+	/* refactorization; reset L->nz and L->minor to restart factorization */
+	/* ------------------------------------------------------------------ */
+
+	L->minor = n ;
+	Lnz = L->nz ;
+	for (k = 0 ; k < n ; k++)
+	{
+	    Lnz [k] = 1 ;
+	}
+    }
+
+    ASSERT (is_ll == L->is_ll) ;
+    ASSERT (L->xtype != CHOLMOD_PATTERN) ;
+    DEBUG (CHOLMOD(dump_factor) (L, "L ready", Common)) ;
+    DEBUG (CHOLMOD(dump_sparse) (A, "A ready", Common)) ;
+    DEBUG (if (stype == 0) CHOLMOD(dump_sparse) (F, "F ready", Common)) ;
+
+    /* inputs, can be modified on output: */
+    Lp = L->p ;		/* size n+1 */
+    ASSERT (Lp != NULL) ;
+
+    /* outputs, contents defined on input for incremental case only: */
+    Lnz = L->nz ;	/* size n */
+    Lnext = L->next ;	/* size n+2 */
+    Li = L->i ;		/* size L->nzmax, can change in size */
+    Lx = L->x ;		/* size L->nzmax or 2*L->nzmax, can change in size */
+    Lz = L->z ;		/* size L->nzmax for zomplex case, can change in size */
+    nzmax = L->nzmax ;
+    ASSERT (Lnz != NULL && Li != NULL && Lx != NULL) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Iwork = Common->Iwork ;
+    Stack = Iwork ;		/* size n (i/i/l) */
+    Flag = Common->Flag ;	/* size n, Flag [i] < mark must hold */
+    Wx = Common->Xwork ;	/* size n if real, 2*n if complex or 
+				 * zomplex.  Xwork [i] == 0 must hold. */
+    Wz = Wx + n ;		/* size n for zomplex case only */
+    mark = Common->mark ;
+    ASSERT ((Int) Common->xworksize >= (L->xtype == CHOLMOD_REAL ? 1:2)*n) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compute LDL' or LL' factorization by rows */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef MASK
+#define NEXT(k) k = RLinkUp [k]
+#else
+#define NEXT(k) k++
+#endif
+
+    for (k = kstart ; k < ((Int) kend) ; NEXT(k))
+    {
+	PRINT1 (("\n===============K "ID" Lnz [k] "ID"\n", k, Lnz [k])) ;
+
+	/* ------------------------------------------------------------------ */
+	/* compute pattern of kth row of L and scatter kth input column */
+	/* ------------------------------------------------------------------ */
+
+	/* column k of L is currently empty */
+	ASSERT (Lnz [k] == 1) ;
+	ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 2*n, Common)) ;
+
+	top = n ;		/* Stack is empty */
+	Flag [k] = mark ;	/* do not include diagonal entry in Stack */
+
+	/* use Li [Lp [i]+1] for etree */
+#define PARENT(i) (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY
+
+	if (stype > 0)
+	{
+	    /* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */
+	    p = Ap [k] ;
+	    pend = (packed) ? (Ap [k+1]) : (p + Anz [k]) ;
+	    /* W [i] = Ax [i] ; scatter column of A */
+#define SCATTER ASSIGN(Wx,Wz,i, Ax,Az,p)
+	    SUBTREE ;
+#undef SCATTER
+	}
+	else
+	{
+	    /* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */
+	    pf = Fp [k] ;
+	    pfend = (Fpacked) ? (Fp [k+1]) : (pf + Fnz [k]) ;
+	    for ( ; pf < pfend ; pf++)
+	    {
+		/* get nonzero entry F (t,k) */
+		t = Fi [pf] ;
+		/* fk = Fx [pf] */
+		ASSIGN (fx, fz, 0, Fx, Fz, pf) ;
+		p = Ap [t] ;
+		pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ;
+		multadds = 0 ;
+		/* W [i] += Ax [p] * fx ; scatter column of A*A' */
+#define SCATTER MULTADD (Wx,Wz,i, Ax,Az,p, fx,fz,0) ; multadds++  ;
+		SUBTREE ;
+#undef SCATTER
+#ifdef REAL
+		fl += 2 * ((double) multadds) ;
+#else
+		fl += 8 * ((double) multadds) ;
+#endif
+	    }
+	}
+
+#undef PARENT
+
+	/* ------------------------------------------------------------------ */
+	/* if mask is present, set the corresponding entries in W to zero */
+	/* ------------------------------------------------------------------ */
+
+#ifdef MASK
+        /* remove the dead element of Wx */
+        if (mask != NULL)
+        {
+
+#if 0
+	    /* older version */
+            for (p = n; p > top;)
+            {
+                i = Stack [--p] ;
+                if ( mask [i] >= 0 )
+		{
+		    CLEAR (Wx,Wz,i) ;	/* set W(i) to zero */
+		}
+            }
+#endif
+
+            for (s = top ; s < n ; s++)
+            {
+                i = Stack [s] ;
+                if (mask [i] >= 0)
+		{
+		    CLEAR (Wx,Wz,i) ;	/* set W(i) to zero */
+		}
+            }
+
+        }
+#endif
+
+	/* nonzero pattern of kth row of L is now in Stack [top..n-1].
+	 * Flag [Stack [top..n-1]] is equal to mark, but no longer needed */
+
+	mark = CHOLMOD(clear_flag) (Common) ;
+
+	/* ------------------------------------------------------------------ */
+	/* compute kth row of L and store in column form */
+	/* ------------------------------------------------------------------ */
+
+	/* Solve L (0:k-1, 0:k-1) * y (0:k-1) = b (0:k-1) where
+	 * b (0:k) = A (0:k,k) or A(0:k,:) * F(:,k) is in W and Stack.
+	 *
+	 * For LDL' factorization:
+	 * L (k, 0:k-1) = y (0:k-1) ./ D (0:k-1)
+	 * D (k) = b (k) - L (k, 0:k-1) * y (0:k-1)
+	 *
+	 * For LL' factorization:
+	 * L (k, 0:k-1) = y (0:k-1)
+	 * L (k,k) = sqrt (b (k) - L (k, 0:k-1) * L (0:k-1, k))
+	 */
+
+	/* dk = W [k] + beta */
+	ADD_REAL (dk,0, Wx,k, beta,0) ;
+
+#ifndef REAL
+	/* In the unsymmetric case, the imaginary part of W[k] must be real,
+	 * since F is assumed to be the complex conjugate transpose of A.  In
+	 * the symmetric case, W[k] is the diagonal of A.  If the imaginary part
+	 * of W[k] is nonzero, then the Cholesky factorization cannot be
+	 * computed; A is not positive definite */
+	dk_imaginary = (stype > 0) ? (IMAG_IS_NONZERO (Wx,Wz,k)) : FALSE ;
+#endif
+
+	/* W [k] = 0.0 ; */
+	CLEAR (Wx,Wz,k) ;
+
+	for (s = top ; s < n ; s++)
+	{
+	    /* get i for each nonzero entry L(k,i) */
+	    i = Stack [s] ;
+
+	    /* y = W [i] ; */
+	    ASSIGN (yx,yz,0, Wx,Wz,i) ;
+
+	    /* W [i] = 0.0 ; */
+	    CLEAR (Wx,Wz,i) ;
+
+	    lnz = Lnz [i] ;
+	    p = Lp [i] ;
+	    ASSERT (lnz > 0 && Li [p] == i) ;
+	    pend = p + lnz ;
+
+	    /* di = Lx [p] ; the diagonal entry L or D(i,i), which is real */
+	    ASSIGN_REAL (di,0, Lx,p) ;
+
+	    if (i >= (Int) L->minor || IS_ZERO (di [0]))
+	    {
+		/* For the LL' factorization, L(i,i) is zero.  For the LDL',
+		 * D(i,i) is zero.  Skip column i of L, and set L(k,i) = 0. */
+		CLEAR (lx,lz,0) ;
+		p = pend ;
+	    }
+	    else if (is_ll)
+	    {
+#ifdef REAL
+		fl += 2 * ((double) (pend - p - 1)) + 3 ;
+#else
+		fl += 8 * ((double) (pend - p - 1)) + 6 ;
+#endif
+		/* forward solve using L (i:(k-1),i) */
+		/* divide by L(i,i), which must be real and nonzero */
+		/* y /= di [0] */
+		DIV_REAL (yx,yz,0, yx,yz,0, di,0) ;
+		for (p++ ; p < pend ; p++)
+		{
+		    /* W [Li [p]] -= Lx [p] * y ; */
+		    MULTSUB (Wx,Wz,Li[p], Lx,Lz,p, yx,yz,0) ;
+		}
+		/* do not scale L; compute dot product for L(k,k) */
+		/* L(k,i) = conj(y) ; */
+		ASSIGN_CONJ (lx,lz,0, yx,yz,0) ;
+		/* d -= conj(y) * y ; */
+		LLDOT (dk,0, yx,yz,0) ;
+	    }
+	    else
+	    {
+#ifdef REAL
+		fl += 2 * ((double) (pend - p - 1)) + 3 ;
+#else
+		fl += 8 * ((double) (pend - p - 1)) + 6 ;
+#endif
+		/* forward solve using D (i,i) and L ((i+1):(k-1),i) */
+		for (p++ ; p < pend ; p++)
+		{
+		    /* W [Li [p]] -= Lx [p] * y ; */
+		    MULTSUB (Wx,Wz,Li[p], Lx,Lz,p, yx,yz,0) ;
+		}
+		/* Scale L (k,0:k-1) for LDL' factorization, compute D (k,k)*/
+#ifdef REAL
+		/* L(k,i) = y/d */
+		lx [0] = yx [0] / di [0] ;
+		/* d -= L(k,i) * y */
+		dk [0] -= lx [0] * yx [0] ;
+#else
+		/* L(k,i) = conj(y) ; */
+		ASSIGN_CONJ (lx,lz,0, yx,yz,0) ;
+		/* L(k,i) /= di ; */
+		DIV_REAL (lx,lz,0, lx,lz,0, di,0) ;
+		/* d -= conj(y) * y / di */
+		LDLDOT (dk,0, yx,yz,0, di,0) ;
+#endif
+	    }
+
+	    /* determine if column i of L can hold the new L(k,i) entry */
+	    if (p >= Lp [Lnext [i]])
+	    {
+		/* column i needs to grow */
+		PRINT1 (("Factor Colrealloc "ID", old Lnz "ID"\n", i, Lnz [i]));
+		if (!CHOLMOD(reallocate_column) (i, lnz + 1, L, Common))
+		{
+		    /* out of memory, L is now simplicial symbolic */
+		    for (i = 0 ; i < n ; i++)
+		    {
+			/* W [i] = 0 ; */
+			CLEAR (Wx,Wz,i) ;
+		    }
+		    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, n, Common)) ;
+		    return (FALSE) ;
+		}
+		Li = L->i ;		/* L->i, L->x, L->z may have moved */
+		Lx = L->x ;
+		Lz = L->z ;
+		p = Lp [i] + lnz ;	/* contents of L->p changed */
+		ASSERT (p < Lp [Lnext [i]]) ;
+	    }
+
+	    /* store L (k,i) in the column form matrix of L */
+	    Li [p] = k ;
+	    /* Lx [p] = L(k,i) ; */
+	    ASSIGN (Lx,Lz,p, lx,lz,0) ;
+	    Lnz [i]++ ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* ensure abs (d) >= dbound if dbound is given, and store it in L */
+	/* ------------------------------------------------------------------ */
+
+	p = Lp [k] ;
+	Li [p] = k ;
+
+	if (k >= (Int) L->minor)
+	{
+	    /* the matrix is already not positive definite */
+	    dk [0] = 0 ;
+	}
+	else if (use_dbound)
+	{
+	    /* modify the diagonal to force LL' or LDL' to exist */
+	    dk [0] = CHOLMOD(dbound) (is_ll ? fabs (dk [0]) : dk [0], Common) ;
+	}
+	else if ((is_ll ? (IS_LE_ZERO (dk [0])) : (IS_ZERO (dk [0])))
+#ifndef REAL
+		|| dk_imaginary
+#endif
+		)
+	{
+	    /* the matrix has just been found to be not positive definite */
+	    dk [0] = 0 ;
+	    L->minor = k ;
+	    ERROR (CHOLMOD_NOT_POSDEF, "not positive definite") ;
+	}
+
+	if (is_ll)
+	{
+	    /* this is counted as one flop, below */
+	    dk [0] = sqrt (dk [0]) ;
+	}
+
+	/* Lx [p] = D(k,k) = d ; real part only */
+	ASSIGN_REAL (Lx,p, dk,0) ;
+	CLEAR_IMAG (Lx,Lz,p) ;
+    }
+
+#undef NEXT
+
+    if (is_ll) fl += MAX ((Int) kend - (Int) kstart, 0) ;   /* count sqrt's */
+    Common->rowfacfl = fl ;
+
+    DEBUG (CHOLMOD(dump_factor) (L, "final cholmod_rowfac", Common)) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, n, Common)) ;
+    return (TRUE) ;
+}
+#undef PATTERN
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
diff --git a/src/C/SuiteSparse/CHOLMOD/Cholesky/t_cholmod_solve.c b/src/C/SuiteSparse/CHOLMOD/Cholesky/t_cholmod_solve.c
new file mode 100644
index 0000000..a70594a
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Cholesky/t_cholmod_solve.c
@@ -0,0 +1,164 @@
+/* ========================================================================== */
+/* === Cholesky/t_cholmod_solve ============================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Template routine for cholmod_solve.  Supports any numeric xtype (real,
+ * complex, or zomplex).  The xtypes of all matrices (L and Y) must match.
+ */
+
+#include "cholmod_template.h"
+
+/* ========================================================================== */
+/* === simplicial template solvers ========================================== */
+/* ========================================================================== */
+
+/* LL': solve Lx=b with non-unit diagonal */
+#define LL
+#include "t_cholmod_lsolve.c"
+
+/* LDL': solve LDx=b */
+#define LD
+#include "t_cholmod_lsolve.c"
+
+/* LDL': solve Lx=b with unit diagonal */
+#include "t_cholmod_lsolve.c"
+
+/* LL': solve L'x=b with non-unit diagonal */
+#define LL
+#include "t_cholmod_ltsolve.c"
+
+/* LDL': solve DL'x=b */
+#define LD
+#include "t_cholmod_ltsolve.c"
+
+/* LDL': solve L'x=b with unit diagonal */
+#include "t_cholmod_ltsolve.c"
+
+
+/* ========================================================================== */
+/* === t_ldl_dsolve ========================================================= */
+/* ========================================================================== */
+
+/* Solve Dx=b for an LDL' factorization, where Y holds b' on input and x' on
+ * output. */
+
+static void TEMPLATE (ldl_dsolve)
+(
+    cholmod_factor *L,
+    cholmod_dense *Y		/* nr-by-n with leading dimension nr */
+)
+{
+    double d [1] ;
+    double *Lx, *Yx, *Yz ;
+    Int *Lp ;
+    Int n, nrhs, k, p, k1, k2 ;
+
+    ASSERT (L->xtype == Y->xtype) ; /* L and Y must have the same xtype */
+    ASSERT (L->n == Y->ncol) ;	    /* dimensions must match */
+    ASSERT (Y->nrow == Y->d) ;	    /* leading dimension of Y = # rows of Y */
+    ASSERT (L->xtype != CHOLMOD_PATTERN) ;  /* L is not symbolic */
+    ASSERT (!(L->is_super) && !(L->is_ll)) ;	/* L is simplicial LDL' */
+
+    nrhs = Y->nrow ;
+    n = L->n ;
+    Lp = L->p ;
+    Lx = L->x ;
+    Yx = Y->x ;
+    Yz = Y->z ;
+    for (k = 0 ; k < n ; k++)
+    {
+	k1 = k*nrhs ;
+	k2 = (k+1)*nrhs ;
+	ASSIGN_REAL (d,0, Lx,Lp[k]) ;
+	for (p = k1 ; p < k2 ; p++)
+	{
+	    DIV_REAL (Yx,Yz,p, Yx,Yz,p, d,0) ;
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === t_simplicial_solver ================================================== */
+/* ========================================================================== */
+
+/* Solve a linear system, where Y' contains the (array-transposed) right-hand
+ * side on input, and the solution on output.  No permutations are applied;
+ * these must have already been applied to Y on input. */
+
+static void TEMPLATE (simplicial_solver)
+(
+    int sys,		    /* system to solve */
+    cholmod_factor *L,	    /* factor to use, a simplicial LL' or LDL' */
+    cholmod_dense *Y	    /* right-hand-side on input, solution on output */
+)
+{
+    if (L->is_ll)
+    {
+	/* The factorization is LL' */
+	if (sys == CHOLMOD_A || sys == CHOLMOD_LDLt)
+	{
+	    /* Solve Ax=b or LL'x=b */
+	    TEMPLATE (ll_lsolve_k) (L, Y) ;
+	    TEMPLATE (ll_ltsolve_k) (L, Y) ;
+	}
+	else if (sys == CHOLMOD_L || sys == CHOLMOD_LD)
+	{
+	    /* Solve Lx=b */
+	    TEMPLATE (ll_lsolve_k) (L, Y) ;
+	}
+	else if (sys == CHOLMOD_Lt || sys == CHOLMOD_DLt)
+	{
+	    /* Solve L'x=b */
+	    TEMPLATE (ll_ltsolve_k) (L, Y) ;
+	}
+    }
+    else
+    {
+	/* The factorization is LDL' */
+	if (sys == CHOLMOD_A || sys == CHOLMOD_LDLt)
+	{
+	    /* Solve Ax=b or LDL'x=b */
+	    TEMPLATE (ldl_lsolve_k) (L, Y) ;
+	    TEMPLATE (ldl_dltsolve_k) (L, Y) ;
+	}
+	else if (sys == CHOLMOD_LD)
+	{
+	    /* Solve LDx=b */
+	    TEMPLATE (ldl_ldsolve_k) (L, Y) ;
+	}
+	else if (sys == CHOLMOD_L)
+	{
+	    /* Solve Lx=b */
+	    TEMPLATE (ldl_lsolve_k) (L, Y) ;
+	}
+	else if (sys == CHOLMOD_Lt)
+	{
+	    /* Solve L'x=b */
+	    TEMPLATE (ldl_ltsolve_k) (L, Y) ;
+	}
+	else if (sys == CHOLMOD_DLt)
+	{
+	    /* Solve DL'x=b */
+	    TEMPLATE (ldl_dltsolve_k) (L, Y) ;
+	}
+	else if (sys == CHOLMOD_D)
+	{
+	    /* Solve Dx=b */
+	    TEMPLATE (ldl_dsolve) (L, Y) ;
+	}
+    }
+}
+
+#undef PATTERN
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/License.txt b/src/C/SuiteSparse/CHOLMOD/Core/License.txt
new file mode 100644
index 0000000..51b795e
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/License.txt
@@ -0,0 +1,25 @@
+CHOLMOD/Core Module.  Copyright (C) 2005-2006, Univ. of Florida.
+Author: Timothy A. Davis
+CHOLMOD is also available under other licenses; contact authors for details.
+http://www.cise.ufl.edu/research/sparse
+
+Note that this license is for the CHOLMOD/Core module only.
+All CHOLMOD modules are licensed separately.
+
+
+--------------------------------------------------------------------------------
+
+
+This Module is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This Module is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this Module; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/cholmod_aat.c b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_aat.c
new file mode 100644
index 0000000..0b2b75b
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_aat.c
@@ -0,0 +1,300 @@
+/* ========================================================================== */
+/* === Core/cholmod_aat ===================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* C = A*A' or C = A(:,f)*A(:,f)'
+ *
+ * A can be packed or unpacked, sorted or unsorted, but must be stored with
+ * both upper and lower parts (A->stype of zero).  C is returned as packed,
+ * C->stype of zero (both upper and lower parts present), and unsorted.  See
+ * cholmod_ssmult in the MatrixOps Module for a more general matrix-matrix
+ * multiply.
+ *
+ * You can trivially convert C into a symmetric upper/lower matrix by
+ * changing C->stype = 1 or -1 after calling this routine.
+ *
+ * workspace:
+ *	Flag (A->nrow),
+ *	Iwork (max (A->nrow, A->ncol)) if fset present,
+ *	Iwork (A->nrow) if no fset,
+ *	W (A->nrow) if mode > 0,
+ *	allocates temporary copy for A'.
+ *
+ * A can be pattern or real.  Complex or zomplex cases are supported only
+ * if the mode is <= 0 (in which case the numerical values are ignored).
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+cholmod_sparse *CHOLMOD(aat)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* input matrix; C=A*A' is constructed */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag)
+			 * -2: pattern only, no diagonal, add 50% + n extra
+			 * space to C */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double fjt ;
+    double *Ax, *Fx, *Cx, *W ;
+    Int *Ap, *Anz, *Ai, *Fp, *Fi, *Cp, *Ci, *Flag ;
+    cholmod_sparse *C, *F ;
+    Int packed, j, i, pa, paend, pf, pfend, n, mark, cnz, t, p, values, diag,
+	extra ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    values = (mode > 0) && (A->xtype != CHOLMOD_PATTERN) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN,
+	    values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ;
+    if (A->stype)
+    {
+	ERROR (CHOLMOD_INVALID, "matrix cannot be symmetric") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    diag = (mode >= 0) ;
+    n = A->nrow ;
+    CHOLMOD(allocate_work) (n, MAX (A->ncol, A->nrow), values ? n : 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n : 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_sparse) (A, "A", Common) >= 0) ;
+
+    /* get the A matrix */
+    Ap  = A->p ;
+    Anz = A->nz ;
+    Ai  = A->i ;
+    Ax  = A->x ;
+    packed = A->packed ;
+
+    /* get workspace */
+    W = Common->Xwork ;		/* size n, unused if values is FALSE */
+    Flag = Common->Flag ;	/* size n, Flag [0..n-1] < mark on input*/
+
+    /* ---------------------------------------------------------------------- */
+    /* F = A' or A(:,f)' */
+    /* ---------------------------------------------------------------------- */
+
+    /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/
+    F = CHOLMOD(ptranspose) (A, values, NULL, fset, fsize, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    Fp = F->p ;
+    Fi = F->i ;
+    Fx = F->x ;
+
+    /* ---------------------------------------------------------------------- */
+    /* count the number of entries in the result C */
+    /* ---------------------------------------------------------------------- */
+
+    cnz = 0 ;
+    for (j = 0 ; j < n ; j++)
+    {
+	/* clear the Flag array */
+	mark = CHOLMOD(clear_flag) (Common) ;
+
+	/* exclude the diagonal, if requested */
+	if (!diag)
+	{
+	    Flag [j] = mark ;
+	}
+
+	/* for each nonzero F(t,j) in column j, do: */
+	pfend = Fp [j+1] ;
+	for (pf = Fp [j] ; pf < pfend ; pf++)
+	{
+	    /* F(t,j) is nonzero */
+	    t = Fi [pf] ;
+
+	    /* add the nonzero pattern of A(:,t) to the pattern of C(:,j) */
+	    pa = Ap [t] ;
+	    paend = (packed) ? (Ap [t+1]) : (pa + Anz [t]) ;
+	    for ( ; pa < paend ; pa++)
+	    {
+		i = Ai [pa] ;
+		if (Flag [i] != mark)
+		{
+		    Flag [i] = mark ;
+		    cnz++ ;
+		}
+	    }
+	}
+	if (cnz < 0)
+	{
+	    break ;	    /* integer overflow case */
+	}
+    }
+
+    extra = (mode == -2) ? (cnz/2 + n) : 0 ;
+
+    mark = CHOLMOD(clear_flag) (Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check for integer overflow */
+    /* ---------------------------------------------------------------------- */
+
+    if (cnz < 0 || (cnz + extra) < 0)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	CHOLMOD(clear_flag) (Common) ;
+	CHOLMOD(free_sparse) (&F, Common) ;
+	return (NULL) ;	    /* problem too large */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate C */
+    /* ---------------------------------------------------------------------- */
+
+    C = CHOLMOD(allocate_sparse) (n, n, cnz + extra, FALSE, TRUE, 0,
+	    values ? A->xtype : CHOLMOD_PATTERN, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free_sparse) (&F, Common) ;
+	return (NULL) ;	    /* out of memory */
+    }
+
+    Cp = C->p ;
+    Ci = C->i ;
+    Cx = C->x ;
+
+    /* ---------------------------------------------------------------------- */
+    /* C = A*A' */
+    /* ---------------------------------------------------------------------- */
+
+    cnz = 0 ;
+
+    if (values)
+    {
+
+	/* pattern and values */
+	for (j = 0 ; j < n ; j++)
+	{
+	    /* clear the Flag array */
+	    mark = CHOLMOD(clear_flag) (Common) ;
+
+	    /* start column j of C */
+	    Cp [j] = cnz ;
+
+	    /* for each nonzero F(t,j) in column j, do: */
+	    pfend = Fp [j+1] ;
+	    for (pf = Fp [j] ; pf < pfend ; pf++)
+	    {
+		/* F(t,j) is nonzero */
+		t = Fi [pf] ;
+		fjt = Fx [pf] ;
+
+		/* add the nonzero pattern of A(:,t) to the pattern of C(:,j)
+		 * and scatter the values into W */
+		pa = Ap [t] ;
+		paend = (packed) ? (Ap [t+1]) : (pa + Anz [t]) ;
+		for ( ; pa < paend ; pa++)
+		{
+		    i = Ai [pa] ;
+		    if (Flag [i] != mark)
+		    {
+			Flag [i] = mark ;
+			Ci [cnz++] = i ;
+		    }
+		    W [i] += Ax [pa] * fjt ;
+		}
+	    }
+
+	    /* gather the values into C(:,j) */
+	    for (p = Cp [j] ; p < cnz ; p++)
+	    {
+		i = Ci [p] ;
+		Cx [p] = W [i] ;
+		W [i] = 0 ;
+	    }
+	}
+
+    }
+    else
+    {
+
+	/* pattern only */
+	for (j = 0 ; j < n ; j++)
+	{
+	    /* clear the Flag array */
+	    mark = CHOLMOD(clear_flag) (Common) ;
+
+	    /* exclude the diagonal, if requested */
+	    if (!diag)
+	    {
+		Flag [j] = mark ;
+	    }
+
+	    /* start column j of C */
+	    Cp [j] = cnz ;
+
+	    /* for each nonzero F(t,j) in column j, do: */
+	    pfend = Fp [j+1] ;
+	    for (pf = Fp [j] ; pf < pfend ; pf++)
+	    {
+		/* F(t,j) is nonzero */
+		t = Fi [pf] ;
+
+		/* add the nonzero pattern of A(:,t) to the pattern of C(:,j) */
+		pa = Ap [t] ;
+		paend = (packed) ? (Ap [t+1]) : (pa + Anz [t]) ;
+		for ( ; pa < paend ; pa++)
+		{
+		    i = Ai [pa] ;
+		    if (Flag [i] != mark)
+		    {
+			Flag [i] = mark ;
+			Ci [cnz++] = i ;
+		    }
+		}
+	    }
+	}
+    }
+
+    Cp [n] = cnz ;
+    ASSERT (IMPLIES (mode != -2, MAX (1,cnz) == C->nzmax)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* clear workspace and free temporary matrices and return result */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(free_sparse) (&F, Common) ;
+    CHOLMOD(clear_flag) (Common) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n : 0, Common)) ;
+    DEBUG (i = CHOLMOD(dump_sparse) (C, "aat", Common)) ;
+    ASSERT (IMPLIES (mode < 0, i == 0)) ;
+    return (C) ;
+}
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/cholmod_add.c b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_add.c
new file mode 100644
index 0000000..c7fbba5
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_add.c
@@ -0,0 +1,278 @@
+/* ========================================================================== */
+/* === Core/cholmod_add ===================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* C = alpha*A + beta*B, or spones(A+B).  Result is packed, with sorted or
+ * unsorted columns.  This routine is much faster and takes less memory if C
+ * is allowed to have unsorted columns.
+ *
+ * If A and B are both symmetric (in upper form) then C is the same.  Likewise,
+ * if A and B are both symmetric (in lower form) then C is the same.
+ * Otherwise, C is unsymmetric.  A and B must have the same dimension.
+ *
+ * workspace: Flag (nrow), W (nrow) if values, Iwork (max (nrow,ncol)).
+ *	allocates temporary copies for A and B if they are symmetric.
+ *	allocates temporary copy of C if it is to be returned sorted.
+ *
+ * A and B can have an xtype of pattern or real.  Complex or zomplex cases
+ * are supported only if the "values" input parameter is FALSE.
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+cholmod_sparse *CHOLMOD(add)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	    /* matrix to add */
+    cholmod_sparse *B,	    /* matrix to add */
+    double alpha [2],	    /* scale factor for A */
+    double beta [2],	    /* scale factor for B */
+    int values,		    /* if TRUE compute the numerical values of C */
+    int sorted,		    /* if TRUE, sort columns of C */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Bx, *Cx, *W ;
+    Int apacked, up, lo, nrow, ncol, bpacked, nzmax, pa, paend, pb, pbend, i,
+	j, p, mark, nz ;
+    Int *Ap, *Ai, *Anz, *Bp, *Bi, *Bnz, *Flag, *Cp, *Ci ;
+    cholmod_sparse *A2, *B2, *C ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    RETURN_IF_NULL (B, NULL) ;
+    values = values &&
+	(A->xtype != CHOLMOD_PATTERN) && (B->xtype != CHOLMOD_PATTERN) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN,
+	    values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ;
+    RETURN_IF_XTYPE_INVALID (B, CHOLMOD_PATTERN,
+	    values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ;
+    if (A->nrow != B->nrow || A->ncol != B->ncol)
+    {
+	/* A and B must have the same dimensions */
+	ERROR (CHOLMOD_INVALID, "A and B dimesions do not match") ;
+	return (NULL) ;
+    }
+    /* A and B must have the same numerical type if values is TRUE (both must
+     * be CHOLMOD_REAL, this is implicitly checked above) */
+
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+    CHOLMOD(allocate_work) (nrow, MAX (nrow,ncol), values ? nrow : 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    if (nrow <= 1)
+    {
+	/* C will be implicitly sorted, so no need to sort it here */
+	sorted = FALSE ;
+    }
+
+    /* convert A or B to unsymmetric, if necessary */
+    A2 = NULL ;
+    B2 = NULL ;
+
+    if (A->stype != B->stype)
+    {
+	if (A->stype)
+	{
+	    /* workspace: Iwork (max (nrow,ncol)) */
+	    A2 = CHOLMOD(copy) (A, 0, values, Common) ;
+	    if (Common->status < CHOLMOD_OK)
+	    {
+		return (NULL) ;	    /* out of memory */
+	    }
+	    A = A2 ;
+	}
+	if (B->stype)
+	{
+	    /* workspace: Iwork (max (nrow,ncol)) */
+	    B2 = CHOLMOD(copy) (B, 0, values, Common) ;
+	    if (Common->status < CHOLMOD_OK)
+	    {
+		CHOLMOD(free_sparse) (&A2, Common) ;
+		return (NULL) ;	    /* out of memory */
+	    }
+	    B = B2 ;
+	}
+    }
+
+    /* get the A matrix */
+    ASSERT (A->stype == B->stype) ;
+    up = (A->stype > 0) ;
+    lo = (A->stype < 0) ;
+
+    Ap  = A->p ;
+    Anz = A->nz ;
+    Ai  = A->i ;
+    Ax  = A->x ;
+    apacked = A->packed ;
+
+    /* get the B matrix */
+    Bp  = B->p ;
+    Bnz = B->nz ;
+    Bi  = B->i ;
+    Bx  = B->x ;
+    bpacked = B->packed ;
+
+    /* get workspace */
+    W = Common->Xwork ;	    /* size nrow, used if values is TRUE */
+    Flag = Common->Flag ;   /* size nrow, Flag [0..nrow-1] < mark on input */
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the result C */
+    /* ---------------------------------------------------------------------- */
+
+    /* If integer overflow occurs, nzmax < 0 and the allocate fails properly
+     * (likewise in most other matrix manipulation routines). */
+    nzmax = A->nzmax + B->nzmax ;
+    C = CHOLMOD(allocate_sparse) (nrow, ncol, nzmax, FALSE, TRUE,
+	    SIGN (A->stype), values ? A->xtype : CHOLMOD_PATTERN, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free_sparse) (&A2, Common) ;
+	CHOLMOD(free_sparse) (&B2, Common) ;
+	return (NULL) ;	    /* out of memory */
+    }
+
+    Cp = C->p ;
+    Ci = C->i ;
+    Cx = C->x ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compute C = alpha*A + beta*B */
+    /* ---------------------------------------------------------------------- */
+
+    nz = 0 ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	Cp [j] = nz ;
+
+	/* clear the Flag array */
+	mark = CHOLMOD(clear_flag) (Common) ;
+
+	/* scatter B into W */
+	pb = Bp [j] ;
+	pbend = (bpacked) ? (Bp [j+1]) : (pb + Bnz [j]) ;
+	for (p = pb ; p < pbend ; p++)
+	{
+	    i = Bi [p] ;
+	    if ((up && i > j) || (lo && i < j))
+	    {
+		continue ;
+	    }
+	    Flag [i] = mark ;
+	    if (values)
+	    {
+		W [i] = beta [0] * Bx [p] ;
+	    }
+	}
+
+	/* add A and gather from W into C(:,j) */
+	pa = Ap [j] ;
+	paend = (apacked) ? (Ap [j+1]) : (pa + Anz [j]) ;
+	for (p = pa ; p < paend ; p++)
+	{
+	    i = Ai [p] ;
+	    if ((up && i > j) || (lo && i < j))
+	    {
+		continue ;
+	    }
+	    Flag [i] = EMPTY ;
+	    Ci [nz] = i ;
+	    if (values)
+	    {
+		Cx [nz] = W [i] + alpha [0] * Ax [p] ;
+		W [i] = 0 ;
+	    }
+	    nz++ ;
+	}
+
+	/* gather remaining entries into C(:,j), using pattern of B */
+	for (p = pb ; p < pbend ; p++)
+	{
+	    i = Bi [p] ;
+	    if ((up && i > j) || (lo && i < j))
+	    {
+		continue ;
+	    }
+	    if (Flag [i] == mark)
+	    {
+		Ci [nz] = i ;
+		if (values)
+		{
+		    Cx [nz] = W [i] ;
+		    W [i] = 0 ;
+		}
+		nz++ ;
+	    }
+	}
+    }
+
+    Cp [ncol] = nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* reduce C in size and free temporary matrices */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (MAX (1,nz) <= C->nzmax) ;
+    CHOLMOD(reallocate_sparse) (nz, C, Common) ;
+    ASSERT (Common->status >= CHOLMOD_OK) ;
+
+    /* clear the Flag array */
+    mark = CHOLMOD(clear_flag) (Common) ;
+
+    CHOLMOD(free_sparse) (&A2, Common) ;
+    CHOLMOD(free_sparse) (&B2, Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* sort C, if requested */
+    /* ---------------------------------------------------------------------- */
+
+    if (sorted)
+    {
+	/* workspace: Iwork (max (nrow,ncol)) */
+	if (!CHOLMOD(sort) (C, Common))
+	{
+	    CHOLMOD(free_sparse) (&C, Common) ;
+	    if (Common->status < CHOLMOD_OK)
+	    {
+		return (NULL) ;		/* out of memory */
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return result */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_sparse) (C, "add", Common) >= 0) ;
+    return (C) ;
+}
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/cholmod_band.c b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_band.c
new file mode 100644
index 0000000..2e5f0ac
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_band.c
@@ -0,0 +1,374 @@
+/* ========================================================================== */
+/* === Core/cholmod_band ==================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* C = tril (triu (A,k1), k2)
+ *
+ * C is a matrix consisting of the diagonals of A from k1 to k2.
+ *
+ * k=0 is the main diagonal of A, k=1 is the superdiagonal, k=-1 is the
+ * subdiagonal, and so on.  If A is m-by-n, then:
+ *
+ *	k1=-m		    C = tril (A,k2)
+ *	k2=n		    C = triu (A,k1)
+ *	k1=0 and k2=0	    C = diag(A), except C is a matrix, not a vector
+ *
+ * Values of k1 and k2 less than -m are treated as -m, and values greater
+ * than n are treated as n.
+ *
+ * A can be of any symmetry (upper, lower, or unsymmetric); C is returned in
+ * the same form, and packed.  If A->stype > 0, entries in the lower
+ * triangular part of A are ignored, and the opposite is true if
+ * A->stype < 0.  If A has sorted columns, then so does C.
+ * C has the same size as A.
+ *
+ * If inplace is TRUE, then the matrix A is modified in place.
+ * Only packed matrices can be converted in place.
+ *
+ * C can be returned as a numerical valued matrix (if A has numerical values
+ * and mode > 0), as a pattern-only (mode == 0), or as a pattern-only but with
+ * the diagonal entries removed (mode < 0).
+ *
+ * workspace: none
+ *
+ * A can have an xtype of pattern or real.  Complex and zomplex cases supported
+ * only if mode <= 0 (in which case the numerical values are ignored).
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+static cholmod_sparse *band		/* returns C, or NULL if failure */
+(
+    /* ---- input or in/out if inplace is TRUE --- */
+    cholmod_sparse *A,
+    /* ---- input ---- */
+    UF_long k1,	    /* ignore entries below the k1-st diagonal */
+    UF_long k2,	    /* ignore entries above the k2-nd diagonal */
+    int mode,	    /* >0: numerical, 0: pattern, <0: pattern (no diagonal) */
+    int inplace,    /* if TRUE, then convert A in place */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Cx ;
+    Int packed, nz, j, p, pend, i, ncol, nrow, jlo, jhi, ilo, ihi, sorted,
+	values, diag ;
+    Int *Ap, *Anz, *Ai, *Cp, *Ci ;
+    cholmod_sparse *C ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    values = (mode > 0) && (A->xtype != CHOLMOD_PATTERN) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN,
+	    values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ;
+    packed = A->packed ;
+    diag = (mode >= 0) ;
+    if (inplace && !packed)
+    {
+	/* cannot operate on an unpacked matrix in place */
+	ERROR (CHOLMOD_INVALID, "cannot operate on unpacked matrix in-place") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+
+    PRINT1 (("k1 %ld k2 %ld\n", k1, k2)) ;
+    Ap  = A->p ;
+    Anz = A->nz ;
+    Ai  = A->i ;
+    Ax  = A->x ;
+    sorted = A->sorted ;
+
+
+    if (A->stype > 0)
+    {
+	/* ignore any entries in strictly lower triangular part of A */
+	k1 = MAX (k1, 0) ;
+    }
+    if (A->stype < 0)
+    {
+	/* ignore any entries in strictly upper triangular part of A */
+	k2 = MIN (k2, 0) ;
+    }
+    ncol = A->ncol ;
+    nrow = A->nrow ;
+
+    /* ensure k1 and k2 are in the range -nrow to +ncol to
+     * avoid possible integer overflow if k1 and k2 are huge */
+    k1 = MAX (-nrow, k1) ;
+    k1 = MIN (k1, ncol) ;
+    k2 = MAX (-nrow, k2) ;
+    k2 = MIN (k2, ncol) ;
+
+    /* consider columns jlo to jhi.  columns outside this range are empty */
+    jlo = MAX (k1, 0) ;
+    jhi = MIN (k2+nrow, ncol) ;
+
+    if (k1 > k2)
+    {
+	/* nothing to do */
+	jlo = ncol ;
+	jhi = ncol ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate C, or operate on A in place */
+    /* ---------------------------------------------------------------------- */
+
+    if (inplace)
+    {
+	/* convert A in place */
+	C = A ;
+    }
+    else
+    {
+	/* count the number of entries in the result C */
+	nz = 0 ;
+	if (sorted)
+	{
+	    for (j = jlo ; j < jhi ; j++)
+	    {
+		ilo = j-k2 ;
+		ihi = j-k1 ;
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i > ihi)
+		    {
+			break ;
+		    }
+		    if (i >= ilo && (diag || i != j))
+		    {
+			nz++ ;
+		    }
+		}
+	    }
+	}
+	else
+	{
+	    for (j = jlo ; j < jhi ; j++)
+	    {
+		ilo = j-k2 ;
+		ihi = j-k1 ;
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i >= ilo && i <= ihi && (diag || i != j))
+		    {
+			nz++ ;
+		    }
+		}
+	    }
+	}
+	/* allocate C; A will not be modified.  C is sorted if A is sorted */
+	C = CHOLMOD(allocate_sparse) (A->nrow, ncol, nz, sorted, TRUE,
+		A->stype, values ? A->xtype : CHOLMOD_PATTERN, Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    return (NULL) ;	/* out of memory */
+	}
+    }
+
+    Cp = C->p ;
+    Ci = C->i ;
+    Cx = C->x ;
+
+    /* ---------------------------------------------------------------------- */
+    /* construct C */
+    /* ---------------------------------------------------------------------- */
+
+    /* columns 0 to jlo-1 are empty */
+    for (j = 0 ; j < jlo ; j++)
+    {
+	Cp [j] = 0 ;
+    }
+
+    nz = 0 ;
+    if (sorted)
+    {
+	if (values)
+	{
+	    /* pattern and values */
+	    ASSERT (diag) ;
+	    for (j = jlo ; j < jhi ; j++)
+	    {
+		ilo = j-k2 ;
+		ihi = j-k1 ;
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		Cp [j] = nz ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i > ihi)
+		    {
+			break ;
+		    }
+		    if (i >= ilo)
+		    {
+			Ci [nz] = i ;
+			Cx [nz] = Ax [p] ;
+			nz++ ;
+		    }
+		}
+	    }
+	}
+	else
+	{
+	    /* pattern only, perhaps with no diagonal */
+	    for (j = jlo ; j < jhi ; j++)
+	    {
+		ilo = j-k2 ;
+		ihi = j-k1 ;
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		Cp [j] = nz ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i > ihi)
+		    {
+			break ;
+		    }
+		    if (i >= ilo && (diag || i != j))
+		    {
+			Ci [nz++] = i ;
+		    }
+		}
+	    }
+	}
+    }
+    else
+    {
+	if (values)
+	{
+	    /* pattern and values */
+	    ASSERT (diag) ;
+	    for (j = jlo ; j < jhi ; j++)
+	    {
+		ilo = j-k2 ;
+		ihi = j-k1 ;
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		Cp [j] = nz ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i >= ilo && i <= ihi)
+		    {
+			Ci [nz] = i ;
+			Cx [nz] = Ax [p] ;
+			nz++ ;
+		    }
+		}
+	    }
+	}
+	else
+	{
+	    /* pattern only, perhaps with no diagonal */
+	    for (j = jlo ; j < jhi ; j++)
+	    {
+		ilo = j-k2 ;
+		ihi = j-k1 ;
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		Cp [j] = nz ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i >= ilo && i <= ihi && (diag || i != j))
+		    {
+			Ci [nz++] = i ;
+		    }
+		}
+	    }
+	}
+    }
+
+    /* columns jhi to ncol-1 are empty */
+    for (j = jhi ; j <= ncol ; j++)
+    {
+	Cp [j] = nz ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* reduce A in size if done in place */
+    /* ---------------------------------------------------------------------- */
+
+    if (inplace)
+    {
+	/* free the unused parts of A, and reduce A->i and A->x in size */
+	ASSERT (MAX (1,nz) <= A->nzmax) ;
+	CHOLMOD(reallocate_sparse) (nz, A, Common) ;
+	ASSERT (Common->status >= CHOLMOD_OK) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the result C */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG (i = CHOLMOD(dump_sparse) (C, "band", Common)) ;
+    ASSERT (IMPLIES (mode < 0, i == 0)) ;
+    return (C) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_band ========================================================= */
+/* ========================================================================== */
+
+cholmod_sparse *CHOLMOD(band)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to extract band matrix from */
+    UF_long k1,		/* ignore entries below the k1-st diagonal */
+    UF_long k2,		/* ignore entries above the k2-nd diagonal */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag) */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    return (band (A, k1, k2, mode, FALSE, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_band_inplace ================================================= */
+/* ========================================================================== */
+
+int CHOLMOD(band_inplace)
+(
+    /* ---- input ---- */
+    UF_long k1,		/* ignore entries below the k1-st diagonal */
+    UF_long k2,		/* ignore entries above the k2-nd diagonal */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag) */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix from which entries not in band are removed */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    return (band (A, k1, k2, mode, TRUE, Common) != NULL) ;
+}
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/cholmod_change_factor.c b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_change_factor.c
new file mode 100644
index 0000000..cc90b0e
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_change_factor.c
@@ -0,0 +1,1227 @@
+/* ========================================================================== */
+/* === Core/cholmod_change_factor =========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Change the numeric/symbolic, LL/LDL, simplicial/super, packed/unpacked,
+ * monotonic/non-monotonic status of a cholmod_factor object.
+ *
+ * There are four basic classes of factor types:
+ *
+ * (1) simplicial symbolic:  Consists of two size-n arrays: the fill-reducing
+ *	permutation (L->Perm) and the nonzero count for each column of L
+ *	(L->ColCount).  All other factor types also include this information.
+ *	L->ColCount may be exact (obtained from the analysis routines), or
+ *	it may be a guess.  During factorization, and certainly after update/
+ *	downdate, the columns of L can have a different number of nonzeros.
+ *	L->ColCount is used to allocate space.  L->ColCount is exact for the
+ *	supernodal factorizations.  The nonzero pattern of L is not kept.
+ *
+ * (2) simplicial numeric:  These represent L in a compressed column form.  The
+ *	variants of this type are:
+ *
+ *	LDL':	L is unit diagonal.  Row indices in column j are located in
+ *	    L->i [L->p [j] ... L->p [j] + L->nz [j]], and corresponding numeric
+ *	    values are in the same locations in L->x.  The total number of
+ *	    entries is the sum of L->nz [j].  The unit diagonal is not stored;
+ *	    D is stored on the diagonal of L instead.  L->p may or may not be
+ *	    monotonic.  The order of storage of the columns in L->i and L->x is
+ *	    given by a doubly-linked list (L->prev and L->next).  L->p is of
+ *	    size n+1, but only the first n entries are used (it is used if L
+ *	    is converted to a sparse matrix via cholmod_factor_to_sparse).
+ *
+ *	    For the complex case, L->x is stored interleaved with real/imag
+ *	    parts, and is of size 2*lnz*sizeof(double).  For the zomplex case,
+ *	    L->x is of size lnz*sizeof(double) and holds the real part; L->z
+ *	    is the same size and holds the imaginary part.
+ *
+ *	LL':  This is identical to the LDL' form, except that the non-unit
+ *	    diagonal of L is stored as the first entry in each column of L.
+ *
+ * (3) supernodal symbolic:  A representation of the nonzero pattern of the
+ *	supernodes for a supernodal factorization.  There are L->nsuper
+ *	supernodes.  Columns L->super [k] to L->super [k+1]-1 are in the kth
+ *	supernode.  The row indices for the kth supernode are in
+ *	L->s [L->pi [k] ... L->pi [k+1]-1].  The numerical values are not
+ *	allocated (L->x), but when they are they will be located in
+ *	L->x [L->px [k] ... L->px [k+1]-1], and the L->px array is defined
+ *	in this factor type.
+ *
+ *	For the complex case, L->x is stored interleaved with real/imag parts,
+ *	and is of size 2*L->xsize*sizeof(double).  The zomplex supernodal case
+ *	is not supported, since it is not compatible with LAPACK and the BLAS.
+ *
+ * (4) supernodal numeric:  Always an LL' factorization.  L is non-unit
+ *      diagonal.  L->x contains the numerical values of the supernodes, as
+ *      described above for the supernodal symbolic factor.
+ *	For the complex case, L->x is stored interleaved, and is of size
+ *	2*L->xsize*sizeof(double).  The zomplex supernodal case is not
+ *	supported, since it is not compatible with LAPACK and the BLAS.
+ *
+ *      FUTURE WORK: support a supernodal LDL' factor.
+ *
+ *
+ * In all cases, the row indices in each column (L->i for simplicial L and
+ * L->s for supernodal L) are kept sorted from low indices to high indices.
+ * This means the diagonal of L (or D for LDL' factors) is always kept as the
+ * first entry in each column.
+ *
+ * The cholmod_change_factor routine can do almost all possible conversions.
+ * It cannot do the following conversions:
+ *
+ *	(1) Simplicial numeric types cannot be converted to a supernodal
+ *	    symbolic type.  This would simultaneously deallocate the
+ *	    simplicial pattern and numeric values and reallocate uninitialized
+ *	    space for the supernodal pattern.  This isn't useful for the user,
+ *	    and not needed by CHOLMOD's own routines either.
+ *
+ *	(2) Only a symbolic factor (simplicial to supernodal) can be converted
+ *	    to a supernodal numeric factor.
+ *
+ * Some conversions are meant only to be used internally by other CHOLMOD
+ * routines, and should not be performed by the end user.  They allocate space
+ * whose contents are undefined:
+ *
+ *	(1) converting from simplicial symbolic to supernodal symbolic.
+ *	(2) converting any factor to supernodal numeric.
+ *
+ * workspace: no conversion routine uses workspace in Common.  No temporary
+ *	workspace is allocated.
+ *
+ * Supports all xtypes, except that there is no supernodal zomplex L.
+ *
+ * The to_xtype parameter is used only when converting from symbolic to numeric
+ * or numeric to symbolic.  It cannot be used to convert a numeric xtype (real,
+ * complex, or zomplex) to a different numeric xtype.  For that conversion,
+ * use cholmod_factor_xtype instead.
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+static void natural_list (cholmod_factor *L) ;
+
+/* ========================================================================== */
+/* === TEMPLATE ============================================================= */
+/* ========================================================================== */
+
+#define REAL
+#include "t_cholmod_change_factor.c"
+#define COMPLEX
+#include "t_cholmod_change_factor.c"
+#define ZOMPLEX
+#include "t_cholmod_change_factor.c"
+
+
+/* ========================================================================== */
+/* === L_is_packed ========================================================== */
+/* ========================================================================== */
+
+/* Return TRUE if the columns of L are packed, FALSE otherwise.  For debugging
+ * only. */
+
+#ifndef NDEBUG
+static int L_is_packed (cholmod_factor *L, cholmod_common *Common)
+{
+    Int j ;
+    Int *Lnz = L->nz ;
+    Int *Lp = L->p ;
+    Int n = L->n ;
+
+    if (L->xtype == CHOLMOD_PATTERN || L->is_super)
+    {
+	return (TRUE) ;
+    }
+
+    if (Lnz == NULL || Lp == NULL)
+    {
+	return (TRUE) ;
+    }
+
+    for (j = 0 ; j < n ; j++)
+    {
+	PRINT3 (("j: "ID" Lnz "ID" Lp[j+1] "ID" Lp[j] "ID"\n", j, Lnz [j],
+		Lp [j+1], Lp [j])) ;
+	if (Lnz [j] != (Lp [j+1] - Lp [j]))
+	{
+	    PRINT2 (("L is not packed\n")) ;
+	    return (FALSE) ;
+	}
+    }
+    return (TRUE) ;
+}
+#endif
+
+
+/* ========================================================================== */
+/* === natural_list ========================================================= */
+/* ========================================================================== */
+
+/* Create a naturally-ordered doubly-linked list of columns. */
+
+static void natural_list (cholmod_factor *L)
+{
+    Int head, tail, n, j ;
+    Int *Lnext, *Lprev ;
+    Lnext = L->next ;
+    Lprev = L->prev ;
+    ASSERT (Lprev != NULL && Lnext != NULL) ;
+    n = L->n ;
+    head = n+1 ;
+    tail = n ;
+    Lnext [head] = 0 ;
+    Lprev [head] = EMPTY ;
+    Lnext [tail] = EMPTY ;
+    Lprev [tail] = n-1 ;
+    for (j = 0 ; j < n ; j++)
+    {
+	Lnext [j] = j+1 ;
+	Lprev [j] = j-1 ;
+    }
+    Lprev [0] = head ;
+    L->is_monotonic = TRUE ;
+}
+
+
+/* ========================================================================== */
+/* === allocate_simplicial_numeric ========================================== */
+/* ========================================================================== */
+
+/* Allocate O(n) arrays for simplicial numeric factorization.  Initializes
+ * the link lists only.  Does not allocate the L->i, L->x, or L->z arrays. */
+
+static int allocate_simplicial_numeric
+(
+    cholmod_factor *L,
+    cholmod_common *Common
+)
+{
+    Int n ;
+    Int *Lp, *Lnz, *Lprev, *Lnext ;
+    size_t n1, n2 ;
+
+    PRINT1 (("Allocate simplicial\n")) ;
+
+    ASSERT (L->xtype == CHOLMOD_PATTERN || L->is_super) ;
+    ASSERT (L->p == NULL) ;
+    ASSERT (L->nz == NULL) ;
+    ASSERT (L->prev == NULL) ;
+    ASSERT (L->next == NULL) ;
+
+    n = L->n ;
+
+    /* this cannot cause size_t overflow */
+    n1 = ((size_t) n) + 1 ;
+    n2 = ((size_t) n) + 2 ;
+
+    Lp = CHOLMOD(malloc) (n1, sizeof (Int), Common) ;
+    Lnz = CHOLMOD(malloc) (n, sizeof (Int), Common) ;
+    Lprev = CHOLMOD(malloc) (n2, sizeof (Int), Common) ;
+    Lnext = CHOLMOD(malloc) (n2, sizeof (Int), Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free) (n1, sizeof (Int), Lp,    Common) ;
+	CHOLMOD(free) (n,   sizeof (Int), Lnz,   Common) ;
+	CHOLMOD(free) (n2, sizeof (Int), Lprev, Common) ;
+	CHOLMOD(free) (n2, sizeof (Int), Lnext, Common) ;
+	PRINT1 (("Allocate simplicial failed\n")) ;
+	return (FALSE) ;	/* out of memory */
+    }
+
+    /* ============================================== commit the changes to L */
+
+    L->p = Lp ;
+    L->nz = Lnz ;
+    L->prev = Lprev ;
+    L->next = Lnext ;
+    /* initialize a doubly linked list for columns in natural order */
+    natural_list (L) ;
+    PRINT1 (("Allocate simplicial done\n")) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === simplicial_symbolic_to_super_symbolic ================================ */
+/* ========================================================================== */
+
+/* Convert a simplicial symbolic factor supernodal symbolic factor.  Does not
+ * initialize the new space. */
+
+static int simplicial_symbolic_to_super_symbolic
+(
+    cholmod_factor *L,
+    cholmod_common *Common
+)
+{
+    Int nsuper, xsize, ssize ;
+    Int *Lsuper, *Lpi, *Lpx, *Ls ;
+    size_t nsuper1 ;
+
+    ASSERT (L->xtype == CHOLMOD_PATTERN && !(L->is_super)) ;
+
+    xsize  = L->xsize ;
+    ssize  = L->ssize ;
+    nsuper = L->nsuper ;
+    nsuper1 = ((size_t) nsuper) + 1 ;
+
+    PRINT1 (("simple sym to super sym: ssize "ID" xsize "ID" nsuper "ID""
+	" status %d\n", ssize, xsize, nsuper, Common->status)) ;
+
+    /* O(nsuper) arrays, where nsuper <= n */
+    Lsuper = CHOLMOD(malloc) (nsuper1, sizeof (Int), Common) ;
+    Lpi    = CHOLMOD(malloc) (nsuper1, sizeof (Int), Common) ;
+    Lpx    = CHOLMOD(malloc) (nsuper1, sizeof (Int), Common) ;
+
+    /* O(ssize) array, where ssize <= nnz(L), and usually much smaller */
+    Ls = CHOLMOD(malloc) (ssize, sizeof (Int), Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free) (nsuper1, sizeof (Int), Lsuper, Common) ;
+	CHOLMOD(free) (nsuper1, sizeof (Int), Lpi,    Common) ;
+	CHOLMOD(free) (nsuper1, sizeof (Int), Lpx,    Common) ;
+	CHOLMOD(free) (ssize,    sizeof (Int), Ls,     Common) ;
+	return (FALSE) ;	/* out of memory */
+    }
+
+    /* ============================================== commit the changes to L */
+
+    ASSERT (Lsuper != NULL && Lpi != NULL && Lpx != NULL && Ls != NULL) ;
+
+    L->maxcsize = 0 ;
+    L->maxesize = 0 ;
+
+    L->super = Lsuper ;
+    L->pi = Lpi ;
+    L->px = Lpx ;
+    L->s  = Ls ;
+    Ls [0] = EMPTY ;	    /* supernodal pattern undefined */
+
+    L->is_super = TRUE ;
+    L->is_ll = TRUE ;	    /* supernodal LDL' not supported */
+    L->xtype = CHOLMOD_PATTERN ;
+    L->dtype = DTYPE ;
+    L->minor = L->n ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === any_to_simplicial_symbolic =========================================== */
+/* ========================================================================== */
+
+/* Convert any factor L to a simplicial symbolic factor, leaving only L->Perm
+ * and L->ColCount.  Cannot fail.  Any of the components of L (except Perm and
+ * ColCount) may already be free'd.  */
+
+static void any_to_simplicial_symbolic
+(
+    cholmod_factor *L,
+    int to_ll,
+    cholmod_common *Common
+)
+{
+    Int n, lnz, xs, ss, s, e ;
+    size_t n1, n2 ;
+
+    /* ============================================== commit the changes to L */
+
+    n = L->n ;
+    lnz = L->nzmax ;
+    s = L->nsuper + 1 ;
+    xs = (L->is_super) ? ((Int) (L->xsize)) : (lnz) ;
+    e = (L->xtype == CHOLMOD_COMPLEX ? 2 : 1) ;
+    ss = L->ssize ;
+
+    /* this cannot cause size_t overflow */
+    n1 = ((size_t) n) + 1 ;
+    n2 = ((size_t) n) + 2 ;
+
+    /* free all but the symbolic analysis (Perm and ColCount) */
+    L->p     = CHOLMOD(free) (n1,  sizeof (Int),      L->p,     Common) ;
+    L->i     = CHOLMOD(free) (lnz, sizeof (Int),      L->i,     Common) ;
+    L->x     = CHOLMOD(free) (xs,  e*sizeof (double), L->x,     Common) ;
+    L->z     = CHOLMOD(free) (lnz, sizeof (double),   L->z,     Common) ;
+    L->nz    = CHOLMOD(free) (n,   sizeof (Int),      L->nz,    Common) ;
+    L->next  = CHOLMOD(free) (n2,  sizeof (Int),      L->next,  Common) ;
+    L->prev  = CHOLMOD(free) (n2,  sizeof (Int),      L->prev,  Common) ;
+    L->super = CHOLMOD(free) (s,   sizeof (Int),      L->super, Common) ;
+    L->pi    = CHOLMOD(free) (s,   sizeof (Int),      L->pi,    Common) ;
+    L->px    = CHOLMOD(free) (s,   sizeof (Int),      L->px,    Common) ;
+    L->s     = CHOLMOD(free) (ss,  sizeof (Int),      L->s,     Common) ;
+    L->nzmax = 0 ;
+    L->is_super = FALSE ;
+    L->xtype = CHOLMOD_PATTERN ;
+    L->dtype = DTYPE ;
+    L->minor = n ;
+    L->is_ll = to_ll ;
+}
+
+
+/* ========================================================================== */
+/* === ll_super_to_super_symbolic =========================================== */
+/* ========================================================================== */
+
+/* Convert a numerical supernodal L to symbolic supernodal.  Cannot fail. */
+
+static void ll_super_to_super_symbolic
+(
+    cholmod_factor *L,
+    cholmod_common *Common
+)
+{
+
+    /* ============================================== commit the changes to L */
+
+    /* free all but the supernodal numerical factor */
+    ASSERT (L->xtype != CHOLMOD_PATTERN && L->is_super && L->is_ll) ;
+    DEBUG (CHOLMOD(dump_factor) (L, "start to super symbolic", Common)) ;
+    L->x = CHOLMOD(free) (L->xsize,
+	    (L->xtype == CHOLMOD_COMPLEX ? 2 : 1) * sizeof (double), L->x,
+	    Common) ;
+    L->xtype = CHOLMOD_PATTERN ;
+    L->dtype = DTYPE ;
+    L->minor = L->n ;
+    L->is_ll = TRUE ;	    /* supernodal LDL' not supported */
+    DEBUG (CHOLMOD(dump_factor) (L, "done  to super symbolic", Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === simplicial_symbolic_to_simplicial_numeric ============================ */
+/* ========================================================================== */
+
+/* Convert a simplicial symbolic L to a simplicial numeric L; allocate space
+ * for L using L->ColCount from symbolic analysis, and set L to identity.
+ *
+ * If packed < 0, then this routine is creating a copy of another factor
+ * (via cholmod_copy_factor).  In this case, the space is not initialized. */
+
+static void simplicial_symbolic_to_simplicial_numeric
+(
+    cholmod_factor *L,
+    int to_ll,
+    int packed,
+    int to_xtype,
+    cholmod_common *Common
+)
+{
+    double grow0, grow1, xlen, xlnz ;
+    double *Lx, *Lz ;
+    Int *Li, *Lp, *Lnz, *ColCount ;
+    Int n, grow, grow2, p, j, lnz, len, ok, e ;
+
+    ASSERT (L->xtype == CHOLMOD_PATTERN && !(L->is_super)) ;
+    if (!allocate_simplicial_numeric (L, Common))
+    {
+	PRINT1 (("out of memory, allocate simplicial numeric\n")) ;
+	return ;	/* out of memory */
+    }
+    ASSERT (L->ColCount != NULL && L->nz != NULL && L->p != NULL) ;
+    ASSERT (L->x == NULL && L->z == NULL && L->i == NULL) ;
+
+    ColCount = L->ColCount ;
+    Lnz = L->nz ;
+    Lp = L->p ;
+    ok = TRUE ;
+    n = L->n ;
+
+    if (packed < 0)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* used by cholmod_copy_factor to allocate a copy of a factor object */
+	/* ------------------------------------------------------------------ */
+
+	lnz = L->nzmax ;
+	L->nzmax = 0 ;
+
+    }
+    else if (packed)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* LDL' or LL' packed */
+	/* ------------------------------------------------------------------ */
+
+	PRINT1 (("convert to packed LL' or LDL'\n")) ;
+	lnz = 0 ;
+	for (j = 0 ; ok && j < n ; j++)
+	{
+	    /* ensure len is in the range 1 to n-j */
+	    len = ColCount [j] ;
+	    len = MAX (1, len) ;
+	    len = MIN (len, n-j) ;
+	    lnz += len ;
+	    ok = (lnz >= 0) ;
+	}
+	for (j = 0 ; j <= n ; j++)
+	{
+	    Lp [j] = j ;
+	}
+	for (j = 0 ; j < n ; j++)
+	{
+	    Lnz [j] = 1 ;
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* LDL' unpacked */
+	/* ------------------------------------------------------------------ */
+
+	PRINT1 (("convert to unpacked\n")) ;
+	/* compute new lnzmax */
+	/* if any parameter is NaN, grow is false */
+	grow0 = Common->grow0 ;
+	grow1 = Common->grow1 ;
+	grow2 = Common->grow2 ;
+	grow0 = IS_NAN (grow0) ? 1 : grow0 ;
+	grow1 = IS_NAN (grow1) ? 1 : grow1 ;
+	/* fl.pt. compare, but no NaN's: */
+	grow = (grow0 >= 1.0) && (grow1 >= 1.0) && (grow2 > 0) ;
+	PRINT1 (("init, grow1 %g grow2 "ID"\n", grow1, grow2)) ;
+	/* initialize Lp and Lnz for each column */
+	lnz = 0 ;
+	for (j = 0 ; ok && j < n ; j++)
+	{
+	    Lp [j] = lnz ;
+	    Lnz [j] = 1 ;
+
+	    /* ensure len is in the range 1 to n-j */
+	    len = ColCount [j] ;
+	    len = MAX (1, len) ;
+	    len = MIN (len, n-j) ;
+
+	    /* compute len in double to avoid integer overflow */
+	    PRINT1 (("ColCount ["ID"] = "ID"\n", j, len)) ;
+	    if (grow)
+	    {
+		xlen = (double) len ;
+		xlen = grow1 * xlen + grow2 ;
+		xlen = MIN (xlen, n-j) ;
+		len = (Int) xlen ;
+	    }
+	    ASSERT (len >= 1 && len <= n-j) ;
+	    lnz += len ;
+	    ok = (lnz >= 0) ;
+	}
+	if (ok)
+	{
+	    Lp [n] = lnz ;
+	    if (grow)
+	    {
+		/* add extra space */
+		xlnz = (double) lnz ;
+		xlnz *= grow0 ;
+		xlnz = MIN (xlnz, Size_max) ;
+		xlnz = MIN (xlnz, ((double) n * (double) n + (double) n) / 2) ;
+		lnz = (Int) xlnz ;
+	    }
+	}
+    }
+
+    lnz = MAX (1, lnz) ;
+
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+    }
+
+    /* allocate L->i, L->x, and L->z */
+    PRINT1 (("resizing from zero size to lnz "ID"\n", lnz)) ;
+    ASSERT (L->nzmax == 0) ;
+    e = (to_xtype == CHOLMOD_COMPLEX ? 2 : 1) ;
+    if (!ok || !CHOLMOD(realloc_multiple) (lnz, 1, to_xtype, &(L->i), NULL,
+		&(L->x), &(L->z), &(L->nzmax), Common))
+    {
+	L->p    = CHOLMOD(free) (n+1, sizeof (Int),      L->p, Common) ;
+	L->nz   = CHOLMOD(free) (n,   sizeof (Int),      L->nz, Common) ;
+	L->prev = CHOLMOD(free) (n+2, sizeof (Int),      L->prev, Common) ;
+	L->next = CHOLMOD(free) (n+2, sizeof (Int),      L->next, Common) ;
+	L->i    = CHOLMOD(free) (lnz, sizeof (Int),      L->i, Common) ;
+	L->x    = CHOLMOD(free) (lnz, e*sizeof (double), L->x, Common) ;
+	L->z    = CHOLMOD(free) (lnz, sizeof (double),   L->z, Common) ;
+	PRINT1 (("cannot realloc simplicial numeric\n")) ;
+	return ;	/* out of memory */
+    }
+
+    /* ============================================== commit the changes to L */
+
+    /* initialize L to be the identity matrix */
+    L->xtype = to_xtype ;
+    L->dtype = DTYPE ;
+    L->minor = n ;
+
+    Li = L->i ;
+    Lx = L->x ;
+    Lz = L->z ;
+
+#if 0
+    if (lnz == 1)
+    {
+	/* the user won't expect to access this entry, but some CHOLMOD
+	 * routines may.  Set it to zero so that valgrind doesn't complain. */
+	switch (to_xtype)
+	{
+	    case CHOLMOD_REAL:
+		Lx [0] = 0 ;
+		break ;
+
+	    case CHOLMOD_COMPLEX:
+		Lx [0] = 0 ;
+		Lx [1] = 0 ;
+		break ;
+
+	    case CHOLMOD_ZOMPLEX:
+		Lx [0] = 0 ;
+		Lz [0] = 0 ;
+		break ;
+	}
+    }
+#endif
+
+    if (packed >= 0)
+    {
+	/* create the unit diagonal for either the LL' or LDL' case */
+
+	switch (L->xtype)
+	{
+	    case CHOLMOD_REAL:
+		for (j = 0 ; j < n ; j++)
+		{
+		    ASSERT (Lp [j] < Lp [j+1]) ;
+		    p = Lp [j] ;
+		    Li [p] = j ;
+		    Lx [p] = 1 ;
+		}
+		break ;
+
+	    case CHOLMOD_COMPLEX:
+		for (j = 0 ; j < n ; j++)
+		{
+		    ASSERT (Lp [j] < Lp [j+1]) ;
+		    p = Lp [j] ;
+		    Li [p] = j ;
+		    Lx [2*p  ] = 1 ;
+		    Lx [2*p+1] = 0 ;
+		}
+		break ;
+
+	    case CHOLMOD_ZOMPLEX:
+		for (j = 0 ; j < n ; j++)
+		{
+		    ASSERT (Lp [j] < Lp [j+1]) ;
+		    p = Lp [j] ;
+		    Li [p] = j ;
+		    Lx [p] = 1 ;
+		    Lz [p] = 0 ;
+		}
+		break ;
+	}
+    }
+
+    L->is_ll = to_ll ;
+
+    PRINT1 (("done convert simplicial symbolic to numeric\n")) ;
+}
+
+
+/* ========================================================================== */
+/* === change_simplicial_numeric ============================================ */
+/* ========================================================================== */
+
+/* Change LL' to LDL', LDL' to LL', or leave as-is.
+ *
+ * If to_packed is TRUE, then the columns of L are packed and made monotonic
+ * (to_monotonic is ignored; it is implicitly TRUE).
+ *
+ * If to_monotonic is TRUE but to_packed is FALSE, the columns of L are made
+ * monotonic but not packed.
+ *
+ * If both to_packed and to_monotonic are FALSE, then the columns of L are
+ * left as-is, and the conversion is done in place.
+ *
+ * If L is already monotonic, or if it is to be left non-monotonic, then this
+ * conversion always succeeds.
+ *
+ * When converting an LDL' to LL' factorization, any column with a negative
+ * or zero diagonal entry is not modified so that conversion back to LDL' will
+ * succeed.  This can result in a matrix L with a negative entry on the diagonal
+ * If the kth entry on the diagonal of D is negative, it and the kth column of
+ * L are left unchanged.  A subsequent conversion back to an LDL' form will also
+ * leave the column unchanged, so the correct LDL' factorization will be
+ * restored.  L->minor is set to the smallest k for which D (k,k) is negative.
+ */
+
+static void change_simplicial_numeric
+(
+    cholmod_factor *L,
+    int to_ll,
+    int to_packed,
+    int to_monotonic,
+    cholmod_common *Common
+)
+{
+    double grow0, grow1, xlen, xlnz ;
+    void *newLi, *newLx, *newLz ;
+    double *Lx, *Lz ;
+    Int *Lp, *Li, *Lnz ;
+    Int make_monotonic, grow2, n, j, lnz, len, grow, ok, make_ll, make_ldl ;
+    size_t nzmax0 ;
+
+    PRINT1 (("\n===Change simplicial numeric: %d %d %d\n",
+	    to_ll, to_packed, to_monotonic)) ;
+    DEBUG (CHOLMOD(dump_factor) (L, "change simplicial numeric", Common)) ;
+    ASSERT (L->xtype != CHOLMOD_PATTERN && !(L->is_super)) ;
+
+    make_monotonic = ((to_packed || to_monotonic) && !(L->is_monotonic)) ;
+    make_ll  = (to_ll && !(L->is_ll)) ;
+    make_ldl = (!to_ll && L->is_ll) ;
+
+    n = L->n ;
+    Lp = L->p ;
+    Li = L->i ;
+    Lx = L->x ;
+    Lz = L->z ;
+    Lnz = L->nz ;
+
+    grow = FALSE ;
+    grow0 = Common->grow0 ;
+    grow1 = Common->grow1 ;
+    grow2 = Common->grow2 ;
+    grow0 = IS_NAN (grow0) ? 1 : grow0 ;
+    grow1 = IS_NAN (grow1) ? 1 : grow1 ;
+    ok = TRUE ;
+    newLi = NULL ;
+    newLx = NULL ; 
+    newLz = NULL ; 
+    lnz = 0 ;
+
+    if (make_monotonic)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* Columns out of order, but will be reordered and optionally packed. */
+	/* ------------------------------------------------------------------ */
+
+	PRINT1 (("L is non-monotonic\n")) ;
+
+	/* compute new L->nzmax */
+	if (!to_packed)
+	{
+	    /* if any parameter is NaN, grow is false */
+	    /* fl.pt. comparisons below are false if any parameter is NaN */
+	    grow = (grow0 >= 1.0) && (grow1 >= 1.0) && (grow2 > 0) ;
+	}
+	for (j = 0 ; ok && j < n ; j++)
+	{
+	    len = Lnz [j] ;
+	    ASSERT (len >= 1 && len <= n-j) ;
+
+	    /* compute len in double to avoid integer overflow */
+	    if (grow)
+	    {
+		xlen = (double) len ;
+		xlen = grow1 * xlen + grow2 ;
+		xlen = MIN (xlen, n-j) ;
+		len = (Int) xlen ;
+	    }
+	    ASSERT (len >= Lnz [j] && len <= n-j) ;
+
+	    PRINT2 (("j: "ID" Lnz[j] "ID" len "ID" p "ID"\n",
+			j, Lnz [j], len, lnz)) ;
+
+	    lnz += len ;
+	    ok = (lnz >= 0) ;
+	}
+
+	if (!ok)
+	{
+	    ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	    return ;
+	}
+
+	if (grow)
+	{
+	    xlnz = (double) lnz ;
+	    xlnz *= grow0 ;
+	    xlnz = MIN (xlnz, Size_max) ;
+	    xlnz = MIN (xlnz, ((double) n * (double) n + (double) n) / 2) ;
+	    lnz = (Int) xlnz ;
+	}
+
+	lnz = MAX (1, lnz) ;
+	PRINT1 (("final lnz "ID"\n", lnz)) ;
+	nzmax0 = 0 ;
+
+	CHOLMOD(realloc_multiple) (lnz, 1, L->xtype, &newLi, NULL,
+		&newLx, &newLz, &nzmax0, Common) ;
+
+	if (Common->status < CHOLMOD_OK)
+	{
+	    return ;	    /* out of memory */
+	}
+    }
+
+    /* ============================================== commit the changes to L */
+
+    /* ---------------------------------------------------------------------- */
+    /* convert the simplicial L, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (L->xtype)
+    {
+
+	case CHOLMOD_REAL:
+	    r_change_simplicial_numeric (L, to_ll, to_packed,
+		    newLi, newLx, newLz, lnz, grow, grow1, grow2,
+		    make_ll, make_monotonic, make_ldl, Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    c_change_simplicial_numeric (L, to_ll, to_packed,
+		    newLi, newLx, newLz, lnz, grow, grow1, grow2,
+		    make_ll, make_monotonic, make_ldl, Common) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    z_change_simplicial_numeric (L, to_ll, to_packed,
+		    newLi, newLx, newLz, lnz, grow, grow1, grow2,
+		    make_ll, make_monotonic, make_ldl, Common) ;
+	    break ;
+    }
+
+    DEBUG (CHOLMOD(dump_factor) (L, "L simplicial changed", Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === ll_super_to_simplicial_numeric ======================================= */
+/* ========================================================================== */
+
+/* Convert a supernodal numeric factorization to any simplicial numeric one.
+ * Leaves L->xtype unchanged (real or complex, not zomplex since there is
+ * no supernodal zomplex L). */
+
+static void ll_super_to_simplicial_numeric
+(
+    cholmod_factor *L,
+    int to_packed,
+    int to_ll,
+    cholmod_common *Common
+)
+{
+    Int *Ls, *Lpi, *Lpx, *Super, *Li ;
+    Int n, lnz, s, nsuper, psi, psend, nsrow, nscol, k1, k2, erows ;
+
+    DEBUG (CHOLMOD(dump_factor) (L, "start LL super to simplicial", Common)) ;
+    PRINT1 (("super -> simplicial (%d %d)\n", to_packed, to_ll)) ;
+    ASSERT (L->xtype != CHOLMOD_PATTERN && L->is_ll && L->is_super) ;
+    ASSERT (L->x != NULL && L->i == NULL) ;
+
+    n = L->n ;
+    nsuper = L->nsuper ;
+    Lpi = L->pi ;
+    Lpx = L->px ;
+    Ls = L->s ;
+    Super = L->super ;
+
+    /* Int overflow cannot occur since supernodal L already exists */
+
+    if (to_packed)
+    {
+	/* count the number of nonzeros in L.  Each supernode is of the form
+	 *
+	 *    l	. . .	    For this example, nscol = 4 (# columns). nsrow = 9.
+	 *    l l . .	    The "." entries are allocated in the supernodal
+	 *    l l l .	    factor, but not used.  They are not copied to the
+	 *    l l l l	    simplicial factor.  Some "l" and "e" entries may be
+	 *    e e e e	    numerically zero and even symbolically zero if a
+	 *    e e e e	    tight simplicial factorization or resymbol were
+	 *    e e e e	    done, because of numerical cancellation and relaxed
+	 *    e e e e	    supernode amalgamation, respectively.
+	 *    e e e e
+	 */
+	lnz = 0 ;
+	for (s = 0 ; s < nsuper ; s++)
+	{
+	    k1 = Super [s] ;
+	    k2 = Super [s+1] ;
+	    psi = Lpi [s] ;
+	    psend = Lpi [s+1] ;
+	    nsrow = psend - psi ;
+	    nscol = k2 - k1 ;
+	    ASSERT (nsrow >= nscol) ;
+	    erows = nsrow - nscol ;
+
+	    /* lower triangular part, including the diagonal,
+	     * counting the "l" terms in the figure above. */
+	    lnz += nscol * (nscol+1) / 2 ;
+
+	    /* rectangular part, below the diagonal block (the "e" terms) */
+	    lnz += nscol * erows ;
+	}
+	ASSERT (lnz <= (Int) (L->xsize)) ;
+    }
+    else
+    {
+	/* Li will be the same size as Lx */
+	lnz = L->xsize ;
+    }
+    ASSERT (lnz >= 0) ;
+    PRINT1 (("simplicial lnz = "ID"  to_packed: %d  to_ll: %d L->xsize %g\n",
+		lnz, to_ll, to_packed, (double) L->xsize)) ;
+
+    Li = CHOLMOD(malloc) (lnz, sizeof (Int), Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return ;	/* out of memory */
+    }
+
+    if (!allocate_simplicial_numeric (L, Common))
+    {
+	CHOLMOD(free) (lnz, sizeof (Int), Li, Common) ;
+	return ;	/* out of memory */
+    }
+
+    /* ============================================== commit the changes to L */
+
+    L->i = Li ;
+    L->nzmax = lnz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert the supernodal L, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (L->xtype)
+    {
+
+	case CHOLMOD_REAL:
+	    r_ll_super_to_simplicial_numeric (L, to_packed, to_ll, Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    c_ll_super_to_simplicial_numeric (L, to_packed, to_ll, Common) ;
+	    break ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* free unused parts of L */
+    /* ---------------------------------------------------------------------- */
+
+    L->super = CHOLMOD(free) (nsuper+1, sizeof (Int), L->super, Common) ;
+    L->pi    = CHOLMOD(free) (nsuper+1, sizeof (Int), L->pi, Common) ;
+    L->px    = CHOLMOD(free) (nsuper+1, sizeof (Int), L->px, Common) ;
+    L->s     = CHOLMOD(free) (L->ssize, sizeof (Int), L->s, Common) ;
+
+    L->ssize = 0 ;
+    L->xsize = 0 ;
+    L->nsuper = 0 ;
+    L->maxesize = 0 ;
+    L->maxcsize = 0 ;
+
+    L->is_super = FALSE ;
+
+    DEBUG (CHOLMOD(dump_factor) (L, "done  LL super to simplicial", Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === super_symbolic_to_ll_super =========================================== */
+/* ========================================================================== */
+
+/* Convert a supernodal symbolic factorization to a supernodal numeric
+ * factorization by allocating L->x.  Contents of L->x are undefined.
+ */
+
+static int super_symbolic_to_ll_super
+(
+    int to_xtype,
+    cholmod_factor *L,
+    cholmod_common *Common
+)
+{
+    double *Lx ;
+    Int wentry = (to_xtype == CHOLMOD_REAL) ? 1 : 2 ;
+    PRINT1 (("convert super sym to num\n")) ;
+    ASSERT (L->xtype == CHOLMOD_PATTERN && L->is_super) ;
+    Lx = CHOLMOD(malloc) (L->xsize, wentry * sizeof (double), Common) ;
+    PRINT1 (("xsize %g\n", (double) L->xsize)) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+
+    /* ============================================== commit the changes to L */
+
+    if (L->xsize == 1)
+    {
+	/* the caller won't expect to access this entry, but some CHOLMOD
+	 * routines may.  Set it to zero so that valgrind doesn't complain. */
+	switch (to_xtype)
+	{
+	    case CHOLMOD_REAL:
+		Lx [0] = 0 ;
+		break ;
+
+	    case CHOLMOD_COMPLEX:
+		Lx [0] = 0 ;
+		Lx [1] = 0 ;
+		break ;
+	}
+    }
+
+    L->x = Lx ;
+    L->xtype = to_xtype ;
+    L->dtype = DTYPE ;
+    L->minor = L->n ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_change_factor ================================================ */
+/* ========================================================================== */
+
+/* Convert a factor L.  Some conversions simply allocate uninitialized space
+ * that meant to be filled later.
+ *
+ * If the conversion fails, the factor is left in its original form, with one
+ * exception.  Converting a supernodal symbolic factor to a simplicial numeric
+ * one (with L=D=I) may leave the factor in simplicial symbolic form.
+ *
+ * Memory allocated for each conversion is listed below.
+ */
+
+int CHOLMOD(change_factor)
+(
+    /* ---- input ---- */
+    int to_xtype,	/* convert to CHOLMOD_PATTERN, _REAL, _COMPLEX, or
+			 * _ZOMPLEX */
+    int to_ll,		/* TRUE: convert to LL', FALSE: LDL' */
+    int to_super,	/* TRUE: convert to supernodal, FALSE: simplicial */
+    int to_packed,	/* TRUE: pack simplicial columns, FALSE: do not pack */
+    int to_monotonic,	/* TRUE: put simplicial columns in order, FALSE: not */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (to_xtype < CHOLMOD_PATTERN || to_xtype > CHOLMOD_ZOMPLEX)
+    {
+	ERROR (CHOLMOD_INVALID, "xtype invalid") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    PRINT1 (("-----convert from (%d,%d,%d,%d,%d) to (%d,%d,%d,%d,%d)\n",
+    L->xtype, L->is_ll, L->is_super, L_is_packed (L, Common), L->is_monotonic,
+    to_xtype, to_ll,    to_super,    to_packed,               to_monotonic)) ;
+
+    /* ensure all parameters are TRUE/FALSE */
+    to_ll = BOOLEAN (to_ll) ;
+    to_super = BOOLEAN (to_super) ;
+
+    ASSERT (BOOLEAN (L->is_ll) == L->is_ll) ;
+    ASSERT (BOOLEAN (L->is_super) == L->is_super) ;
+
+    if (to_super && to_xtype == CHOLMOD_ZOMPLEX)
+    {
+	ERROR (CHOLMOD_INVALID, "supernodal zomplex L not supported") ;
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* convert */
+    /* ---------------------------------------------------------------------- */
+
+    if (to_xtype == CHOLMOD_PATTERN)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* convert to symbolic */
+	/* ------------------------------------------------------------------ */
+
+	if (!to_super)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* convert any factor into a simplicial symbolic factor */
+	    /* -------------------------------------------------------------- */
+
+	    any_to_simplicial_symbolic (L, to_ll, Common) ;    /* cannot fail */
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* convert to a supernodal symbolic factor */
+	    /* -------------------------------------------------------------- */
+
+	    if (L->xtype != CHOLMOD_PATTERN && L->is_super)
+	    {
+		/* convert from supernodal numeric to supernodal symbolic.
+		 * this preserves symbolic pattern of L, discards numeric
+		 * values */
+		ll_super_to_super_symbolic (L, Common) ;       /* cannot fail */
+	    }
+	    else if (L->xtype == CHOLMOD_PATTERN && !(L->is_super))
+	    {
+		/* convert from simplicial symbolic to supernodal symbolic.
+		 * contents of supernodal pattern are uninitialized.  Not meant
+		 * for the end user. */
+		simplicial_symbolic_to_super_symbolic (L, Common) ;
+	    }
+	    else
+	    {
+		/* cannot convert from simplicial numeric to supernodal
+		 * symbolic */
+		ERROR (CHOLMOD_INVALID,
+			"cannot convert L to supernodal symbolic") ;
+	    }
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* convert to numeric */
+	/* ------------------------------------------------------------------ */
+	    
+	if (to_super)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* convert to supernodal numeric factor */
+	    /* -------------------------------------------------------------- */
+
+	    if (L->xtype == CHOLMOD_PATTERN)
+	    {
+		if (L->is_super)
+		{
+		    /* Convert supernodal symbolic to supernodal numeric.
+		     * Contents of supernodal numeric values are uninitialized.
+		     * This is used by cholmod_super_numeric.  Not meant for
+		     * the end user. */
+		    super_symbolic_to_ll_super (to_xtype, L, Common) ;
+		}
+		else
+		{
+		    /* Convert simplicial symbolic to supernodal numeric.
+		     * Contents not defined.  This is used by
+		     * Core/cholmod_copy_factor only.  Not meant for the end
+		     * user. */
+		    if (!simplicial_symbolic_to_super_symbolic (L, Common))
+		    {
+			/* failure, convert back to simplicial symbolic */
+			any_to_simplicial_symbolic (L, to_ll, Common) ;
+		    }
+		    else
+		    {
+			/* conversion to super symbolic OK, allocate numeric
+			 * part */
+			super_symbolic_to_ll_super (to_xtype, L, Common) ;
+		    }
+		}
+	    }
+	    else
+	    {
+		/* nothing to do if L is already in supernodal numeric form */
+		if (!(L->is_super))
+		{
+		    ERROR (CHOLMOD_INVALID,
+			"cannot convert simplicial L to supernodal") ;
+		}
+		/* FUTURE WORK: convert to/from supernodal LL' and LDL' */
+	    }
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* convert any factor to simplicial numeric */
+	    /* -------------------------------------------------------------- */
+
+	    if (L->xtype == CHOLMOD_PATTERN && !(L->is_super))
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* convert simplicial symbolic to simplicial numeric (L=I,D=I)*/
+		/* ---------------------------------------------------------- */
+
+		simplicial_symbolic_to_simplicial_numeric (L, to_ll, to_packed,
+			to_xtype, Common) ;
+
+	    }
+	    else if (L->xtype != CHOLMOD_PATTERN && L->is_super)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* convert a supernodal LL' to simplicial numeric */
+		/* ---------------------------------------------------------- */
+
+		ll_super_to_simplicial_numeric (L, to_packed, to_ll, Common) ;
+
+	    }
+	    else if (L->xtype == CHOLMOD_PATTERN && L->is_super)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* convert a supernodal symbolic to simplicial numeric (L=D=I)*/
+		/* ---------------------------------------------------------- */
+
+		any_to_simplicial_symbolic (L, to_ll, Common) ;
+		/* if the following fails, it leaves the factor in simplicial
+		 * symbolic form */
+		simplicial_symbolic_to_simplicial_numeric (L, to_ll, to_packed,
+			to_xtype, Common) ;
+
+	    }
+	    else
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* change a simplicial numeric factor */
+		/* ---------------------------------------------------------- */
+
+		/* change LL' to LDL', LDL' to LL', or leave as-is.  pack the
+		 * columns of L, or leave as-is.  Ensure the columns are
+		 * monotonic, or leave as-is. */
+
+		change_simplicial_numeric (L, to_ll, to_packed, to_monotonic,
+			Common) ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return result */
+    /* ---------------------------------------------------------------------- */
+
+    return (Common->status >= CHOLMOD_OK) ;
+}
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/cholmod_common.c b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_common.c
new file mode 100644
index 0000000..d954024
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_common.c
@@ -0,0 +1,657 @@
+/* ========================================================================== */
+/* === Core/cholmod_common ================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Core utility routines for the cholmod_common object:
+ *
+ * Primary routines:
+ * -----------------
+ * cholmod_start		the first call to CHOLMOD
+ * cholmod_finish		the last call to CHOLMOD
+ *
+ * Secondary routines:
+ * -------------------
+ * cholmod_defaults		restore (most) default control parameters
+ * cholmod_allocate_work	allocate (or reallocate) workspace in Common
+ * cholmod_free_work		free workspace in Common
+ * cholmod_clear_flag		clear Common->Flag in workspace
+ * cholmod_maxrank		column dimension of Common->Xwork workspace
+ *
+ * The Common object is unique.  It cannot be allocated or deallocated by
+ * CHOLMOD, since it contains the definition of the memory management routines
+ * used (pointers to malloc, free, realloc, and calloc, or their equivalent).
+ * The Common object contains workspace that is used between calls to
+ * CHOLMOD routines.  This workspace allocated by CHOLMOD as needed, by
+ * cholmod_allocate_work and cholmod_free_work.
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+/* ========================================================================== */
+/* === cholmod_start ======================================================== */
+/* ========================================================================== */
+
+/* Initialize Common default parameters and statistics.  Sets workspace
+ * pointers to NULL.
+ *
+ * This routine must be called just once, prior to calling any other CHOLMOD
+ * routine.  Do not call this routine after any other CHOLMOD routine (except
+ * cholmod_finish, to start a new CHOLMOD session), or a memory leak will
+ * occur.
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(start)
+(
+    cholmod_common *Common
+)
+{
+    if (Common == NULL)
+    {
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* user error handling routine */
+    /* ---------------------------------------------------------------------- */
+
+    Common->error_handler = NULL ;
+
+    /* ---------------------------------------------------------------------- */
+    /* integer and numerical types */
+    /* ---------------------------------------------------------------------- */
+
+    Common->itype = ITYPE ;
+    Common->dtype = DTYPE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* default control parameters */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(defaults) (Common) ;
+    Common->try_catch = FALSE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* memory management routines */
+    /* ---------------------------------------------------------------------- */
+
+    /* The user can replace cholmod's memory management routines by redefining
+     * these function pointers. */
+
+#ifndef NMALLOC
+    /* stand-alone ANSI C program */
+    Common->malloc_memory  = malloc ;
+    Common->free_memory    = free ;
+    Common->realloc_memory = realloc ;
+    Common->calloc_memory  = calloc ;
+#else
+    /* no memory manager defined at compile-time; MUST define one at run-time */
+    Common->malloc_memory  = NULL ;
+    Common->free_memory    = NULL ;
+    Common->realloc_memory = NULL ;
+    Common->calloc_memory  = NULL ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* complex arithmetic routines */
+    /* ---------------------------------------------------------------------- */
+
+    Common->complex_divide = CHOLMOD(divcomplex) ;
+    Common->hypotenuse = CHOLMOD(hypot) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print routine */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NPRINT
+    /* stand-alone ANSI C program */
+    Common->print_function = printf ;
+#else
+    /* printing disabled */
+    Common->print_function = NULL ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* This code assumes the workspace held in Common is not initialized.  If
+     * it is, then a memory leak will occur because the pointers are
+     * overwritten with NULL. */
+
+    Common->nrow = 0 ;
+    Common->mark = EMPTY ;
+    Common->xworksize = 0 ;
+    Common->iworksize = 0 ;
+    Common->Flag = NULL ;
+    Common->Head = NULL ;
+    Common->Iwork = NULL ;
+    Common->Xwork = NULL ;
+    Common->no_workspace_reallocate = FALSE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* statistics */
+    /* ---------------------------------------------------------------------- */
+
+    /* fl and lnz are computed in cholmod_analyze and cholmod_rowcolcounts */
+    Common->fl = EMPTY ;
+    Common->lnz = EMPTY ;
+
+    /* modfl is computed in cholmod_updown, cholmod_rowadd, and cholmod_rowdel*/
+    Common->modfl = EMPTY ;
+
+    /* all routines use status as their error-report code */
+    Common->status = CHOLMOD_OK ;
+
+    Common->malloc_count = 0 ;	/* # calls to malloc minus # calls to free */
+    Common->memory_usage = 0 ;	/* peak memory usage (in bytes) */
+    Common->memory_inuse = 0 ;	/* current memory in use (in bytes) */
+
+    Common->nrealloc_col = 0 ;
+    Common->nrealloc_factor = 0 ;
+    Common->ndbounds_hit = 0 ;
+    Common->rowfacfl = 0 ;
+    Common->aatfl = EMPTY ;
+
+    /* Common->called_nd is TRUE if cholmod_analyze called or NESDIS */
+    Common->called_nd = FALSE ;
+
+    DEBUG_INIT ("cholmod start") ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_defaults ===================================================== */
+/* ========================================================================== */
+
+/* Set Common default parameters, except for the function pointers.
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(defaults)
+(
+    cholmod_common *Common
+)
+{
+    Int i ;
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* default control parameters */
+    /* ---------------------------------------------------------------------- */
+
+    Common->dbound = 0.0 ;
+    Common->grow0 = 1.2 ;
+    Common->grow1 = 1.2 ;
+    Common->grow2 = 5 ;
+    Common->maxrank = 8 ;
+
+    Common->final_asis = TRUE ;
+    Common->final_super = TRUE ;
+    Common->final_ll = FALSE ;
+    Common->final_pack = TRUE ;
+    Common->final_monotonic = TRUE ;
+    Common->final_resymbol = FALSE ;
+
+    /* use simplicial factorization if flop/nnz(L) < 40, supernodal otherwise */
+    Common->supernodal = CHOLMOD_AUTO ;
+    Common->supernodal_switch = 40 ;
+
+    Common->nrelax [0] = 4 ;
+    Common->nrelax [1] = 16 ;
+    Common->nrelax [2] = 48 ;
+    Common->zrelax [0] = 0.8 ;
+    Common->zrelax [1] = 0.1 ;
+    Common->zrelax [2] = 0.05 ;
+
+    Common->prefer_zomplex = FALSE ;
+    Common->prefer_upper = TRUE ;
+    Common->prefer_binary = FALSE ;
+    Common->quick_return_if_not_posdef = FALSE ;
+
+    /* METIS workarounds */
+    Common->metis_memory = 0.0 ;    /* > 0 for memory guard (2 is reasonable) */
+    Common->metis_nswitch = 3000 ;
+    Common->metis_dswitch = 0.66 ;
+
+    Common->print = 3 ;
+    Common->precise = FALSE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* default ordering methods */
+    /* ---------------------------------------------------------------------- */
+
+    /* Note that if the Partition module is not installed, the CHOLMOD_METIS
+     * and CHOLMOD_NESDIS methods will not be available.  cholmod_analyze will
+     * report the CHOLMOD_NOT_INSTALLED error, and safely skip over them.
+     */
+
+#if (CHOLMOD_MAXMETHODS < 9)
+#error "CHOLMOD_MAXMETHODS must be 9 or more (defined in cholmod_core.h)."
+#endif
+
+    /* default strategy: try given, AMD, and then METIS if AMD reports high
+     * fill-in.  NESDIS can be used instead, if Common->default_nesdis is TRUE.
+     */
+    Common->nmethods = 0 ;		/* use default strategy */
+    Common->default_nesdis = FALSE ;	/* use METIS in default strategy */
+
+    Common->current = 0 ;	/* current method being tried */
+    Common->selected = 0 ;	/* the best method selected */
+
+    /* first, fill each method with default parameters */
+    for (i = 0 ; i <= CHOLMOD_MAXMETHODS ; i++)
+    {
+	/* CHOLMOD's default method is AMD for A or AA' */
+	Common->method [i].ordering = CHOLMOD_AMD ;
+
+	/* CHOLMOD nested dissection and minimum degree parameter */
+	Common->method [i].prune_dense = 10.0 ;	/* dense row/col control */
+
+	/* min degree parameters (AMD, COLAMD, SYMAMD, CAMD, CCOLAMD, CSYMAMD)*/
+	Common->method [i].prune_dense2 = -1 ;	/* COLAMD dense row control */
+	Common->method [i].aggressive = TRUE ;	/* aggressive absorption */
+	Common->method [i].order_for_lu = FALSE ;/* order for Cholesky not LU */
+
+	/* CHOLMOD's nested dissection (METIS + constrained AMD) */
+	Common->method [i].nd_small = 200 ;	/* small graphs aren't cut */
+	Common->method [i].nd_compress = TRUE ;	/* compress graph & subgraphs */
+	Common->method [i].nd_camd = 1 ;	/* use CAMD */
+	Common->method [i].nd_components = FALSE ;  /* lump connected comp. */
+	Common->method [i].nd_oksep = 1.0 ;	/* sep ok if < oksep*n */
+
+	/* statistics for each method are not yet computed */
+	Common->method [i].fl = EMPTY ;
+	Common->method [i].lnz = EMPTY ;
+    }
+
+    Common->postorder = TRUE ;	/* follow ordering with weighted postorder */
+
+    /* Next, define some methods.  The first five use default parameters. */
+    Common->method [0].ordering = CHOLMOD_GIVEN ;   /* skip if UserPerm NULL */
+    Common->method [1].ordering = CHOLMOD_AMD ;
+    Common->method [2].ordering = CHOLMOD_METIS ;
+    Common->method [3].ordering = CHOLMOD_NESDIS ;
+    Common->method [4].ordering = CHOLMOD_NATURAL ;
+
+    /* CHOLMOD's nested dissection with large leaves of separator tree */
+    Common->method [5].ordering = CHOLMOD_NESDIS ;
+    Common->method [5].nd_small = 20000 ;
+
+    /* CHOLMOD's nested dissection with tiny leaves, and no AMD ordering */
+    Common->method [6].ordering = CHOLMOD_NESDIS ;
+    Common->method [6].nd_small = 4 ;
+    Common->method [6].nd_camd = 0 ;		/* no CSYMAMD or CAMD */
+
+    /* CHOLMOD's nested dissection with no dense node removal */
+    Common->method [7].ordering = CHOLMOD_NESDIS ;
+    Common->method [7].prune_dense = -1. ;
+
+    /* COLAMD for A*A', AMD for A */
+    Common->method [8].ordering = CHOLMOD_COLAMD ;
+
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_finish ======================================================= */
+/* ========================================================================== */
+
+/* The last call to CHOLMOD must be cholmod_finish.  You may call this routine
+ * more than once, and can safely call any other CHOLMOD routine after calling
+ * it (including cholmod_start).
+ *
+ * The statistics and parameter settings in Common are preserved.  The
+ * workspace in Common is freed.  This routine is just another name for
+ * cholmod_free_work.
+ */
+
+int CHOLMOD(finish)
+(
+    cholmod_common *Common
+)
+{
+    return (CHOLMOD(free_work) (Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_allocate_work ================================================ */
+/* ========================================================================== */
+
+/* Allocate and initialize workspace for CHOLMOD routines, or increase the size
+ * of already-allocated workspace.  If enough workspace is already allocated,
+ * then nothing happens.
+ *
+ * workspace: Flag (nrow), Head (nrow+1), Iwork (iworksize), Xwork (xworksize)
+ */
+
+int CHOLMOD(allocate_work)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows in the matrix A */
+    size_t iworksize,	/* size of Iwork */
+    size_t xworksize,	/* size of Xwork */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *W ;
+    Int *Head ;
+    Int i ;
+    size_t nrow1 ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* Allocate Flag (nrow) and Head (nrow+1) */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = MAX (1, nrow) ;
+
+    /* nrow1 = nrow + 1 */
+    nrow1 = CHOLMOD(add_size_t) (nrow, 1, &ok) ;
+    if (!ok)
+    {
+	/* nrow+1 causes size_t overflow ; problem is too large */
+	Common->status = CHOLMOD_TOO_LARGE ;
+	CHOLMOD(free_work) (Common) ;
+	return (FALSE) ;
+    }
+
+    if (nrow > Common->nrow)
+    {
+
+	if (Common->no_workspace_reallocate)
+	{
+	    /* CHOLMOD is not allowed to change the workspace here */
+	    Common->status = CHOLMOD_INVALID ;
+	    return (FALSE) ;
+	}
+
+	/* free the old workspace (if any) and allocate new space */
+	Common->Flag = CHOLMOD(free) (Common->nrow,  sizeof (Int), Common->Flag,
+		Common) ;
+	Common->Head = CHOLMOD(free) (Common->nrow+1,sizeof (Int), Common->Head,
+		Common) ;
+	Common->Flag = CHOLMOD(malloc) (nrow,   sizeof (Int), Common) ;
+	Common->Head = CHOLMOD(malloc) (nrow1, sizeof (Int), Common) ;
+
+	/* record the new size of Flag and Head */
+	Common->nrow = nrow ;
+
+	if (Common->status < CHOLMOD_OK)
+	{
+	    CHOLMOD(free_work) (Common) ;
+	    return (FALSE) ;
+	}
+
+	/* initialize Flag and Head */
+	Common->mark = EMPTY ;
+	CHOLMOD(clear_flag) (Common) ;
+	Head = Common->Head ;
+	for (i = 0 ; i <= (Int) (nrow) ; i++)
+	{
+	    Head [i] = EMPTY ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* Allocate Iwork (iworksize) */
+    /* ---------------------------------------------------------------------- */
+
+    iworksize = MAX (1, iworksize) ;
+    if (iworksize > Common->iworksize)
+    {
+
+	if (Common->no_workspace_reallocate)
+	{
+	    /* CHOLMOD is not allowed to change the workspace here */
+	    Common->status = CHOLMOD_INVALID ;
+	    return (FALSE) ;
+	}
+
+	/* free the old workspace (if any) and allocate new space.
+	 * integer overflow safely detected in cholmod_malloc */
+	CHOLMOD(free) (Common->iworksize, sizeof (Int), Common->Iwork, Common) ;
+	Common->Iwork = CHOLMOD(malloc) (iworksize, sizeof (Int), Common) ;
+
+	/* record the new size of Iwork */
+	Common->iworksize = iworksize ;
+
+	if (Common->status < CHOLMOD_OK)
+	{
+	    CHOLMOD(free_work) (Common) ;
+	    return (FALSE) ;
+	}
+
+	/* note that Iwork does not need to be initialized */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* Allocate Xwork (xworksize) and set it to ((double) 0.) */
+    /* ---------------------------------------------------------------------- */
+
+    /* make sure xworksize is >= 1 */
+    xworksize = MAX (1, xworksize) ;
+    if (xworksize > Common->xworksize)
+    {
+
+	if (Common->no_workspace_reallocate)
+	{
+	    /* CHOLMOD is not allowed to change the workspace here */
+	    Common->status = CHOLMOD_INVALID ;
+	    return (FALSE) ;
+	}
+
+	/* free the old workspace (if any) and allocate new space */
+	CHOLMOD(free) (Common->xworksize, sizeof (double), Common->Xwork,
+		Common) ;
+	Common->Xwork = CHOLMOD(malloc) (xworksize, sizeof (double), Common) ;
+
+	/* record the new size of Xwork */
+	Common->xworksize = xworksize ;
+
+	if (Common->status < CHOLMOD_OK)
+	{
+	    CHOLMOD(free_work) (Common) ;
+	    return (FALSE) ;
+	}
+
+	/* initialize Xwork */
+	W = Common->Xwork ;
+	for (i = 0 ; i < (Int) xworksize ; i++)
+	{
+	    W [i] = 0. ;
+	}
+    }
+
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_free_work ==================================================== */
+/* ========================================================================== */
+
+/* Deallocate the CHOLMOD workspace.
+ *
+ * workspace: deallocates all workspace in Common
+ */
+
+int CHOLMOD(free_work)
+(
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->Flag  = CHOLMOD(free) (Common->nrow, sizeof (Int),
+	    Common->Flag, Common) ;
+    Common->Head  = CHOLMOD(free) (Common->nrow+1, sizeof (Int),
+	    Common->Head, Common) ;
+    Common->Iwork = CHOLMOD(free) (Common->iworksize, sizeof (Int),
+	    Common->Iwork, Common) ;
+    Common->Xwork = CHOLMOD(free) (Common->xworksize, sizeof (double),
+	    Common->Xwork, Common) ;
+    Common->nrow = 0 ;
+    Common->iworksize = 0 ;
+    Common->xworksize = 0 ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_clear_flag =================================================== */
+/* ========================================================================== */
+
+/* Increment mark to ensure Flag [0..nrow-1] < mark.  If integer overflow
+ * occurs, or mark was initially negative, reset the entire array.  This is
+ * not an error condition, but an intended function of the Flag workspace.
+ *
+ * workspace: Flag (nrow).  Does not modify Flag if nrow is zero.
+ */
+
+UF_long CHOLMOD(clear_flag)
+(
+    cholmod_common *Common
+)
+{
+    Int i, nrow, *Flag ;
+
+    RETURN_IF_NULL_COMMON (-1) ;
+
+    Common->mark++ ;
+    if (Common->mark <= 0)
+    {
+	nrow = Common->nrow ;
+	Flag = Common->Flag ;
+	PRINT2 (("reset Flag: nrow "ID"\n", nrow)) ;
+	PRINT2 (("reset Flag: mark %ld\n", Common->mark)) ;
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    Flag [i] = EMPTY ;
+	}
+	Common->mark = 0 ;
+    }
+    return (Common->mark) ;
+}
+
+
+/* ========================================================================== */
+/* ==== cholmod_maxrank ===================================================== */
+/* ========================================================================== */
+
+/* Find a valid value of Common->maxrank.  Returns 0 if error, or 2, 4, or 8
+ * if successful. */
+
+size_t CHOLMOD(maxrank)	/* returns validated value of Common->maxrank */
+(
+    /* ---- input ---- */
+    size_t n,		/* A and L will have n rows */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    size_t maxrank ;
+    RETURN_IF_NULL_COMMON (0) ;
+    maxrank = Common->maxrank ;
+    if (n > 0)
+    {
+	/* Ensure maxrank*n*sizeof(double) does not result in integer overflow.
+	 * If n is so large that 2*n*sizeof(double) results in integer overflow
+	 * (n = 268,435,455 if an Int is 32 bits), then maxrank will be 0 or 1,
+	 * but maxrank will be set to 2 below.  2*n will not result in integer
+	 * overflow, and CHOLMOD will run out of memory or safely detect integer
+	 * overflow elsewhere.
+	 */
+	maxrank = MIN (maxrank, Size_max / (n * sizeof (double))) ;
+    }
+    if (maxrank <= 2)
+    {
+	maxrank = 2 ;
+    }
+    else if (maxrank <= 4)
+    {
+	maxrank = 4 ;
+    }
+    else
+    {
+	maxrank = 8 ;
+    }
+    return (maxrank) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dbound ======================================================= */
+/* ========================================================================== */
+
+/* Ensure the absolute value of a diagonal entry, D (j,j), is greater than
+ * Common->dbound.  This routine is not meant for the user to call.  It is used
+ * by the various LDL' factorization and update/downdate routines.  The
+ * default value of Common->dbound is zero, and in that case this routine is not
+ * called at all.  No change is made if D (j,j) is NaN.  CHOLMOD does not call
+ * this routine if Common->dbound is NaN.
+ */
+
+double CHOLMOD(dbound)	/* returns modified diagonal entry of D */
+(
+    /* ---- input ---- */
+    double dj,		/* diagonal entry of D, for LDL' factorization */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double dbound ;
+    RETURN_IF_NULL_COMMON (0) ;
+    if (!IS_NAN (dj))
+    {
+	dbound = Common->dbound ;
+	if (dj < 0)
+	{
+	    if (dj > -dbound)
+	    {
+		dj = -dbound ;
+		Common->ndbounds_hit++ ;
+		if (Common->status == CHOLMOD_OK)
+		{
+		    ERROR (CHOLMOD_DSMALL, "diagonal below threshold") ;
+		}
+	    }
+	}
+	else
+	{
+	    if (dj < dbound)
+	    {
+		dj = dbound ;
+		Common->ndbounds_hit++ ;
+		if (Common->status == CHOLMOD_OK)
+		{
+		    ERROR (CHOLMOD_DSMALL, "diagonal below threshold") ;
+		}
+	    }
+	}
+    }
+    return (dj) ;
+}
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/cholmod_complex.c b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_complex.c
new file mode 100644
index 0000000..8bef584
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_complex.c
@@ -0,0 +1,547 @@
+/* ========================================================================== */
+/* === Core/cholmod_complex ================================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* If you convert a matrix that contains uninitialized data, valgrind will
+ * complain.  This can occur in a factor L which has gaps (a partial
+ * factorization, or after updates that change the nonzero pattern), an
+ * unpacked sparse matrix, a dense matrix with leading dimension d > # of rows,
+ * or any matrix (dense, sparse, triplet, or factor) with more space allocated
+ * than is used.  You can safely ignore any of these complaints by valgrind. */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+/* ========================================================================== */
+/* === cholmod_hypot ======================================================== */
+/* ========================================================================== */
+
+/* There is an equivalent routine called hypot in <math.h>, which conforms
+ * to ANSI C99.  However, CHOLMOD does not assume that ANSI C99 is available.
+ * You can use the ANSI C99 hypot routine with:
+ *
+ *	#include <math.h>
+ *	Common->hypotenuse = hypot ;
+ *
+ * Default value of the Common->hypotenuse pointer is cholmod_hypot.
+ *
+ * s = hypot (x,y) computes s = sqrt (x*x + y*y) but does so more accurately.
+ * The NaN cases for the double relops x >= y and x+y == x are safely ignored.
+ */
+
+double CHOLMOD(hypot) (double x, double y)
+{
+    double s, r ;
+    x = fabs (x) ;
+    y = fabs (y) ;
+    if (x >= y)
+    {
+	if (x + y == x)
+	{
+	    s = x ;
+	}
+	else
+	{
+	    r = y / x ;
+	    s = x * sqrt (1.0 + r*r) ;
+	}
+    }
+    else
+    {
+	if (y + x == y)
+	{
+	    s = y ;
+	}
+	else
+	{
+	    r = x / y ;
+	    s = y * sqrt (1.0 + r*r) ;
+	}
+    } 
+    return (s) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_divcomplex =================================================== */
+/* ========================================================================== */
+
+/* c = a/b where c, a, and b are complex.  The real and imaginary parts are
+ * passed as separate arguments to this routine.  The NaN case is ignored
+ * for the double relop br >= bi.  Returns 1 if the denominator is zero,
+ * 0 otherwise.  Note that this return value is the single exception to the
+ * rule that all CHOLMOD routines that return int return TRUE if successful
+ * or FALSE otherise.
+ *
+ * This uses ACM Algo 116, by R. L. Smith, 1962, which tries to avoid
+ * underflow and overflow.
+ *
+ * c can be the same variable as a or b.
+ *
+ * Default value of the Common->complex_divide pointer is cholmod_divcomplex.
+ */
+
+int CHOLMOD(divcomplex)
+(
+    double ar, double ai,	/* real and imaginary parts of a */
+    double br, double bi,	/* real and imaginary parts of b */
+    double *cr, double *ci	/* real and imaginary parts of c */
+)
+{
+    double tr, ti, r, den ;
+    if (fabs (br) >= fabs (bi))
+    {
+	r = bi / br ;
+	den = br + r * bi ;
+	tr = (ar + ai * r) / den ;
+	ti = (ai - ar * r) / den ;
+    }
+    else
+    {
+	r = br / bi ;
+	den = r * br + bi ;
+	tr = (ar * r + ai) / den ;
+	ti = (ai * r - ar) / den ;
+    }
+    *cr = tr ;
+    *ci = ti ;
+    return (IS_ZERO (den)) ;
+}
+
+
+/* ========================================================================== */
+/* === change_complexity ==================================================== */
+/* ========================================================================== */
+
+/* X and Z represent an array of size nz, with numeric xtype given by xtype_in.
+ *
+ * If xtype_in is:
+ * CHOLMOD_PATTERN: X and Z must be NULL.
+ * CHOLMOD_REAL:    X is of size nz, Z must be NULL.
+ * CHOLMOD_COMPLEX: X is of size 2*nz, Z must be NULL.
+ * CHOLMOD_ZOMPLEX: X is of size nz, Z is of size nz.
+ *
+ * The array is changed into the numeric xtype given by xtype_out, with the
+ * same definitions of X and Z above.  Note that the input conditions, above,
+ * are not checked.  These are checked in the caller routine.
+ *
+ * Returns TRUE if successful, FALSE otherwise.  X and Z are not modified if
+ * not successful.
+ */
+
+static int change_complexity
+(
+    /* ---- input ---- */
+    Int nz,		/* size of X and/or Z */
+    int xtype_in,	/* xtype of X and Z on input */
+    int xtype_out,	/* requested xtype of X and Z on output */
+    int xtype1,		/* xtype_out must be in the range [xtype1 .. xtype2] */
+    int xtype2,
+    /* ---- in/out --- */
+    void **XX,		/* old X on input, new X on output */
+    void **ZZ,		/* old Z on input, new Z on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Xold, *Zold, *Xnew, *Znew ;
+    Int k ;
+    size_t nz2 ;
+
+    if (xtype_out < xtype1 || xtype_out > xtype2)
+    {
+	ERROR (CHOLMOD_INVALID, "invalid xtype") ;
+	return (FALSE) ;
+    }
+
+    Common->status = CHOLMOD_OK ;
+    Xold = *XX ;
+    Zold = *ZZ ;
+
+    switch (xtype_in)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* converting from pattern */
+	/* ------------------------------------------------------------------ */
+
+	case CHOLMOD_PATTERN:
+
+	    switch (xtype_out)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* pattern -> real */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_REAL:
+		    /* allocate X and set to all ones */
+		    Xnew = CHOLMOD(malloc) (nz, sizeof (double), Common) ;
+		    if (Common->status < CHOLMOD_OK)
+		    {
+			return (FALSE) ;
+		    }
+		    for (k = 0 ; k < nz ; k++)
+		    {
+			Xnew [k] = 1 ;
+		    }
+		    *XX = Xnew ;
+		    break ;
+
+		/* ---------------------------------------------------------- */
+		/* pattern -> complex */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_COMPLEX:
+		    /* allocate X and set to all ones */
+		    Xnew = CHOLMOD(malloc) (nz, 2*sizeof (double), Common) ;
+		    if (Common->status < CHOLMOD_OK)
+		    {
+			return (FALSE) ;
+		    }
+		    for (k = 0 ; k < nz ; k++)
+		    {
+			Xnew [2*k  ] = 1 ;
+			Xnew [2*k+1] = 0 ;
+		    }
+		    *XX = Xnew ;
+		    break ;
+
+		/* ---------------------------------------------------------- */
+		/* pattern -> zomplex */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_ZOMPLEX:
+		    /* allocate X and Z and set to all ones */
+		    Xnew = CHOLMOD(malloc) (nz, sizeof (double), Common) ;
+		    Znew = CHOLMOD(malloc) (nz, sizeof (double), Common) ;
+		    if (Common->status < CHOLMOD_OK)
+		    {
+			CHOLMOD(free) (nz, sizeof (double), Xnew, Common) ;
+			CHOLMOD(free) (nz, sizeof (double), Znew, Common) ;
+			return (FALSE) ;
+		    }
+		    for (k = 0 ; k < nz ; k++)
+		    {
+			Xnew [k] = 1 ;
+			Znew [k] = 0 ;
+		    }
+		    *XX = Xnew ;
+		    *ZZ = Znew ;
+		    break ;
+	    }
+	    break ;
+
+	/* ------------------------------------------------------------------ */
+	/* converting from real */
+	/* ------------------------------------------------------------------ */
+
+	case CHOLMOD_REAL:
+
+	    switch (xtype_out)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* real -> pattern */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_PATTERN:
+		    /* free X */
+		    *XX = CHOLMOD(free) (nz, sizeof (double), *XX, Common) ;
+		    break ;
+
+		/* ---------------------------------------------------------- */
+		/* real -> complex */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_COMPLEX:
+		    /* allocate a new X and copy the old X */
+		    Xnew = CHOLMOD(malloc) (nz, 2*sizeof (double), Common) ;
+		    if (Common->status < CHOLMOD_OK)
+		    {
+			return (FALSE) ;
+		    }
+		    for (k = 0 ; k < nz ; k++)
+		    {
+			Xnew [2*k  ] = Xold [k] ;
+			Xnew [2*k+1] = 0 ;
+		    }
+		    CHOLMOD(free) (nz, sizeof (double), *XX, Common) ;
+		    *XX = Xnew ;
+		    break ;
+
+		/* ---------------------------------------------------------- */
+		/* real -> zomplex */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_ZOMPLEX:
+		    /* allocate a new Z and set it to zero */
+		    Znew = CHOLMOD(malloc) (nz, sizeof (double), Common) ;
+		    if (Common->status < CHOLMOD_OK)
+		    {
+			return (FALSE) ;
+		    }
+		    for (k = 0 ; k < nz ; k++)
+		    {
+			Znew [k] = 0 ;
+		    }
+		    *ZZ = Znew ;
+		    break ;
+	    }
+	    break ;
+
+	/* ------------------------------------------------------------------ */
+	/* converting from complex */
+	/* ------------------------------------------------------------------ */
+
+	case CHOLMOD_COMPLEX:
+
+	    switch (xtype_out)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* complex -> pattern */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_PATTERN:
+		    /* free X */
+		    *XX = CHOLMOD(free) (nz, 2*sizeof (double), *XX, Common) ;
+		    break ;
+
+		/* ---------------------------------------------------------- */
+		/* complex -> real */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_REAL:
+		    /* pack the real part of X, discarding the imaginary part */
+		    for (k = 0 ; k < nz ; k++)
+		    {
+			Xold [k] = Xold [2*k] ;
+		    }
+		    /* shrink X in half (this cannot fail) */
+		    nz2 = 2*nz ;
+		    *XX = CHOLMOD(realloc) (nz, sizeof (double), *XX, &nz2,
+			    Common) ;
+		    break ;
+
+		/* ---------------------------------------------------------- */
+		/* complex -> zomplex */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_ZOMPLEX:
+		    /* allocate X and Z and copy the old X into them */
+		    Xnew = CHOLMOD(malloc) (nz, sizeof (double), Common) ;
+		    Znew = CHOLMOD(malloc) (nz, sizeof (double), Common) ;
+		    if (Common->status < CHOLMOD_OK)
+		    {
+			CHOLMOD(free) (nz, sizeof (double), Xnew, Common) ;
+			CHOLMOD(free) (nz, sizeof (double), Znew, Common) ;
+			return (FALSE) ;
+		    }
+		    for (k = 0 ; k < nz ; k++)
+		    {
+			Xnew [k] = Xold [2*k  ] ;
+			Znew [k] = Xold [2*k+1] ;
+		    }
+		    CHOLMOD(free) (nz, 2*sizeof (double), *XX, Common) ;
+		    *XX = Xnew ;
+		    *ZZ = Znew ;
+		    break ;
+	    }
+	    break ;
+
+	/* ------------------------------------------------------------------ */
+	/* converting from zomplex */
+	/* ------------------------------------------------------------------ */
+
+	case CHOLMOD_ZOMPLEX:
+
+	    switch (xtype_out)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* zomplex -> pattern */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_PATTERN:
+		    /* free X and Z */
+		    *XX = CHOLMOD(free) (nz, sizeof (double), *XX, Common) ;
+		    *ZZ = CHOLMOD(free) (nz, sizeof (double), *ZZ, Common) ;
+		    break ;
+
+		/* ---------------------------------------------------------- */
+		/* zomplex -> real */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_REAL:
+		    /* free the imaginary part */
+		    *ZZ = CHOLMOD(free) (nz, sizeof (double), *ZZ, Common) ;
+		    break ;
+
+		/* ---------------------------------------------------------- */
+		/* zomplex -> complex */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_COMPLEX:
+		    Xnew = CHOLMOD(malloc) (nz, 2*sizeof (double), Common) ;
+		    if (Common->status < CHOLMOD_OK)
+		    {
+			return (FALSE) ;
+		    }
+		    for (k = 0 ; k < nz ; k++)
+		    {
+			Xnew [2*k  ] = Xold [k] ;
+			Xnew [2*k+1] = Zold [k] ;
+		    }
+		    CHOLMOD(free) (nz, sizeof (double), *XX, Common) ;
+		    CHOLMOD(free) (nz, sizeof (double), *ZZ, Common) ;
+		    *XX = Xnew ;
+		    *ZZ = NULL ;
+		    break ;
+
+	    }
+	    break ;
+    }
+
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_sparse_xtype ================================================= */
+/* ========================================================================== */
+
+/* Change the numeric xtype of a sparse matrix.  Supports any type on input
+ * and output (pattern, real, complex, or zomplex). */
+
+int CHOLMOD(sparse_xtype)
+(
+    /* ---- input ---- */
+    int to_xtype,	/* requested xtype */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* sparse matrix to change */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int ok ;
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+
+    ok = change_complexity (A->nzmax, A->xtype, to_xtype,
+	    CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, &(A->x), &(A->z), Common) ;
+    if (ok)
+    {
+	A->xtype = to_xtype ;
+    }
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_triplet_xtype ================================================ */
+/* ========================================================================== */
+
+/* Change the numeric xtype of a triplet matrix.  Supports any type on input
+ * and output (pattern, real, complex, or zomplex). */
+
+int CHOLMOD(triplet_xtype)
+(
+    /* ---- input ---- */
+    int to_xtype,	/* requested xtype */
+    /* ---- in/out --- */
+    cholmod_triplet *T,	/* triplet matrix to change */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int ok ;
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (T, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (T, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    ok = change_complexity (T->nzmax, T->xtype, to_xtype,
+	    CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, &(T->x), &(T->z), Common) ;
+    if (ok)
+    {
+	T->xtype = to_xtype ;
+    }
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dense_xtype ================================================= */
+/* ========================================================================== */
+
+/* Change the numeric xtype of a dense matrix.  Supports real, complex or
+ * zomplex on input and output */
+
+int CHOLMOD(dense_xtype)
+(
+    /* ---- input ---- */
+    int to_xtype,	/* requested xtype */
+    /* ---- in/out --- */
+    cholmod_dense *X,	/* dense matrix to change */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int ok ;
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (X, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    ok = change_complexity (X->nzmax, X->xtype, to_xtype,
+	    CHOLMOD_REAL, CHOLMOD_ZOMPLEX, &(X->x), &(X->z), Common) ;
+    if (ok)
+    {
+	X->xtype = to_xtype ;
+    }
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_factor_xtype ================================================= */
+/* ========================================================================== */
+
+/* Change the numeric xtype of a factor.  Supports real, complex or zomplex on
+ * input and output.   Supernodal zomplex factors are not supported. */
+
+int CHOLMOD(factor_xtype)
+(
+    /* ---- input ---- */
+    int to_xtype,	/* requested xtype */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to change */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int ok ;
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (L->is_super &&
+	    (L->xtype == CHOLMOD_ZOMPLEX || to_xtype == CHOLMOD_ZOMPLEX))
+    {
+	ERROR (CHOLMOD_INVALID, "invalid xtype for supernodal L") ;
+	return (FALSE) ;
+    }
+    ok = change_complexity ((L->is_super ? L->xsize : L->nzmax), L->xtype,
+	    to_xtype, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, &(L->x), &(L->z), Common) ;
+    if (ok)
+    {
+	L->xtype = to_xtype ;
+    }
+    return (ok) ;
+}
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/cholmod_copy.c b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_copy.c
new file mode 100644
index 0000000..d4532ad
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_copy.c
@@ -0,0 +1,407 @@
+/* ========================================================================== */
+/* === Core/cholmod_copy ==================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* C = A, which allocates C and copies A into C, with possible change of
+ * stype.  The diagonal can optionally be removed.  The numerical entries
+ * can optionally be copied.  This routine differs from cholmod_copy_sparse,
+ * which makes an exact copy of a sparse matrix.
+ *
+ * A can be of any type (packed/unpacked, upper/lower/unsymmetric).  C is
+ * packed and can be of any stype (upper/lower/unsymmetric), except that if
+ * A is rectangular C can only be unsymmetric.  If the stype of A and C
+ * differ, then the appropriate conversion is made.
+ *
+ * Symmetry of A (A->stype):
+ * <0: lower: assume A is symmetric with just tril(A); the rest of A is ignored
+ *  0  unsym: assume A is unsymmetric; consider all entries in A
+ * >0  upper: assume A is symmetric with just triu(A); the rest of A is ignored
+ *
+ * Symmetry of C (stype parameter):
+ * <0  lower: return just tril(C)
+ *  0  unsym: return all of C
+ * >0  upper: return just triu(C)
+ *
+ * In MATLAB:					    Using cholmod_copy:
+ * ----------					    ----------------------------
+ * C = A ;					    A unsymmetric, C unsymmetric
+ * C = tril (A) ;				    A unsymmetric, C lower
+ * C = triu (A) ;				    A unsymmetric, C upper
+ * U = triu (A) ; L = tril (U',-1) ; C = L+U ;	    A upper, C unsymmetric
+ * C = triu (A)' ;				    A upper, C lower
+ * C = triu (A) ;				    A upper, C upper
+ * L = tril (A) ; U = triu (L',1) ; C = L+U ;	    A lower, C unsymmetric
+ * C = tril (A) ;				    A lower, C lower
+ * C = tril (A)' ;				    A lower, C upper
+ *
+ * workspace: Iwork (max (nrow,ncol))
+ *
+ * A can have an xtype of pattern or real.  Complex and zomplex cases only
+ * supported when mode <= 0 (in which case the numerical values are ignored).
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+
+/* ========================================================================== */
+/* === copy_sym_to_unsym ==================================================== */
+/* ========================================================================== */
+
+/* Construct an unsymmetric copy of a symmetric sparse matrix.  This does the
+ * work for as C = cholmod_copy (A, 0, mode, Common) when A is symmetric.
+ * In this case, extra space can be added to C.
+ */
+
+static cholmod_sparse *copy_sym_to_unsym
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag)
+			 * -2: pattern only, no diagonal, add 50% + n extra
+			 * space to C */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double aij ;
+    double *Ax, *Cx ;
+    Int *Ap, *Ai, *Anz, *Cp, *Ci, *Wj, *Iwork ;
+    cholmod_sparse *C ;
+    Int nrow, ncol, nz, packed, j, p, pend, i, pc, up, lo, values, diag,
+	astype, extra ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+    Ap  = A->p ;
+    Anz = A->nz ;
+    Ai  = A->i ;
+    Ax  = A->x ;
+    packed = A->packed ;
+    values = (mode > 0) && (A->xtype != CHOLMOD_PATTERN) ;
+    diag = (mode >= 0) ;
+
+    astype = SIGN (A->stype) ;
+    up = (astype > 0) ;
+    lo = (astype < 0) ;
+    ASSERT (astype != 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* create an unsymmetric copy of a symmetric matrix */
+    /* ---------------------------------------------------------------------- */
+
+    Iwork = Common->Iwork ;
+    Wj = Iwork ;		    /* size ncol (i/i/l) */
+
+    /* In MATLAB notation, for converting a symmetric/upper matrix:
+     *	U = triu (A) ;
+     *	L = tril (U',-1) ;
+     *	C = L + U ;
+     *
+     * For converting a symmetric/lower matrix to unsymmetric:
+     *	L = tril (A) ;
+     *	U = triu (L',1) ;
+     *	C = L + U ;
+     */
+    ASSERT (up || lo) ;
+    PRINT1 (("copy: convert symmetric to unsym\n")) ;
+
+    /* count the number of entries in each column of C */
+    for (j = 0 ; j < ncol ; j++)
+    {
+	Wj [j] = 0 ;
+    }
+    for (j = 0 ; j < ncol ; j++)
+    {
+	p = Ap [j] ;
+	pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	for ( ; p < pend ; p++)
+	{
+	    i = Ai [p] ;
+	    if (i == j)
+	    {
+		/* the diagonal entry A(i,i) will appear just once
+		 * (unless it is excluded with mode < 0) */
+		if (diag)
+		{
+		    Wj [j]++ ;
+		}
+	    }
+	    else if ((up && i < j) || (lo && i > j))
+	    {
+		/* upper case:  A(i,j) is in the strictly upper part;
+		 * A(j,i) will be added to the strictly lower part of C.
+		 * lower case is the opposite. */
+		Wj [j]++ ;
+		Wj [i]++ ;
+	    }
+	}
+    }
+    nz = 0 ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	nz += Wj [j] ;
+    }
+
+    extra = (mode == -2) ? (nz/2 + ncol) : 0 ;
+
+    /* allocate C.  C is sorted if and only if A is sorted */
+    C = CHOLMOD(allocate_sparse) (nrow, ncol, nz + extra, A->sorted, TRUE, 0,
+	    values ? A->xtype : CHOLMOD_PATTERN, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;
+    }
+
+    Cp = C->p ;
+    Ci = C->i ;
+    Cx = C->x ;
+
+    /* construct the column pointers for C */
+    p = 0 ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	Cp [j] = p ;
+	p += Wj [j] ;
+    }
+    Cp [ncol] = p ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	Wj [j] = Cp [j] ;
+    }
+
+    /* construct C */
+    if (values)
+    {
+
+	/* pattern and values */
+	ASSERT (diag) ;
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		aij = Ax [p] ;
+		if (i == j)
+		{
+		    /* add diagonal entry A(i,i) to column i */
+		    pc = Wj [i]++ ;
+		    Ci [pc] = i ;
+		    Cx [pc] = aij ;
+		}
+		else if ((up && i < j) || (lo && i > j))
+		{
+		    /* add A(i,j) to column j */
+		    pc = Wj [j]++ ;
+		    Ci [pc] = i ;
+		    Cx [pc] = aij ;
+		    /* add A(j,i) to column i */
+		    pc = Wj [i]++ ;
+		    Ci [pc] = j ;
+		    Cx [pc] = aij ;
+		}
+	    }
+	}
+
+    }
+    else
+    {
+
+	/* pattern only, possibly excluding the diagonal */
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		if (i == j)
+		{
+		    /* add diagonal entry A(i,i) to column i
+		     * (unless it is excluded with mode < 0) */
+		    if (diag)
+		    {
+			Ci [Wj [i]++] = i ;
+		    }
+		}
+		else if ((up && i < j) || (lo && i > j))
+		{
+		    /* add A(i,j) to column j */
+		    Ci [Wj [j]++] = i ;
+		    /* add A(j,i) to column i */
+		    Ci [Wj [i]++] = j ;
+		}
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the result */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG (i = CHOLMOD(dump_sparse) (C, "copy_sym_to_unsym", Common)) ;
+    PRINT1 (("mode %d nnzdiag "ID"\n", mode, i)) ;
+    ASSERT (IMPLIES (mode < 0, i == 0)) ;
+    return (C) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_copy ========================================================= */
+/* ========================================================================== */
+
+cholmod_sparse *CHOLMOD(copy)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    int stype,		/* requested stype of C */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag) */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *C ;
+    Int nrow, ncol, up, lo, values, diag, astype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    values = (mode > 0) && (A->xtype != CHOLMOD_PATTERN) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN,
+	    values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ;
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+    if ((stype || A->stype) && nrow != ncol)
+    {
+	/* inputs invalid */
+	ERROR (CHOLMOD_INVALID, "matrix invalid") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(allocate_work) (0, MAX (nrow,ncol), 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    diag = (mode >= 0) ;
+    astype = SIGN (A->stype) ;
+    stype = SIGN (stype) ;
+    up = (astype > 0) ;
+    lo = (astype < 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    if (astype == stype)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* symmetry of A and C are the same */
+	/* ------------------------------------------------------------------ */
+
+	/* copy A into C, keeping the same symmetry.  If A is symmetric
+	 * entries in the ignored part of A are not copied into C */
+	C = CHOLMOD(band) (A, -nrow, ncol, mode, Common) ;
+
+    }
+    else if (!astype)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* convert unsymmetric matrix A into a symmetric matrix C */
+	/* ------------------------------------------------------------------ */
+
+	if (stype > 0)
+	{
+	    /* C = triu (A) */
+	    C = CHOLMOD(band) (A, 0, ncol, mode, Common) ;
+	}
+	else
+	{
+	    /* C = tril (A) */
+	    C = CHOLMOD(band) (A, -nrow, 0, mode, Common) ;
+	}
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+	    return (NULL) ;
+	}
+	C->stype = stype ;
+
+    }
+    else if (astype == -stype)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* transpose a symmetric matrix */
+	/* ------------------------------------------------------------------ */
+
+	/* converting upper to lower or lower to upper */
+	/* workspace: Iwork (nrow) */
+	C = CHOLMOD(transpose) (A, values, Common) ;
+	if (!diag)
+	{
+	    /* remove diagonal, if requested */
+	    CHOLMOD(band_inplace) (-nrow, ncol, -1, C, Common) ;
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* create an unsymmetric copy of a symmetric matrix */
+	/* ------------------------------------------------------------------ */
+
+	C = copy_sym_to_unsym (A, mode, Common) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return if error */
+    /* ---------------------------------------------------------------------- */
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the result */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG (diag = CHOLMOD(dump_sparse) (C, "copy", Common)) ;
+    PRINT1 (("mode %d nnzdiag "ID"\n", mode, diag)) ;
+    ASSERT (IMPLIES (mode < 0, diag == 0)) ;
+    return (C) ;
+}
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/cholmod_dense.c b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_dense.c
new file mode 100644
index 0000000..57cb6de
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_dense.c
@@ -0,0 +1,640 @@
+/* ========================================================================== */
+/* === Core/cholmod_dense =================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Core utility routines for the cholmod_dense object:
+ *
+ * The solve routines and some of the MatrixOps and Modify routines use dense
+ * matrices as inputs.  These are held in column-major order.  With a leading
+ * dimension of d, the entry in row i and column j is held in x [i+j*d].
+ *
+ * Primary routines:
+ * -----------------
+ * cholmod_allocate_dense	allocate a dense matrix
+ * cholmod_free_dense		free a dense matrix
+ *
+ * Secondary routines:
+ * -------------------
+ * cholmod_zeros		allocate a dense matrix of all zeros
+ * cholmod_ones			allocate a dense matrix of all ones
+ * cholmod_eye			allocate a dense identity matrix 
+ * cholmod_sparse_to_dense	create a dense matrix copy of a sparse matrix
+ * cholmod_dense_to_sparse	create a sparse matrix copy of a dense matrix
+ * cholmod_copy_dense		create a copy of a dense matrix
+ * cholmod_copy_dense2		copy a dense matrix (pre-allocated)
+ *
+ * All routines in this file can handle the real, complex, and zomplex cases.
+ * Pattern-only dense matrices are not supported.  cholmod_sparse_to_dense can
+ * take a pattern-only input sparse matrix, however, and cholmod_dense_to_sparse
+ * can generate a pattern-only output sparse matrix.
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+/* ========================================================================== */
+/* === TEMPLATE ============================================================= */
+/* ========================================================================== */
+
+#define PATTERN
+#include "t_cholmod_dense.c"
+#define REAL
+#include "t_cholmod_dense.c"
+#define COMPLEX
+#include "t_cholmod_dense.c"
+#define ZOMPLEX
+#include "t_cholmod_dense.c"
+
+
+/* ========================================================================== */
+/* === cholmod_allocate_dense =============================================== */
+/* ========================================================================== */
+
+/* Allocate a dense matrix with leading dimension d.  The space is not
+ * initialized.
+ */
+
+cholmod_dense *CHOLMOD(allocate_dense)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    size_t d,		/* leading dimension */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *X ;
+    size_t nzmax, nzmax0 ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    if (d < nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "leading dimension invalid") ;
+	return (NULL) ;
+    }
+    if (xtype < CHOLMOD_REAL || xtype > CHOLMOD_ZOMPLEX)
+    {
+	ERROR (CHOLMOD_INVALID, "xtype invalid") ;
+	return (NULL) ;
+    }
+
+    /* ensure the dimensions do not cause integer overflow */
+    (void) CHOLMOD(add_size_t) (ncol, 2, &ok) ;
+
+    /* nzmax = MAX (1, d*ncol) ; */
+    nzmax = CHOLMOD(mult_size_t) (d, ncol, &ok) ;
+    nzmax = MAX (1, nzmax) ;
+
+    if (!ok || nrow > Int_max || ncol > Int_max || nzmax > Int_max)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate header */
+    /* ---------------------------------------------------------------------- */
+
+    X = CHOLMOD(malloc) (sizeof (cholmod_dense), 1, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    PRINT1 (("cholmod_allocate_dense %d-by-%d nzmax %d xtype %d\n",
+		nrow, ncol, nzmax, xtype)) ;
+
+    X->nrow = nrow ;
+    X->ncol = ncol ;
+    X->nzmax = nzmax ;
+    X->xtype = xtype ;
+    X->dtype = DTYPE ;
+    X->x = NULL ;
+    X->z = NULL ;
+    X->d = d ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the matrix itself */
+    /* ---------------------------------------------------------------------- */
+
+    nzmax0 = 0 ;
+    CHOLMOD(realloc_multiple) (nzmax, 0, xtype, NULL, NULL, &(X->x), &(X->z),
+	    &nzmax0, Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free_dense) (&X, Common) ;
+	return (NULL) ;	    /* out of memory */
+    }
+
+    return (X) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_zeros ======================================================== */
+/* ========================================================================== */
+
+/* Allocate a dense matrix and set it to zero */
+
+cholmod_dense *CHOLMOD(zeros)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *X ;
+    double *Xx, *Xz ;
+    Int i, nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate a dense matrix and set it to zero */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    X = CHOLMOD(allocate_dense) (nrow, ncol, nrow, xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* NULL Common, out of memory, or inputs invalid */
+    }
+
+    Xx = X->x ;
+    Xz = X->z ;
+    nz = MAX (1, X->nzmax) ;
+
+    switch (xtype)
+    {
+	case CHOLMOD_REAL:
+	    for (i = 0 ; i < nz ; i++)
+	    {
+		Xx [i] = 0 ;
+	    }
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    for (i = 0 ; i < 2*nz ; i++)
+	    {
+		Xx [i] = 0 ;
+	    }
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    for (i = 0 ; i < nz ; i++)
+	    {
+		Xx [i] = 0 ;
+	    }
+	    for (i = 0 ; i < nz ; i++)
+	    {
+		Xz [i] = 0 ;
+	    }
+	    break ;
+    }
+
+    return (X) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_ones ========================================================= */
+/* ========================================================================== */
+
+/* Allocate a dense matrix and set it to zero */
+
+cholmod_dense *CHOLMOD(ones)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *X ;
+    double *Xx, *Xz ;
+    Int i, nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate a dense matrix and set it to all ones */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    X = CHOLMOD(allocate_dense) (nrow, ncol, nrow, xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* NULL Common, out of memory, or inputs invalid */
+    }
+
+    Xx = X->x ;
+    Xz = X->z ;
+    nz = MAX (1, X->nzmax) ;
+
+    switch (xtype)
+    {
+	case CHOLMOD_REAL:
+	    for (i = 0 ; i < nz ; i++)
+	    {
+		Xx [i] = 1 ;
+	    }
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    for (i = 0 ; i < nz ; i++)
+	    {
+		Xx [2*i  ] = 1 ;
+		Xx [2*i+1] = 0 ;
+	    }
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    for (i = 0 ; i < nz ; i++)
+	    {
+		Xx [i] = 1 ;
+	    }
+	    for (i = 0 ; i < nz ; i++)
+	    {
+		Xz [i] = 0 ;
+	    }
+	    break ;
+    }
+
+    return (X) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_eye ========================================================== */
+/* ========================================================================== */
+
+/* Allocate a dense matrix and set it to the identity matrix */
+
+cholmod_dense *CHOLMOD(eye)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *X ;
+    double *Xx, *Xz ;
+    Int i, n, nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate a dense matrix and set it to the identity matrix */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    X = CHOLMOD(zeros) (nrow, ncol, xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* NULL Common, out of memory, or inputs invalid */
+    }
+
+    nz = MAX (1, nrow*ncol) ;
+    Xx = X->x ;
+    Xz = X->z ;
+
+    n = MIN (nrow, ncol) ;
+
+    switch (xtype)
+    {
+	case CHOLMOD_REAL:
+	case CHOLMOD_ZOMPLEX:
+	    for (i = 0 ; i < n ; i++)
+	    {
+		Xx [i + i*nrow] = 1 ;
+	    }
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    for (i = 0 ; i < n ; i++)
+	    {
+		Xx [2 * (i + i*nrow)] = 1 ;
+	    }
+	    break ;
+    }
+
+    return (X) ;
+}
+
+/* ========================================================================== */
+/* === cholmod_free_dense =================================================== */
+/* ========================================================================== */
+
+/* free a dense matrix
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(free_dense)
+(
+    /* ---- in/out --- */
+    cholmod_dense **XHandle,	/* dense matrix to deallocate, NULL on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *X ;
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+
+    if (XHandle == NULL)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+    X = *XHandle ;
+    if (X == NULL)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+
+    switch (X->xtype)
+    {
+	case CHOLMOD_REAL:
+	    X->x = CHOLMOD(free) (X->nzmax, sizeof (double), X->x, Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    X->x = CHOLMOD(free) (X->nzmax, 2*sizeof (double), X->x, Common) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    X->x = CHOLMOD(free) (X->nzmax, sizeof (double), X->x, Common) ;
+	    X->z = CHOLMOD(free) (X->nzmax, sizeof (double), X->z, Common) ;
+	    break ;
+    }
+
+    *XHandle = CHOLMOD(free) (1, sizeof (cholmod_dense), (*XHandle), Common) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_sparse_to_dense ============================================== */
+/* ========================================================================== */
+
+/* Convert a sparse matrix to a dense matrix.
+ * The output dense matrix has the same xtype as the input sparse matrix,
+ * except that a pattern-only sparse matrix A is converted into a real dense
+ * matrix X, with 1's and 0's.  All xtypes are supported.
+ */
+
+cholmod_dense *CHOLMOD(sparse_to_dense)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *X = NULL ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ;
+    if (A->stype && A->nrow != A->ncol)
+    {
+	ERROR (CHOLMOD_INVALID, "matrix invalid") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+    ASSERT (CHOLMOD(dump_sparse) (A, "A", Common) >= 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert the matrix, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (A->xtype)
+    {
+	case CHOLMOD_PATTERN:
+	    X = p_cholmod_sparse_to_dense (A, Common) ;
+	    break ;
+
+	case CHOLMOD_REAL:
+	    X = r_cholmod_sparse_to_dense (A, Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    X = c_cholmod_sparse_to_dense (A, Common) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    X = z_cholmod_sparse_to_dense (A, Common) ;
+	    break ;
+    }
+    return (X) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dense_to_sparse ============================================== */
+/* ========================================================================== */
+
+/* Convert a dense matrix to a sparse matrix, similar to the MATLAB statements:
+ *
+ * C = sparse (X)			values = TRUE
+ * C = spones (sparse (X))		values = FALSE
+ *
+ * except that X must be double (it can be of many different types in MATLAB)
+ *
+ * The resulting sparse matrix C has the same numeric xtype as the input dense
+ * matrix X, unless "values" is FALSE (in which case C is real, where C(i,j)=1
+ * if (i,j) is an entry in X.
+ */
+
+cholmod_sparse *CHOLMOD(dense_to_sparse)
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to copy */
+    int values,		/* TRUE if values to be copied, FALSE otherwise */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *C = NULL ;
+
+    DEBUG (CHOLMOD(dump_dense) (X, "X", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (X, NULL) ;
+    RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ;
+    if (X->d < X->nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "matrix invalid") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert the matrix, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (X->xtype)
+    {
+	case CHOLMOD_REAL:
+	    C = r_cholmod_dense_to_sparse (X, values, Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    C = c_cholmod_dense_to_sparse (X, values, Common) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    C = z_cholmod_dense_to_sparse (X, values, Common) ;
+	    break ;
+    }
+    return (C) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_copy_dense2 ================================================== */
+/* ========================================================================== */
+
+/* Y = X, where X and Y are both already allocated.  The leading dimensions of
+ * X and Y may differ, but both must be >= the # of rows in X and Y.
+ * Entries in rows nrow to d-1 are not copied from X, since the space might not
+ * be initialized.  Y->nzmax is unchanged.  X->nzmax is typically
+ * (X->d)*(X->ncol), but a user might modify that condition outside of any
+ * CHOLMOD routine.
+ *
+ * The two dense matrices X and Y must have the same numeric xtype.
+ */
+
+int CHOLMOD(copy_dense2)
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to copy */
+    /* ---- output --- */
+    cholmod_dense *Y,	/* copy of matrix X */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (X, FALSE) ;
+    RETURN_IF_NULL (Y, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (Y, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (X->nrow != Y->nrow || X->ncol != Y->ncol || X->xtype != Y->xtype)
+    {
+	ERROR (CHOLMOD_INVALID, "X and Y must have same dimensions and xtype") ;
+	return (FALSE) ;
+    }
+    if (X->d < X->nrow || Y->d < Y->nrow
+	    || (X->d * X->ncol) > X->nzmax || (Y->d * Y->ncol) > Y->nzmax)
+    {
+	ERROR (CHOLMOD_INVALID, "X and/or Y invalid") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy the matrix, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (X->xtype)
+    {
+	case CHOLMOD_REAL:
+	    r_cholmod_copy_dense2 (X, Y) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    c_cholmod_copy_dense2 (X, Y) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    z_cholmod_copy_dense2 (X, Y) ;
+	    break ;
+    }
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_copy_dense =================================================== */
+/* ========================================================================== */
+
+/* Y = X, copy a dense matrix */
+
+cholmod_dense *CHOLMOD(copy_dense)
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *Y ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (X, NULL) ;
+    RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate result */
+    /* ---------------------------------------------------------------------- */
+
+    Y = CHOLMOD(allocate_dense) (X->nrow, X->ncol, X->d, X->xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory or X invalid */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* Y = X */
+    /* ---------------------------------------------------------------------- */
+
+    /* This cannot fail (X and Y are allocated, and have the same nrow, ncol
+     * d, and xtype) */
+    CHOLMOD(copy_dense2) (X, Y, Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* return result */
+    /* ---------------------------------------------------------------------- */
+
+    return (Y) ;
+}
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/cholmod_error.c b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_error.c
new file mode 100644
index 0000000..b1e5d4c
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_error.c
@@ -0,0 +1,80 @@
+/* ========================================================================== */
+/* === Core/cholmod_error =================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD error-handling routine.  */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+/* ========================================================================== */
+/* ==== cholmod_error ======================================================= */
+/* ========================================================================== */
+
+/* An error has occurred.  Set the status, optionally print an error message,
+ * and call the user error-handling routine (if it exists).  If
+ * Common->try_catch is TRUE, then CHOLMOD is inside a try/catch block.
+ * The status is set, but no message is printed and the user error handler
+ * is not called.  This is not (yet) an error, since CHOLMOD may recover.
+ *
+ * In the current version, this try/catch mechanism is used internally only in
+ * cholmod_analyze, which tries multiple ordering methods and picks the best
+ * one.  If one or more ordering method fails, it keeps going.  Only one
+ * ordering needs to succeed for cholmod_analyze to succeed.
+ */
+
+int CHOLMOD(error)
+(
+    /* ---- input ---- */
+    int status,		/* error status */
+    char *file,		/* name of source code file where error occured */ 
+    int line,		/* line number in source code file where error occured*/
+    char *message,	/* error message */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+
+    Common->status = status ;
+
+    if (!(Common->try_catch))
+    {
+
+#ifndef NPRINT
+	/* print a warning or error message */
+	if (Common->print_function != NULL)
+	{
+	    if (status > 0 && Common->print > 1)
+	    {
+		(Common->print_function) ("CHOLMOD warning: %s\n", message) ;
+		fflush (stdout) ;
+		fflush (stderr) ;
+	    }
+	    else if (Common->print > 0)
+	    {
+		(Common->print_function) ("CHOLMOD error: %s\n", message) ;
+		fflush (stdout) ;
+		fflush (stderr) ;
+	    }
+	}
+#endif
+
+	/* call the user error handler, if it exists */
+	if (Common->error_handler != NULL)
+	{
+	    Common->error_handler (status, file, line, message) ;
+	}
+    }
+
+    return (TRUE) ;
+}
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/cholmod_factor.c b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_factor.c
new file mode 100644
index 0000000..8af9b38
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_factor.c
@@ -0,0 +1,935 @@
+/* ========================================================================== */
+/* === Core/cholmod_factor ================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Core utility routines for the cholmod_factor object:
+ *
+ * The data structure for an LL' or LDL' factorization is too complex to
+ * describe in one sentence.  This object can hold the symbolic analysis alone,
+ * or in combination with a "simplicial" (similar to a sparse matrix) or
+ * "supernodal" form of the numerical factorization.  Only the routine to free
+ * a factor is primary, since a factor object is created by the factorization
+ * routine (cholmod_factorize).  It must be freed with cholmod_free_factor.
+ *
+ * Primary routine:
+ * ----------------
+ * cholmod_free_factor		free a factor
+ *
+ * Secondary routines:
+ * -------------------
+ * cholmod_allocate_factor	allocate a symbolic factor (LL' or LDL')
+ * cholmod_reallocate_factor	change the # entries in a factor 
+ * cholmod_change_factor	change the type of factor (e.g., LDL' to LL')
+ * cholmod_pack_factor		pack the columns of a factor
+ * cholmod_reallocate_column	resize a single column of a factor
+ * cholmod_factor_to_sparse	create a sparse matrix copy of a factor
+ * cholmod_copy_factor		create a copy of a factor
+ *
+ * Note that there is no cholmod_sparse_to_factor routine to create a factor
+ * as a copy of a sparse matrix.  It could be done, after a fashion, but a
+ * lower triangular sparse matrix would not necessarily have a chordal graph,
+ * which would break the many CHOLMOD routines that rely on this property.
+ *
+ * The cholmod_factor_to_sparse routine is provided so that matrix operations
+ * in the MatrixOps module may be applied to L.  Those operations operate on
+ * cholmod_sparse objects, and they are not guaranteed to maintain the chordal
+ * property of L.  Such a modified L cannot be safely converted back to a
+ * cholmod_factor object.
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+
+/* ========================================================================== */
+/* === cholmod_allocate_factor ============================================== */
+/* ========================================================================== */
+
+/* Allocate a simplicial symbolic factor, with L->Perm and L->ColCount allocated
+ * and initialized to "empty" values (Perm [k] = k, and ColCount[k] = 1).
+ * The integer and numerical parts of L are not allocated.  L->xtype is returned
+ * as CHOLMOD_PATTERN and L->is_super are returned as FALSE.  L->is_ll is also
+ * returned FALSE, but this may be modified when the matrix is factorized.
+ *
+ * This is sufficient (but far from ideal) for input to cholmod_factorize,
+ * since the simplicial LL' or LDL' factorization (cholmod_rowfac) can
+ * reallocate the columns of L as needed.  The primary purpose of this routine
+ * is to allocate space for a symbolic factorization, for the "expert" user to
+ * do his or her own symbolic analysis.  The typical user should use
+ * cholmod_analyze instead of this routine.
+ *
+ * workspace: none
+ */
+
+cholmod_factor *CHOLMOD(allocate_factor)
+(
+    /* ---- input ---- */
+    size_t n,		/* L is n-by-n */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int j ;
+    Int *Perm, *ColCount ;
+    cholmod_factor *L ;
+    int ok = TRUE ;
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ensure the dimension does not cause integer overflow */
+    (void) CHOLMOD(add_size_t) (n, 2, &ok) ;
+    if (!ok || n > Int_max)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (NULL) ;
+    }
+
+    L = CHOLMOD(malloc) (sizeof (cholmod_factor), 1, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+    L->n = n ;
+    L->is_ll = FALSE ;
+    L->is_super = FALSE ;
+    L->is_monotonic = TRUE ;
+    L->itype = ITYPE ;
+    L->xtype = CHOLMOD_PATTERN ;
+    L->dtype = DTYPE ;
+
+    /* allocate the purely symbolic part of L */
+    L->ordering = CHOLMOD_NATURAL ;
+    L->Perm = CHOLMOD(malloc) (n, sizeof (Int), Common) ;
+    L->ColCount = CHOLMOD(malloc) (n, sizeof (Int), Common) ;
+
+    /* simplicial part of L is empty */
+    L->nzmax = 0 ;
+    L->p = NULL ;
+    L->i = NULL ;
+    L->x = NULL ;
+    L->z = NULL ;
+    L->nz = NULL ;
+    L->next = NULL ;
+    L->prev = NULL ;
+
+    /* supernodal part of L is also empty */
+    L->nsuper = 0 ;
+    L->ssize = 0 ;
+    L->xsize = 0 ;
+    L->maxesize = 0 ;
+    L->maxcsize = 0 ;
+    L->super = NULL ;
+    L->pi = NULL ;
+    L->px = NULL ;
+    L->s = NULL ;
+
+    /* L has not been factorized */
+    L->minor = n ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free_factor) (&L, Common) ;
+	return (NULL) ;		/* out of memory */
+    }
+
+    /* initialize Perm and ColCount */
+    Perm = L->Perm ;
+    for (j = 0 ; j < ((Int) n) ; j++)
+    {
+	Perm [j] = j ;
+    }
+    ColCount = L->ColCount ;
+    for (j = 0 ; j < ((Int) n) ; j++)
+    {
+	ColCount [j] = 1 ;
+    }
+
+    return (L) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_free_factor ================================================== */
+/* ========================================================================== */
+
+/* Free a factor object.
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(free_factor)
+(
+    /* ---- in/out --- */
+    cholmod_factor **LHandle,	/* factor to free, NULL on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int n, lnz, xs, ss, s ;
+    cholmod_factor *L ;
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+
+    if (LHandle == NULL)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+    L = *LHandle ;
+    if (L == NULL)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+
+    n = L->n ;
+    lnz = L->nzmax ;
+    s = L->nsuper + 1 ;
+    xs = (L->is_super) ? ((Int) (L->xsize)) : (lnz) ;
+    ss = L->ssize ;
+
+    /* symbolic part of L */
+    CHOLMOD(free) (n,   sizeof (Int), L->Perm,     Common) ;
+    CHOLMOD(free) (n,   sizeof (Int), L->ColCount, Common) ;
+
+    /* simplicial form of L */
+    CHOLMOD(free) (n+1, sizeof (Int), L->p,        Common) ;
+    CHOLMOD(free) (lnz, sizeof (Int), L->i,        Common) ;
+    CHOLMOD(free) (n,   sizeof (Int), L->nz,       Common) ;
+    CHOLMOD(free) (n+2, sizeof (Int), L->next,     Common) ;
+    CHOLMOD(free) (n+2, sizeof (Int), L->prev,     Common) ;
+
+    /* supernodal form of L */
+    CHOLMOD(free) (s,   sizeof (Int), L->pi,       Common) ;
+    CHOLMOD(free) (s,   sizeof (Int), L->px,       Common) ;
+    CHOLMOD(free) (s,   sizeof (Int), L->super,    Common) ;
+    CHOLMOD(free) (ss,  sizeof (Int), L->s,        Common) ;
+
+    /* numerical values for both simplicial and supernodal L */
+    if (L->xtype == CHOLMOD_REAL)
+    {
+	CHOLMOD(free) (xs, sizeof (double), L->x, Common) ;
+    }
+    else if (L->xtype == CHOLMOD_COMPLEX)
+    {
+	CHOLMOD(free) (xs, 2*sizeof (double), L->x, Common) ;
+    }
+    else if (L->xtype == CHOLMOD_ZOMPLEX)
+    {
+	CHOLMOD(free) (xs, sizeof (double), L->x, Common) ;
+	CHOLMOD(free) (xs, sizeof (double), L->z, Common) ;
+    }
+
+    *LHandle = CHOLMOD(free) (1, sizeof (cholmod_factor), (*LHandle), Common) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_reallocate_factor ============================================ */
+/* ========================================================================== */
+
+/* Change the size of L->i and L->x, or allocate them if their current size
+ * is zero.  L must be simplicial.
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(reallocate_factor)
+(
+    /* ---- input ---- */
+    size_t nznew,	/* new # of entries in L */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    PRINT1 (("realloc factor: xtype %d\n", L->xtype)) ;
+    if (L->is_super)
+    {
+	/* L must be simplicial, and not symbolic */
+	ERROR (CHOLMOD_INVALID, "L invalid") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+    PRINT1 (("realloc factor %g to %g\n", (double) L->nzmax, (double) nznew)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* resize (or allocate) the L->i and L->x components of the factor */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(realloc_multiple) (nznew, 1, L->xtype, &(L->i), NULL,
+	    &(L->x), &(L->z), &(L->nzmax), Common) ;
+    return (Common->status == CHOLMOD_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_reallocate_column =========================================== */
+/* ========================================================================== */
+
+/* Column j needs more space, reallocate it at the end of L->i and L->x.
+ * If the reallocation fails, the factor is converted to a simplicial
+ * symbolic factor (no pattern, just L->Perm and L->ColCount).
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(reallocate_column)
+(
+    /* ---- input ---- */
+    size_t j,		/* the column to reallocate */
+    size_t need,	/* required size of column j */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double xneed ;
+    double *Lx, *Lz ;
+    Int *Lp, *Lprev, *Lnext, *Li, *Lnz ;
+    Int n, pold, pnew, len, k, tail ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (L->is_super)
+    {
+	ERROR (CHOLMOD_INVALID, "L must be simplicial") ;
+	return (FALSE) ;
+    }
+    n = L->n ;
+    if (j >= L->n || need == 0)
+    {
+	ERROR (CHOLMOD_INVALID, "j invalid") ;
+	return (FALSE) ;	    /* j out of range */
+    }
+    Common->status = CHOLMOD_OK ;
+
+    DEBUG (CHOLMOD(dump_factor) (L, "start colrealloc", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* increase the size of L if needed */
+    /* ---------------------------------------------------------------------- */
+
+    /* head = n+1 ; */
+    tail = n ;
+    Lp = L->p ;
+    Lnz = L->nz ;
+    Lprev = L->prev ;
+    Lnext = L->next ;
+
+    ASSERT (Lnz != NULL) ;
+    ASSERT (Lnext != NULL && Lprev != NULL) ;
+    PRINT1 (("col %g need %g\n", (double) j, (double) need)) ;
+
+    /* column j cannot have more than n-j entries if all entries are present */
+    need = MIN (need, n-j) ;
+
+    /* compute need in double to avoid integer overflow */
+    if (Common->grow1 >= 1.0)
+    {
+	xneed = (double) need ;
+	xneed = Common->grow1 * xneed + Common->grow2 ;
+	xneed = MIN (xneed, n-j) ;
+	need = (Int) xneed ;
+    }
+    PRINT1 (("really new need %g current %g\n", (double) need,
+	    (double) (Lp [Lnext [j]] - Lp [j]))) ;
+    ASSERT (need >= 1 && need <= n-j) ;
+
+    if (Lp [Lnext [j]] - Lp [j] >= (Int) need)
+    {
+	/* no need to reallocate the column, it's already big enough */
+	PRINT1 (("colrealloc: quick return %g %g\n",
+	    (double) (Lp [Lnext [j]] - Lp [j]), (double) need)) ;
+	return (TRUE) ;
+
+    }
+
+    if (Lp [tail] + need > L->nzmax)
+    {
+	/* use double to avoid integer overflow */
+	xneed = (double) need ;
+	if (Common->grow0 < 1.2)	    /* fl. pt. compare, false if NaN */
+	{
+	    /* if grow0 is less than 1.2 or NaN, don't use it */
+	    xneed = 1.2 * (((double) L->nzmax) + xneed + 1) ;
+	}
+	else
+	{
+	    xneed = Common->grow0 * (((double) L->nzmax) + xneed + 1) ;
+	}
+	if (xneed > Size_max ||
+		!CHOLMOD(reallocate_factor) ((Int) xneed, L, Common))
+	{
+	    /* out of memory, convert to simplicial symbolic */
+	    CHOLMOD(change_factor) (CHOLMOD_PATTERN, L->is_ll, FALSE, TRUE,
+		    TRUE, L, Common) ;
+	    ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory; L now symbolic") ;
+	    return (FALSE) ;	    /* out of memory */
+	}
+	PRINT1 (("\n=== GROW L from %g to %g\n",
+		    (double) L->nzmax, (double) xneed)) ;
+	/* pack all columns so that each column has at most grow2 free space */
+	CHOLMOD(pack_factor) (L, Common) ;
+	ASSERT (Common->status == CHOLMOD_OK) ;
+	Common->nrealloc_factor++ ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* reallocate the column */
+    /* ---------------------------------------------------------------------- */
+
+    Common->nrealloc_col++ ;
+
+    Li = L->i ;
+    Lx = L->x ;
+    Lz = L->z ;
+
+    /* remove j from its current position in the list */
+    Lnext [Lprev [j]] = Lnext [j] ;
+    Lprev [Lnext [j]] = Lprev [j] ;
+
+    /* place j at the end of the list */
+    Lnext [Lprev [tail]] = j ;
+    Lprev [j] = Lprev [tail] ;
+    Lnext [j] = n ;
+    Lprev [tail] = j ;
+
+    /* L is no longer monotonic; columns are out-of-order */
+    L->is_monotonic = FALSE ;
+
+    /* allocate space for column j */
+    pold = Lp [j] ;
+    pnew = Lp [tail] ;
+    Lp [j] = pnew  ;
+    Lp [tail] += need ;
+
+    /* copy column j to the new space */
+    len = Lnz [j] ;
+    for (k = 0 ; k < len ; k++)
+    {
+	Li [pnew + k] = Li [pold + k] ;
+    }
+
+    if (L->xtype == CHOLMOD_REAL)
+    {
+	for (k = 0 ; k < len ; k++)
+	{
+	    Lx [pnew + k] = Lx [pold + k] ;
+	}
+    }
+    else if (L->xtype == CHOLMOD_COMPLEX)
+    {
+	for (k = 0 ; k < len ; k++)
+	{
+	    Lx [2*(pnew + k)  ] = Lx [2*(pold + k)  ] ;
+	    Lx [2*(pnew + k)+1] = Lx [2*(pold + k)+1] ;
+	}
+    }
+    else if (L->xtype == CHOLMOD_ZOMPLEX)
+    {
+	for (k = 0 ; k < len ; k++)
+	{
+	    Lx [pnew + k] = Lx [pold + k] ;
+	    Lz [pnew + k] = Lz [pold + k] ;
+	}
+    }
+
+    DEBUG (CHOLMOD(dump_factor) (L, "colrealloc done", Common)) ;
+
+    /* successful reallocation of column j of L */
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_pack_factor ================================================== */
+/* ========================================================================== */
+
+/* Pack the columns of a simplicial LDL' or LL' factor.  This can be followed
+ * by a call to cholmod_reallocate_factor to reduce the size of L to the exact
+ * size required by the factor, if desired.  Alternatively, you can leave the
+ * size of L->i and L->x the same, to allow space for future updates/rowadds.
+ *
+ * Each column is reduced in size so that it has at most Common->grow2 free
+ * space at the end of the column.
+ *
+ * Does nothing and returns silently if given any other type of factor.
+ *
+ * Does NOT force the columns of L to be monotonic.  It thus differs from
+ * cholmod_change_factor (xtype, -, FALSE, TRUE, TRUE, L, Common), which
+ * packs the columns and ensures that they appear in monotonic order.
+ */
+
+int CHOLMOD(pack_factor)
+(
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Lx, *Lz ;
+    Int *Lp, *Li, *Lnz, *Lnext ;
+    Int pnew, j, k, pold, len, n, head, tail, grow2 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    DEBUG (CHOLMOD(dump_factor) (L, "start pack", Common)) ;
+    PRINT1 (("PACK factor %d\n", L->is_super)) ;
+
+    if (L->xtype == CHOLMOD_PATTERN || L->is_super)
+    {
+	/* nothing to do unless L is simplicial numeric */
+	return (TRUE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* pack */
+    /* ---------------------------------------------------------------------- */
+
+    grow2 = Common->grow2 ;
+    PRINT1 (("\nPACK grow2 "ID"\n", grow2)) ;
+
+    pnew = 0 ;
+    n = L->n ;
+    Lp = L->p ;
+    Li = L->i ;
+    Lx = L->x ;
+    Lz = L->z ;
+    Lnz = L->nz ;
+    Lnext = L->next ;
+
+    head = n+1 ;
+    tail = n ;
+
+    for (j = Lnext [head] ; j != tail ; j = Lnext [j])
+    {
+	/* pack column j */
+	pold = Lp [j] ;
+	len = Lnz [j] ;
+	ASSERT (len > 0) ;
+	PRINT2 (("col "ID" pnew "ID" pold "ID"\n", j, pnew, pold)) ;
+	if (pnew < pold)
+	{
+	    PRINT2 (("    pack this column\n")) ;
+
+	    for (k = 0 ; k < len ; k++)
+	    {
+		Li [pnew + k] = Li [pold + k] ;
+	    }
+
+	    if (L->xtype == CHOLMOD_REAL)
+	    {
+		for (k = 0 ; k < len ; k++)
+		{
+		    Lx [pnew + k] = Lx [pold + k] ;
+		}
+	    }
+	    else if (L->xtype == CHOLMOD_COMPLEX)
+	    {
+		for (k = 0 ; k < len ; k++)
+		{
+		    Lx [2*(pnew + k)  ] = Lx [2*(pold + k)  ] ;
+		    Lx [2*(pnew + k)+1] = Lx [2*(pold + k)+1] ;
+		}
+	    }
+	    else if (L->xtype == CHOLMOD_ZOMPLEX)
+	    {
+		for (k = 0 ; k < len ; k++)
+		{
+		    Lx [pnew + k] = Lx [pold + k] ;
+		    Lz [pnew + k] = Lz [pold + k] ;
+		}
+	    }
+
+	    Lp [j] = pnew ;
+	}
+	len = MIN (len + grow2, n - j) ;
+	pnew = MIN (Lp [j] + len, Lp [Lnext [j]]) ;
+    }
+    PRINT2 (("final pnew = "ID"\n", pnew)) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_factor_to_sparse ============================================= */
+/* ========================================================================== */
+
+/* Constructs a column-oriented sparse matrix containing the pattern and values
+ * of a simplicial or supernodal numerical factor, and then converts the factor
+ * into a simplicial symbolic factor.  If L is already packed, monotonic,
+ * and simplicial (which is the case when cholmod_factorize uses the simplicial
+ * Cholesky factorization algorithm) then this routine requires only O(1)
+ * memory and takes O(1) time.
+ *
+ * Only operates on numeric factors (real, complex, or zomplex).  Does not
+ * change the numeric L->xtype (the resulting sparse matrix has the same xtype
+ * as L).  If this routine fails, L is left unmodified.
+ */
+
+cholmod_sparse *CHOLMOD(factor_to_sparse)
+(
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to copy, converted to symbolic on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *Lsparse ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (L, NULL) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ;
+    Common->status = CHOLMOD_OK ;
+    DEBUG (CHOLMOD(dump_factor) (L, "start convert to matrix", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert to packed, monotonic, simplicial, numeric */
+    /* ---------------------------------------------------------------------- */
+
+    /* leave as LL or LDL' */
+    if (!CHOLMOD(change_factor) (L->xtype, L->is_ll, FALSE, TRUE, TRUE, L,
+		Common))
+    {
+	ERROR (CHOLMOD_INVALID, "cannot convert L") ;
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* create Lsparse */
+    /* ---------------------------------------------------------------------- */
+
+    /* allocate the header for Lsparse, the sparse matrix version of L */
+    Lsparse = CHOLMOD(malloc) (sizeof (cholmod_sparse), 1, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;		/* out of memory */
+    }
+
+    /* transfer the contents from L to Lsparse */
+    Lsparse->nrow = L->n ;
+    Lsparse->ncol = L->n ;
+    Lsparse->p = L->p ;
+    Lsparse->i = L->i ;
+    Lsparse->x = L->x ;
+    Lsparse->z = L->z ;
+    Lsparse->nz = NULL ;
+    Lsparse->stype = 0 ;
+    Lsparse->itype = L->itype ;
+    Lsparse->xtype = L->xtype ;
+    Lsparse->dtype = L->dtype ;
+    Lsparse->sorted = TRUE ;
+    Lsparse->packed = TRUE ;
+    Lsparse->nzmax = L->nzmax ;
+    ASSERT (CHOLMOD(dump_sparse) (Lsparse, "Lsparse", Common) >= 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert L to symbolic, but do not free contents transfered to Lsparse */
+    /* ---------------------------------------------------------------------- */
+
+    L->p = NULL ;
+    L->i = NULL ;
+    L->x = NULL ;
+    L->z = NULL ;
+    L->xtype = CHOLMOD_PATTERN ;
+    CHOLMOD(change_factor) (CHOLMOD_PATTERN, FALSE, FALSE, TRUE, TRUE, L,
+	    Common) ;
+
+    return (Lsparse) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_copy_factor ================================================== */
+/* ========================================================================== */
+
+/* Create an exact copy of a factor, with one exception:
+ *
+ * Entries in unused space are not copied (they might not be initialized,
+ *	and copying them would cause program checkers such as purify and
+ *	valgrind to complain).
+ *
+ * Note that a supernodal L cannot be zomplex.
+ */
+
+cholmod_factor *CHOLMOD(copy_factor)
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to copy */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_factor *L2 ;
+    double *Lx, *L2x, *Lz, *L2z ;
+    Int *Perm, *ColCount, *Lp, *Li, *Lnz, *Lnext, *Lprev, *Lsuper, *Lpi, *Lpx,
+	*Ls, *Perm2, *ColCount2, *L2p, *L2i, *L2nz, *L2next, *L2prev, *L2super,
+	*L2pi, *L2px, *L2s ;
+    Int n, j, p, pend, s, xsize, ssize, nsuper ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (L, NULL) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ;
+    Common->status = CHOLMOD_OK ;
+    DEBUG (CHOLMOD(dump_factor) (L, "start copy", Common)) ;
+
+    n = L->n ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate a simplicial symbolic factor  */
+    /* ---------------------------------------------------------------------- */
+
+    /* allocates L2->Perm and L2->ColCount */
+    L2 = CHOLMOD(allocate_factor) (n, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+    ASSERT (L2->xtype == CHOLMOD_PATTERN && !(L2->is_super)) ;
+
+    Perm = L->Perm ;
+    ColCount = L->ColCount ;
+    Perm2 = L2->Perm ;
+    ColCount2 = L2->ColCount ;
+    L2->ordering = L->ordering ;
+
+    for (j = 0 ; j < n ; j++)
+    {
+	Perm2 [j] = Perm [j] ;
+    }
+    for (j = 0 ; j < n ; j++)
+    {
+	ColCount2 [j] = ColCount [j] ;
+    }
+    L2->is_ll = L->is_ll ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy the rest of the factor */
+    /* ---------------------------------------------------------------------- */
+
+    if (L->xtype != CHOLMOD_PATTERN && !(L->super))
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* allocate a simplicial numeric factor */
+	/* ------------------------------------------------------------------ */
+
+	/* allocate L2->p, L2->nz, L2->prev, L2->next, L2->i, and L2->x.
+	 * packed = -1 so that cholmod_change_factor allocates space of
+	 * size L2->nzmax */
+	L2->nzmax = L->nzmax ;
+	if (!CHOLMOD(change_factor) (L->xtype, L->is_ll, FALSE, -1, TRUE,
+		    L2, Common))
+	{
+	    CHOLMOD(free_factor) (&L2, Common) ;
+	    return (NULL) ;	/* out of memory */
+	}
+	ASSERT (L->nzmax == L2->nzmax) ;
+
+	/* ------------------------------------------------------------------ */
+	/* copy the contents of a simplicial numeric factor */
+	/* ------------------------------------------------------------------ */
+
+	Lp = L->p ;
+	Li = L->i ;
+	Lx = L->x ;
+	Lz = L->z ;
+	Lnz = L->nz ;
+	Lnext = L->next ;
+	Lprev = L->prev ;
+
+	L2p = L2->p ;
+	L2i = L2->i ;
+	L2x = L2->x ;
+	L2z = L2->z ;
+	L2nz = L2->nz ;
+	L2next = L2->next ;
+	L2prev = L2->prev ;
+	L2->xtype = L->xtype ;
+	L2->dtype = L->dtype ;
+
+	for (j = 0 ; j <= n ; j++)
+	{
+	    L2p [j] = Lp [j] ;
+	}
+
+	for (j = 0 ; j < n+2 ; j++)
+	{
+	    L2prev [j] = Lprev [j] ;
+	}
+
+	for (j = 0 ; j < n+2 ; j++)
+	{
+	    L2next [j] = Lnext [j] ;
+	}
+
+	for (j = 0 ; j < n ; j++)
+	{
+	    L2nz [j] = Lnz [j] ;
+	}
+
+	for (j = 0 ; j < n ; j++)
+	{
+	    p = Lp [j] ;
+	    pend = p + Lnz [j] ;
+	    for ( ; p < pend ; p++)
+	    {
+		L2i [p] = Li [p] ;
+	    }
+	    p = Lp [j] ;
+
+	    if (L->xtype == CHOLMOD_REAL)
+	    {
+		for ( ; p < pend ; p++)
+		{
+		    L2x [p] = Lx [p] ;
+		}
+	    }
+	    else if (L->xtype == CHOLMOD_COMPLEX)
+	    {
+		for ( ; p < pend ; p++)
+		{
+		    L2x [2*p  ] = Lx [2*p  ] ;
+		    L2x [2*p+1] = Lx [2*p+1] ;
+		}
+	    }
+	    else if (L->xtype == CHOLMOD_ZOMPLEX)
+	    {
+		for ( ; p < pend ; p++)
+		{
+		    L2x [p] = Lx [p] ;
+		    L2z [p] = Lz [p] ;
+		}
+	    }
+
+	}
+
+    }
+    else if (L->is_super)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* copy a supernodal factor */
+	/* ------------------------------------------------------------------ */
+
+	xsize = L->xsize ;
+	ssize = L->ssize ;
+	nsuper = L->nsuper ;
+
+	L2->xsize = xsize ;
+	L2->ssize = ssize ;
+	L2->nsuper = nsuper ;
+
+	/* allocate L2->super, L2->pi, L2->px, and L2->s.  Allocate L2->x if
+	 * L is numeric */
+	if (!CHOLMOD(change_factor) (L->xtype, TRUE, TRUE, TRUE, TRUE, L2,
+		    Common))
+	{
+	    CHOLMOD(free_factor) (&L2, Common) ;
+	    return (NULL) ;	/* out of memory */
+	}
+
+	ASSERT (L2->s != NULL) ;
+
+	/* ------------------------------------------------------------------ */
+	/* copy the contents of a supernodal factor */
+	/* ------------------------------------------------------------------ */
+
+	Lsuper = L->super ;
+	Lpi = L->pi ;
+	Lpx = L->px ;
+	Ls = L->s ;
+	Lx = L->x ;
+
+	L2super = L2->super ;
+	L2pi = L2->pi ;
+	L2px = L2->px ;
+	L2s = L2->s ;
+	L2x = L2->x ;
+
+	L2->maxcsize = L->maxcsize ;
+	L2->maxesize = L->maxesize ;
+
+	for (s = 0 ; s <= nsuper ; s++)
+	{
+	    L2super [s] = Lsuper [s] ;
+	}
+	for (s = 0 ; s <= nsuper ; s++)
+	{
+	    L2pi [s] = Lpi [s] ;
+	}
+	for (s = 0 ; s <= nsuper ; s++)
+	{
+	    L2px [s] = Lpx [s] ;
+	}
+
+	L2s [0] = 0 ;
+	for (p = 0 ; p < ssize ; p++)
+	{
+	    L2s [p] = Ls [p] ;
+	}
+
+	if (L->xtype == CHOLMOD_REAL)
+	{
+	    for (p = 0 ; p < xsize ; p++)
+	    {
+		L2x [p] = Lx [p] ;
+	    }
+	}
+	else if (L->xtype == CHOLMOD_COMPLEX)
+	{
+	    for (p = 0 ; p < 2*xsize ; p++)
+	    {
+		L2x [p] = Lx [p] ;
+	    }
+	}
+    }
+
+    L2->minor = L->minor ;
+    L2->is_monotonic = L->is_monotonic ;
+
+    DEBUG (CHOLMOD(dump_factor) (L2, "L2 got copied", Common)) ;
+    ASSERT (L2->xtype == L->xtype && L2->is_super == L->is_super) ;
+    return (L2) ;
+}
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/cholmod_memory.c b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_memory.c
new file mode 100644
index 0000000..141f006
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_memory.c
@@ -0,0 +1,565 @@
+/* ========================================================================== */
+/* === Core/cholmod_memory ================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Core memory management routines:
+ *
+ * Primary routines:
+ * -----------------
+ * cholmod_malloc		malloc wrapper
+ * cholmod_free			free wrapper
+ *
+ * Secondary routines:
+ * -------------------
+ * cholmod_calloc		calloc wrapper
+ * cholmod_realloc		realloc wrapper
+ * cholmod_realloc_multiple	realloc wrapper for multiple objects
+ *
+ * The user may make use of these, just like malloc and free.  You can even
+ * malloc an object and safely free it with cholmod_free, and visa versa
+ * (except that the memory usage statistics will be corrupted).  These routines
+ * do differ from malloc and free.  If cholmod_free is given a NULL pointer,
+ * for example, it does nothing (unlike the ANSI free).  cholmod_realloc does
+ * not return NULL if given a non-NULL pointer and a nonzero size, even if it
+ * fails (it sets an error code in Common->status instead).
+ *
+ * CHOLMOD keeps track of the amount of memory it has allocated, and so the
+ * cholmod_free routine includes as a parameter the size of the object being
+ * freed.  This is only used for memory usage statistics, which are very useful
+ * in finding memory leaks in your program.  If you, the user of CHOLMOD, pass
+ * the wrong size, the only consequence is that the memory usage statistics
+ * will be invalid.  This will causes assertions to fail if CHOLMOD is
+ * compiled with debugging enabled, but otherwise it will cause no errors.
+ *
+ * The cholmod_free_* routines for each CHOLMOD object keep track of the size
+ * of the blocks they free, so they do not require you to pass their sizes
+ * as a parameter.
+ *
+ * If a block of size zero is requested, these routines allocate a block of
+ * size one instead.
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+/* ========================================================================== */
+/* === cholmod_add_size_t =================================================== */
+/* ========================================================================== */
+
+/* Safely compute a+b, and check for integer overflow.  If overflow occurs,
+ * return 0 and set OK to FALSE.  Also return 0 if OK is FALSE on input. */
+
+size_t CHOLMOD(add_size_t) (size_t a, size_t b, int *ok)
+{
+    size_t s = a + b ;
+    (*ok) = (*ok) && (s >= a) ;
+    return ((*ok) ? s : 0) ;
+}
+
+/* ========================================================================== */
+/* === cholmod_mult_size_t ================================================== */
+/* ========================================================================== */
+
+/* Safely compute a*k, where k should be small, and check for integer overflow.
+ * If overflow occurs, return 0 and set OK to FALSE.  Also return 0 if OK is
+ * FALSE on input. */
+
+size_t CHOLMOD(mult_size_t) (size_t a, size_t k, int *ok)
+{
+    size_t p = 0, s ;
+    while (*ok)
+    {
+	if (k % 2)
+	{
+	    p = p + a ;
+	    (*ok) = (*ok) && (p >= a) ;
+	}
+	k = k / 2 ;
+	if (!k) return (p) ;
+	s = a + a ;
+	(*ok) = (*ok) && (s >= a) ;
+	a = s ;
+    }
+    return (0) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_malloc ======================================================= */
+/* ========================================================================== */
+
+/* Wrapper around malloc routine.  Allocates space of size MAX(1,n)*size, where
+ * size is normally a sizeof (...).
+ *
+ * This routine, cholmod_calloc, and cholmod_realloc do not set Common->status
+ * to CHOLMOD_OK on success, so that a sequence of cholmod_malloc's, _calloc's,
+ * or _realloc's can be used.  If any of them fails, the Common->status will
+ * hold the most recent error status.
+ *
+ * Usage, for a pointer to int:
+ *
+ *	p = cholmod_malloc (n, sizeof (int), Common)
+ *
+ * Uses a pointer to the malloc routine (or its equivalent) defined in Common.
+ */
+
+void *CHOLMOD(malloc)	/* returns pointer to the newly malloc'd block */
+(
+    /* ---- input ---- */
+    size_t n,		/* number of items */
+    size_t size,	/* size of each item */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    void *p ;
+    size_t s ;
+    int ok = TRUE ;
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    if (size == 0)
+    {
+	ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0")  ;
+	p = NULL ;
+    }
+    else if (n >= (Size_max / size) || n >= Int_max)
+    {
+	/* object is too big to allocate without causing integer overflow */
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	p = NULL ;
+    }
+    else
+    {
+	/* call malloc, or its equivalent */
+	s = CHOLMOD(mult_size_t) (MAX (1,n), size, &ok) ;
+	p = ok ? ((Common->malloc_memory) (s)) : NULL ;
+	if (p == NULL)
+	{
+	    /* failure: out of memory */
+	    ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ;
+	}
+	else
+	{
+	    /* success: increment the count of objects allocated */
+	    Common->malloc_count++ ;
+	    Common->memory_inuse += (n * size) ;
+	    Common->memory_usage =
+		MAX (Common->memory_usage, Common->memory_inuse) ;
+	    PRINTM (("cholmod_malloc %p %d cnt: %d inuse %d\n",
+		    p, n*size, Common->malloc_count, Common->memory_inuse)) ;
+	}
+    }
+    return (p) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_free ========================================================= */
+/* ========================================================================== */
+
+/* Wrapper around free routine.  Returns NULL, which can be assigned to the
+ * pointer being freed, as in:
+ *
+ *	p = cholmod_free (n, sizeof (int), p, Common) ;
+ *
+ * In CHOLMOD, the syntax:
+ *
+ *	cholmod_free (n, sizeof (int), p, Common) ;
+ *
+ * is used if p is a local pointer and the routine is returning shortly.
+ * Uses a pointer to the free routine (or its equivalent) defined in Common.
+ * Nothing is freed if the pointer is NULL.
+ */
+
+void *CHOLMOD(free)	/* always returns NULL */
+(
+    /* ---- input ---- */
+    size_t n,		/* number of items */
+    size_t size,	/* size of each item */
+    /* ---- in/out --- */
+    void *p,		/* block of memory to free */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (NULL) ;
+    if (p != NULL)
+    {
+	/* only free the object if the pointer is not NULL */
+	/* call free, or its equivalent */
+	(Common->free_memory) (p) ;
+	Common->malloc_count-- ;
+	Common->memory_inuse -= (n * size) ;
+	PRINTM (("cholmod_free   %p %d cnt: %d inuse %d\n",
+		p, n*size, Common->malloc_count, Common->memory_inuse)) ;
+	/* This assertion will fail if the user calls cholmod_malloc and
+	 * cholmod_free with mismatched memory sizes.  It shouldn't fail
+	 * otherwise. */
+	DEBUG (if (Common->malloc_count == 0 && Common->memory_inuse != 0)
+	    PRINT0 (("inuse: %d\n", Common->memory_inuse))) ;
+	ASSERT (IMPLIES (Common->malloc_count == 0, Common->memory_inuse == 0));
+    }
+    /* return NULL, and the caller should assign this to p.  This avoids
+     * freeing the same pointer twice. */
+    return (NULL) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_calloc ======================================================= */
+/* ========================================================================== */
+
+/* Wrapper around calloc routine.
+ *
+ * Uses a pointer to the calloc routine (or its equivalent) defined in Common.
+ * This routine is identical to malloc, except that it zeros the newly allocated
+ * block to zero.
+ */
+
+void *CHOLMOD(calloc)	/* returns pointer to the newly calloc'd block */
+(
+    /* ---- input ---- */
+    size_t n,		/* number of items */
+    size_t size,	/* size of each item */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    void *p ;
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    if (size == 0)
+    {
+	ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0") ;
+	p = NULL ;
+    }
+    else if (n >= (Size_max / size) || n >= Int_max)
+    {
+	/* object is too big to allocate without causing integer overflow */
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	p = NULL ;
+    }
+    else
+    {
+	/* call calloc, or its equivalent */
+	p = (Common->calloc_memory) (MAX (1,n), size) ;
+	if (p == NULL)
+	{
+	    /* failure: out of memory */
+	    ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ;
+	}
+	else
+	{
+	    /* success: increment the count of objects allocated */
+	    Common->malloc_count++ ;
+	    Common->memory_inuse += (n * size) ;
+	    Common->memory_usage =
+		MAX (Common->memory_usage, Common->memory_inuse) ;
+	    PRINTM (("cholmod_calloc %p %d cnt: %d inuse %d\n",
+		    p, n*size, Common->malloc_count, Common->memory_inuse)) ;
+	}
+    }
+    return (p) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_realloc ====================================================== */
+/* ========================================================================== */
+
+/* Wrapper around realloc routine.  Given a pointer p to a block of size
+ * (*n)*size memory, it changes the size of the block pointed to by p to be
+ * MAX(1,nnew)*size in size.  It may return a pointer different than p.  This
+ * should be used as (for a pointer to int):
+ *
+ *	p = cholmod_realloc (nnew, sizeof (int), p, *n, Common) ;
+ *
+ * If p is NULL, this is the same as p = cholmod_malloc (...).
+ * A size of nnew=0 is treated as nnew=1.
+ *
+ * If the realloc fails, p is returned unchanged and Common->status is set
+ * to CHOLMOD_OUT_OF_MEMORY.  If successful, Common->status is not modified,
+ * and p is returned (possibly changed) and pointing to a large block of memory.
+ *
+ * Uses a pointer to the realloc routine (or its equivalent) defined in Common.
+ */
+
+void *CHOLMOD(realloc)	/* returns pointer to reallocated block */
+(
+    /* ---- input ---- */
+    size_t nnew,	/* requested # of items in reallocated block */
+    size_t size,	/* size of each item */
+    /* ---- in/out --- */
+    void *p,		/* block of memory to realloc */
+    size_t *n,		/* current size on input, nnew on output if successful*/
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    size_t nold = (*n) ;
+    void *pnew ;
+    size_t s ;
+    int ok = TRUE ;
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    if (size == 0)
+    {
+	ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0") ;
+	p = NULL ;
+    }
+    else if (p == NULL)
+    {
+	/* A fresh object is being allocated. */
+	PRINT1 (("realloc fresh: %d %d\n", nnew, size)) ;
+	p = CHOLMOD(malloc) (nnew, size, Common) ;
+	*n = (p == NULL) ? 0 : nnew ;
+    }
+    else if (nold == nnew)
+    {
+	/* Nothing to do.  Do not change p or n. */
+	PRINT1 (("realloc nothing: %d %d\n", nnew, size)) ;
+    }
+    else if (nnew >= (Size_max / size) || nnew >= Int_max)
+    {
+	/* failure: nnew is too big.  Do not change p or n. */
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+    }
+    else
+    {
+	/* The object exists, and is changing to some other nonzero size. */
+	/* call realloc, or its equivalent */
+	PRINT1 (("realloc : %d to %d, %d\n", nold, nnew, size)) ;
+	pnew = NULL ;
+
+	s = CHOLMOD(mult_size_t) (MAX (1,nnew), size, &ok) ;
+	pnew = ok ? ((Common->realloc_memory) (p, s)) : NULL ;
+
+	if (pnew == NULL)
+	{
+	    /* Do not change p, since it still points to allocated memory */
+	    if (nnew <= nold)
+	    {
+		/* The attempt to reduce the size of the block from n to
+		 * nnew has failed.  The current block is not modified, so
+		 * pretend to succeed, but do not change p.  Do change
+		 * CHOLMOD's notion of the size of the block, however. */
+		*n = nnew ;
+		PRINTM (("nnew <= nold failed, pretend to succeed\n")) ;
+		PRINTM (("cholmod_realloc_old: %p %d cnt: %d inuse %d\n"
+			 "cholmod_realloc_new: %p %d cnt: %d inuse %d\n",
+		    p, nold*size, Common->malloc_count-1,
+				  Common->memory_inuse - nold*size,
+		    p, nnew*size, Common->malloc_count,
+				  Common->memory_inuse + (nnew-nold)*size)) ;
+		Common->memory_inuse += ((nnew-nold) * size) ;
+	    }
+	    else
+	    {
+		/* Increasing the size of the block has failed.
+		 * Do not change n. */
+		ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ;
+	    }
+	}
+	else
+	{
+	    /* success: return revised p and change the size of the block */
+	    PRINTM (("cholmod_realloc_old: %p %d cnt: %d inuse %d\n"
+		     "cholmod_realloc_new: %p %d cnt: %d inuse %d\n",
+		p, nold*size,    Common->malloc_count-1,
+				 Common->memory_inuse - nold*size,
+		pnew, nnew*size, Common->malloc_count,
+				 Common->memory_inuse + (nnew-nold)*size)) ;
+	    p = pnew ;
+	    *n = nnew ;
+	    Common->memory_inuse += ((nnew-nold) * size) ;
+	}
+	Common->memory_usage = MAX (Common->memory_usage, Common->memory_inuse);
+    }
+
+    return (p) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_realloc_multiple ============================================= */
+/* ========================================================================== */
+
+/* reallocate multiple blocks of memory, all of the same size (up to two integer
+ * and two real blocks).  Either reallocations all succeed, or all are returned
+ * in the original size (they are freed if the original size is zero).  The nnew
+ * blocks are of size 1 or more.
+ */
+
+int CHOLMOD(realloc_multiple)
+(
+    /* ---- input ---- */
+    size_t nnew,	/* requested # of items in reallocated blocks */
+    int nint,		/* number of int/UF_long blocks */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* ---- in/out --- */
+    void **I,		/* int or UF_long block */
+    void **J,		/* int or UF_long block */
+    void **X,		/* complex or double block */
+    void **Z,		/* zomplex case only: double block */
+    size_t *nold_p,	/* current size of the I,J,X,Z blocks on input,
+			 * nnew on output if successful */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *xx, *zz ;
+    size_t i, j, x, z, nold ;
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+
+    if (xtype < CHOLMOD_PATTERN || xtype > CHOLMOD_ZOMPLEX)
+    {
+	ERROR (CHOLMOD_INVALID, "invalid xtype") ;
+	return (FALSE) ;
+    }
+
+    nold = *nold_p ;
+
+    if (nint < 1 && xtype == CHOLMOD_PATTERN)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+
+    i = nold ;
+    j = nold ;
+    x = nold ;
+    z = nold ;
+
+    if (nint > 0)
+    {
+	*I = CHOLMOD(realloc) (nnew, sizeof (Int), *I, &i, Common) ;
+    }
+    if (nint > 1)
+    {
+	*J = CHOLMOD(realloc) (nnew, sizeof (Int), *J, &j, Common) ;
+    }
+
+    switch (xtype)
+    {
+	case CHOLMOD_REAL:
+	    *X = CHOLMOD(realloc) (nnew, sizeof (double), *X, &x, Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    *X = CHOLMOD(realloc) (nnew, 2*sizeof (double), *X, &x, Common) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    *X = CHOLMOD(realloc) (nnew, sizeof (double), *X, &x, Common) ;
+	    *Z = CHOLMOD(realloc) (nnew, sizeof (double), *Z, &z, Common) ;
+	    break ;
+    }
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* one or more realloc's failed.  Resize all back down to nold. */
+
+	if (nold == 0)
+	{
+
+	    if (nint > 0)
+	    {
+		*I = CHOLMOD(free) (i, sizeof (Int), *I, Common) ;
+	    }
+	    if (nint > 1)
+	    {
+		*J = CHOLMOD(free) (j, sizeof (Int), *J, Common) ;
+	    }
+
+	    switch (xtype)
+	    {
+		case CHOLMOD_REAL:
+		    *X = CHOLMOD(free) (x, sizeof (double), *X, Common) ;
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    *X = CHOLMOD(free) (x, 2*sizeof (double), *X, Common) ;
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    *X = CHOLMOD(free) (x, sizeof (double), *X, Common) ;
+		    *Z = CHOLMOD(free) (x, sizeof (double), *Z, Common) ;
+		    break ;
+	    }
+
+	}
+	else
+	{
+	    if (nint > 0)
+	    {
+		*I = CHOLMOD(realloc) (nold, sizeof (Int), *I, &i, Common) ;
+	    }
+	    if (nint > 1)
+	    {
+		*J = CHOLMOD(realloc) (nold, sizeof (Int), *J, &j, Common) ;
+	    }
+
+	    switch (xtype)
+	    {
+		case CHOLMOD_REAL:
+		    *X = CHOLMOD(realloc) (nold, sizeof (double), *X, &x,
+			    Common) ;
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    *X = CHOLMOD(realloc) (nold, 2*sizeof (double), *X, &x,
+			    Common) ;
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    *X = CHOLMOD(realloc) (nold, sizeof (double), *X, &x,
+			    Common) ;
+		    *Z = CHOLMOD(realloc) (nold, sizeof (double), *Z, &z,
+			    Common) ;
+		    break ;
+	    }
+
+	}
+
+	return (FALSE) ;
+    }
+
+    if (nold == 0)
+    {
+	/* New space was allocated.  Clear the first entry so that valgrind
+	 * doesn't complain about its access in change_complexity
+	 * (Core/cholmod_complex.c). */
+	xx = *X ;
+	zz = *Z ;
+	switch (xtype)
+	{
+	    case CHOLMOD_REAL:
+		xx [0] = 0 ;
+		break ;
+
+	    case CHOLMOD_COMPLEX:
+		xx [0] = 0 ;
+		xx [1] = 0 ;
+		break ;
+
+	    case CHOLMOD_ZOMPLEX:
+		xx [0] = 0 ;
+		zz [0] = 0 ;
+		break ;
+	}
+    }
+
+    /* all realloc's succeeded, change size to reflect realloc'ed size. */
+    *nold_p = nnew ;
+    return (TRUE) ;
+}
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/cholmod_sparse.c b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_sparse.c
new file mode 100644
index 0000000..059f855
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_sparse.c
@@ -0,0 +1,652 @@
+/* ========================================================================== */
+/* === Core/cholmod_sparse ================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Core utility routines for the cholmod_sparse object:
+ *
+ * A sparse matrix is held in compressed column form.  In the basic type
+ * ("packed", which corresponds to a MATLAB sparse matrix), an n-by-n matrix
+ * with nz entries is held in three arrays: p of size n+1, i of size nz, and x
+ * of size nz.  Row indices of column j are held in i [p [j] ... p [j+1]-1] and
+ * in the same locations in x.  There may be no duplicate entries in a column.
+ * Row indices in each column may be sorted or unsorted (CHOLMOD keeps track).
+ *
+ * Primary routines:
+ * -----------------
+ * cholmod_allocate_sparse	allocate a sparse matrix
+ * cholmod_free_sparse		free a sparse matrix
+ *
+ * Secondary routines:
+ * -------------------
+ * cholmod_reallocate_sparse	change the size (# entries) of sparse matrix
+ * cholmod_nnz			number of nonzeros in a sparse matrix
+ * cholmod_speye		sparse identity matrix
+ * cholmod_spzeros		sparse zero matrix
+ * cholmod_copy_sparse		create a copy of a sparse matrix
+ *
+ * All xtypes are supported (pattern, real, complex, and zomplex)
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+
+/* ========================================================================== */
+/* === cholmod_allocate_sparse ============================================== */
+/* ========================================================================== */
+
+/* Allocate space for a matrix.  A->i and A->x are not initialized.  A->p
+ * (and A->nz if A is not packed) are set to zero, so a matrix containing no
+ * entries (all zero) is returned.  See also cholmod_spzeros.
+ *
+ * workspace: none
+ */
+
+cholmod_sparse *CHOLMOD(allocate_sparse)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of A */
+    size_t ncol,	/* # of columns of A */
+    size_t nzmax,	/* max # of nonzeros of A */
+    int sorted,		/* TRUE if columns of A sorted, FALSE otherwise */
+    int packed,		/* TRUE if A will be packed, FALSE otherwise */
+    int stype,		/* stype of A */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *A ;
+    Int *Ap, *Anz ;
+    size_t nzmax0 ;
+    Int j ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    if (stype != 0 && nrow != ncol)
+    {
+	ERROR (CHOLMOD_INVALID, "rectangular matrix with stype != 0 invalid") ;
+	return (NULL) ;
+    }
+    if (xtype < CHOLMOD_PATTERN || xtype > CHOLMOD_ZOMPLEX)
+    {
+	ERROR (CHOLMOD_INVALID, "xtype invalid") ;
+	return (NULL) ;
+    }
+    /* ensure the dimensions do not cause integer overflow */
+    (void) CHOLMOD(add_size_t) (ncol, 2, &ok) ;
+    if (!ok || nrow > Int_max || ncol > Int_max || nzmax > Int_max)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate header */
+    /* ---------------------------------------------------------------------- */
+
+    A = CHOLMOD(malloc) (sizeof (cholmod_sparse), 1, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+    PRINT1 (("cholmod_allocate_sparse %d-by-%d nzmax %d sorted %d packed %d"
+		" xtype %d\n", nrow, ncol, nzmax, sorted, packed, xtype)) ;
+
+    nzmax = MAX (1, nzmax) ;
+
+    A->nrow = nrow ;
+    A->ncol = ncol ;
+    A->nzmax = nzmax ;
+    A->packed = packed ;    /* default is packed (A->nz not present) */
+    A->stype = stype ;
+    A->itype = ITYPE ;
+    A->xtype = xtype ;
+    A->dtype = DTYPE ;
+
+    A->nz = NULL ;
+    A->p = NULL ;
+    A->i = NULL ;
+    A->x = NULL ;
+    A->z = NULL ;
+
+    /* A 1-by-m matrix always has sorted columns */
+    A->sorted = (nrow <= 1) ? TRUE : sorted ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the matrix itself */
+    /* ---------------------------------------------------------------------- */
+
+    /* allocate O(ncol) space */
+    A->p = CHOLMOD(malloc) (((size_t) ncol)+1, sizeof (Int), Common) ;
+    if (!packed)
+    {
+	A->nz = CHOLMOD(malloc) (ncol, sizeof (Int), Common) ;
+    }
+
+    /* allocate O(nz) space */
+    nzmax0 = 0 ;
+    CHOLMOD(realloc_multiple) (nzmax, 1, xtype, &(A->i), NULL, &(A->x), &(A->z),
+	    &nzmax0, Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free_sparse) (&A, Common) ;
+	return (NULL) ;	    /* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* initialize A->p and A->nz so that A is an empty matrix */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;
+    for (j = 0 ; j <= (Int) ncol ; j++)
+    {
+	Ap [j] = 0 ;
+    }
+    if (!packed)
+    {
+	Anz = A->nz ;
+	for (j = 0 ; j < (Int) ncol ; j++)
+	{
+	    Anz [j] = 0 ;
+	}
+    }
+    return (A) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_free_sparse ================================================== */
+/* ========================================================================== */
+
+/* free a sparse matrix
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(free_sparse)
+(
+    /* ---- in/out --- */
+    cholmod_sparse **AHandle,	/* matrix to deallocate, NULL on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int n, nz ;
+    cholmod_sparse *A ;
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+
+    if (AHandle == NULL)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+    A = *AHandle ;
+    if (A == NULL)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+    n = A->ncol ;
+    nz = A->nzmax ;
+    A->p  = CHOLMOD(free) (n+1, sizeof (Int), A->p,  Common) ;
+    A->i  = CHOLMOD(free) (nz,  sizeof (Int), A->i,  Common) ;
+    A->nz = CHOLMOD(free) (n,   sizeof (Int), A->nz, Common) ;
+
+    switch (A->xtype)
+    {
+	case CHOLMOD_REAL:
+	    A->x = CHOLMOD(free) (nz, sizeof (double), A->x,  Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    A->x = CHOLMOD(free) (nz, 2*sizeof (double), A->x,  Common) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    A->x = CHOLMOD(free) (nz, sizeof (double), A->x,  Common) ;
+	    A->z = CHOLMOD(free) (nz, sizeof (double), A->z,  Common) ;
+	    break ;
+    }
+
+    *AHandle = CHOLMOD(free) (1, sizeof (cholmod_sparse), (*AHandle), Common) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_reallocate_sparse ============================================ */
+/* ========================================================================== */
+
+/* Change the size of A->i, A->x, and A->z, or allocate them if their current
+ * size is zero.  A->x and A->z are not modified if A->xtype is CHOLMOD_PATTERN.
+ * A->z is not modified unless A->xtype is CHOLMOD_ZOMPLEX.
+ * 
+ * workspace: none
+ */
+
+int CHOLMOD(reallocate_sparse)
+(
+    /* ---- input ---- */
+    size_t nznew,	/* new # of entries in A */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix to reallocate */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    PRINT1 (("realloc matrix %d to %d, xtype: %d\n",
+		A->nzmax, nznew, A->xtype)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* resize the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(realloc_multiple) (MAX (1,nznew), 1, A->xtype, &(A->i), NULL,
+	    &(A->x), &(A->z), &(A->nzmax), Common) ;
+
+    return (Common->status == CHOLMOD_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_speye ======================================================== */
+/* ========================================================================== */
+
+/* Return a sparse identity matrix. */
+
+cholmod_sparse *CHOLMOD(speye)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of A */
+    size_t ncol,	/* # of columns of A */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Az ;
+    cholmod_sparse *A ;
+    Int *Ap, *Ai ;
+    Int j, n ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    n = MIN (nrow, ncol) ;
+    A = CHOLMOD(allocate_sparse) (nrow, ncol, n, TRUE, TRUE, 0, xtype,
+	    Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory or inputs invalid */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* create the identity matrix */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;
+    Ai = A->i ;
+    Ax = A->x ;
+    Az = A->z ;
+
+    for (j = 0 ; j < n ; j++)
+    {
+	Ap [j] = j ;
+    }
+    for (j = n ; j <= ((Int) ncol) ; j++)
+    {
+	Ap [j] = n ;
+    }
+    for (j = 0 ; j < n ; j++)
+    {
+	Ai [j] = j ;
+    }
+
+    switch (xtype)
+    {
+	case CHOLMOD_REAL:
+	    for (j = 0 ; j < n ; j++)
+	    {
+		Ax [j] = 1 ;
+	    }
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    for (j = 0 ; j < n ; j++)
+	    {
+		Ax [2*j  ] = 1 ;
+		Ax [2*j+1] = 0 ;
+	    }
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    for (j = 0 ; j < n ; j++)
+	    {
+		Ax [j] = 1 ;
+	    }
+	    for (j = 0 ; j < n ; j++)
+	    {
+		Az [j] = 0 ;
+	    }
+	    break ;
+    }
+
+    return (A) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_spzeros ====================================================== */
+/* ========================================================================== */
+
+/* Return a sparse zero matrix. */
+
+cholmod_sparse *CHOLMOD(spzeros)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of A */
+    size_t ncol,	/* # of columns of A */
+    size_t nzmax,	/* max # of nonzeros of A */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    return (CHOLMOD(allocate_sparse) (nrow, ncol, nzmax, TRUE, TRUE, 0, xtype,
+	    Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_nnz ========================================================== */
+/* ========================================================================== */
+
+/* Return the number of entries in a sparse matrix.
+ *
+ * workspace: none
+ * integer overflow cannot occur, since the matrix is already allocated.
+ */
+
+UF_long CHOLMOD(nnz)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Ap, *Anz ;
+    size_t nz ;
+    Int j, ncol ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (EMPTY) ;
+    RETURN_IF_NULL (A, EMPTY) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* return nnz (A) */
+    /* ---------------------------------------------------------------------- */
+
+    ncol = A->ncol ;
+    if (A->packed)
+    {
+	Ap = A->p ;
+	RETURN_IF_NULL (Ap, EMPTY) ;
+	nz = Ap [ncol] ;
+    }
+    else
+    {
+	Anz = A->nz ;
+	RETURN_IF_NULL (Anz, EMPTY) ;
+	nz = 0 ;
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    nz += MAX (0, Anz [j]) ;
+	}
+    }
+    return (nz) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_copy_sparse ================================================== */
+/* ========================================================================== */
+
+/* C = A.  Create an exact copy of a sparse matrix, with one exception.
+ * Entries in unused space are not copied (they might not be initialized,
+ * and copying them would cause program checkers such as purify and
+ * valgrind to complain).  The xtype of the resulting matrix C is the same as
+ * the xtype of the input matrix A.
+ *
+ * See also Core/cholmod_copy, which copies a matrix with possible changes
+ * in stype, presence of diagonal entries, pattern vs. numerical values,
+ * real and/or imaginary parts, and so on.
+ */
+
+cholmod_sparse *CHOLMOD(copy_sparse)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Cx, *Az, *Cz ;
+    Int *Ap, *Ai, *Anz, *Cp, *Ci, *Cnz ;
+    cholmod_sparse *C ;
+    Int p, pend, j, ncol, packed, nzmax, nz, xtype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ;
+    if (A->stype != 0 && A->nrow != A->ncol)
+    {
+	ERROR (CHOLMOD_INVALID, "rectangular matrix with stype != 0 invalid") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+    ASSERT (CHOLMOD(dump_sparse) (A, "A original", Common) >= 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    ncol = A->ncol ;
+    nzmax = A->nzmax ;
+    packed = A->packed ;
+    Ap = A->p ;
+    Ai = A->i ;
+    Ax = A->x ;
+    Az = A->z ;
+    Anz = A->nz ;
+    xtype = A->xtype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the copy */
+    /* ---------------------------------------------------------------------- */
+
+    C = CHOLMOD(allocate_sparse) (A->nrow, A->ncol, A->nzmax, A->sorted,
+	    A->packed, A->stype, A->xtype, Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    Cp = C->p ;
+    Ci = C->i ;
+    Cx = C->x ;
+    Cz = C->z ;
+    Cnz = C->nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    for (j = 0 ; j <= ncol ; j++)
+    {
+	Cp [j] = Ap [j] ;
+    }
+
+    if (packed)
+    {
+	nz = Ap [ncol] ;
+	for (p = 0 ; p < nz ; p++)
+	{
+	    Ci [p] = Ai [p] ;
+	}
+
+	switch (xtype)
+	{
+	    case CHOLMOD_REAL:
+		for (p = 0 ; p < nz ; p++)
+		{
+		    Cx [p] = Ax [p] ;
+		}
+		break ;
+
+	    case CHOLMOD_COMPLEX:
+		for (p = 0 ; p < 2*nz ; p++)
+		{
+		    Cx [p] = Ax [p] ;
+		}
+		break ;
+
+	    case CHOLMOD_ZOMPLEX:
+		for (p = 0 ; p < nz ; p++)
+		{
+		    Cx [p] = Ax [p] ;
+		    Cz [p] = Az [p] ;
+		}
+		break ;
+	}
+
+    }
+    else
+    {
+
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    Cnz [j] = Anz [j] ;
+	}
+
+	switch (xtype)
+	{
+	    case CHOLMOD_PATTERN:
+		for (j = 0 ; j < ncol ; j++)
+		{
+		    p = Ap [j] ;
+		    pend = p + Anz [j] ;
+		    for ( ; p < pend ; p++)
+		    {
+			Ci [p] = Ai [p] ;
+		    }
+		}
+		break ;
+
+	    case CHOLMOD_REAL:
+		for (j = 0 ; j < ncol ; j++)
+		{
+		    p = Ap [j] ;
+		    pend = p + Anz [j] ;
+		    for ( ; p < pend ; p++)
+		    {
+			Ci [p] = Ai [p] ;
+			Cx [p] = Ax [p] ;
+		    }
+		}
+		break ;
+
+	    case CHOLMOD_COMPLEX:
+		for (j = 0 ; j < ncol ; j++)
+		{
+		    p = Ap [j] ;
+		    pend = p + Anz [j] ;
+		    for ( ; p < pend ; p++)
+		    {
+			Ci [p] = Ai [p] ;
+			Cx [2*p  ] = Ax [2*p  ] ;
+			Cx [2*p+1] = Ax [2*p+1] ;
+		    }
+		}
+		break ;
+
+	    case CHOLMOD_ZOMPLEX:
+		for (j = 0 ; j < ncol ; j++)
+		{
+		    p = Ap [j] ;
+		    pend = p + Anz [j] ;
+		    for ( ; p < pend ; p++)
+		    {
+			Ci [p] = Ai [p] ;
+			Cx [p] = Ax [p] ;
+			Cz [p] = Az [p] ;
+		    }
+		}
+		break ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the result */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_sparse) (C, "C copy", Common) >= 0) ;
+    return (C) ;
+}
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/cholmod_transpose.c b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_transpose.c
new file mode 100644
index 0000000..7e94aa8
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_transpose.c
@@ -0,0 +1,1139 @@
+/* ========================================================================== */
+/* === Core/cholmod_transpose =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Core utility routines for the cholmod_sparse object to
+ * compute the transpose or permuted transpose of a matrix:
+ *
+ * Primary routines:
+ * -----------------
+ * cholmod_transpose		transpose sparse matrix
+ * cholmod_ptranspose		transpose and permute sparse matrix
+ * cholmod_sort			sort row indices in each column of sparse matrix
+ *
+ * Secondary routines:
+ * -------------------
+ * cholmod_transpose_unsym	transpose unsymmetric sparse matrix
+ * cholmod_transpose_sym	transpose symmetric sparse matrix
+ *
+ * All xtypes (pattern, real, complex, and zomplex) are supported.
+ *
+ * ---------------------------------------
+ * Unsymmetric case: A->stype is zero.
+ * ---------------------------------------
+ *
+ * Computes F = A', F = A (:,f)' or F = A (p,f)', except that the indexing by
+ * f does not work the same as the MATLAB notation (see below).  A->stype
+ * is zero, which denotes that both the upper and lower triangular parts of
+ * A are present (and used).  A may in fact be symmetric in pattern and/or
+ * value; A->stype just denotes which part of A are stored.  A may be
+ * rectangular.
+ *
+ * p is a permutation of 0:m-1, and f is a subset of 0:n-1, where A is m-by-n.
+ * There can be no duplicate entries in p or f.
+ *
+ * The set f is held in fset and fsize.
+ *	fset = NULL means ":" in MATLAB. fsize is ignored.
+ *	fset != NULL means f = fset [0..fsize-1].
+ *	fset != NULL and fsize = 0 means f is the empty set.
+ *
+ * Columns not in the set f are considered to be zero.  That is,
+ * if A is 5-by-10 then F = A (:,[3 4])' is not 2-by-5, but 10-by-5, and rows
+ * 3 and 4 of F are equal to columns 3 and 4 of A (the other rows of F are
+ * zero).  More precisely, in MATLAB notation:
+ *
+ *	[m n] = size (A) ;
+ *	F = A ;
+ *	notf = ones (1,n) ;
+ *	notf (f) = 0 ;
+ *	F (:, find (notf)) = 0
+ *	F = F'
+ *
+ * If you want the MATLAB equivalent F=A(p,f) operation, use cholmod_submatrix
+ * instead (which does not compute the transpose).
+ *
+ * F->nzmax must be large enough to hold the matrix F.  It is not modified.
+ * If F->nz is present then F->nz [j] = # of entries in column j of F.
+ *
+ * A can be sorted or unsorted, with packed or unpacked columns.
+ *
+ * If f is present and not sorted in ascending order, then F is unsorted
+ * (that is, it may contain columns whose row indices do not appear in
+ * ascending order).  Otherwise, F is sorted (the row indices in each
+ * column of F appear in strictly ascending order).
+ *
+ * F is returned in packed or unpacked form, depending on F->packed on input.
+ * If F->packed is false, then F is returned in unpacked form (F->nz must be
+ * present).  Each row i of F is large enough to hold all the entries in row i
+ * of A, even if f is provided.  That is, F->i and
+ * F->x [F->p [i] .. F->p [i] + F->nz [i] - 1] contain all entries in A (i,f),
+ * but F->p [i+1] - F->p [i] is equal to the number of nonzeros in A (i,:),
+ * not just A (i,f).
+ *
+ * The cholmod_transpose_unsym routine is the only operation in CHOLMOD that
+ * can produce an unpacked matrix.
+ *
+ * ---------------------------------------
+ * Symmetric case: A->stype is nonzero.
+ * ---------------------------------------
+ *
+ * Computes F = A' or F = A(p,p)', the transpose or permuted transpose, where
+ * A->stype is nonzero.
+ *
+ * If A->stype > 0, then A is a symmetric matrix where just the upper part
+ * of the matrix is stored.  Entries in the lower triangular part may be
+ * present, but are ignored.  A must be square.  If F=A', then F is returned
+ * sorted; otherwise F is unsorted for the F=A(p,p)' case.
+ *
+ * There can be no duplicate entries in p.
+ * The fset and fsize parameters are not used.
+ *
+ * Three kinds of transposes are available, depending on the "values" parameter:
+ * 0: do not transpose the numerical values; create a CHOLMOD_PATTERN matrix
+ * 1: array transpose
+ * 2: complex conjugate transpose (same as 2 if input is real or pattern)
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * For cholmod_transpose_unsym and cholmod_transpose_sym, the output matrix
+ * F must already be pre-allocated by the caller, with the correct dimensions.
+ * If F is not valid or has the wrong dimensions, it is not modified.
+ * Otherwise, if F is too small, the transpose is not computed; the contents
+ * of F->p contain the column pointers of the resulting matrix, where
+ * F->p [F->ncol] > F->nzmax.  In this case, the remaining contents of F are
+ * not modified.  F can still be properly free'd with cholmod_free_sparse.
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+
+/* ========================================================================== */
+/* === TEMPLATE ============================================================= */
+/* ========================================================================== */
+
+#define PATTERN
+#include "t_cholmod_transpose.c"
+#define REAL
+#include "t_cholmod_transpose.c"
+#define COMPLEX
+#include "t_cholmod_transpose.c"
+#define COMPLEX
+#define NCONJUGATE
+#include "t_cholmod_transpose.c"
+#define ZOMPLEX
+#include "t_cholmod_transpose.c"
+#define ZOMPLEX
+#define NCONJUGATE
+#include "t_cholmod_transpose.c"
+
+
+/* ========================================================================== */
+/* === cholmod_transpose_unsym ============================================== */
+/* ========================================================================== */
+
+/* Compute F = A', A (:,f)', or A (p,f)', where A is unsymmetric and F is
+ * already allocated.  See cholmod_transpose for a simpler routine.
+ *
+ * workspace:
+ * Iwork (MAX (nrow,ncol)) if fset is present
+ * Iwork (nrow) if fset is NULL
+ *
+ * The xtype of A and F must match, unless values is zero or F->xtype is
+ * CHOLMOD_PATTERN (in which case only the pattern of A is transpose into F).
+ */
+
+int CHOLMOD(transpose_unsym)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    int values,		/* 2: complex conj. transpose, 1: array transpose,
+			   0: do not transpose the numerical values */
+    Int *Perm,		/* size nrow, if present (can be NULL) */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- output --- */
+    cholmod_sparse *F,	/* F = A', A(:,f)', or A(p,f)' */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Fp, *Fnz, *Ap, *Ai, *Anz, *Wi ;
+    Int nrow, ncol, permute, use_fset, Apacked, Fpacked, p, pend,
+	i, j, k, Fsorted, nf, jj, jlast ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (F, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (F, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (A->nrow != F->ncol || A->ncol != F->nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "F has the wrong dimensions") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nf = fsize ;
+    use_fset = (fset != NULL) ;
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+
+    Ap = A->p ;		/* size A->ncol+1, column pointers of A */
+    Ai = A->i ;		/* size nz = Ap [A->ncol], row indices of A */
+    Anz = A->nz ;
+    Apacked = A->packed ;
+    ASSERT (IMPLIES (!Apacked, Anz != NULL)) ;
+
+    permute = (Perm != NULL) ;
+
+    Fp = F->p ;		/* size A->nrow+1, row pointers of F */
+    Fnz = F->nz ;
+    Fpacked = F->packed ;
+    ASSERT (IMPLIES (!Fpacked, Fnz != NULL)) ;
+
+    nf = (use_fset) ? nf : ncol ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* s = nrow + ((fset != NULL) ? ncol : 0) */
+    s = CHOLMOD(add_size_t) (nrow, ((fset != NULL) ? ncol : 0), &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (0, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+
+    Wi = Common->Iwork ;	/* size nrow (i/l/l) */
+
+    /* ---------------------------------------------------------------------- */
+    /* check Perm and fset */
+    /* ---------------------------------------------------------------------- */
+
+    if (permute)
+    {
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    Wi [i] = 1 ;
+	}
+	for (k = 0 ; k < nrow ; k++)
+	{
+	    i = Perm [k] ;
+	    if (i < 0 || i > nrow || Wi [i] == 0)
+	    {
+		ERROR (CHOLMOD_INVALID, "invalid permutation") ;
+		return (FALSE) ;
+	    }
+	    Wi [i] = 0 ;
+	}
+    }
+
+    if (use_fset)
+    {
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    Wi [j] = 1 ;
+	}
+	for (k = 0 ; k < nf ; k++)
+	{
+	    j = fset [k] ;
+	    if (j < 0 || j > ncol || Wi [j] == 0)
+	    {
+		ERROR (CHOLMOD_INVALID, "invalid fset") ;
+		return (FALSE) ;
+	    }
+	    Wi [j] = 0 ;
+	}
+    }
+
+    /* Perm and fset are now valid */
+    ASSERT (CHOLMOD(dump_perm) (Perm, nrow, nrow, "Perm", Common)) ;
+    ASSERT (CHOLMOD(dump_perm) (fset, nf, ncol, "fset", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* count the entries in each row of A or A(:,f) */
+    /* ---------------------------------------------------------------------- */
+
+    for (i = 0 ; i < nrow ; i++)
+    {
+	Wi [i] = 0 ;
+    }
+
+    jlast = EMPTY ;
+    Fsorted = TRUE ;
+
+    if (use_fset)
+    {
+	/* count entries in each row of A(:,f) */
+	for (jj = 0 ; jj < nf ; jj++)
+	{
+	    j = fset [jj] ;
+	    if (j <= jlast)
+	    {
+		Fsorted = FALSE ;
+	    }
+	    p = Ap [j] ;
+	    pend = (Apacked) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		Wi [Ai [p]]++ ;
+	    }
+	    jlast = j ;
+	}
+
+	/* save the nz counts if F is unpacked, and recount all of A */
+	if (!Fpacked)
+	{
+	    if (permute)
+	    {
+		for (i = 0 ; i < nrow ; i++)
+		{
+		    Fnz [i] = Wi [Perm [i]] ;
+		}
+	    }
+	    else
+	    {
+		for (i = 0 ; i < nrow ; i++)
+		{
+		    Fnz [i] = Wi [i] ;
+		}
+	    }
+	    for (i = 0 ; i < nrow ; i++)
+	    {
+		Wi [i] = 0 ;
+	    }
+
+	    /* count entries in each row of A */
+	    for (j = 0 ; j < ncol ; j++)
+	    {
+		p = Ap [j] ;
+		pend = (Apacked) ? (Ap [j+1]) : (p + Anz [j]) ;
+		for ( ; p < pend ; p++)
+		{
+		    Wi [Ai [p]]++ ;
+		}
+	    }
+	}
+
+    }
+    else
+    {
+
+	/* count entries in each row of A */
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (Apacked) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		Wi [Ai [p]]++ ;
+	    }
+	}
+
+	/* save the nz counts if F is unpacked */
+	if (!Fpacked)
+	{
+	    if (permute)
+	    {
+		for (i = 0 ; i < nrow ; i++)
+		{
+		    Fnz [i] = Wi [Perm [i]] ;
+		}
+	    }
+	    else
+	    {
+		for (i = 0 ; i < nrow ; i++)
+		{
+		    Fnz [i] = Wi [i] ;
+		}
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the row pointers */
+    /* ---------------------------------------------------------------------- */
+
+    p = 0 ;
+    if (permute)
+    {
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    Fp [i] = p ;
+	    p += Wi [Perm [i]] ;
+	}
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    Wi [Perm [i]] = Fp [i] ;
+	}
+    }
+    else
+    {
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    Fp [i] = p ;
+	    p += Wi [i] ;
+	}
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    Wi [i] = Fp [i] ;
+	}
+    }
+    Fp [nrow] = p ;
+
+    if (p > (Int) (F->nzmax))
+    {
+	ERROR (CHOLMOD_INVALID, "F is too small") ;
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* transpose matrix, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    ok = FALSE ;
+    if (values == 0 || F->xtype == CHOLMOD_PATTERN)
+    {
+	ok = p_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ;
+    }
+    else if (F->xtype == CHOLMOD_REAL)
+    {
+	ok = r_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ;
+    }
+    else if (F->xtype == CHOLMOD_COMPLEX)
+    {
+	if (values == 1)
+	{
+	    /* array transpose */
+	    ok = ct_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ;
+	}
+	else
+	{
+	    /* complex conjugate transpose */
+	    ok = c_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ;
+	}
+    }
+    else if (F->xtype == CHOLMOD_ZOMPLEX)
+    {
+	if (values == 1)
+	{
+	    /* array transpose */
+	    ok = zt_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ;
+	}
+	else
+	{
+	    /* complex conjugate transpose */
+	    ok = z_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* finalize result F */
+    /* ---------------------------------------------------------------------- */
+
+    if (ok)
+    {
+	F->sorted = Fsorted ;
+    }
+    ASSERT (CHOLMOD(dump_sparse) (F, "output F unsym", Common) >= 0) ;
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_transpose_sym ================================================ */
+/* ========================================================================== */
+
+/* Compute F = A' or A (p,p)', where A is symmetric and F is already allocated.
+ * See cholmod_transpose for a simpler routine.
+ *
+ * workspace:  Iwork (nrow) if Perm NULL, Iwork (2*nrow) if Perm non-NULL.
+ */
+
+int CHOLMOD(transpose_sym)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    int values,		/* 2: complex conj. transpose, 1: array transpose,
+			   0: do not transpose the numerical values */
+    Int *Perm,		/* size nrow, if present (can be NULL) */
+    /* ---- output --- */
+    cholmod_sparse *F,	/* F = A' or A(p,p)' */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Ap, *Anz, *Ai, *Fp, *Wi, *Pinv, *Iwork ;
+    Int p, pend, packed, upper, permute, jold, n, i, j, k, iold ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (F, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (F, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (A->nrow != A->ncol || A->stype == 0)
+    {
+	/* this routine handles square symmetric matrices only */
+	ERROR (CHOLMOD_INVALID, "matrix must be symmetric") ;
+	return (FALSE) ;
+    }
+    if (A->nrow != F->ncol || A->ncol != F->nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "F has the wrong dimensions") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    permute = (Perm != NULL) ;
+    n = A->nrow ;
+    Ap = A->p ;		/* size A->ncol+1, column pointers of A */
+    Ai = A->i ;		/* size nz = Ap [A->ncol], row indices of A */
+    Anz = A->nz ;
+    packed = A->packed ;
+    ASSERT (IMPLIES (!packed, Anz != NULL)) ;
+    upper = (A->stype > 0) ;
+
+    Fp = F->p ;		/* size A->nrow+1, row pointers of F */
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* s = (Perm != NULL) ? 2*n : n */
+    s = CHOLMOD(add_size_t) (n, ((Perm != NULL) ? n : 0), &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (0, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Iwork = Common->Iwork ;
+    Wi   = Iwork ;	    /* size n (i/l/l) */
+    Pinv = Iwork + n ;	    /* size n (i/i/l) , unused if Perm NULL */
+
+    /* ---------------------------------------------------------------------- */
+    /* check Perm and construct inverse permutation */
+    /* ---------------------------------------------------------------------- */
+
+    if (permute)
+    {
+	for (i = 0 ; i < n ; i++)
+	{
+	    Pinv [i] = EMPTY ;
+	}
+	for (k = 0 ; k < n ; k++)
+	{
+	    i = Perm [k] ;
+	    if (i < 0 || i > n || Pinv [i] != EMPTY)
+	    {
+		ERROR (CHOLMOD_INVALID, "invalid permutation") ;
+		return (FALSE) ;
+	    }
+	    Pinv [i] = k ;
+	}
+    }
+
+    /* Perm is now valid */
+    ASSERT (CHOLMOD(dump_perm) (Perm, n, n, "Perm", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* count the entries in each row of F */
+    /* ---------------------------------------------------------------------- */
+
+    for (i = 0 ; i < n ; i++)
+    {
+	Wi [i] = 0 ;
+    }
+
+    if (packed)
+    {
+	if (permute)
+	{
+	    if (upper)
+	    {
+		/* packed, permuted, upper */
+		for (j = 0 ; j < n ; j++)
+		{
+		    jold = Perm [j] ;
+		    pend = Ap [jold+1] ;
+		    for (p = Ap [jold] ; p < pend ; p++)
+		    {
+			iold = Ai [p] ;
+			if (iold <= jold)
+			{
+			    i = Pinv [iold] ;
+			    Wi [MIN (i, j)]++ ;
+			}
+		    }
+		}
+	    }
+	    else
+	    {
+		/* packed, permuted, lower */
+		for (j = 0 ; j < n ; j++)
+		{
+		    jold = Perm [j] ;
+		    pend = Ap [jold+1] ;
+		    for (p = Ap [jold] ; p < pend ; p++)
+		    {
+			iold = Ai [p] ;
+			if (iold >= jold)
+			{
+			    i = Pinv [iold] ;
+			    Wi [MAX (i, j)]++ ;
+			}
+		    }
+		}
+	    }
+	}
+	else
+	{
+	    if (upper)
+	    {
+		/* packed, unpermuted, upper */
+		for (j = 0 ; j < n ; j++)
+		{
+		    pend = Ap [j+1] ;
+		    for (p = Ap [j] ; p < pend ; p++)
+		    {
+			i = Ai [p] ;
+			if (i <= j)
+			{
+			    Wi [i]++ ;
+			}
+		    }
+		}
+	    }
+	    else
+	    {
+		/* packed, unpermuted, lower */
+		for (j = 0 ; j < n ; j++)
+		{
+		    pend = Ap [j+1] ;
+		    for (p = Ap [j] ; p < pend ; p++)
+		    {
+			i = Ai [p] ;
+			if (i >= j)
+			{
+			    Wi [i]++ ;
+			}
+		    }
+		}
+	    }
+	}
+    }
+    else
+    {
+	if (permute)
+	{
+	    if (upper)
+	    {
+		/* unpacked, permuted, upper */
+		for (j = 0 ; j < n ; j++)
+		{
+		    jold = Perm [j] ;
+		    p = Ap [jold] ;
+		    pend = p + Anz [jold] ;
+		    for ( ; p < pend ; p++)
+		    {
+			iold = Ai [p] ;
+			if (iold <= jold)
+			{
+			    i = Pinv [iold] ;
+			    Wi [MIN (i, j)]++ ;
+			}
+		    }
+		}
+	    }
+	    else
+	    {
+		/* unpacked, permuted, lower */
+		for (j = 0 ; j < n ; j++)
+		{
+		    jold = Perm [j] ;
+		    p = Ap [jold] ;
+		    pend = p + Anz [jold] ;
+		    for ( ; p < pend ; p++)
+		    {
+			iold = Ai [p] ;
+			if (iold >= jold)
+			{
+			    i = Pinv [iold] ;
+			    Wi [MAX (i, j)]++ ;
+			}
+		    }
+		}
+	    }
+	}
+	else
+	{
+	    if (upper)
+	    {
+		/* unpacked, unpermuted, upper */
+		for (j = 0 ; j < n ; j++)
+		{
+		    p = Ap [j] ;
+		    pend = p + Anz [j] ;
+		    for ( ; p < pend ; p++)
+		    {
+			i = Ai [p] ;
+			if (i <= j)
+			{
+			    Wi [i]++ ;
+			}
+		    }
+		}
+	    }
+	    else
+	    {
+		/* unpacked, unpermuted, lower */
+		for (j = 0 ; j < n ; j++)
+		{
+		    p = Ap [j] ;
+		    pend = p + Anz [j] ;
+		    for ( ; p < pend ; p++)
+		    {
+			i = Ai [p] ;
+			if (i >= j)
+			{
+			    Wi [i]++ ;
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the row pointers */
+    /* ---------------------------------------------------------------------- */
+
+    p = 0 ;
+    for (i = 0 ; i < n ; i++)
+    {
+	Fp [i] = p ;
+	p += Wi [i] ;
+    }
+    Fp [n] = p ;
+    for (i = 0 ; i < n ; i++)
+    {
+	Wi [i] = Fp [i] ;
+    }
+
+    if (p > (Int) (F->nzmax))
+    {
+	ERROR (CHOLMOD_INVALID, "F is too small") ;
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* transpose matrix, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    ok = FALSE ;
+    if (values == 0 || F->xtype == CHOLMOD_PATTERN)
+    {
+	PRINT2 (("\n:::: p_transpose_sym Perm %p\n", Perm)) ;
+	ok = p_cholmod_transpose_sym (A, Perm, F, Common) ;
+    }
+    else if (F->xtype == CHOLMOD_REAL)
+    {
+	PRINT2 (("\n:::: r_transpose_sym Perm %p\n", Perm)) ;
+	ok = r_cholmod_transpose_sym (A, Perm, F, Common) ;
+    }
+    else if (F->xtype == CHOLMOD_COMPLEX)
+    {
+	if (values == 1)
+	{
+	    /* array transpose */
+	    PRINT2 (("\n:::: ct_transpose_sym Perm %p\n", Perm)) ;
+	    ok = ct_cholmod_transpose_sym (A, Perm, F, Common) ;
+	}
+	else
+	{
+	    /* complex conjugate transpose */
+	    PRINT2 (("\n:::: c_transpose_sym Perm %p\n", Perm)) ;
+	    ok = c_cholmod_transpose_sym (A, Perm, F, Common) ;
+	}
+    }
+    else if (F->xtype == CHOLMOD_ZOMPLEX)
+    {
+	if (values == 1)
+	{
+	    /* array transpose */
+	    PRINT2 (("\n:::: zt_transpose_sym Perm %p\n", Perm)) ;
+	    ok = zt_cholmod_transpose_sym (A, Perm, F, Common) ;
+	}
+	else
+	{
+	    /* complex conjugate transpose */
+	    PRINT2 (("\n:::: z_transpose_sym Perm %p\n", Perm)) ;
+	    ok = z_cholmod_transpose_sym (A, Perm, F, Common) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* finalize result F */
+    /* ---------------------------------------------------------------------- */
+
+    /* F is sorted if there is no permutation vector */
+    if (ok)
+    {
+	F->sorted = !permute ;
+	F->packed = TRUE ;
+	F->stype = - SIGN (A->stype) ;	/* flip the stype */
+	ASSERT (CHOLMOD(dump_sparse) (F, "output F sym", Common) >= 0) ;
+    }
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_transpose ==================================================== */
+/* ========================================================================== */
+
+/* Returns A'.  See also cholmod_ptranspose below. */
+
+cholmod_sparse *CHOLMOD(transpose)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    int values,		/* 2: complex conj. transpose, 1: array transpose,
+			   0: do not transpose the numerical values
+			   (returns its result as CHOLMOD_PATTERN) */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    return (CHOLMOD(ptranspose) (A, values, NULL, NULL, 0, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_ptranspose =================================================== */
+/* ========================================================================== */
+
+/* Return A' or A(p,p)' if A is symmetric.  Return A', A(:,f)', or A(p,f)' if
+ * A is unsymmetric.
+ *
+ * workspace:
+ * Iwork (MAX (nrow,ncol)) if unsymmetric and fset is non-NULL
+ * Iwork (nrow) if unsymmetric and fset is NULL
+ * Iwork (2*nrow) if symmetric and Perm is non-NULL.
+ * Iwork (nrow) if symmetric and Perm is NULL.
+ *
+ * A simple worst-case upper bound on the workspace is nrow+ncol.
+ */
+
+cholmod_sparse *CHOLMOD(ptranspose)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    int values,		/* 2: complex conj. transpose, 1: array transpose,
+			   0: do not transpose the numerical values */
+    Int *Perm,		/* if non-NULL, F = A(p,f) or A(p,p) */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Ap, *Anz ;
+    cholmod_sparse *F ;
+    Int nrow, ncol, use_fset, j, jj, fnz, packed, stype, nf, xtype ;
+    size_t ineed ;
+    int ok = TRUE ;
+
+    nf = fsize ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ;
+    stype = A->stype ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+
+    if (stype != 0)
+    {
+	use_fset = FALSE ;
+	if (Perm != NULL)
+	{
+	    ineed = CHOLMOD(mult_size_t) (A->nrow, 2, &ok) ;
+	}
+	else
+	{
+	    ineed = A->nrow ;
+	}
+    }
+    else
+    {
+	use_fset = (fset != NULL) ;
+	if (use_fset)
+	{
+	    ineed = MAX (A->nrow, A->ncol) ;
+	}
+	else
+	{
+	    ineed = A->nrow ;
+	}
+    }
+
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (NULL) ;
+    }
+
+    CHOLMOD(allocate_work) (0, ineed, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;
+    Anz = A->nz ;
+    packed = A->packed ;
+    ASSERT (IMPLIES (!packed, Anz != NULL)) ;
+    xtype = values ? A->xtype : CHOLMOD_PATTERN ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate F */
+    /* ---------------------------------------------------------------------- */
+
+    /* determine # of nonzeros in F */
+    if (stype != 0)
+    {
+	/* F=A' or F=A(p,p)', fset is ignored */
+	fnz = CHOLMOD(nnz) (A, Common) ;
+    }
+    else
+    {
+	nf = (use_fset) ? nf : ncol ;
+	if (use_fset)
+	{
+	    fnz = 0 ;
+	    /* F=A(:,f)' or F=A(p,f)' */
+	    for (jj = 0 ; jj < nf ; jj++)
+	    {
+		/* The fset is not yet checked; it will be thoroughly checked
+		 * in cholmod_transpose_unsym.  For now, just make sure we don't
+		 * access Ap and Anz out of bounds. */
+		j = fset [jj] ;
+		if (j >= 0 && j < ncol)
+		{
+		    fnz += packed ? (Ap [j+1] - Ap [j]) : MAX (0, Anz [j]) ;
+		}
+	    }
+	}
+	else
+	{
+	    /* F=A' or F=A(p,:)' */
+	    fnz = CHOLMOD(nnz) (A, Common) ;
+	}
+    }
+
+    /* F is ncol-by-nrow, fnz nonzeros, sorted unless f is present and unsorted,
+     * packed, of opposite stype as A, and with/without numerical values */
+    F = CHOLMOD(allocate_sparse) (ncol, nrow, fnz, TRUE, TRUE, -SIGN(stype),
+	    xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* transpose and optionally permute the matrix A */
+    /* ---------------------------------------------------------------------- */
+
+    if (stype != 0)
+    {
+	/* F = A (p,p)', using upper or lower triangular part of A only */
+	ok = CHOLMOD(transpose_sym) (A, values, Perm, F, Common) ;
+    }
+    else
+    {
+	/* F = A (p,f)' */
+	ok = CHOLMOD(transpose_unsym) (A, values, Perm, fset, nf, F, Common) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the matrix F, or NULL if an error occured */
+    /* ---------------------------------------------------------------------- */
+
+    if (!ok)
+    {
+	CHOLMOD(free_sparse) (&F, Common) ;
+    }
+    return (F) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_sort ========================================================= */
+/* ========================================================================== */
+
+/* Sort the columns of A, in place.  Returns A in packed form, even if it
+ * starts as unpacked.  Removes entries in the ignored part of a symmetric
+ * matrix.
+ *
+ * workspace: Iwork (max (nrow,ncol)).  Allocates additional workspace for a
+ * temporary copy of A'.
+ */
+
+int CHOLMOD(sort)
+(
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix to sort */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Ap ;
+    cholmod_sparse *F ;
+    Int anz, ncol, nrow, stype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    nrow = A->nrow ;
+    if (nrow <= 1)
+    {
+	/* a 1-by-n sparse matrix must be sorted */
+	A->sorted = TRUE ;
+	return (TRUE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    ncol = A->ncol ;
+    CHOLMOD(allocate_work) (0, MAX (nrow, ncol), 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    anz = CHOLMOD(nnz) (A, Common) ;
+    stype = A->stype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* sort the columns of the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    /* allocate workspace for transpose: ncol-by-nrow, same # of nonzeros as A,
+     * sorted, packed, same stype as A, and of the same numeric type as A. */
+    F = CHOLMOD(allocate_sparse) (ncol, nrow, anz, TRUE, TRUE, stype,
+	    A->xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+
+    if (stype != 0)
+    {
+	/* F = A', upper or lower triangular part only */
+	CHOLMOD(transpose_sym) (A, 1, NULL, F, Common) ;
+	A->packed = TRUE ;
+	/* A = F' */
+	CHOLMOD(transpose_sym) (F, 1, NULL, A, Common) ;
+    }
+    else
+    {
+	/* F = A' */
+	CHOLMOD(transpose_unsym) (A, 1, NULL, NULL, 0, F, Common) ;
+	A->packed = TRUE ;
+	/* A = F' */
+	CHOLMOD(transpose_unsym) (F, 1, NULL, NULL, 0, A, Common) ;
+    }
+
+    ASSERT (A->sorted && A->packed) ;
+    ASSERT (CHOLMOD(dump_sparse) (A, "Asorted", Common) >= 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* reduce A in size, if needed.  This must succeed. */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;
+    anz = Ap [ncol] ;
+    ASSERT ((size_t) anz <= A->nzmax) ;
+    CHOLMOD(reallocate_sparse) (anz, A, Common) ;
+    ASSERT (Common->status >= CHOLMOD_OK) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free workspace */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(free_sparse) (&F, Common) ;
+    return (TRUE) ;
+}
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/cholmod_triplet.c b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_triplet.c
new file mode 100644
index 0000000..5ce7ad8
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/cholmod_triplet.c
@@ -0,0 +1,773 @@
+/* ========================================================================== */
+/* === Core/cholmod_triplet ================================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Core utility routines for the cholmod_triplet object:
+ *
+ * A sparse matrix held in triplet form is the simplest one for a user to
+ * create.  It consists of a list of nz entries in arbitrary order, held in
+ * three arrays: i, j, and x, each of length nk.  The kth entry is in row i[k],
+ * column j[k], with value x[k].  There may be duplicate values; if A(i,j)
+ * appears more than once, its value is the sum of the entries with those row
+ * and column indices.
+ *
+ * Primary routines:
+ * -----------------
+ * cholmod_allocate_triplet	allocate a triplet matrix
+ * cholmod_free_triplet		free a triplet matrix
+ *
+ * Secondary routines:
+ * -------------------
+ * cholmod_reallocate_triplet	reallocate a triplet matrix
+ * cholmod_sparse_to_triplet	create a triplet matrix copy of a sparse matrix
+ * cholmod_triplet_to_sparse	create a sparse matrix copy of a triplet matrix
+ * cholmod_copy_triplet		create a copy of a triplet matrix
+ *
+ * The relationship between an m-by-n cholmod_sparse matrix A and a
+ * cholmod_triplet matrix (i, j, and x) is identical to how they are used in
+ * the MATLAB "sparse" and "find" functions:
+ *
+ *	[i j x] = find (A)
+ *	[m n] = size (A)
+ *	A = sparse (i,j,x,m,n)
+ *
+ * with the exception that the cholmod_sparse matrix may be "unpacked", may
+ * have either sorted or unsorted columns (depending on the option selected),
+ * and may be symmetric with just the upper or lower triangular part stored.
+ * Likewise, the cholmod_triplet matrix may contain just the entries in the
+ * upper or lower triangular part of a symmetric matrix.
+ *
+ * MATLAB sparse matrices are always "packed", always have sorted columns,
+ * and always store both parts of a symmetric matrix.  In some cases, MATLAB
+ * behaves like CHOLMOD by ignoring entries in the upper or lower triangular
+ * part of a matrix that is otherwise assumed to be symmetric (such as the
+ * input to chol).  In CHOLMOD, that option is a characteristic of the object.
+ * In MATLAB, that option is based on how a matrix is used as the input to
+ * a function.
+ *
+ * The triplet matrix is provided to give the user a simple way of constructing
+ * a sparse matrix.  There are very few operations supported for triplet
+ * matrices.  The assumption is that they will be converted to cholmod_sparse
+ * matrix form first.
+ *
+ * Adding two triplet matrices simply involves concatenating the contents of
+ * the three arrays (i, j, and x).   To permute a triplet matrix, just replace
+ * the row and column indices with their permuted values.  For example, if
+ * P is a permutation vector, then P [k] = j means row/column j is the kth
+ * row/column in C=P*A*P'.  In MATLAB notation, C=A(p,p).  If Pinv is an array
+ * of size n and T is the triplet form of A, then:
+ *
+ *	Ti = T->i ;
+ *	Tj = T->j ;
+ *	for (k = 0 ; k < n  ; k++) Pinv [P [k]] = k ;
+ *	for (k = 0 ; k < nz ; k++) Ti [k] = Pinv [Ti [k]] ;
+ *	for (k = 0 ; k < nz ; k++) Tj [k] = Pinv [Tj [k]] ;
+ *
+ * overwrites T with the triplet form of C=P*A*P'.  The conversion
+ *
+ *	C = cholmod_triplet_to_sparse (T, 0, &Common) ;
+ *
+ * will then return the matrix C = P*A*P'.
+ *
+ * Note that T->stype > 0 means that entries in the lower triangular part of
+ * T are transposed into the upper triangular part when T is converted to
+ * sparse matrix (cholmod_sparse) form with cholmod_triplet_to_sparse.  The
+ * opposite is true for T->stype < 0.
+ *
+ * Since the triplet matrix T is so simple to generate, it's quite easy
+ * to remove entries that you do not want, prior to converting T to the
+ * cholmod_sparse form.  So if you include these entries in T, CHOLMOD
+ * assumes that there must be a reason (such as the one above).  Thus,
+ * no entry in a triplet matrix is ever ignored.
+ *
+ * Other operations, such as extacting a submatrix, horizontal and vertical
+ * concatenation, multiply a triplet matrix times a dense matrix, are also
+ * simple.  Multiplying two triplet matrices is not trivial; the simplest
+ * method is to convert them to cholmod_sparse matrices first.
+ *
+ * Supports all xtypes (pattern, real, complex, and zomplex).
+ */
+ 
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+
+/* ========================================================================== */
+/* === TEMPLATE ============================================================= */
+/* ========================================================================== */
+
+#define PATTERN
+#include "t_cholmod_triplet.c"
+#define REAL
+#include "t_cholmod_triplet.c"
+#define COMPLEX
+#include "t_cholmod_triplet.c"
+#define ZOMPLEX
+#include "t_cholmod_triplet.c"
+
+
+/* ========================================================================== */
+/* === cholmod_allocate_triplet ============================================= */
+/* ========================================================================== */
+
+/* allocate space for a triplet matrix
+ *
+ * workspace: none
+ */
+
+cholmod_triplet *CHOLMOD(allocate_triplet)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of T */
+    size_t ncol,	/* # of columns of T */
+    size_t nzmax,	/* max # of nonzeros of T */
+    int stype,		/* stype of T */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_triplet *T ;
+    size_t nzmax0 ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    if (xtype < CHOLMOD_PATTERN || xtype > CHOLMOD_ZOMPLEX)
+    {
+	ERROR (CHOLMOD_INVALID, "xtype invalid") ;
+	return (NULL) ;
+    }
+    /* ensure the dimensions do not cause integer overflow */
+    (void) CHOLMOD(add_size_t) (ncol, 2, &ok) ;
+    if (!ok || nrow > Int_max || ncol > Int_max || nzmax > Int_max)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (NULL) ;
+    }
+
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate header */
+    /* ---------------------------------------------------------------------- */
+
+    T = CHOLMOD(malloc) (sizeof (cholmod_triplet), 1, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    PRINT1 (("cholmod_allocate_triplet %d-by-%d nzmax %d xtype %d\n",
+		nrow, ncol, nzmax, xtype)) ;
+
+    nzmax = MAX (1, nzmax) ;
+
+    T->nrow = nrow ;
+    T->ncol = ncol ;
+    T->nzmax = nzmax ;
+    T->nnz = 0 ;
+    T->stype = stype ;
+    T->itype = ITYPE ;
+    T->xtype = xtype ;
+    T->dtype = DTYPE ;
+
+    T->j = NULL ;
+    T->i = NULL ;
+    T->x = NULL ;
+    T->z = NULL ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the matrix itself */
+    /* ---------------------------------------------------------------------- */
+
+    nzmax0 = 0 ;
+    CHOLMOD(realloc_multiple) (nzmax, 2, xtype, &(T->i), &(T->j),
+		&(T->x), &(T->z), &nzmax0, Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free_triplet) (&T, Common) ;
+	return (NULL) ;	    /* out of memory */
+    }
+
+    return (T) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_free_triplet ================================================= */
+/* ========================================================================== */
+
+/* free a triplet matrix
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(free_triplet)
+(
+    /* ---- in/out --- */
+    cholmod_triplet **THandle,    /* matrix to deallocate, NULL on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int nz ;
+    cholmod_triplet *T ;
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+
+    if (THandle == NULL)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+    T = *THandle ;
+    if (T == NULL)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+    nz = T->nzmax ;
+    T->j = CHOLMOD(free) (nz, sizeof (Int), T->j, Common) ;
+    T->i = CHOLMOD(free) (nz, sizeof (Int), T->i, Common) ;
+    if (T->xtype == CHOLMOD_REAL)
+    {
+	T->x = CHOLMOD(free) (nz, sizeof (double), T->x, Common) ;
+    }
+    else if (T->xtype == CHOLMOD_COMPLEX)
+    {
+	T->x = CHOLMOD(free) (nz, 2*sizeof (double), T->x, Common) ;
+    }
+    else if (T->xtype == CHOLMOD_ZOMPLEX)
+    {
+	T->x = CHOLMOD(free) (nz, sizeof (double), T->x, Common) ;
+	T->z = CHOLMOD(free) (nz, sizeof (double), T->z, Common) ;
+    }
+    *THandle = CHOLMOD(free) (1, sizeof (cholmod_triplet), (*THandle), Common) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_reallocate_triplet =========================================== */
+/* ========================================================================== */
+
+/* Change the size of T->i, T->j, and T->x, or allocate them if their current
+ * size is zero.  T->x is not modified if T->xtype is CHOLMOD_PATTERN.
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(reallocate_triplet)
+(
+    /* ---- input ---- */
+    size_t nznew,	/* new # of entries in T */
+    /* ---- in/out --- */
+    cholmod_triplet *T,	/* triplet matrix to modify */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (T, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (T, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    PRINT1 (("realloc triplet %d to %d, xtype: %d\n",
+		T->nzmax, nznew, T->xtype)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* resize the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(realloc_multiple) (MAX (1,nznew), 2, T->xtype, &(T->i), &(T->j),
+	    &(T->x), &(T->z), &(T->nzmax), Common) ;
+
+    return (Common->status == CHOLMOD_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_triplet_to_sparse ============================================ */
+/* ========================================================================== */
+
+/* Convert a set of triplets into a cholmod_sparse matrix.  In MATLAB notation,
+ * for unsymmetric matrices:
+ *
+ *	A = sparse (Ti, Tj, Tx, nrow, ncol, nzmax) ;
+ *
+ * For the symmetric upper case:
+ *
+ *	A = sparse (min(Ti,Tj), max(Ti,Tj), Tx, nrow, ncol, nzmax) ;
+ *
+ * For the symmetric lower case:
+ *
+ *	A = sparse (max(Ti,Tj), min(Ti,Tj), Tx, nrow, ncol, nzmax) ;
+ *
+ * If Tx is NULL, then A->x is not allocated, and only the pattern of A is
+ * computed.  A is returned in packed form, and can be of any stype
+ * (upper/lower/unsymmetric).  It has enough space to hold the values in T,
+ * or nzmax, whichever is larger.
+ *
+ * workspace: Iwork (max (nrow,ncol))
+ *	allocates a temporary copy of its output matrix.
+ *
+ * The resulting sparse matrix has the same xtype as the input triplet matrix.
+ */
+
+cholmod_sparse *CHOLMOD(triplet_to_sparse)
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* matrix to copy */
+    size_t nzmax,	/* allocate at least this much space in output matrix */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *R, *A = NULL ;
+    Int *Wj, *Rp, *Ri, *Rnz, *Ti, *Tj ;
+    Int i, j, p, k, stype, nrow, ncol, nz, ok ;
+    size_t anz = 0 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (T, NULL) ;
+    Ti = T->i ;
+    Tj = T->j ;
+    RETURN_IF_NULL (Ti, NULL) ;
+    RETURN_IF_NULL (Tj, NULL) ;
+    RETURN_IF_XTYPE_INVALID (T, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ;
+    stype = SIGN (T->stype) ;
+    if (stype && T->nrow != T->ncol)
+    {
+	/* inputs invalid */
+	ERROR (CHOLMOD_INVALID, "matrix invalid") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+    DEBUG (CHOLMOD(dump_triplet) (T, "T", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = T->nrow ;
+    ncol = T->ncol ;
+    nz = T->nnz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(allocate_work) (0, MAX (nrow, ncol), 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate temporary matrix R */
+    /* ---------------------------------------------------------------------- */
+
+    R = CHOLMOD(allocate_sparse) (ncol, nrow, nz, FALSE, FALSE, -stype,
+	    T->xtype, Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    Rp = R->p ;
+    Ri = R->i ;
+    Rnz = R->nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* count the entries in each row of A (also counting duplicates) */
+    /* ---------------------------------------------------------------------- */
+
+    for (i = 0 ; i < nrow ; i++)
+    {
+	Rnz [i] = 0 ;	
+    }
+
+    if (stype > 0)
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    i = Ti [k] ;
+	    j = Tj [k] ;
+	    if (i < 0 || i >= nrow || j < 0 || j >= ncol)
+	    {
+		ERROR (CHOLMOD_INVALID, "index out of range") ;
+		break ;
+	    }
+	    /* A will be symmetric with just the upper triangular part stored.
+	     * Create a matrix R that is lower triangular.  Entries in the
+	     * upper part of R are transposed to the lower part. */
+	    Rnz [MIN (i,j)]++ ;
+	}
+    }
+    else if (stype < 0)
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    i = Ti [k] ;
+	    j = Tj [k] ;
+	    if (i < 0 || i >= nrow || j < 0 || j >= ncol)
+	    {
+		ERROR (CHOLMOD_INVALID, "index out of range") ;
+		break ;
+	    }
+	    /* A will be symmetric with just the lower triangular part stored.
+	     * Create a matrix R that is upper triangular.  Entries in the
+	     * lower part of R are transposed to the upper part. */
+	    Rnz [MAX (i,j)]++ ;
+	}
+    }
+    else
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    i = Ti [k] ;
+	    j = Tj [k] ;
+	    if (i < 0 || i >= nrow || j < 0 || j >= ncol)
+	    {
+		ERROR (CHOLMOD_INVALID, "index out of range") ;
+		break ;
+	    }
+	    /* constructing an unsymmetric matrix */
+	    Rnz [i]++ ;
+	}
+    }
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* triplet matrix is invalid */
+	CHOLMOD(free_sparse) (&R, Common) ;
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the row pointers */
+    /* ---------------------------------------------------------------------- */
+
+    p = 0 ;
+    for (i = 0 ; i < nrow ; i++)
+    {
+	Rp [i] = p ;
+	p += Rnz [i] ;
+    }
+    Rp [nrow] = p ;
+
+    /* use Wj (i/l/l) as temporary row pointers */
+    Wj = Common->Iwork ;	/* size MAX (nrow,ncol) FUTURE WORK: (i/l/l) */
+    for (i = 0 ; i < nrow ; i++)
+    {
+	Wj [i] = Rp [i] ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct triplet matrix, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (T->xtype)
+    {
+	case CHOLMOD_PATTERN:
+	    anz = p_cholmod_triplet_to_sparse (T, R, Common) ;
+	    break ;
+
+	case CHOLMOD_REAL:
+	    anz = r_cholmod_triplet_to_sparse (T, R, Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    anz = c_cholmod_triplet_to_sparse (T, R, Common) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    anz = z_cholmod_triplet_to_sparse (T, R, Common) ;
+	    break ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* A = R' (array transpose, not complex conjugate transpose) */
+    /* ---------------------------------------------------------------------- */
+
+    /* workspace: Iwork (R->nrow), which is A->ncol */
+
+    ASSERT (CHOLMOD(dump_sparse) (R, "R", Common) >= 0) ;
+
+    A = CHOLMOD(allocate_sparse) (nrow, ncol, MAX (anz, nzmax), TRUE, TRUE,
+	stype, T->xtype, Common) ;
+
+    if (stype)
+    {
+	ok = CHOLMOD(transpose_sym) (R, 1, NULL, A, Common) ;
+    }
+    else
+    {
+	ok = CHOLMOD(transpose_unsym) (R, 1, NULL, NULL, 0, A, Common) ; 
+    }
+
+    CHOLMOD(free_sparse) (&R, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free_sparse) (&A, Common) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return result */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_sparse) (A, "A = triplet(T) result", Common) >= 0) ;
+    return (A) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_sparse_to_triplet ============================================ */
+/* ========================================================================== */
+
+/* Converts a sparse column-oriented matrix to triplet form.
+ * The resulting triplet matrix has the same xtype as the sparse matrix.
+ *
+ * workspace: none
+ */
+
+cholmod_triplet *CHOLMOD(sparse_to_triplet)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Az, *Tx, *Tz ;
+    Int *Ap, *Ai, *Ti, *Tj, *Anz ;
+    cholmod_triplet *T ;
+    Int i, xtype, p, pend, k, j, nrow, ncol, nz, stype, packed, up, lo,
+	both ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ;
+    stype = SIGN (A->stype) ;
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+    if (stype && nrow != ncol)
+    {
+	/* inputs invalid */
+	ERROR (CHOLMOD_INVALID, "matrix invalid") ;
+	return (NULL) ;
+    }
+    Ax = A->x ;
+    Az = A->z ;
+    xtype = A->xtype ;
+    Common->status = CHOLMOD_OK ;
+
+    ASSERT (CHOLMOD(dump_sparse) (A, "A", Common) >= 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate triplet matrix */
+    /* ---------------------------------------------------------------------- */
+
+    nz = CHOLMOD(nnz) (A, Common) ;
+    T = CHOLMOD(allocate_triplet) (nrow, ncol, nz, A->stype, A->xtype, Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* convert to a sparse matrix */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;
+    Ai = A->i ;
+    Anz = A->nz ;
+    packed = A->packed ;
+
+    Ti = T->i ;
+    Tj = T->j ;
+    Tx = T->x ;
+    Tz = T->z ;
+    T->stype = A->stype ;
+
+    both = (A->stype == 0) ;
+    up = (A->stype > 0) ;
+    lo = (A->stype < 0) ;
+
+    k = 0 ;
+
+    for (j = 0 ; j < ncol ; j++)
+    {
+	p = Ap [j] ;
+	pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	for ( ; p < pend ; p++)
+	{
+	    i = Ai [p] ;
+	    if (both || (up && i <= j) || (lo && i >= j))
+	    {
+		Ti [k] = Ai [p] ;
+		Tj [k] = j ;
+
+		if (xtype == CHOLMOD_REAL)
+		{
+		    Tx [k] = Ax [p] ;
+		}
+		else if (xtype == CHOLMOD_COMPLEX)
+		{
+		    Tx [2*k  ] = Ax [2*p  ] ;
+		    Tx [2*k+1] = Ax [2*p+1] ;
+		}
+		else if (xtype == CHOLMOD_ZOMPLEX)
+		{
+		    Tx [k] = Ax [p] ;
+		    Tz [k] = Az [p] ;
+		}
+
+		k++ ;
+		ASSERT (k <= nz) ;
+	    }
+	}
+    }
+
+    T->nnz = k ;
+
+    /* ---------------------------------------------------------------------- */
+    /* return result */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_triplet) (T, "T", Common)) ;
+    return (T) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_copy_triplet ================================================= */
+/* ========================================================================== */
+
+/* Create an exact copy of a triplet matrix, except that entries in unused
+ * space are not copied (they might not be initialized, and copying them would
+ * cause program checkers such as purify and valgrind to complain).
+ * The output triplet matrix has the same xtype as the input triplet matrix.
+ */
+
+cholmod_triplet *CHOLMOD(copy_triplet)
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Tx, *Tz, *Cx, *Cz ;
+    Int *Ci, *Cj, *Ti, *Tj ;
+    cholmod_triplet *C ;
+    Int xtype, k, nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (T, NULL) ;
+    RETURN_IF_XTYPE_INVALID (T, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ;
+    nz = T->nnz ;
+    Ti = T->i ;
+    Tj = T->j ;
+    Tx = T->x ;
+    Tz = T->z ;
+    xtype = T->xtype ;
+    RETURN_IF_NULL (Ti, NULL) ;
+    RETURN_IF_NULL (Tj, NULL) ;
+    Common->status = CHOLMOD_OK ;
+    DEBUG (CHOLMOD(dump_triplet) (T, "T input", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate copy */
+    /* ---------------------------------------------------------------------- */
+
+    C = CHOLMOD(allocate_triplet) (T->nrow, T->ncol, T->nzmax, T->stype,
+	    xtype, Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* copy the triplet matrix */
+    /* ---------------------------------------------------------------------- */
+
+    Ci = C->i ;
+    Cj = C->j ;
+    Cx = C->x ;
+    Cz = C->z ;
+    C->nnz = nz ;
+
+    for (k = 0 ; k < nz ; k++)
+    {
+	Ci [k] = Ti [k] ;
+    }
+    for (k = 0 ; k < nz ; k++)
+    {
+	Cj [k] = Tj [k] ;
+    }
+
+    if (xtype == CHOLMOD_REAL)
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    Cx [k] = Tx [k] ;
+	}
+    }
+    else if (xtype == CHOLMOD_COMPLEX)
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    Cx [2*k  ] = Tx [2*k  ] ;
+	    Cx [2*k+1] = Tx [2*k+1] ;
+	}
+    }
+    else if (xtype == CHOLMOD_ZOMPLEX)
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    Cx [k] = Tx [k] ;
+	    Cz [k] = Tz [k] ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the result */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_triplet) (C, "C triplet copy", Common)) ;
+    return (C) ;
+}
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/lesser.txt b/src/C/SuiteSparse/CHOLMOD/Core/lesser.txt
new file mode 100644
index 0000000..8add30a
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/lesser.txt
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+

+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+

+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+

+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+

+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+

+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+

+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+

+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+

+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_change_factor.c b/src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_change_factor.c
new file mode 100644
index 0000000..548f883
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_change_factor.c
@@ -0,0 +1,661 @@
+/* ========================================================================== */
+/* === Core/t_cholmod_change_factor ========================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Template routine for cholmod_change_factor.  All xtypes supported. */
+
+#include "cholmod_template.h"
+
+/* ========================================================================== */
+/* === t_change_simplicial_numeric ========================================== */
+/* ========================================================================== */
+
+static void TEMPLATE (change_simplicial_numeric)
+(
+    cholmod_factor *L,
+    Int to_ll,
+    Int to_packed,
+    Int *newLi,
+    double *newLx,
+    double *newLz,
+    Int lnz,
+    Int grow,
+    double grow1,
+    Int grow2,
+    Int make_ll,
+    Int make_monotonic,
+    Int make_ldl,
+    cholmod_common *Common
+)
+{
+    double xlen, dj [1], ljj [1], lj2 [1] ;
+    double *Lx, *Lz ;
+    Int *Lp, *Li, *Lnz ;
+    Int n, j, len, pnew, pold, k, p, pend ;
+
+    n = L->n ;
+    Lp = L->p ;
+    Li = L->i ;
+    Lx = L->x ;
+    Lz = L->z ;
+    Lnz = L->nz ;
+
+    if (make_ll)
+    {
+	L->minor = n ;
+    }
+
+    if (make_monotonic)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* reorder the columns to make them monotonic */
+	/* ------------------------------------------------------------------ */
+
+	pnew = 0 ;
+	for (j = 0 ; j < n ; j++)
+	{
+	    /* copy and pack column j */
+	    len = Lnz [j] ;
+	    PRINT2 (("j: "ID" Lnz[j] "ID" len "ID" p "ID"\n",
+			j, Lnz [j], len, pnew)) ;
+	    pold = Lp [j] ;
+	    ASSERT (Li [pold] == j) ;
+
+	    if (make_ll)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* copy and convert LDL' to LL' */
+		/* ---------------------------------------------------------- */
+
+		/* dj = Lx [pold] ; */
+		ASSIGN_REAL (dj,0, Lx,pold) ;
+
+		if (IS_LE_ZERO (dj [0]))
+		{
+		    /* Conversion has failed; matrix is not positive definite.
+		     * Do not modify the column so that the LDL' factorization
+		     * can be restored if desired, by converting back to LDL'.
+		     * Continue the conversion, but flag the error. */
+		    if (L->minor == (size_t) n)
+		    {
+			ERROR (CHOLMOD_NOT_POSDEF, "L not positive definite") ;
+			L->minor = j ;
+		    }
+		    for (k = 0 ; k < len ; k++)
+		    {
+			newLi [pnew + k] = Li [pold + k] ;
+			/* newLx [pnew + k] = Lx [pold + k] ; */
+			ASSIGN (newLx, newLz, pnew+k, Lx, Lz, pold+k) ;
+		    }
+		}
+		else
+		{
+		    ljj [0] = sqrt (dj [0]) ;
+		    newLi [pnew] = j ;
+		    /* newLx [pnew] = ljj ; */
+		    ASSIGN_REAL (newLx, pnew, ljj, 0) ;
+		    CLEAR_IMAG (newLx, newLz, pnew) ;
+
+		    for (k = 1 ; k < len ; k++)
+		    {
+			newLi [pnew + k] = Li [pold + k] ;
+			/* newLx [pnew + k] = Lx [pold + k] * ljj ; */
+			MULT_REAL (newLx, newLz, pnew+k, Lx, Lz, pold+k, ljj,0);
+		    }
+		}
+
+	    }
+	    else if (make_ldl)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* copy and convert LL' to LDL' */
+		/* ---------------------------------------------------------- */
+
+		/* ljj = Lx [pold] ; */
+		ASSIGN_REAL (ljj, 0, Lx, pold) ;
+
+		if (ljj [0] <= 0)
+		{
+		    /* matrix is not positive-definite; copy column as-is */
+		    for (k = 0 ; k < len ; k++)
+		    {
+			newLi [pnew + k] = Li [pold + k] ;
+			/* newLx [pnew + k] = Lx [pold + k] ; */
+			ASSIGN (newLx, newLz, pnew+k, Lx, Lz, pold+k) ;
+		    }
+		}
+		else
+		{
+		    newLi [pnew] = j ;
+		    /* newLx [pnew] = ljj*ljj ; */
+		    lj2 [0] = ljj [0] * ljj [0] ;
+		    ASSIGN_REAL (newLx, pnew, lj2, 0) ;
+		    CLEAR_IMAG (newLx, newLz, pnew) ;
+
+		    for (k = 1 ; k < len ; k++)
+		    {
+			newLi [pnew + k] = Li [pold + k] ;
+			/* newLx [pnew + k] = Lx [pold + k] / ljj ; */
+			DIV_REAL (newLx, newLz, pnew+k, Lx, Lz, pold+k, ljj,0) ;
+		    }
+		}
+
+	    }
+	    else
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* copy and leave LL' or LDL' as-is */
+		/* ---------------------------------------------------------- */
+
+		for (k = 0 ; k < len ; k++)
+		{
+		    newLi [pnew + k] = Li [pold + k] ;
+		    /* newLx [pnew + k] = Lx [pold + k] ; */
+		    ASSIGN (newLx, newLz, pnew+k, Lx, Lz, pold+k) ;
+		}
+	    }
+
+	    Lp [j] = pnew ;
+
+	    /* compute len in double to avoid integer overflow */
+	    if (grow)
+	    {
+		xlen = (double) len ;
+		xlen = grow1 * xlen + grow2 ;
+		xlen = MIN (xlen, n-j) ;
+		len = (Int) xlen ;
+	    }
+	    ASSERT (len >= Lnz [j] && len <= n-j) ;
+	    pnew += len ;
+	    ASSERT (pnew > 0) ;	    /* integer overflow case already covered */
+	}
+	Lp [n] = pnew ;
+	PRINT1 (("final pnew = "ID", lnz "ID" lnzmax %g\n",
+		    pnew, lnz, (double) L->nzmax)) ;
+	ASSERT (pnew <= lnz) ;
+
+	/* free the old L->i and L->x and replace with the new ones */
+	CHOLMOD(free) (L->nzmax, sizeof (Int), L->i, Common) ;
+
+#ifdef REAL
+	CHOLMOD(free) (L->nzmax, sizeof (double), L->x, Common) ;
+#elif defined (COMPLEX)
+	CHOLMOD(free) (L->nzmax, 2*sizeof (double), L->x, Common) ;
+#else
+	CHOLMOD(free) (L->nzmax, sizeof (double), L->x, Common) ;
+	CHOLMOD(free) (L->nzmax, sizeof (double), L->z, Common) ;
+#endif
+
+	L->i = newLi ;
+	L->x = newLx ;
+	L->z = newLz ;
+	L->nzmax = lnz ;
+
+	/* reconstruct the link list */
+	natural_list (L) ;
+
+    }
+    else if (to_packed)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* already monotonic, just pack the columns of L */
+	/* ------------------------------------------------------------------ */
+
+	pnew = 0 ;
+
+	if (make_ll)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* pack and convert LDL' to LL' */
+	    /* -------------------------------------------------------------- */
+
+	    for (j = 0 ; j < n ; j++)
+	    {
+		/* pack column j */
+		pold = Lp [j] ;
+		len = Lnz [j] ;
+		ASSERT (len > 0) ;
+		ASSERT (Li [pold] == j) ;
+		PRINT2 (("col "ID" pnew "ID" pold "ID"\n", j, pnew, pold)) ;
+
+		/* dj = Lx [pold] ; */
+		ASSIGN_REAL (dj,0, Lx,pold) ;
+
+		if (IS_LE_ZERO (dj [0]))
+		{
+		    /* Conversion has failed; matrix is not positive definite.
+		     * Do not modify the column so that the LDL' factorization
+		     * can be restored if desired, by converting back to LDL'.
+		     * Continue the conversion, but flag the error. */
+		    if (L->minor == (size_t) n)
+		    {
+			ERROR (CHOLMOD_NOT_POSDEF, "L not positive definite") ;
+			L->minor = j ;
+		    }
+		    for (k = 0 ; k < len ; k++)
+		    {
+			Li [pnew + k] = Li [pold + k] ;
+			/* Lx [pnew + k] = Lx [pold + k] ; */
+			ASSIGN (Lx, Lz, pnew+k, Lx, Lz, pold+k) ;
+		    }
+		}
+		else
+		{
+		    ljj [0] = sqrt (dj [0]) ;
+		    Li [pnew] = j ;
+
+		    /* Lx [pnew] = ljj ; */
+		    ASSIGN_REAL (Lx, pnew, ljj, 0) ;
+		    CLEAR_IMAG (Lx, Lz, pnew) ;
+
+		    for (k = 1 ; k < len ; k++)
+		    {
+			Li [pnew + k] = Li [pold + k] ;
+			/* Lx [pnew + k] = Lx [pold + k] * ljj ; */
+			MULT_REAL (Lx, Lz, pnew+k, Lx, Lz, pold+k, ljj,0) ;
+		    }
+		}
+		Lp [j] = pnew ;
+		pnew += len ;
+	    }
+
+	}
+	else if (make_ldl)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* pack and convert LL' to LDL' */
+	    /* -------------------------------------------------------------- */
+
+	    for (j = 0 ; j < n ; j++)
+	    {
+		/* pack column j */
+		pold = Lp [j] ;
+		len = Lnz [j] ;
+
+		/* ljj = Lx [pold] ; */
+		ASSIGN_REAL (ljj, 0, Lx, pold) ;
+
+		ASSERT (len > 0) ;
+		PRINT2 (("col "ID" pnew "ID" pold "ID"\n", j, pnew, pold)) ;
+		if (ljj [0] <= 0)
+		{
+		    /* matrix is not positive-definite; pack column as-is */
+		    for (k = 0 ; k < len ; k++)
+		    {
+			Li [pnew + k] = Li [pold + k] ;
+			/* Lx [pnew + k] = Lx [pold + k] ; */
+			ASSIGN (Lx, Lz, pnew+k, Lx, Lz, pold+k) ;
+		    }
+		}
+		else
+		{
+		    Li [pnew] = Li [pold] ;
+
+		    /* Lx [pnew] = ljj*ljj ; */
+		    lj2 [0] = ljj [0] * ljj [0] ;
+		    ASSIGN_REAL (Lx, pnew, lj2, 0) ;
+		    CLEAR_IMAG (Lx, Lz, pnew) ;
+
+		    for (k = 1 ; k < len ; k++)
+		    {
+			Li [pnew + k] = Li [pold + k] ;
+			/* Lx [pnew + k] = Lx [pold + k] / ljj ; */
+			DIV_REAL (Lx, Lz, pnew+k, Lx, Lz, pold+k, ljj,0) ;
+		    }
+		}
+		Lp [j] = pnew ;
+		pnew += len ;
+	    }
+
+	}
+	else
+	{
+
+	    /* ---------------------------------------------------------- */
+	    /* pack and leave LL' or LDL' as-is */
+	    /* ---------------------------------------------------------- */
+
+	    for (j = 0 ; j < n ; j++)
+	    {
+		/* pack column j */
+		pold = Lp [j] ;
+		len = Lnz [j] ;
+		ASSERT (len > 0) ;
+		PRINT2 (("col "ID" pnew "ID" pold "ID"\n", j, pnew, pold)) ;
+		if (pnew < pold)
+		{
+		    PRINT2 (("    pack this column\n")) ;
+		    for (k = 0 ; k < len ; k++)
+		    {
+			Li [pnew + k] = Li [pold + k] ;
+			/* Lx [pnew + k] = Lx [pold + k] ; */
+			ASSIGN (Lx, Lz, pnew+k, Lx, Lz, pold+k) ;
+		    }
+		    Lp [j] = pnew ;
+		}
+		pnew += len ;
+	    }
+	}
+
+	Lp [n] = pnew ;
+	PRINT2 (("Lp [n] = "ID"\n", pnew)) ;
+
+    }
+    else if (make_ll)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* convert LDL' to LL', but do so in-place */
+	/* ------------------------------------------------------------------ */
+
+	for (j = 0 ; j < n ; j++)
+	{
+	    p = Lp [j] ;
+	    pend = p + Lnz [j] ;
+
+	    /* dj = Lx [p] ; */
+	    ASSIGN_REAL (dj,0, Lx,p) ;
+
+	    if (IS_LE_ZERO (dj [0]))
+	    {
+		/* Conversion has failed; matrix is not positive definite.
+		 * Do not modify the column so that the LDL' factorization
+		 * can be restored if desired, by converting back to LDL'.
+		 * Continue the conversion, but flag the error. */
+		if (L->minor == (size_t) n)
+		{
+		    ERROR (CHOLMOD_NOT_POSDEF, "L not positive definite") ;
+		    L->minor = j ;
+		}
+	    }
+	    else
+	    {
+		ljj [0] = sqrt (dj [0]) ;
+		/* Lx [p] = ljj ; */
+		ASSIGN_REAL (Lx,p, ljj,0) ;
+		CLEAR_IMAG (Lx, Lz, p) ;
+
+		for (p++ ; p < pend ; p++)
+		{
+		    /* Lx [p] *= ljj ; */
+		    MULT_REAL (Lx,Lz,p, Lx,Lz,p, ljj,0) ;
+		}
+	    }
+	}
+
+    }
+    else if (make_ldl)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* convert LL' to LDL', but do so in-place */
+	/* ------------------------------------------------------------------ */
+
+	for (j = 0 ; j < n ; j++)
+	{
+	    p = Lp [j] ;
+	    pend = p + Lnz [j] ;
+
+	    /* ljj = Lx [p] ; */
+	    ASSIGN_REAL (ljj, 0, Lx, p) ;
+
+	    if (ljj [0] > 0)
+	    {
+		/* Lx [p] = ljj*ljj ; */
+		lj2 [0] = ljj [0] * ljj [0] ;
+		ASSIGN_REAL (Lx, p, lj2, 0) ;
+		CLEAR_IMAG (Lx, Lz, p) ;
+
+		for (p++ ; p < pend ; p++)
+		{
+		    /* Lx [p] /= ljj ; */
+		    DIV_REAL (Lx,Lz,p, Lx,Lz,p, ljj,0) ;
+		}
+	    }
+	}
+    }
+
+    L->is_ll = to_ll ;
+
+    DEBUG (CHOLMOD(dump_factor) (L, "done change simplicial numeric", Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === t_ll_super_to_simplicial_numeric ===================================== */
+/* ========================================================================== */
+
+/* A supernodal L can only be real or complex, not zomplex */
+
+#ifndef ZOMPLEX
+
+static void TEMPLATE (ll_super_to_simplicial_numeric)
+(
+    cholmod_factor *L,
+    Int to_packed,
+    Int to_ll,
+    cholmod_common *Common
+)
+{
+    double ljj [1], lj2 [1] ;
+    double *Lx ;
+    Int *Ls, *Lpi, *Lpx, *Super, *Lp, *Li, *Lnz ;
+    Int n, lnz, s, nsuper, p, psi, psx, psend, nsrow, nscol, ii, jj, j, k1, k2,
+	q ;
+
+    L->is_ll = to_ll ;
+
+    Lp = L->p ;
+    Li = L->i ;
+    Lx = L->x ;
+    Lnz = L->nz ;
+    lnz = L->nzmax ;
+
+    n = L->n ;
+    nsuper = L->nsuper ;
+    Lpi = L->pi ;
+    Lpx = L->px ;
+    Ls = L->s ;
+    Super = L->super ;
+
+    p = 0 ;
+
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	k1 = Super [s] ;
+	k2 = Super [s+1] ;
+	psi = Lpi [s] ;
+	psend = Lpi [s+1] ;
+	psx = Lpx [s] ;
+	nsrow = psend - psi ;
+	nscol = k2 - k1 ;
+
+	for (jj = 0 ; jj < nscol ; jj++)
+	{
+	    /* column j of L starts here */
+	    j = jj + k1 ;
+
+	    if (to_ll)
+	    {
+		if (to_packed)
+		{
+
+		    /* ------------------------------------------------------ */
+		    /* convert to LL' packed */
+		    /* ------------------------------------------------------ */
+
+		    Lp [j] = p ;
+		    PRINT2 (("Col j "ID" p "ID"\n", j, p)) ;
+		    for (ii = jj ; ii < nsrow ; ii++)
+		    {
+			/* get L(i,j) from supernode and store in column j */
+			ASSERT (p < (Int) (L->xsize) && p <= psx+ii+jj*nsrow) ;
+			Li [p] = Ls [psi + ii] ;
+			/* Lx [p] = Lx [psx + ii + jj*nsrow] ; */
+			q = psx + ii + jj*nsrow ;
+			ASSIGN (Lx,-,p, Lx,-,q) ;
+			PRINT2 (("  i "ID" ", Li [p])) ;
+			XPRINT2 (Lx,-,q) ;
+			PRINT2 (("\n")) ;
+			p++ ;
+		    }
+		    Lnz [j] = p - Lp [j] ;
+
+		}
+		else
+		{
+
+		    /* ------------------------------------------------------ */
+		    /* convert to LL' unpacked */
+		    /* ------------------------------------------------------ */
+
+		    p = psx + jj + jj*nsrow ;
+		    Lp [j] = p ;
+		    Li [p] = j ;
+		    Lnz [j] = nsrow - jj ;
+		    p++ ;
+		    for (ii = jj + 1 ; ii < nsrow ; ii++)
+		    {
+			/* get L(i,j) from supernode and store in column j */
+			Li [psx + ii + jj*nsrow] = Ls [psi + ii] ;
+		    }
+
+		}
+	    }
+	    else
+	    {
+		if (to_packed)
+		{
+
+		    /* ------------------------------------------------------ */
+		    /* convert to LDL' packed */
+		    /* ------------------------------------------------------ */
+
+		    Lp [j] = p ;
+		    PRINT2 (("Col j "ID" p "ID"\n", Lp [j], p)) ;
+		    /* ljj = Lx [psx + jj + jj*nsrow] ; */
+		    ASSIGN_REAL (ljj, 0, Lx, psx + jj + jj*nsrow) ;
+
+		    if (ljj [0] <= 0)
+		    {
+			/* the matrix is not positive definite; do not divide */
+			/* Lx [p] = ljj ; */
+			ASSIGN_REAL (Lx, p, ljj, 0) ;
+			CLEAR_IMAG (Lx, Lz, p) ;
+			ljj [0] = 1 ;
+		    }
+		    else
+		    {
+			lj2 [0] = ljj [0] * ljj [0] ;
+			/* Lx [p] = ljj*ljj ; */
+			ASSIGN_REAL (Lx, p, lj2, 0) ;
+			CLEAR_IMAG (Lx, Lz, p) ;
+		    }
+		    Li [p] = j ;
+		    p++ ;
+		    for (ii = jj + 1 ; ii < nsrow ; ii++)
+		    {
+			/* get L(i,j) from supernode and store in column j */
+			ASSERT (p < (Int) (L->xsize) && p <= psx+ii+jj*nsrow) ;
+			Li [p] = Ls [psi + ii] ;
+
+			/* Lx [p] = Lx [psx + ii + jj*nsrow] / ljj ; */
+			q = psx + ii + jj*nsrow ;
+			DIV_REAL (Lx, Lz, p, Lx, Lz, q, ljj,0) ;
+
+			PRINT2 (("  i "ID" %g\n", Li [p], Lx [p])) ;
+			p++ ;
+		    }
+		    Lnz [j] = p - Lp [j] ;
+
+		}
+		else
+		{
+
+		    /* ------------------------------------------------------ */
+		    /* convert to LDL' unpacked */
+		    /* ------------------------------------------------------ */
+
+		    p = psx + jj + jj*nsrow ;
+		    Lp [j] = p ;
+
+		    /* ljj = Lx [p] ; */
+		    ASSIGN_REAL (ljj,0, Lx,p) ;
+
+		    if (ljj [0] <= 0)
+		    {
+			/* the matrix is not positive definite; do not divide */
+			/* Lx [p] = ljj ; */
+			ASSIGN_REAL (Lx, p, ljj, 0) ;
+			CLEAR_IMAG (Lx, Lz, p) ;
+			ljj [0] = 1 ;
+		    }
+		    else
+		    {
+			lj2 [0] = ljj [0] * ljj [0] ;
+			/* Lx [p] = ljj*ljj ; */
+			ASSIGN_REAL (Lx, p, lj2, 0) ;
+			CLEAR_IMAG (Lx, Lz, p) ;
+		    }
+		    Li [p] = j ;
+		    Lnz [j] = nsrow - jj ;
+		    p++ ;
+		    for (ii = jj + 1 ; ii < nsrow ; ii++)
+		    {
+			/* get L(i,j) from supernode and store in column j */
+			Li [psx + ii + jj*nsrow] = Ls [psi + ii] ;
+
+			/* Lx [psx + ii + jj*nsrow] /= ljj ; */
+			q = psx + ii + jj*nsrow ;
+			DIV_REAL (Lx, Lz, q, Lx, Lz, q, ljj,0) ;
+		    }
+		}
+	    }
+	}
+    }
+
+    if (to_packed)
+    {
+	Lp [n] = p ;
+	PRINT1 (("Final Lp "ID" n "ID" lnz "ID"\n", p, n, lnz)) ;
+	ASSERT (Lp [n] == lnz) ;
+	ASSERT (lnz <= (Int) (L->xsize)) ;
+	/* reduce size of L->x to match L->i.  This cannot fail. */
+	L->x = CHOLMOD(realloc) (lnz, 
+#ifdef COMPLEX
+		2 *
+#endif
+		sizeof (double), L->x, &(L->xsize), Common) ;
+	ASSERT (lnz == (Int) (L->xsize)) ;
+	Common->status = CHOLMOD_OK ;
+    }
+    else
+    {
+	Lp [n] = Lpx [nsuper] ;
+	ASSERT (MAX (1,Lp [n]) == (Int) (L->xsize)) ;
+	ASSERT (MAX (1,Lp [n]) == (Int) (L->nzmax)) ;
+    }
+}
+
+#endif
+
+#undef PATTERN
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_dense.c b/src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_dense.c
new file mode 100644
index 0000000..6be9e6d
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_dense.c
@@ -0,0 +1,266 @@
+/* ========================================================================== */
+/* === Core/t_cholmod_dense ================================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Template routine for cholmod_dense.  All xtypes supported, except that there
+ * are no dense matrices with an xtype of pattern. */
+
+#include "cholmod_template.h"
+
+/* ========================================================================== */
+/* === t_cholmod_sparse_to_dense ============================================ */
+/* ========================================================================== */
+
+static cholmod_dense *TEMPLATE (cholmod_sparse_to_dense)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Xx, *Az, *Xz ;
+    Int *Ap, *Ai, *Anz ;
+    cholmod_dense *X ;
+    Int i, j, p, pend, nrow, ncol, packed ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+    packed = A->packed ;
+    Ap = A->p ;
+    Ai = A->i ;
+    Ax = A->x ;
+    Az = A->z ;
+    Anz = A->nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate result */
+    /* ---------------------------------------------------------------------- */
+
+    X = CHOLMOD(zeros) (nrow, ncol, XTYPE2, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+    Xx = X->x ;
+    Xz = X->z ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy into dense matrix */
+    /* ---------------------------------------------------------------------- */
+
+    if (A->stype < 0)
+    {
+	/* A is symmetric with lower stored, but both parts of X are present */
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		if (i >= j)
+		{
+		    ASSIGN2 (Xx, Xz, i+j*nrow, Ax, Az, p) ;
+		    ASSIGN2_CONJ (Xx, Xz, j+i*nrow, Ax, Az, p) ;
+		}
+	    }
+	}
+    }
+    else if (A->stype > 0)
+    {
+	/* A is symmetric with upper stored, but both parts of X are present */
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		if (i <= j)
+		{
+		    ASSIGN2 (Xx, Xz, i+j*nrow, Ax, Az, p) ;
+		    ASSIGN2_CONJ (Xx, Xz, j+i*nrow, Ax, Az, p) ;
+		}
+	    }
+	}
+    }
+    else
+    {
+	/* both parts of A and X are present */
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		ASSIGN2 (Xx, Xz, i+j*nrow, Ax, Az, p) ;
+	    }
+	}
+    }
+
+    return (X) ;
+}
+
+
+#ifndef PATTERN
+
+/* There are no dense matrices of xtype CHOLMOD_PATTERN */
+
+/* ========================================================================== */
+/* === t_cholmod_dense_to_sparse ============================================ */
+/* ========================================================================== */
+
+static cholmod_sparse *TEMPLATE (cholmod_dense_to_sparse)
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to copy */
+    int values,		/* TRUE if values to be copied, FALSE otherwise */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Xx, *Cx, *Xz, *Cz ;
+    Int *Ci, *Cp ;
+    cholmod_sparse *C ;
+    Int i, j, p, d, nrow, ncol, nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = X->nrow ;
+    ncol = X->ncol ;
+    d = X->d ;
+    Xx = X->x ;
+    Xz = X->z ;
+
+    /* ---------------------------------------------------------------------- */
+    /* count the number of nonzeros in the result */
+    /* ---------------------------------------------------------------------- */
+
+    nz = 0 ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    if (ENTRY_IS_NONZERO (Xx, Xz, i+j*d))
+	    {
+		nz++ ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the result C */
+    /* ---------------------------------------------------------------------- */
+
+    C = CHOLMOD(allocate_sparse) (nrow, ncol, nz, TRUE, TRUE, 0,
+	    values ? XTYPE : CHOLMOD_PATTERN, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+    Cp = C->p ;
+    Ci = C->i ;
+    Cx = C->x ;
+    Cz = C->z ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy the dense matrix X into the sparse matrix C */
+    /* ---------------------------------------------------------------------- */
+
+    p = 0 ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	Cp [j] = p ;
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    if (ENTRY_IS_NONZERO (Xx, Xz, i+j*d))
+	    {
+		Ci [p] = i ;
+		if (values)
+		{
+		    ASSIGN (Cx, Cz, p, Xx, Xz, i+j*d) ;
+		}
+		p++ ;
+	    }
+	}
+    }
+    ASSERT (p == nz) ;
+    Cp [ncol] = nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* return result */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_sparse) (C, "C", Common) >= 0) ;
+    return (C) ;
+}
+
+
+/* ========================================================================== */
+/* === t_cholmod_copy_dense2 ================================================ */
+/* ========================================================================== */
+
+/* Y = X, where X and Y are both already allocated.  */
+
+static int TEMPLATE (cholmod_copy_dense2)
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to copy */
+    /* ---- output --- */
+    cholmod_dense *Y	/* copy of matrix X */
+)
+{
+    double *Xx, *Xz, *Yx, *Yz ;
+    Int i, j, nrow, ncol, dy, dx ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Xx = X->x ;
+    Xz = X->z ;
+    Yx = Y->x ;
+    Yz = Y->z ;
+    dx = X->d ;
+    dy = Y->d ;
+    nrow = X->nrow ;
+    ncol = X->ncol ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy */
+    /* ---------------------------------------------------------------------- */
+
+    CLEAR (Yx, Yz, 0) ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    ASSIGN (Yx, Yz, i+j*dy, Xx, Xz, i+j*dx) ;
+	}
+    }
+    return (TRUE) ;
+}
+
+#endif
+
+#undef PATTERN
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_transpose.c b/src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_transpose.c
new file mode 100644
index 0000000..f36a20b
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_transpose.c
@@ -0,0 +1,318 @@
+/* ========================================================================== */
+/* === Core/t_cholmod_transpose ============================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Template routine for cholmod_transpose.  All xtypes are supported.  For
+ * complex matrices, either the array tranpose or complex conjugate transpose
+ * can be computed. */
+
+#include "cholmod_template.h"
+
+/* ========================================================================== */
+/* === t_cholmod_transpose_unsym ============================================ */
+/* ========================================================================== */
+
+/* Compute F = A', A (:,f)', or A (p,f)', where A is unsymmetric and F is
+ * already allocated.  The complex case performs either the array transpose
+ * or complex conjugate transpose.
+ *
+ * workspace:
+ * Iwork (MAX (nrow,ncol)) if fset is present
+ * Iwork (nrow) if fset is NULL
+ */
+
+static int TEMPLATE (cholmod_transpose_unsym)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    Int *Perm,		/* size nrow, if present (can be NULL) */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    Int nf,		/* size of fset */
+    /* ---- output --- */
+    cholmod_sparse *F,	/* F = A', A(:,f)', or A(p,f)' */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Az, *Fx, *Fz ;
+    Int *Ap, *Anz, *Ai, *Fp, *Fnz, *Fj, *Wi, *Iwork ;
+    Int j, p, pend, nrow, ncol, Apacked, use_fset, fp, Fpacked, jj, permute ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    /* ensure the xtype of A and F match (ignored if this is pattern version) */
+    if (!XTYPE_OK (A->xtype))
+    {
+	ERROR (CHOLMOD_INVALID, "real/complex mismatch") ;
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    use_fset = (fset != NULL) ;
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+
+    Ap = A->p ;		/* size A->ncol+1, column pointers of A */
+    Ai = A->i ;		/* size nz = Ap [A->ncol], row indices of A */
+    Ax = A->x ;		/* size nz, real values of A */
+    Az = A->z ;		/* size nz, imag values of A */
+    Anz = A->nz ;
+    Apacked = A->packed ;
+    ASSERT (IMPLIES (!Apacked, Anz != NULL)) ;
+
+    permute = (Perm != NULL) ;
+
+    Fp = F->p ;		/* size A->nrow+1, row pointers of F */
+    Fj = F->i ;		/* size nz, column indices of F */
+    Fx = F->x ;		/* size nz, real values of F */
+    Fz = F->z ;		/* size nz, imag values of F */
+    Fnz = F->nz ;
+    Fpacked = F->packed ;
+    ASSERT (IMPLIES (!Fpacked, Fnz != NULL)) ;
+
+    nf = (use_fset) ? nf : ncol ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Iwork = Common->Iwork ;
+    Wi = Iwork ;		/* size nrow (i/l/l) */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the transpose */
+    /* ---------------------------------------------------------------------- */
+
+    for (jj = 0 ; jj < nf ; jj++)
+    {
+	j = (use_fset) ? (fset [jj]) : jj ;
+	p = Ap [j] ;
+	pend = (Apacked) ? (Ap [j+1]) : (p + Anz [j]) ;
+	for ( ; p < pend ; p++)
+	{
+	    fp = Wi [Ai [p]]++ ;
+	    Fj [fp] = j ;
+#ifdef NCONJUGATE
+	    ASSIGN (Fx, Fz, fp, Ax, Az, p) ;
+#else
+	    ASSIGN_CONJ (Fx, Fz, fp, Ax, Az, p) ;
+#endif
+	}
+    }
+
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === t_cholmod_transpose_sym ============================================== */
+/* ========================================================================== */
+
+/* Compute F = A' or A (p,p)', where A is symmetric and F is already allocated.
+ * The complex case performs either the array transpose or complex conjugate
+ * transpose.
+ *
+ * workspace:  Iwork (nrow) if Perm NULL, Iwork (2*nrow) if Perm non-NULL.
+ */
+
+static int TEMPLATE (cholmod_transpose_sym)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    Int *Perm,		/* size n, if present (can be NULL) */
+    /* ---- output --- */
+    cholmod_sparse *F,	/* F = A' or A(p,p)' */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Az, *Fx, *Fz ;
+    Int *Ap, *Anz, *Ai, *Fp, *Fj, *Wi, *Pinv, *Iwork ;
+    Int p, pend, packed, fp, upper, permute, jold, n, i, j, iold ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    /* ensure the xtype of A and F match (ignored if this is pattern version) */
+    if (!XTYPE_OK (A->xtype))
+    {
+	ERROR (CHOLMOD_INVALID, "real/complex mismatch") ;
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    permute = (Perm != NULL) ;
+    n = A->nrow ;
+    Ap = A->p ;		/* size A->ncol+1, column pointers of A */
+    Ai = A->i ;		/* size nz = Ap [A->ncol], row indices of A */
+    Ax = A->x ;		/* size nz, real values of A */
+    Az = A->z ;		/* size nz, imag values of A */
+    Anz = A->nz ;
+    packed = A->packed ;
+    ASSERT (IMPLIES (!packed, Anz != NULL)) ;
+    upper = (A->stype > 0) ;
+
+    Fp = F->p ;		/* size A->nrow+1, row pointers of F */
+    Fj = F->i ;		/* size nz, column indices of F */
+    Fx = F->x ;		/* size nz, real values of F */
+    Fz = F->z ;		/* size nz, imag values of F */
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Iwork = Common->Iwork ;
+    Wi = Iwork ;	/* size n (i/l/l) */
+    Pinv = Iwork + n ;	/* size n (i/i/l) , unused if Perm NULL */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the transpose */
+    /* ---------------------------------------------------------------------- */
+
+    if (permute)
+    {
+	if (upper)
+	{
+	    /* permuted, upper */
+	    for (j = 0 ; j < n ; j++)
+	    {
+		jold = Perm [j] ;
+		p = Ap [jold] ;
+		pend = (packed) ? Ap [jold+1] : p + Anz [jold] ;
+		for ( ; p < pend ; p++)
+		{
+		    iold = Ai [p] ;
+		    if (iold <= jold)
+		    {
+			i = Pinv [iold] ;
+			if (i < j)
+			{
+			    fp = Wi [i]++ ;
+			    Fj [fp] = j ;
+#ifdef NCONJUGATE
+			    ASSIGN (Fx, Fz, fp, Ax, Az, p) ;
+#else
+			    ASSIGN_CONJ (Fx, Fz, fp, Ax, Az, p) ;
+#endif
+			}
+			else
+			{
+			    fp = Wi [j]++ ;
+			    Fj [fp] = i ;
+			    ASSIGN (Fx, Fz, fp, Ax, Az, p) ;
+			}
+		    }
+		}
+	    }
+	}
+	else
+	{
+	    /* permuted, lower */
+	    for (j = 0 ; j < n ; j++)
+	    {
+		jold = Perm [j] ;
+		p = Ap [jold] ;
+		pend = (packed) ? Ap [jold+1] : p + Anz [jold] ;
+		for ( ; p < pend ; p++)
+		{
+		    iold = Ai [p] ;
+		    if (iold >= jold)
+		    {
+			i = Pinv [iold] ;
+			if (i > j)
+			{
+			    fp = Wi [i]++ ;
+			    Fj [fp] = j ;
+#ifdef NCONJUGATE
+			    ASSIGN (Fx, Fz, fp, Ax, Az, p) ;
+#else
+			    ASSIGN_CONJ (Fx, Fz, fp, Ax, Az, p) ;
+#endif
+			}
+			else
+			{
+			    fp = Wi [j]++ ;
+			    Fj [fp] = i ;
+			    ASSIGN (Fx, Fz, fp, Ax, Az, p) ;
+			}
+		    }
+		}
+	    }
+	}
+    }
+    else
+    {
+	if (upper)
+	{
+	    /* unpermuted, upper */
+	    for (j = 0 ; j < n ; j++)
+	    {
+		p = Ap [j] ;
+		pend = (packed) ? Ap [j+1] : p + Anz [j] ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i <= j)
+		    {
+			fp = Wi [i]++ ;
+			Fj [fp] = j ;
+#ifdef NCONJUGATE
+			ASSIGN (Fx, Fz, fp, Ax, Az, p) ;
+#else
+			ASSIGN_CONJ (Fx, Fz, fp, Ax, Az, p) ;
+#endif
+		    }
+		}
+	    }
+	}
+	else
+	{
+	    /* unpermuted, lower */
+	    for (j = 0 ; j < n ; j++)
+	    {
+		p = Ap [j] ;
+		pend = (packed) ? Ap [j+1] : p + Anz [j] ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i >= j)
+		    {
+			fp = Wi [i]++ ;
+			Fj [fp] = j ;
+#ifdef NCONJUGATE
+			ASSIGN (Fx, Fz, fp, Ax, Az, p) ;
+#else
+			ASSIGN_CONJ (Fx, Fz, fp, Ax, Az, p) ;
+#endif
+		    }
+		}
+	    }
+	}
+    }
+
+    return (TRUE) ;
+}
+
+#undef PATTERN
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
+#undef NCONJUGATE
diff --git a/src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_triplet.c b/src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_triplet.c
new file mode 100644
index 0000000..d917175
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_triplet.c
@@ -0,0 +1,176 @@
+/* ========================================================================== */
+/* === Core/t_cholmod_triplet =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Template routine for cholmod_triplet.  All xtypes supported */
+
+#include "cholmod_template.h"
+
+/* ========================================================================== */
+/* === t_cholmod_triplet_to_sparse ========================================== */
+/* ========================================================================== */
+
+static size_t TEMPLATE (cholmod_triplet_to_sparse)
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* matrix to copy */
+    /* ---- in/out --- */
+    cholmod_sparse *R,	/* output matrix */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Rx, *Rz, *Tx, *Tz ;
+    Int *Wj, *Rp, *Ri, *Rnz, *Ti, *Tj  ;
+    Int i, j, p, p1, p2, pdest, pj, k, stype, nrow, ncol, nz ;
+    size_t anz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    /* Wj contains a copy of Rp on input [ */
+    Wj = Common->Iwork ;	/* size MAX (nrow,ncol). (i/l/l) */
+
+    Rp = R->p ;
+    Ri = R->i ;
+    Rnz = R->nz ;
+    Rx = R->x ;
+    Rz = R->z ;
+
+    Ti = T->i ;
+    Tj = T->j ;
+    Tx = T->x ;
+    Tz = T->z ;
+    nz = T->nnz ;
+    nrow = T->nrow ;
+    ncol = T->ncol ;
+    stype = SIGN (T->stype) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the row form */
+    /* ---------------------------------------------------------------------- */
+
+    /* if Ti is jumbled, this part dominates the run time */
+
+    if (stype > 0)
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    i = Ti [k] ;
+	    j = Tj [k] ;
+	    if (i < j)
+	    {
+		/* place triplet (j,i,x) in column i of R */
+		p = Wj [i]++ ;
+		Ri [p] = j ;
+	    }
+	    else
+	    {
+		/* place triplet (i,j,x) in column j of R */
+		p = Wj [j]++ ;
+		Ri [p] = i ;
+	    }
+	    ASSIGN (Rx, Rz, p, Tx, Tz, k) ;
+	}
+    }
+    else if (stype < 0)
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    i = Ti [k] ;
+	    j = Tj [k] ;
+	    if (i > j)
+	    {
+		/* place triplet (j,i,x) in column i of R */
+		p = Wj [i]++ ;
+		Ri [p] = j ;
+	    }
+	    else
+	    {
+		/* place triplet (i,j,x) in column j of R */
+		p = Wj [j]++ ;
+		Ri [p] = i ;
+	    }
+	    ASSIGN (Rx, Rz, p, Tx, Tz, k) ;
+	}
+    }
+    else
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    /* place triplet (i,j,x) in column i of R */
+	    p = Wj [Ti [k]]++ ;
+	    Ri [p] = Tj [k] ;
+	    ASSIGN (Rx, Rz, p, Tx, Tz, k) ;
+	}
+    }
+
+    /* done using Wj (i/l/l) as temporary row pointers ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* sum up duplicates */
+    /* ---------------------------------------------------------------------- */
+
+    /* use Wj (i/l/l) of size ncol to keep track of duplicates in each row [ */
+    for (j = 0 ; j < ncol ; j++)
+    {
+	Wj [j] = EMPTY ;
+    }
+
+    anz = 0 ;
+    for (i = 0 ; i < nrow ; i++)
+    {
+	p1 = Rp [i] ;
+	p2 = Rp [i+1] ;
+	pdest = p1 ;
+	/* at this point Wj [j] < p1 holds true for all columns j, because
+	 * Ri/Rx is stored in row oriented manner */
+	for (p = p1 ; p < p2 ; p++)
+	{
+	    j = Ri [p] ;
+	    pj = Wj [j] ;
+	    if (pj >= p1)
+	    {
+		/* this column index j is already in row i at position pj;
+		 * sum up the duplicate entry */
+		/* Rx [pj] += Rx [p] ; */
+		ASSEMBLE (Rx, Rz, pj, Rx, Rz, p) ;
+	    }
+	    else
+	    {
+		/* keep the entry and keep track in Wj [j] for case above */
+		Wj [j] = pdest ;
+		if (pdest != p)
+		{
+		    Ri [pdest] = j ;
+		    ASSIGN (Rx, Rz, pdest, Rx, Rz, p) ;
+		}
+		pdest++ ;
+	    }
+	}
+	Rnz [i] = pdest - p1 ;
+	anz += (pdest - p1) ;
+    }
+    /* done using Wj to keep track of duplicate entries in each row ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* return number of entries after summing up duplicates */
+    /* ---------------------------------------------------------------------- */
+
+    return (anz) ;
+}
+
+#undef PATTERN
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
diff --git a/src/C/SuiteSparse/CHOLMOD/Doc/ChangeLog b/src/C/SuiteSparse/CHOLMOD/Doc/ChangeLog
new file mode 100644
index 0000000..f16584d
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Doc/ChangeLog
@@ -0,0 +1,146 @@
+Dec 12, 2006, version 1.4.0
+
+    * added support for large files (larger than 2GB)
+
+    * minor MATLAB cleanup
+
+    * renamed MATLAB function from cholmod to cholmod2, to avoid filename clash
+	with itself (the built-in version of cholmod).
+
+Dec 2, 2006, version 1.3.0
+
+    * Major modification to cholmod_read.c; now fully supports all forms of the
+	Matrix Market format.  Added cholmod_read_dense and cholmod_read_matrix
+	functions to cholmod_read.c.  Major changes to mread MATLAB function.
+	Added Common->prefer_binary option for cholmod_read.
+
+    * Added cholmod_write.c (cholmod_write_sparse and cholmod_write_dense
+	functions).  Added mwrite MATLAB function.
+
+    * Added 2nd output argument to sparse2 (Z, binary pattern of explicit
+	zero entries).
+
+    * Added the function cholmod_symmetry to the MatrixOps module.
+	Added spsym MATLAB function.
+
+    * 2nd argument to cholmod_triplet_to_sparse changed from int to size_t.
+
+    * minor correction to cholmod_analyze_ordering, cholmod_dense.c
+
+    * minor change to cholmod_rowfac.c, cholmod_solve.c, ...
+	to allow for easier testing.
+
+Sept 28, 2006, version 1.2.1
+
+    * bug fix to cholmod_matlab.c, when working with sparse INT64 matrices
+	in the "sparse2" function
+
+Aug 31, 2006, version 1.2
+
+    * Common->default_nesdis parameter and Common->called_nd statistic added.
+	Otherwise, no change to user interface.  v1.2 is fully upward
+	compatible with v1.1 (even binary compatible).
+
+    * non-supernodal Lx=b and L'x=b solves simplified, slight increase in
+	performance.
+
+    * update/downdate performance improved.
+
+    * ordering options and output statistics added to MATLAB/cholmod
+	mexFunction.
+
+July 27, 2006, version 1.1.1
+
+    * bug fix for cholmod_rowfac_mask, for the complex case.  Has no
+	effect on MATLAB.
+
+June 27, 2006:
+
+    * trivial changes to nested dissection code, and cholmod_read.c (for
+	debugging, and to add explicit typecasts so compilers don't complain).
+
+May, 2006:
+
+    * Added new routines for LPDASA: cholmod_rowfac_mask, cholmod_updown_mask.
+	Added cholmod_collapse_septree.  Added nd_oksep, nd_components
+	parameters to Common.
+
+Apr 30, 2006: version 1.1
+
+    * added interface to CAMD.  cholmod_nested_dissection can now call
+	CCOLAMD, CSYMAMD, and CAMD.  Common->nd_camd usage extended.
+	New argument added to nesdis mexFunction.  New cholmod_camd function
+	added.  No other changes to CHOLMOD user interface.
+
+    * more careful integer overflow checks.  Added non-user-callable functions
+	to add and multiply size_t integers, with overflow checks.
+
+    * added Common->no_workspace_reallocate
+
+    * flop count is now correct for A*A' case (Common->rowfacfl).
+
+Jan 18, 2006: version 1.0.2
+
+    * bug fix: MATLAB interface incorrect for full logical matrices.
+
+    * Tcov tests modified to generate fewer intentional nan's, to make it
+	easier to look for errors in BLAS libraries that incorrectly
+	generate nan's.
+
+Dec 16, 2005: version 1.0.1
+
+    * bug fix: cholmod_amd allocated too small of a workspace when ordering A*A'
+
+Dec 8, 2005: version 1.0
+
+    * no real changes.  Version 1.0 is the same as version 0.8.  Version 1.0 is
+	simply the formal stable release.
+
+    * known issue:  the floating point operation count, Common->rowfacfl, is
+	statistic is incorrect when factorizing A*A'.  This will be fixed in
+	version 1.1.
+
+Nov 15, 2005: version 0.8
+
+    * bug fix in t_cholmod_super_numeric, for [R,p]=chol(A) usage.
+
+    * Common->quick_return_if_not_posdef added.
+
+    * Added cholmod_row_lsubtree (required for LPDASA)
+
+    * bug fix: cholmod_rcond returned sqrt(1/cond) for an LL' factorization;
+	1/cond is required.
+
+    * new statistics added: flop counts for cholmod_rowfac, # of factor column
+	reallocations, # of factor reallocations due to column reallocations,
+	and # of times the (non-default) bounds on diag(L) are hit.
+
+    * factor column reallocation skipped if space already big enough.
+
+    * bug fix: cholmod_copy_factor did not copy L->is_monotonic.
+
+    * bug fix: cholmod_change_factor (diagonal entry was wrong in one case)
+
+    * rcond added to cholmod mexFunction ([x,rcond] = cholmod(A,b)).
+
+    * cholmod_rowadd, cholmod_rowdel modified.  rowdel no longer removes
+	entries from the matrix; it sets them to zero instead.
+
+Oct 10, 2005: version 0.7
+
+    * minor changes:  minor change to Check/cholmod_check.c (coerce
+	sizeof(...) to (int) when printing. Less strict check on A->p for
+	unpacked matrices) , removed a few unused variables in
+	Check/cholmod_read.c and Demo/cholmod*demo.c, changed "exit(0)" to
+	"return(0)" in Demo/cholmod_simple.c.  Changed Makefile so that "." is
+	not assumed to be on the $path.  Added Cygwin to architecture detection
+	in Include/cholmod_blas.h.  Added cparent and cmember to nesdis.m.
+	Space for future expansion added to cholmod_common.
+
+    * removed "rowmark" from the Modify module, which affects how partial
+	updates to Lx=b solves are done during update/downdate.  Should only
+	affect LPDASA.
+
+    * added CHOLMOD_SUBSUB_VERSION
+
+Aug 31, 2005:  version 0.6 released.
diff --git a/src/C/SuiteSparse/CHOLMOD/Doc/Makefile b/src/C/SuiteSparse/CHOLMOD/Doc/Makefile
new file mode 100644
index 0000000..e661e91
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Doc/Makefile
@@ -0,0 +1,227 @@
+default: all
+
+include ../../UFconfig/UFconfig.mk
+
+all: UserGuide.pdf
+
+I = \
+	../Include/cholmod.h \
+	../Include/cholmod_blas.h \
+	../Include/cholmod_check.h \
+	../Include/cholmod_cholesky.h \
+	../Include/cholmod_complexity.h \
+	../Include/cholmod_config.h \
+	../Include/cholmod_core.h \
+	../Include/cholmod_internal.h \
+	../Include/cholmod_matrixops.h \
+	../Include/cholmod_modify.h \
+	../Include/cholmod_partition.h \
+	../Include/cholmod_supernodal.h \
+	../Include/cholmod_template.h
+
+C = ../Demo/cholmod_simple.c
+
+M = \
+	../MATLAB/analyze.m \
+	../MATLAB/bisect.m \
+	../MATLAB/chol2.m \
+	../MATLAB/cholmod2.m \
+	../MATLAB/cholmod_demo.m \
+	../MATLAB/cholmod_make.m \
+	../MATLAB/etree2.m \
+	../MATLAB/graph_demo.m \
+	../MATLAB/lchol.m \
+	../MATLAB/ldlchol.m \
+	../MATLAB/ldl_normest.m \
+	../MATLAB/ldlsolve.m \
+	../MATLAB/ldlsplit.m \
+	../MATLAB/ldlupdate.m \
+	../MATLAB/lu_normest.m \
+	../MATLAB/metis.m \
+	../MATLAB/nesdis.m \
+	../MATLAB/resymbol.m \
+	../MATLAB/sdmult.m \
+	../MATLAB/sparse2.m \
+	../MATLAB/spsym.m \
+	../MATLAB/mread.m \
+	../MATLAB/mwrite.m \
+	../MATLAB/symbfact2.m
+
+UserGuide.pdf: UserGuide.tex UserGuide.bib $(I) $(C) $(M) Makefile getproto rule.awk header.tex footer.tex getmproto mfooter.tex mheader.tex mfile.awk
+	./getmproto ../MATLAB/analyze.m > _analyze_m.tex
+	./getmproto ../MATLAB/bisect.m > _bisect_m.tex
+	./getmproto ../MATLAB/chol2.m > _chol2_m.tex
+	./getmproto ../MATLAB/cholmod2.m > _cholmod2_m.tex
+	./getmproto ../MATLAB/cholmod_demo.m > _cholmod_demo_m.tex
+	./getmproto ../MATLAB/cholmod_make.m > _cholmod_make_m.tex
+	./getmproto ../MATLAB/etree2.m > _etree2_m.tex
+	./getmproto ../MATLAB/graph_demo.m > _graph_demo_m.tex
+	./getmproto ../MATLAB/lchol.m > _lchol_m.tex
+	./getmproto ../MATLAB/ldlchol.m > _ldlchol_m.tex
+	./getmproto ../MATLAB/ldl_normest.m > _ldl_normest_m.tex
+	./getmproto ../MATLAB/ldlsolve.m > _ldlsolve_m.tex
+	./getmproto ../MATLAB/ldlsplit.m > _ldlsplit_m.tex
+	./getmproto ../MATLAB/ldlupdate.m > _ldlupdate_m.tex
+	./getmproto ../MATLAB/lu_normest.m > _lu_normest_m.tex
+	./getmproto ../MATLAB/metis.m > _metis_m.tex
+	./getmproto ../MATLAB/mread.m > _mread_m.tex
+	./getmproto ../MATLAB/spsym.m > _spsym_m.tex
+	./getmproto ../MATLAB/mwrite.m > _mwrite_m.tex
+	./getmproto ../MATLAB/nesdis.m > _nesdis_m.tex
+	./getmproto ../MATLAB/resymbol.m > _resymbol_m.tex
+	./getmproto ../MATLAB/sdmult.m > _sdmult_m.tex
+	./getmproto ../MATLAB/sparse2.m > _sparse2_m.tex
+	./getmproto ../MATLAB/symbfact2.m > _symbfact2_m.tex
+	./getproto '/include/, /^}/' ../Demo/cholmod_simple.c > _simple.tex
+	./getproto '/typedef struct cholmod_common/, /^}/' ../Include/cholmod_core.h > _common.tex
+	./getproto '/int cholmod_start/, /\*\) ;/' ../Include/cholmod_core.h > _start.tex
+	./getproto '/int cholmod_finish/, /\*\) ;/' ../Include/cholmod_core.h > _finish.tex
+	./getproto '/int cholmod_defaults/, /\*\) ;/' ../Include/cholmod_core.h > _defaults.tex
+	./getproto '/size_t cholmod_maxrank/, /\*\) ;/' ../Include/cholmod_core.h > _maxrank.tex
+	./getproto '/int cholmod_allocate_work/, /\*\) ;/' ../Include/cholmod_core.h > _allocate_work.tex
+	./getproto '/int cholmod_free_work/, /\*\) ;/' ../Include/cholmod_core.h > _free_work.tex
+	./getproto '/long cholmod_clear_flag/, /\*\) ;/' ../Include/cholmod_core.h > _clear_flag.tex
+	./getproto '/int cholmod_error/, /\*\) ;/' ../Include/cholmod_core.h > _error.tex
+	./getproto '/double cholmod_dbound/, /\*\) ;/' ../Include/cholmod_core.h > _dbound.tex
+	./getproto '/double cholmod_hypot/, /double\) ;/' ../Include/cholmod_core.h > _hypot.tex
+	./getproto '/int cholmod_divcomplex/, /\*\) ;/' ../Include/cholmod_core.h > _divcomplex.tex
+	./getproto '/typedef struct cholmod_sparse/, /^}/' ../Include/cholmod_core.h > _sparse.tex
+	./getproto '/cholmod_sparse \*cholmod_allocate_sparse/, /\*\) ;/' ../Include/cholmod_core.h > _allocate_sparse.tex
+	./getproto '/int cholmod_free_sparse/, /\*\) ;/' ../Include/cholmod_core.h > _free_sparse.tex
+	./getproto '/int cholmod_reallocate_sparse/, /\*\) ;/' ../Include/cholmod_core.h > _reallocate_sparse.tex
+	./getproto '/long cholmod_nnz/, /\*\) ;/' ../Include/cholmod_core.h > _nnz.tex
+	./getproto '/cholmod_sparse \*cholmod_speye/, /\*\) ;/' ../Include/cholmod_core.h > _speye.tex
+	./getproto '/cholmod_sparse \*cholmod_spzeros/, /\*\) ;/' ../Include/cholmod_core.h > _spzeros.tex
+	./getproto '/cholmod_sparse \*cholmod_transpose/, /\*\) ;/' ../Include/cholmod_core.h > _transpose.tex
+	./getproto '/int cholmod_transpose_unsym/, /\*\) ;/' ../Include/cholmod_core.h > _transpose_unsym.tex
+	./getproto '/int cholmod_transpose_sym/, /\*\) ;/' ../Include/cholmod_core.h > _transpose_sym.tex
+	./getproto '/cholmod_sparse \*cholmod_ptranspose/, /\*\) ;/' ../Include/cholmod_core.h > _ptranspose.tex
+	./getproto '/int cholmod_sort/, /\*\) ;/' ../Include/cholmod_core.h > _sort.tex
+	./getproto '/cholmod_sparse \*cholmod_band/, /\*\) ;/' ../Include/cholmod_core.h > _band.tex
+	./getproto '/int cholmod_band_inplace/, /\*\) ;/' ../Include/cholmod_core.h > _band_inplace.tex
+	./getproto '/cholmod_sparse \*cholmod_aat/, /\*\) ;/' ../Include/cholmod_core.h > _aat.tex
+	./getproto '/cholmod_sparse \*cholmod_copy_sparse/, /\*\) ;/' ../Include/cholmod_core.h > _copy_sparse.tex
+	./getproto '/cholmod_sparse \*cholmod_copy /, /\*\) ;/' ../Include/cholmod_core.h > _copy.tex
+	./getproto '/cholmod_sparse \*cholmod_add/, /\*\) ;/' ../Include/cholmod_core.h > _add.tex
+	./getproto '/int cholmod_sparse_xtype/, /\*\) ;/' ../Include/cholmod_core.h > _sparse_xtype.tex 
+	./getproto '/typedef struct cholmod_factor/, /^}/' ../Include/cholmod_core.h > _factor.tex 
+	./getproto '/cholmod_factor \*cholmod_allocate_factor/, /\*\) ;/' ../Include/cholmod_core.h > _allocate_factor.tex 
+	./getproto '/int cholmod_free_factor/, /\*\) ;/' ../Include/cholmod_core.h > _free_factor.tex 
+	./getproto '/int cholmod_reallocate_factor/, /\*\) ;/' ../Include/cholmod_core.h > _reallocate_factor.tex 
+	./getproto '/int cholmod_change_factor/, /\*\) ;/' ../Include/cholmod_core.h > _change_factor.tex 
+	./getproto '/int cholmod_pack_factor/, /\*\) ;/' ../Include/cholmod_core.h > _pack_factor.tex 
+	./getproto '/int cholmod_reallocate_column/, /\*\) ;/' ../Include/cholmod_core.h > _reallocate_column.tex 
+	./getproto '/cholmod_sparse \*cholmod_factor_to_sparse/, /\*\) ;/' ../Include/cholmod_core.h > _factor_to_sparse.tex 
+	./getproto '/cholmod_factor \*cholmod_copy_factor/, /\*\) ;/' ../Include/cholmod_core.h > _copy_factor.tex 
+	./getproto '/int cholmod_factor_xtype/, /\*\) ;/' ../Include/cholmod_core.h > _factor_xtype.tex 
+	./getproto '/typedef struct cholmod_dense/, /^}/' ../Include/cholmod_core.h > _dense.tex 
+	./getproto '/cholmod_dense \*cholmod_allocate_dense/, /\*\) ;/' ../Include/cholmod_core.h > _allocate_dense.tex 
+	./getproto '/cholmod_dense \*cholmod_zeros/, /\*\) ;/' ../Include/cholmod_core.h > _zeros.tex 
+	./getproto '/cholmod_dense \*cholmod_ones/, /\*\) ;/' ../Include/cholmod_core.h > _ones.tex 
+	./getproto '/cholmod_dense \*cholmod_eye/, /\*\) ;/' ../Include/cholmod_core.h > _eye.tex 
+	./getproto '/int cholmod_free_dense/, /\*\) ;/' ../Include/cholmod_core.h > _free_dense.tex 
+	./getproto '/cholmod_dense \*cholmod_sparse_to_dense/, /\*\) ;/' ../Include/cholmod_core.h > _sparse_to_dense.tex 
+	./getproto '/cholmod_sparse \*cholmod_dense_to_sparse/, /\*\) ;/' ../Include/cholmod_core.h > _dense_to_sparse.tex 
+	./getproto '/cholmod_dense \*cholmod_copy_dense/, /\*\) ;/' ../Include/cholmod_core.h > _copy_dense.tex 
+	./getproto '/int cholmod_copy_dense2/, /\*\) ;/' ../Include/cholmod_core.h > _copy_dense2.tex 
+	./getproto '/int cholmod_dense_xtype/, /\*\) ;/' ../Include/cholmod_core.h > _dense_xtype.tex 
+	./getproto '/typedef struct cholmod_triplet/, /^}/' ../Include/cholmod_core.h > _triplet.tex 
+	./getproto '/cholmod_triplet \*cholmod_allocate_triplet/, /\*\) ;/' ../Include/cholmod_core.h > _allocate_triplet.tex 
+	./getproto '/int cholmod_free_triplet/, /\*\) ;/' ../Include/cholmod_core.h > _free_triplet.tex 
+	./getproto '/int cholmod_reallocate_triplet/, /\*\) ;/' ../Include/cholmod_core.h > _reallocate_triplet.tex 
+	./getproto '/cholmod_triplet \*cholmod_sparse_to_triplet/, /\*\) ;/' ../Include/cholmod_core.h > _sparse_to_triplet.tex 
+	./getproto '/cholmod_sparse \*cholmod_triplet_to_sparse/, /\*\) ;/' ../Include/cholmod_core.h > _triplet_to_sparse.tex 
+	./getproto '/cholmod_triplet \*cholmod_copy_triplet/, /\*\) ;/' ../Include/cholmod_core.h > _copy_triplet.tex 
+	./getproto '/int cholmod_triplet_xtype/, /\*\) ;/' ../Include/cholmod_core.h > _triplet_xtype.tex 
+	./getproto '/void \*cholmod_malloc/, /\*\) ;/' ../Include/cholmod_core.h > _malloc.tex 
+	./getproto '/void \*cholmod_calloc/, /\*\) ;/' ../Include/cholmod_core.h > _calloc.tex 
+	./getproto '/void \*cholmod_free/, /\*\) ;/' ../Include/cholmod_core.h > _free.tex 
+	./getproto '/void \*cholmod_realloc/, /\*\) ;/' ../Include/cholmod_core.h > _realloc.tex 
+	./getproto '/int cholmod_realloc_multiple/, /\*\) ;/' ../Include/cholmod_core.h > _realloc_multiple.tex 
+	./getproto '/itype defines the/, /define CHOLMOD_SUPERNODAL/' ../Include/cholmod_core.h > _defn.tex 
+	./getproto '/int cholmod_check_common/, /\*\) ;/' ../Include/cholmod_check.h > _check_common.tex 
+	./getproto '/int cholmod_print_common/, /\*\) ;/' ../Include/cholmod_check.h > _print_common.tex 
+	./getproto '/int cholmod_check_sparse/, /\*\) ;/' ../Include/cholmod_check.h > _check_sparse.tex 
+	./getproto '/int cholmod_print_sparse/, /\*\) ;/' ../Include/cholmod_check.h > _print_sparse.tex 
+	./getproto '/int cholmod_check_dense/, /\*\) ;/' ../Include/cholmod_check.h > _check_dense.tex 
+	./getproto '/int cholmod_print_dense/, /\*\) ;/' ../Include/cholmod_check.h > _print_dense.tex 
+	./getproto '/int cholmod_check_factor/, /\*\) ;/' ../Include/cholmod_check.h > _check_factor.tex 
+	./getproto '/int cholmod_print_factor/, /\*\) ;/' ../Include/cholmod_check.h > _print_factor.tex 
+	./getproto '/int cholmod_check_triplet/, /\*\) ;/' ../Include/cholmod_check.h > _check_triplet.tex 
+	./getproto '/int cholmod_print_triplet/, /\*\) ;/' ../Include/cholmod_check.h > _print_triplet.tex 
+	./getproto '/int cholmod_check_subset/, /\*\) ;/' ../Include/cholmod_check.h > _check_subset.tex 
+	./getproto '/int cholmod_print_subset/, /\*\) ;/' ../Include/cholmod_check.h > _print_subset.tex 
+	./getproto '/int cholmod_check_perm/, /\*\) ;/' ../Include/cholmod_check.h > _check_perm.tex
+	./getproto '/int cholmod_print_perm/, /\*\) ;/' ../Include/cholmod_check.h > _print_perm.tex
+	./getproto '/int cholmod_check_parent/, /\*\) ;/' ../Include/cholmod_check.h > _check_parent.tex
+	./getproto '/int cholmod_print_parent/, /\*\) ;/' ../Include/cholmod_check.h > _print_parent.tex
+	./getproto '/cholmod_triplet \*cholmod_read_triplet/, /\*\) ;/' ../Include/cholmod_check.h > _read_triplet.tex
+	./getproto '/cholmod_sparse \*cholmod_read_sparse/, /\*\) ;/' ../Include/cholmod_check.h > _read_sparse.tex
+	./getproto '/cholmod_dense \*cholmod_read_dense/, /\*\) ;/' ../Include/cholmod_check.h > _read_dense.tex
+	./getproto '/void \*cholmod_read_matrix/, /\*\) ;/' ../Include/cholmod_check.h > _read_matrix.tex
+	./getproto '/int cholmod_write_sparse/, /\*\) ;/' ../Include/cholmod_check.h > _write_sparse.tex
+	./getproto '/int cholmod_write_dense/, /\*\) ;/' ../Include/cholmod_check.h > _write_dense.tex
+	./getproto '/cholmod_factor \*cholmod_analyze /, /\*\) ;/' ../Include/cholmod_cholesky.h > _analyze.tex
+	./getproto '/cholmod_factor \*cholmod_analyze_p/, /\*\) ;/' ../Include/cholmod_cholesky.h > _analyze_p.tex
+	./getproto '/int cholmod_factorize /, /\*\) ;/' ../Include/cholmod_cholesky.h > _factorize.tex
+	./getproto '/int cholmod_factorize_p/, /\*\) ;/' ../Include/cholmod_cholesky.h > _factorize_p.tex
+	./getproto '/cholmod_dense \*cholmod_solve/, /\*\) ;/' ../Include/cholmod_cholesky.h > _solve.tex 
+	./getproto '/cholmod_sparse \*cholmod_spsolve/, /\*\) ;/' ../Include/cholmod_cholesky.h > _spsolve.tex 
+	./getproto '/int cholmod_etree/, /\*\) ;/' ../Include/cholmod_cholesky.h > _etree.tex 
+	./getproto '/int cholmod_rowcolcounts/, /\*\) ;/' ../Include/cholmod_cholesky.h > _rowcolcounts.tex 
+	./getproto '/int cholmod_analyze_ordering/, /\*\) ;/' ../Include/cholmod_cholesky.h > _analyze_ordering.tex 
+	./getproto '/int cholmod_amd/, /\*\) ;/' ../Include/cholmod_cholesky.h > _amd.tex 
+	./getproto '/int cholmod_colamd/, /\*\) ;/' ../Include/cholmod_cholesky.h > _colamd.tex 
+	./getproto '/int cholmod_rowfac/, /\*\) ;/' ../Include/cholmod_cholesky.h > _rowfac.tex 
+	./getproto '/int cholmod_rowfac_mask/, /\*\) ;/' ../Include/cholmod_cholesky.h > _rowfac_mask.tex 
+	./getproto '/int cholmod_row_subtree/, /\*\) ;/' ../Include/cholmod_cholesky.h > _row_subtree.tex 
+	./getproto '/int cholmod_row_lsubtree/, /\*\) ;/' ../Include/cholmod_cholesky.h > _row_lsubtree.tex 
+	./getproto '/int cholmod_resymbol /, /\*\) ;/' ../Include/cholmod_cholesky.h > _resymbol.tex
+	./getproto '/int cholmod_resymbol_noperm/, /\*\) ;/' ../Include/cholmod_cholesky.h > _resymbol_noperm.tex 
+	./getproto '/double cholmod_rcond/, /\*\) ;/' ../Include/cholmod_cholesky.h > _rcond.tex
+	./getproto '/long cholmod_postorder/, /\*\) ;/' ../Include/cholmod_cholesky.h > _postorder.tex
+	./getproto '/int cholmod_updown /, /\*\) ;/' ../Include/cholmod_modify.h > _updown.tex
+	./getproto '/int cholmod_updown_solve/, /\*\) ;/' ../Include/cholmod_modify.h > _updown_solve.tex
+	./getproto '/int cholmod_updown_mark/, /\*\) ;/' ../Include/cholmod_modify.h > _updown_mark.tex
+	./getproto '/int cholmod_updown_mask/, /\*\) ;/' ../Include/cholmod_modify.h > _updown_mask.tex
+	./getproto '/int cholmod_rowadd /, /\*\) ;/' ../Include/cholmod_modify.h > _rowadd.tex
+	./getproto '/int cholmod_rowadd_solve/, /\*\) ;/' ../Include/cholmod_modify.h > _rowadd_solve.tex
+	./getproto '/int cholmod_rowadd_mark/, /\*\) ;/' ../Include/cholmod_modify.h > _rowadd_mark.tex
+	./getproto '/int cholmod_rowdel /, /\*\) ;/' ../Include/cholmod_modify.h > _rowdel.tex
+	./getproto '/int cholmod_rowdel_solve/, /\*\) ;/' ../Include/cholmod_modify.h > _rowdel_solve.tex
+	./getproto '/int cholmod_rowdel_mark/, /\*\) ;/' ../Include/cholmod_modify.h > _rowdel_mark.tex
+	./getproto '/int cholmod_drop/, /\*\) ;/' ../Include/cholmod_matrixops.h > _drop.tex
+	./getproto '/double cholmod_norm_dense/, /\*\) ;/' ../Include/cholmod_matrixops.h > _norm_dense.tex
+	./getproto '/double cholmod_norm_sparse/, /\*\) ;/' ../Include/cholmod_matrixops.h > _norm_sparse.tex
+	./getproto '/cholmod_sparse \*cholmod_horzcat/, /\*\) ;/' ../Include/cholmod_matrixops.h > _horzcat.tex
+	./getproto '/define CHOLMOD_SCALAR/, /\*\) ;/' ../Include/cholmod_matrixops.h > _scale.tex
+	./getproto '/int cholmod_sdmult/, /\*\) ;/' ../Include/cholmod_matrixops.h > _sdmult.tex
+	./getproto '/cholmod_sparse \*cholmod_ssmult/, /\*\) ;/' ../Include/cholmod_matrixops.h > _ssmult.tex
+	./getproto '/cholmod_sparse \*cholmod_submatrix/, /\*\) ;/' ../Include/cholmod_matrixops.h > _submatrix.tex
+	./getproto '/cholmod_sparse \*cholmod_vertcat/, /\*\) ;/' ../Include/cholmod_matrixops.h > _vertcat.tex
+	./getproto '/int cholmod_symmetry/, /\*\) ;/' ../Include/cholmod_matrixops.h > _symmetry.tex
+	./getproto '/int cholmod_super_symbolic/, /\*\) ;/' ../Include/cholmod_supernodal.h > _super_symbolic.tex
+	./getproto '/int cholmod_super_numeric/, /\*\) ;/' ../Include/cholmod_supernodal.h > _super_numeric.tex
+	./getproto '/int cholmod_super_lsolve/, /\*\) ;/' ../Include/cholmod_supernodal.h > _super_lsolve.tex
+	./getproto '/int cholmod_super_ltsolve/, /\*\) ;/' ../Include/cholmod_supernodal.h > _super_ltsolve.tex
+	./getproto '/long cholmod_nested_dissection/, /\*\) ;/' ../Include/cholmod_partition.h > _nested_dissection.tex
+	./getproto '/int cholmod_metis/, /\*\) ;/' ../Include/cholmod_partition.h > _metis.tex
+	./getproto '/int cholmod_ccolamd/, /\*\) ;/' ../Include/cholmod_partition.h > _ccolamd.tex
+	./getproto '/int cholmod_camd/, /\*\) ;/' ../Include/cholmod_partition.h > _camd.tex
+	./getproto '/int cholmod_csymamd/, /\*\) ;/' ../Include/cholmod_partition.h > _csymamd.tex
+	./getproto '/int cholmod_csymamd/, /\*\) ;/' ../Include/cholmod_partition.h > _csymamd.tex
+	./getproto '/long cholmod_bisect/, /\*\) ;/' ../Include/cholmod_partition.h > _bisect.tex
+	./getproto '/long cholmod_metis_bisector/, /\*\) ;/' ../Include/cholmod_partition.h > _metis_bisector.tex
+	./getproto '/long cholmod_collapse_septree/, /\*\) ;/' ../Include/cholmod_partition.h > _collapse_septree.tex
+	pdflatex UserGuide
+	bibtex UserGuide
+	pdflatex UserGuide
+	pdflatex UserGuide
+
+distclean: purge
+
+purge: clean
+	- $(RM) _temp.awk _*.tex *.dvi *.aux *.log *.lof *.lot *.toc *.bak *.bbl *.blg
+
+clean:
+	- $(RM) $(CLEAN)
diff --git a/src/C/SuiteSparse/CHOLMOD/Doc/UserGuide.bib b/src/C/SuiteSparse/CHOLMOD/Doc/UserGuide.bib
new file mode 100644
index 0000000..c804ad2
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Doc/UserGuide.bib
@@ -0,0 +1,196 @@
+ at string{SIMAX       = "{SIAM} J. Matrix Anal. Applic."}
+ at string{TOMS        = "{ACM} Trans. Math. Softw."}
+ at string{SIAMJSC     = "{SIAM} J. Sci. Comput."}
+
+ at article{DavisHager06,
+	author={Davis, T. A. and Hager, W. W.},
+	title={Dynamic supernodes in sparse {Cholesky} update/downdate and triangular
+	    solves},
+	journal=TOMS,
+	year={submitted in 2006}
+	}
+
+ at article{ChenDavisHagerRajamanickam06,
+	author={Chen, Y. and Davis, T. A. and Hager, W. W. and Rajamanickam, S.},
+	title={Algorithm 8xx: {CHOLMOD}, supernodal sparse {Cholesky} factorization and
+	    update/downdate},
+	journal=TOMS,
+	year={submitted in 2006}
+	}
+
+ at article{DavisHager99,
+	author={Davis, T. A. and Hager, W. W.},
+	title={Modifying a sparse {C}holesky factorization},
+	journal=SIMAX,
+	year={1999}
+	,volume={20}
+	,number={3}
+	,pages={606--627}
+	}
+
+ at article{DavisHager01,
+	author={Davis, T. A. and Hager, W. W.},
+	title={Multiple-Rank Modifications of a Sparse {C}holesky Factorization},
+	journal=SIMAX,
+	year={2001}
+	,volume={22}
+	,number={4}
+	,pages={997--1013}
+	}
+
+ at article{DavisHager05,
+	author={Davis, T. A. and Hager, W. W.},
+	title={Row modifications of a sparse {Cholesky} factorization},
+	journal=SIMAX,
+	year={2005}
+	,volume={26}
+	,number={3}
+	,pages={621--639}
+	}
+
+ at article{AmestoyDavisDuff96,
+	author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.},
+	title={An approximate minimum degree ordering algorithm},
+	journal=SIMAX,
+	year={1996}
+	,volume={17}
+	,number={4}
+	,pages={886--905}
+	}
+
+ at article{Davis05,
+	author={Davis, T. A.},
+	title={Algorithm 849: A concise sparse {Cholesky} algorithm},
+	journal=TOMS,
+	year={2005},volume={31},number={4},pages={587--591}}
+
+ at article{DavisGilbertLarimoreNg00,
+	author={Davis, T. A. and Gilbert, J. R. and Larimore, S. I. and Ng, E. G.},
+	title={A column approximate minimum degree ordering algorithm},
+	journal=TOMS,
+	year={2004}
+	,volume={30}
+	,number={3}
+	,pages={353--376}}
+
+ at article{DavisGilbertLarimoreNg00_algo,
+	author={Davis, T. A. and Gilbert, J. R. and Larimore, S. I. and Ng, E. G.},
+	title={Algorithm 836:  {COLAMD}, a column approximate minimum degree ordering algorithm},
+	journal=TOMS,
+	year={2004}
+	,volume={30}
+	,number={3}
+	,pages={377--380}}
+
+ at article{NgPeyton91b,
+	author={Ng, E. and Peyton, B.},
+	title={Block sparse {C}holesky algorithms on advanced uniprocessor computers},
+	journal=SIAMJSC,
+	year={1993}
+	,volume={14}
+	,pages={1034--1056}
+	}
+
+ at article{Liu86c,
+	author={Liu, J. W. H.},
+	title={A Compact Row Storage Scheme for {C}holesky Factors Using Elimination Trees},
+	journal=TOMS,
+	year={1986},
+	volume={12},
+	number={2},
+	pages={127--148},
+	}
+
+ at article{Liu90a,
+	author={Liu, J. W. H.},
+	title={The Role of Elimination Trees in Sparse Factorization},
+	journal=SIMAX,
+	year={1990}
+	,volume={11}
+	,number={1}
+	,pages={134--172}
+	}
+
+ at article{GilbertNgPeyton94,
+	author={Gilbert, J. R. and Ng, E. G. and Peyton, B. W.},
+	title={An efficient algorithm to compute row and column counts for sparse {C}holesky factorization},
+	journal=SIMAX,
+	year={1994}
+	,volume={15}
+	,number={4}
+	,pages={1075--1091}
+	}
+
+ at article{GilbertLiNgPeyton01,
+	author={Gilbert, J. R. and Li, X. S. and Ng, E. G. and Peyton, B. W.},
+	title={Computing row and column counts for sparse {QR} and {LU} factorization},
+	journal={{BIT}},
+	year={2001}
+	,volume={41}
+	,number={4}
+	,pages={693--710}
+	}
+
+ at book{LAPACK,
+	author={Anderson, E. and Bai, Z. and Bischof, C. and Blackford, S.  and Demmel, J. and Dongarra, J. and {Du Croz}, J. and Greenbaum, A.  and Hammarling, S. and McKenny, A. and Sorensen, D.},
+	title={{LAPACK} Users' Guide, 3rd ed.},
+	publisher={{SIAM}},
+	year={1999}
+	}
+
+ at article{ACM679a,
+	author={Dongarra, J. J. and {Du Croz}, J. and Duff, I. S. and Hammarling, S.},
+	title={A set of level-3 basic linear algebra subprograms},
+	journal=TOMS,
+	year={1990}
+	,volume={16}
+	,number={1}
+	,pages={1--17}
+	}
+
+
+ at article{KarypisKumar98,
+	author={Karypis, G. and Kumar, V.},
+	title={A fast and high quality multilevel scheme for partitioning irregular graphs},
+	journal=SIAMJSC,
+	year=1998
+	,volume={20}
+	,number={1}
+	,pages={359--392}
+	}
+
+ at article{GilbertMolerSchreiber,
+	author={Gilbert, J. R. and Moler, C. and Schreiber, R.},
+	title={Sparse matrices in {MATLAB}:  design and implementation},
+	journal=SIMAX,
+	year={1992}
+	,volume={13}
+	,number={1}
+	,pages={333--356}
+	}
+
+ at article{AmestoyDavisDuff03,
+	author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.},
+	title={Algorithm 837: {AMD}, an approximate minimum degree ordering algorithm},
+	journal=TOMS,
+	year={2004}
+	,volume={30}
+	,number={3}
+	,pages={381-388}}
+
+
+ at article{GouldHuScott05,
+	author={Gould, N. I. M. and Hu, Y. and Scott, J. A.},
+	title={A numerical evaluation of sparse direct solvers for the solution of large sparse, symmetric linear systems of equations},
+	journal=TOMS,
+	year={to appear}
+	}
+
+ at techreport{GouldHuScott05b,
+	author={Gould, N. I. M. and Hu, Y. and Scott, J. A.},
+	title={Complete results from a numerical evaluation of sparse direct solvers for the solution of large sparse, symmetric linear systems of equations},
+	institution={CCLRC, Rutherford Appleton Laboratory},
+	number={Internal report 2005-1 (revision 1)},
+	year={2005},
+	howpublished={www.numerical.rl.ac.uk/reports/reports.shtml}
+	}
diff --git a/src/C/SuiteSparse/CHOLMOD/Doc/UserGuide.pdf b/src/C/SuiteSparse/CHOLMOD/Doc/UserGuide.pdf
new file mode 100644
index 0000000..d25561f
Binary files /dev/null and b/src/C/SuiteSparse/CHOLMOD/Doc/UserGuide.pdf differ
diff --git a/src/C/SuiteSparse/CHOLMOD/Doc/UserGuide.tex b/src/C/SuiteSparse/CHOLMOD/Doc/UserGuide.tex
new file mode 100644
index 0000000..c3fa5a9
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Doc/UserGuide.tex
@@ -0,0 +1,3366 @@
+%-------------------------------------------------------------------------------
+% The CHOLMOD/Doc/UserGuide.tex file.
+%-------------------------------------------------------------------------------
+
+\documentclass[11pt]{article}
+
+\newcommand{\m}[1]{{\bf{#1}}}       % for matrices and vectors
+\newcommand{\tr}{^{\sf T}}          % transpose
+\newcommand{\new}[1]{\overline{#1}}
+
+\topmargin 0in
+\textheight 9in
+\oddsidemargin 0pt
+\evensidemargin 0pt
+\textwidth 6.5in
+
+\begin{document}
+
+\author{Timothy A. Davis \\
+Dept. of Computer and Information Science and Engineering \\
+Univ. of Florida, Gainesville, FL}
+\title{User Guide for CHOLMOD: a sparse Cholesky factorization and
+modification package}
+\date{Version 1.4, Dec 12, 2006}
+\maketitle
+
+%-------------------------------------------------------------------------------
+\begin{abstract}
+    CHOLMOD\footnote{CHOLMOD is short for CHOLesky MODification,
+    since a key feature of the package is its ability to update/downdate
+    a sparse Cholesky factorization}
+    is a set of routines for factorizing sparse symmetric positive
+    definite matrices of the form $\m{A}$ or $\m{AA}\tr$, updating/downdating
+    a sparse Cholesky factorization, solving linear systems, updating/downdating
+    the solution to the triangular system $\m{Lx}=\m{b}$, and many other sparse
+    matrix functions for both symmetric and unsymmetric matrices.
+    Its supernodal Cholesky factorization
+    relies on LAPACK and the Level-3 BLAS, and obtains a substantial fraction
+    of the peak performance of the BLAS.  Both real and complex matrices
+    are supported.  CHOLMOD is written in ANSI/ISO C, with both
+    C and MATLAB interfaces.  This code works on Microsoft Windows and many versions
+    of Unix and Linux.
+\end{abstract}
+%-------------------------------------------------------------------------------
+
+CHOLMOD Copyright\copyright 2005-2006 by Timothy A. Davis.  Portions are also
+copyrighted by William W. Hager (the {\tt Modify} Module),
+and the University of Florida (the {\tt Partition} and {\tt Core} Modules).
+All Rights Reserved.  Some of CHOLMOD's Modules are distributed under the GNU
+General Public License, and others under the GNU Lesser General Public License.
+Refer to each Module for details.
+CHOLMOD is also available under other licenses that permit its use in
+proprietary applications; contact the authors for details.
+See http://www.cise.ufl.edu/research/sparse for the code and all documentation,
+including this User Guide.
+
+\newpage
+\tableofcontents
+
+%-------------------------------------------------------------------------------
+\newpage \section{Overview}
+%-------------------------------------------------------------------------------
+
+CHOLMOD is a set of ANSI C routines for solving systems of linear
+equations, $\m{Ax}=\m{b}$, when $\m{A}$ is sparse and symmetric positive definite,
+and $\m{x}$ and $\m{b}$ can be either sparse or dense.\footnote{Some support
+is provided for symmetric indefinite matrices.}
+Complex matrices are supported, in two different formats.
+CHOLMOD includes high-performance left-looking supernodal factorization
+and solve methods \cite{NgPeyton91b},
+based on LAPACK \cite{LAPACK} and the BLAS \cite{ACM679a}.
+After a matrix is factorized, its factors can be updated or downdated using
+the techniques described by Davis and Hager
+in \cite{DavisHager99,DavisHager01,DavisHager05}.
+Many additional sparse matrix operations are provided, for both
+symmetric and unsymmetric matrices (square or rectangular), including
+sparse matrix multiply, add, transpose, permutation, scaling,
+norm, concatenation, sub-matrix access, and converting to alternate data structures.
+Interfaces to many ordering methods are provided, including minimum degree
+(AMD \cite{AmestoyDavisDuff96,AmestoyDavisDuff03},
+COLAMD \cite{DavisGilbertLarimoreNg00_algo,DavisGilbertLarimoreNg00}),
+constrained minimum degree (CSYMAMD, CCOLAMD, CAMD), and
+graph-partitioning-based nested dissection (METIS \cite{KarypisKumar98}).
+Most of its operations are available within MATLAB via mexFunction interfaces.
+
+A pair of articles on CHOLMOD has been submitted to the ACM Transactions
+on Mathematical Softare:
+\cite{ChenDavisHagerRajamanickam06,DavisHager06}.
+
+CHOLMOD 1.0 replaces {\tt chol} (the sparse case), {\tt symbfact}, and {\tt etree}
+in MATLAB 7.2 (R2006a), and is used for {\tt x=A}$\backslash${\tt b}
+when {\tt A} is symmetric positive definite \cite{GilbertMolerSchreiber}.
+It will replace {\tt sparse} in a future version of MATLAB.
+
+The C-callable CHOLMOD library consists of 133 user-callable routines and one
+include file.  Each routine comes in two versions, one for {\tt int} integers
+and another for {\tt long}.  Many of the routines can support either real or
+complex matrices, simply by passing a matrix of the appropriate type.
+
+Nick Gould, Yifan Hu, and Jennifer Scott have independently tested CHOLMOD's
+performance, comparing it with nearly a dozen or so other solvers
+\cite{GouldHuScott05,GouldHuScott05b}.  Its performance was quite competitive.
+
+%-------------------------------------------------------------------------------
+\newpage \section{Primary routines and data structures}
+%-------------------------------------------------------------------------------
+
+Five primary CHOLMOD routines are required to factorize $\m{A}$ or $\m{AA}\tr$
+and solve the related system $\m{Ax}=\m{b}$ or $\m{AA}\tr\m{x}=\m{b}$,
+for either the real or complex cases:
+\begin{enumerate}
+\item {\tt cholmod\_start}:
+    This must be the first call to CHOLMOD.
+
+\item {\tt cholmod\_analyze}:
+    Finds a fill-reducing ordering, and performs the symbolic factorization,
+    either simplicial (non-supernodal) or supernodal.
+
+\item {\tt cholmod\_factorize}:
+    Numerical factorization, either simplicial or supernodal, $\m{LL}\tr$ or $\m{LDL}\tr$
+    using either the symbolic factorization from {\tt cholmod\_analyze} or the numerical
+    factorization from a prior call to {\tt cholmod\_factorize}.
+
+\item {\tt cholmod\_solve}:
+    Solves $\m{Ax}=\m{b}$, or many other related systems, where $\m{x}$ and
+    $\m{b}$ are dense matrices.  The {\tt cholmod\_spsolve} routine handles
+    the sparse case.  Any mixture of real and complex $\m{A}$ and $\m{b}$ are
+    allowed.
+
+\item {\tt cholmod\_finish}:
+    This must be the last call to CHOLMOD.
+\end{enumerate}
+
+Additional routines are also required to create and destroy
+the matrices $\m{A}$, $\m{x}$, $\m{b}$, and the $\m{LL}\tr$ or $\m{LDL}\tr$ factorization.
+CHOLMOD has five kinds of data structures, referred to as objects and implemented
+as pointers to {\tt struct}'s:
+
+\begin{enumerate}
+\item {\tt cholmod\_common}:  parameter settings, statistics, and workspace
+    used internally by CHOLMOD.
+    See Section~\ref{cholmod_common} for details.
+
+\item {\tt cholmod\_sparse}:  a sparse matrix in compressed-column form,
+    either pattern-only, real, complex, or ``zomplex.''  In its basic form,
+    the matrix {\tt A} contains:
+    \begin{itemize}
+	\item {\tt A->p}, an integer array of size {\tt A->ncol+1}.
+	\item {\tt A->i}, an integer array of size {\tt A->nzmax}.
+	\item {\tt A->x}, a {\tt double} array of size {\tt A->nzmax} or twice that for the complex case.
+	    This is compatible with the Fortran and ANSI C99 complex data type.
+	\item {\tt A->z}, a {\tt double} array of size {\tt A->nzmax} if {\tt A} is zomplex.
+	    A zomplex matrix has a {\tt z} array, thus the name.
+	    This is compatible with the MATLAB representation of complex matrices.
+    \end{itemize}
+    For all four types of matrices, the row indices of entries of column {\tt j}
+    are located in {\tt A->i [A->p [j] ... A->p [j+1]-1]}.
+    For a real matrix, the corresponding numerical values are in {\tt A->x} at the same location.
+    For a complex matrix, the entry whose row index is {\tt A->i [p]} is contained in
+	{\tt A->x [2*p]} (the real part) and {\tt A->x [2*p+1]} (the imaginary part).
+    For a zomplex matrix, the real part is in {\tt A->x [p]} and imaginary part is in {\tt A->z [p]}.
+    See Section~\ref{cholmod_sparse} for more details.
+
+\item {\tt cholmod\_factor}:
+    A symbolic or numeric factorization, either real, complex, or zomplex.
+    It can be either an $\m{LL}\tr$ or $\m{LDL}\tr$ factorization, and either
+    simplicial or supernodal.  You will normally not need to examine its contents.
+    See Section~\ref{cholmod_factor} for more details.
+
+\item {\tt cholmod\_dense}:
+    A dense matrix, either real, complex or zomplex, in column-major order.
+    This differs from the row-major convention used in C.  A dense matrix {\tt X} contains
+    \begin{itemize}
+	\item {\tt X->x}, a double array of size {\tt X->nzmax} or twice that for the complex case.
+	\item {\tt X->z}, a double array of size {\tt X->nzmax} if {\tt X} is zomplex.
+    \end{itemize}
+    For a real dense matrix $x_{ij}$ is {\tt X->x [i+j*d]} where {\tt d = X->d} is the leading dimension of {\tt X}.
+    For a complex dense matrix, the real part of $x_{ij}$ is {\tt X->x [2*(i+j*d)]} and the imaginary part is {\tt X->x [2*(i+j*d)+1]}.
+    For a zomplex dense matrix, the real part of $x_{ij}$ is {\tt X->x [i+j*d]} and the imaginary part is {\tt X->z [i+j*d]}.
+    Real and complex dense matrices can be passed to LAPACK and the BLAS.
+    See Section~\ref{cholmod_dense} for more details.
+
+\item {\tt cholmod\_triplet}:
+    CHOLMOD's sparse matrix ({\tt cholmod\_sparse}) is the primary input for nearly all CHOLMOD
+    routines, but it can be difficult for the user to construct.
+    A simpler method of creating a sparse matrix is to first create a {\tt cholmod\_triplet} matrix,
+    and then convert it to a {\tt cholmod\_sparse} matrix via
+    the {\tt cholmod\_triplet\_to\_sparse} routine.
+    In its basic form, the triplet matrix {\tt T} contains
+    \begin{itemize}
+	\item {\tt T->i} and {\tt T->j}, integer arrays of size {\tt T->nzmax}.
+	\item {\tt T->x}, a double array of size {\tt T->nzmax} or twice that for the complex case.
+	\item {\tt T->z}, a double array of size {\tt T->nzmax} if {\tt T} is zomplex.
+    \end{itemize}
+    The {\tt k}th entry in the data structure has row index
+    {\tt T->i [k]} and column index {\tt T->j [k]}.
+    For a real triplet matrix, its numerical value is {\tt T->x [k]}.
+    For a complex triplet matrix, its real part is {\tt T->x [2*k]} and its imaginary part is {\tt T->x [2*k+1]}.
+    For a zomplex matrix, the real part is {\tt T->x [k]} and imaginary part is {\tt T->z [k]}.
+    The entries can be in any order, and duplicates are permitted.
+    See Section~\ref{cholmod_triplet} for more details.
+
+\end{enumerate}
+
+Each of the five objects has a routine in CHOLMOD to create and destroy it.
+CHOLMOD provides many other operations on these objects as well.
+A few of the most important ones are illustrated in the sample program in the
+next section.
+
+%-------------------------------------------------------------------------------
+\newpage \section{Simple example program}
+%-------------------------------------------------------------------------------
+
+\input{_simple.tex}
+The {\tt Demo/cholmod\_simple.c} program illustrates the
+basic usage of CHOLMOD.  It reads a triplet matrix from a file
+(in Matrix Market format), converts it into a sparse matrix,
+creates a linear system, solves it, and prints the norm of the residual.
+
+See the {\tt CHOLMOD/Demo/cholmod\_demo.c} program for a more elaborate
+example, and \newline
+{\tt CHOLMOD/Demo/cholmod\_l\_demo.c} for its {\tt long} integer version.
+
+%-------------------------------------------------------------------------------
+\newpage \section{Installation of the C-callable library}
+\label{Install}
+%-------------------------------------------------------------------------------
+
+CHOLMOD requires a suite of external packages, many of which are distributed
+along with CHOLMOD, but three of which are not.  Those included with CHOLMOD are:
+\begin{itemize}
+\item AMD: an approximate minimum degree ordering algorithm,
+    by Tim Davis, Patrick Amestoy, and Iain Duff
+    \cite{AmestoyDavisDuff96,AmestoyDavisDuff03}.
+\item COLAMD: an approximate column minimum degree ordering algorithm,
+    by Tim Davis, Stefan Larimore, John Gilbert, and Esmond Ng
+    \cite{DavisGilbertLarimoreNg00_algo,DavisGilbertLarimoreNg00}.
+\item CCOLAMD: a constrained approximate column minimum degree ordering
+    algorithm,
+    by Tim Davis and Siva Rajamanickam, based directly on COLAMD.
+    This package is not required if CHOLMOD is compiled with the
+    {\tt -DNPARTITION} flag.
+\item CAMD: a constrained approximate minimum degree ordering
+    algorithm,
+    by Tim Davis and Yanqing Chen, based directly on AMD.
+    This package is not required if CHOLMOD is compiled with the
+    {\tt -DNPARTITION} flag.
+\item {\tt UFconfig}: a single place where all sparse matrix packages authored
+    or co-authored by Davis are configured.  Also includes a version of the
+    {\tt xerbla} routine for the BLAS.
+\end{itemize}
+
+Three other packages are required for optimal performance:
+\begin{itemize}
+\item {\tt METIS 4.0.1}: a graph partitioning package by George Karypis,
+    Univ. of Minnesota.  Not needed if {\tt -DNPARTITION} is used.
+    See http://www-users.cs.umn.edu/$\sim$karypis/metis.
+\item BLAS: the Basic Linear Algebra Subprograms.
+    Not needed if {\tt -DNSUPERNODAL} is used.
+    See http://www.netlib.org for the reference BLAS (not meant for production
+    use).  For Kazushige Goto's optimized BLAS (highly recommended for CHOLMOD)
+    see \newline
+    http://www.tacc.utexas.edu/$\sim$kgoto/ or
+    http://www.cs.utexas.edu/users/flame/goto/.
+    I recommend that you avoid the Intel MKL BLAS; one recent
+    version returns NaN's, where both the Goto BLAS and the standard
+    Fortran reference BLAS return the correct answer.
+    See {\tt CHOLMOD/README} for more information.
+\item LAPACK: the Basic Linear Algebra Subprograms.
+    Not needed if {\tt -DNSUPERNODAL} is used.
+    See http://www.netlib.org.
+\end{itemize}
+
+You must first obtain and install METIS, LAPACK, and the BLAS.
+Next edit the system-dependent configurations in the
+{\tt UFconfig/UFconfig.mk} file.  Sample configurations are provided
+for Linux, Macintosh, Sun Solaris, SGI IRIX, IBM AIX, and the DEC/Compaq Alpha.
+The most important configuration is the location of the BLAS, LAPACK, and METIS
+packages, since in its default configuration CHOLMOD cannot be compiled without them.
+
+\noindent
+Here are the various parameters that you can control in your {\tt UFconfig/UFconfig.mk} file:
+\begin{itemize}
+\item {\tt CC = } your C compiler, such as {\tt cc}.
+\item {\tt CFLAGS = } optimization flags, such as {\tt -O}.
+\item {\tt RANLIB = } your system's {\tt ranlib} program, if needed.
+\item {\tt AR =} the command to create a library (such as {\tt ar}).
+\item {\tt RM =} the command to delete a file.
+\item {\tt MV =} the command to rename a file.
+\item {\tt F77 =} the command to compile a Fortran program (optional).
+\item {\tt F77FLAGS =} the Fortran compiler flags (optional).
+\item {\tt F77LIB =} the Fortran libraries (optional).
+\item {\tt LIB = } basic libraries, such as {\tt -lm}.
+\item {\tt MEX =} the command to compile a MATLAB mexFunction.
+\item {\tt BLAS =} your BLAS library.
+\item {\tt LAPACK =} your LAPACK library.
+\item {\tt XERBLA =} a library containing the BLAS {\tt xerbla} routine, if required.
+\item {\tt METIS\_PATH =} the path to your copy of the METIS 4.0.1 source code.
+\item {\tt METIS =} your METIS library.
+\item {\tt CHOLMOD\_CONFIG = } configuration settings specific to CHOLMOD.
+\end{itemize}
+
+\noindent
+CHOLMOD's specific settings are given by the {\tt CHOLMOD\_CONFIG} string:
+\begin{itemize}
+\item {\tt -DNCHECK}:	    do not include the Check module.	   License: GNU LGPL.
+\item {\tt -DNCHOLESKY}:    do not include the Cholesky module.	   License: GNU LGPL.
+\item {\tt -DNPARTITION}:   do not include the Partition module.   License: GNU LGPL.
+\item {\tt -DNGPL}:	    do not include any GNU GPL Modules in the CHOLMOD library.
+\item {\tt -DNMATRIXOPS}:   do not include the MatrixOps module.   License: GNU GPL.
+\item {\tt -DNMODIFY}:	    do not include the Modify module.      License: GNU GPL.
+\item {\tt -DNSUPERNODAL}:  do not include the Supernodal module.  License: GNU GPL.
+\item {\tt -DNPRINT}:	    do not print anything.
+\item {\tt -D'LONGBLAS=long'} or {\tt -DLONGBLAS='long long'}
+			    defines the integers used by LAPACK and the BLAS (defaults to {\tt int}).
+\item {\tt -DNSUNPERF}:	    for Solaris only.  If defined, do not use the Sun Performance Library.
+\item {\tt -DNLARGEFILE}:   CHOLMOD now assumes support for large files (2GB or
+larger).  If this causes problems, you can compile CHOLMOD with -DNLARGEFILE.
+To use large files, you should {\tt \#include "cholmod.h"} (or at least
+{\tt \#include "cholmod\_io64.h"}) before any other {\tt \#include} statements,
+in your application that uses CHOLMOD.  You may need to use {\tt fopen64}
+to create a file pointer to pass to CHOLMOD, if you are using a non-gcc
+compiler.
+\end{itemize}
+
+Type {\tt make} in the {\tt CHOLMOD} directory.  The AMD,
+COLAMD, CAMD, CCOLAMD, and {\tt CHOLMOD} libraries will be compiled,
+as will the C version of the null-output {\tt xerbla} routine in case you need it.
+No Fortran compiler is required in this case.  A short demo program will
+be compiled and tested on a few matrices.  The residuals should all be small.
+Compare your output with the {\tt CHOLMOD/Demo/make.out} file.
+
+CHOLMOD is now ready for use in your own applications.  You must link
+your programs with the
+{\tt CHOLMOD/Lib/libcholmod.a},
+{\tt AMD/Lib/libamd.a},
+{\tt COLAMD/libcolamd.a},
+{\tt CAMD/libcamd.a}, \newline
+{\tt CCOLAMD/libccolamd.a},
+{\tt metis-4.0/libmetis.a},
+LAPACK,
+and
+BLAS libraries,
+as well as the {\tt xerbla} library if you need it
+({\tt UFconfig/xerlib/libcerbla.a} for the C version or
+\newline
+ {\tt UFconfig/xerlib/libxerbla.a} for the Fortran version).
+Your compiler needs to know the location of the CHOLMOD {\tt Include} directory,
+so that it can find the {\tt cholmod.h} include file, by
+adding the {\tt -ICHOLMOD/Include} to your C compiler options
+(modified appropriately to reflect the location of your copy of CHOLMOD).
+
+%-------------------------------------------------------------------------------
+\newpage \section{Using CHOLMOD in MATLAB}
+%-------------------------------------------------------------------------------
+
+CHOLMOD includes a set of m-files and mexFunctions in the CHOLMOD/MATLAB
+directory.  The following functions are provided:
+
+\vspace{0.1in}
+\begin{tabular}{ll}
+\hline
+{\tt analyze}	    & order and analyze a matrix \\
+{\tt bisect}	    & find a node separator \\
+{\tt chol2}	    & same as {\tt chol} \\
+{\tt cholmod2}	    & same as {\tt x=A}$\backslash${\tt b} if {\tt A} is symmetric positive definite \\
+{\tt cholmod\_demo} & a short demo program \\
+{\tt cholmod\_make} & compiles CHOLMOD for use in MATLAB \\
+{\tt etree2}	    & same as {\tt etree} \\
+{\tt graph\_demo}   & graph partitioning demo \\
+{\tt lchol}	    & {\tt L*L'} factorization \\
+{\tt ldlchol}	    & {\tt L*D*L'} factorization \\
+{\tt ldl\_normest}  & estimate {\tt norm(A-L*D*L')} \\
+{\tt ldlsolve}	    & {\tt x = L'}$\backslash${\tt (D}$\backslash${\tt (L}$\backslash${\tt b))} \\
+{\tt ldlsplit}	    & split the output of {\tt ldlchol} into {\tt L} and {\tt D} \\
+{\tt ldlupdate}	    & update/downdate an {\tt L*D*L'} factorization \\
+{\tt lu\_normest}   & estimate {\tt norm(A-L*U')} \\
+{\tt metis}	    & interface to {\tt METIS\_NodeND} ordering \\
+{\tt mread}	    & read a sparse or dense Matrix Market file \\
+{\tt mwrite}	    & write a sparse or dense Matrix Market file \\
+{\tt nesdis}	    & CHOLMOD's nested dissection ordering \\
+{\tt resymbol}	    & recomputes the symbolic factorization \\
+{\tt sdmult}	    & {\tt S*F} where {\tt S} is sparse and {\tt F} is dense \\
+{\tt spsym}	    & determine symmetry \\
+{\tt sparse2}	    & same as {\tt sparse} \\
+{\tt symbfact2}	    & same as {\tt symbfact} \\
+\hline
+\end{tabular}
+
+\vspace{0.1in}\noindent
+Each function is described in the next sections.
+
+\newpage
+\subsection{{\tt analyze}: order and analyze}					\input{_analyze_m.tex}
+\subsection{{\tt bisect}: find a node separator}				\input{_bisect_m.tex}
+\subsection{{\tt chol2}: same as {\tt chol}}					\input{_chol2_m.tex}
+\newpage
+\subsection{{\tt cholmod2}: supernodal backslash}				\input{_cholmod2_m.tex}
+\newpage
+\subsection{{\tt cholmod\_demo}: a short demo program}				\input{_cholmod_demo_m.tex}
+\subsection{{\tt cholmod\_make}: compile CHOLMOD in MATLAB}			\input{_cholmod_make_m.tex}
+\newpage
+\subsection{{\tt etree2}: same as {\tt etree}}					\input{_etree2_m.tex}
+\subsection{{\tt graph\_demo}: graph partitioning demo}				\input{_graph_demo_m.tex}
+\newpage
+\subsection{{\tt lchol}: $\m{LL}\tr$ factorization}				\input{_lchol_m.tex}
+\subsection{{\tt ldlchol}: $\m{LDL}\tr$ factorization}				\input{_ldlchol_m.tex}
+\newpage
+\subsection{{\tt ldl\_normest}: estimate $||\m{A}-\m{LDL}\tr||$}		\input{_ldl_normest_m.tex}
+\subsection{{\tt ldlsolve}: solve using an $\m{LDL}\tr$ factorization}		\input{_ldlsolve_m.tex}
+\subsection{{\tt ldlsplit}: split an $\m{LDL}\tr$ factorization}		\input{_ldlsplit_m.tex}
+\newpage
+\subsection{{\tt ldlupdate}: update/downdate an $\m{LDL}\tr$ factorization}	\input{_ldlupdate_m.tex}
+\newpage
+\subsection{{\tt lu\_normest}: estimate $||\m{A}-\m{LU}||$}			\input{_lu_normest_m.tex}
+\newpage
+\subsection{{\tt mread}: read a sparse or dense matrix from a Matrix Market file}\input{_mread_m.tex}
+\subsection{{\tt mwrite}: write a sparse or densematrix to a Matrix Market file}	\input{_mwrite_m.tex}
+\newpage
+\subsection{{\tt metis}: order with METIS}					\input{_metis_m.tex}
+\newpage
+\subsection{{\tt nesdis}: order with CHOLMOD nested dissection}			\input{_nesdis_m.tex}
+\newpage
+\subsection{{\tt resymbol}: re-do symbolic factorization}			\input{_resymbol_m.tex}
+\subsection{{\tt sdmult}: sparse matrix times dense matrix}			\input{_sdmult_m.tex}
+\newpage
+\subsection{{\tt spsym}: determine symmetry}				\input{_spsym_m.tex}
+\newpage
+\subsection{{\tt sparse2}: same as {\tt sparse}}				\input{_sparse2_m.tex}
+\newpage
+\subsection{{\tt symbfact2}: same as {\tt symbfact}}				\input{_symbfact2_m.tex}
+
+%-------------------------------------------------------------------------------
+\newpage \section{Installation for use in MATLAB}
+%-------------------------------------------------------------------------------
+
+If you wish to use METIS within CHOLMOD, you should first obtain a copy of METIS 4.0.1.
+See http://www-users.cs.umn.edu/$\sim$karypis/metis.  Place your copy
+of the {\tt metis-4.0} directory (folder, for Windows users) in the same directory
+that contains your copy of the {\tt CHOLMOD} directory. If you do not have
+METIS, however, you can still use CHOLMOD.  Some of the CHOLMOD functions will not
+be available ({\tt metis}, {\tt bisect}, and {\tt nesdis}),
+and you may experience higher fill-in for large matrices
+(particularly those arising in 3D finite-element problems) when using
+{\tt analyze}, {\tt chol2}, {\tt cholmod2}, {\tt lchol}, and {\tt ldlchol}.
+There are two methods for compiling CHOLMOD for use in MATLAB; both
+are described below.
+
+%-------------------------------------------------------------------------------
+\subsection{{\tt cholmod\_make}: compiling CHOLMOD in MATLAB}
+%-------------------------------------------------------------------------------
+
+This is the preferred method, since it allows METIS to be reconfigured to
+use the MATLAB memory-management functions instead of {\tt malloc} and {\tt free};
+this avoids the issue of METIS terminating MATLAB if it runs out of memory.
+It is also simpler for Windows users, who do not have the {\tt make}
+command (unless you obtain a copy of {\tt Cygwin}).
+
+Start MATLAB, {\tt cd} to the {\tt CHOLMOD/MATLAB} directory, and
+type {\tt cholmod\_make} in the MATLAB command window.  This will compile
+the MATLAB interfaces for AMD, COLAMD, CAMD, CCOLAMD, METIS, and CHOLMOD.
+If you do not have METIS, type {\tt cholmod\_make('')}.
+If your copy of METIS is in another location, type
+{\tt cholmod\_make ('path')} where {\tt path} is the pathname
+of your copy of the {\tt metis-4.0} directory.
+
+When METIS is compiled {\tt malloc}, {\tt free}, {\tt calloc}, and {\tt realloc}
+are redefined to the MATLAB-equivalents ({\tt mxMalloc}, ...).
+These memory-management functions safely terminate a mexFunction if they
+fail, and will free all memory allocated by the mexFunction.
+Thus, METIS will safely abort without terminating MATLAB, if it runs out
+of memory.
+The {\tt cholmod\_make} handles this redefinition without making any
+changes to your METIS source code.
+
+%-------------------------------------------------------------------------------
+\subsection{Unix {\tt make} for compiling CHOLMOD}
+%-------------------------------------------------------------------------------
+
+You can also compile the CHOLMOD mexFunctions using the Unix/Linux {\tt make}
+command.  When using the {\tt gcc} compiler, I strongly recommend editing the
+{\tt metis-4.0/Makefile.in} file and changing {\tt COPTIONS} to
+\begin{verbatim}
+        COPTIONS = -fexceptions
+\end{verbatim}
+Also ensure {\tt -fexceptions} is in the {\tt CFLAGS} option in the
+{\tt UFconfig/UFconfig.mk} file that comes with CHOLMOD.
+If you do not make these modifications, the CHOLMOD mexFunctions
+will terminate MATLAB if they encounter an error.
+
+Next, compile your METIS 4.0.1 library by typing {\tt make} in the
+{\tt metis-4.0} directory.  Then type {\tt make} in the {\tt CHOLMOD/MATLAB}
+directory.  This will compile the C-callable libraries for
+AMD, COLAMD, CAMD, CCOLAMD, METIS, and CHOLMOD, and then compile the
+mexFunction interfaces to those libraries.
+If METIS tries {\tt malloc} and encounters an out-of-memory condition,
+it calls {\tt abort}, which will terminate MATLAB.  This problem does not
+occur using the method described in the previous section.
+
+%-------------------------------------------------------------------------------
+\newpage \section{Integer and floating-point types, and notation used}
+%-------------------------------------------------------------------------------
+
+CHOLMOD supports both {\tt int} and {\tt long} integers.  CHOLMOD
+routines with the prefix {\tt cholmod\_} use {\tt int} integers,
+{\tt cholmod\_l\_} routines use {\tt long}.  All floating-point
+values are {\tt double}.
+
+The {\tt long} integer is redefinable, via {\tt UFconfig.h}.
+That file defines a C preprocessor token {\tt UF\_long} which is
+{\tt long} on all systems except for Windows-64, in which case it is
+defined as {\tt \_\_int64}.  The intent is that with suitable compile-time
+switches, {\tt int} is a 32-bit integer and {\tt UF\_long} is a 64-bit
+integer.  The term {\tt long} is used to describe the latter
+integer throughout this document (except in the prototypes).
+
+Two kinds of complex matrices are supported: complex and zomplex.
+A complex matrix is held in a manner that is compatible with the
+Fortran and ANSI C99 complex data type.  A complex array of size {\tt n}
+is a {\tt double} array {\tt x} of size {\tt 2*n}, with the real and imaginary
+parts interleaved (the real part comes first, as a {\tt double}, followed the
+imaginary part, also as a {\tt double}.  Thus, the real part of the {\tt k}th
+entry is {\tt x[2*k]} and the imaginary part is {\tt x[2*k+1]}.
+
+A zomplex matrix of size {\tt n} stores its real part in one
+{\tt double} array of size {\tt n} called {\tt x} and its imaginary part
+in another {\tt double} array of size {\tt n} called {\tt z} (thus the
+name ``zomplex'').  This also how MATLAB stores its complex matrices.
+The real part of the {\tt k}th entry is {\tt x[k]} and the imaginary part is
+{\tt z[k]}.
+
+Unlike {\tt UMFPACK}, the same routine name in CHOLMOD is used for pattern-only,
+real, complex, and zomplex matrices.  For example, the statement
+\begin{verbatim}
+    C = cholmod_copy_sparse (A, &Common) ;
+\end{verbatim}
+creates a copy of a pattern, real, complex, or zomplex sparse matrix {\tt A}.
+The xtype (pattern, real, complex, or zomplex) of the resulting sparse matrix {\tt C}
+is the same as {\tt A} (a pattern-only sparse matrix contains no floating-point
+values).  In the above case, {\tt C} and {\tt A} use {\tt int} integers.
+For {\tt long} integers, the statement would become:
+\begin{verbatim}
+    C = cholmod_l_copy_sparse (A, &Common) ;
+\end{verbatim}
+The last parameter of all CHOLMOD routines is always {\tt \&Common},
+a pointer to the
+{\tt cholmod\_common} object, which contains parameters, statistics,
+and workspace used throughout CHOLMOD.
+
+The {\tt xtype} of a CHOLMOD object (sparse matrix, triplet matrix, dense
+matrix, or factorization) determines whether it is pattern-only,
+real, complex, or zomplex.
+
+The names of the {\tt int} versions are primarily used in this document.
+To obtain the name of the {\tt long} version of the same routine, simply
+replace {\tt cholmod\_} with {\tt cholmod\_l\_}.
+
+MATLAB matrix notation is used throughout this document and in
+the comments in the CHOLMOD code itself.  If you are not familiar with
+MATLAB, here is a short introduction to the notation, and a few
+minor variations used in CHOLMOD:
+
+\begin{itemize}
+    \item {\tt C=A+B} and {\tt C=A*B}, respectively are a matrix add and multiply if both
+	{\tt A} and {\tt B} are matrices of appropriate size.  If {\tt A} is
+	a scalar, then it is added to or multiplied with every entry in {\tt B}.
+    \item {\tt a:b} where {\tt a} and {\tt b} are integers refers to the
+	sequence {\tt a}, {\tt a+1}, ... {\tt b}.
+    \item {\tt [A B]} and {\tt [A,B]} are the horizontal concatenation of {\tt A} and {\tt B}.
+    \item {\tt [A;B]} is the vertical concatenation of {\tt A} and {\tt B}.
+    \item {\tt A(i,j)} can refer either to a scalar or a submatrix.
+	For example: \newline
+	\vspace{0.05in}
+	\begin{tabular}{ll}
+	\hline
+	{\tt A(1,1)} & a scalar. \\
+	{\tt A(:,j)} & column {\tt j} of {\tt A}. \\
+	{\tt A(i,:)} & row {\tt i} of {\tt A}. \\
+	{\tt A([1 2], [1 2])} & a 2-by-2 matrix containing the 2-by-2 leading minor of {\tt A}. \\
+	\hline
+	\end{tabular} \newline
+	\vspace{0.1in}
+	If {\tt p} is a permutation of {\tt 1:n}, and {\tt A} is {\tt n}-by-{\tt n},
+	then {\tt A(p,p)} corresponds to the permuted matrix $\m{PAP}\tr$.
+    \item {\tt tril(A)} is the lower triangular part of {\tt A}, including the diagonal.
+    \item {\tt tril(A,k)} is the lower triangular part of {\tt A}, including entries
+	on and below the $k$th diagonal.
+    \item {\tt triu(A)} is the upper triangular part of {\tt A}, including the diagonal.
+    \item {\tt triu(A,k)} is the upper triangular part of {\tt A}, including entries
+	on and above the $k$th diagonal.
+    \item {\tt size(A)} returns the dimensions of {\tt A}.
+    \item {\tt find(x)} if {\tt x} is a vector returns a list of indices {\tt i}
+	for which {\tt x(i)} is nonzero.
+    \item {\tt A'} is the transpose of {\tt A} if {\tt A} is real, or
+	the complex conjugate transpose if {\tt A} is complex.
+    \item {\tt A.'} is the array transpose of {\tt A}.
+    \item {\tt diag(A)} is the diagonal of {\tt A} if {\tt A} is a matrix.
+    \item {\tt C=diag(s)} is a diagonal matrix if {\tt s} is a vector,
+	with the values of {\tt s} on the diagonal of {\tt C}.
+    \item {\tt S=spones(A)} returns a binary matrix {\tt S} with the
+	same nonzero pattern of {\tt A}.
+    \item {\tt nnz(A)} is the number of nonzero entries in {\tt A}.
+\end{itemize}
+
+\noindent Variations to MATLAB notation used in this document:
+\begin{itemize}
+    \item CHOLMOD uses 0-based notation (the first entry in the matrix is
+	{\tt A(0,0)}).  MATLAB is 1-based.  The context is usually clear.
+    \item {\tt I} is the identity matrix.
+    \item {\tt A(:,f)}, where {\tt f} is a set of columns, is interpreted
+	differently in CHOLMOD, but just for the set named {\tt f}.
+	See {\tt cholmod\_transpose\_unsym} for details.
+\end{itemize}
+
+%-------------------------------------------------------------------------------
+\newpage \section{The CHOLMOD Modules, objects, and functions}
+\label{Modules}
+%-------------------------------------------------------------------------------
+
+CHOLMOD contains a total of 133 {\tt int}-based routines (and the same number
+of {\tt long} routines), divided into a set of inter-related
+Modules.  Each Module contains a set of related functions.  The functions
+are divided into two types: Primary and Secondary, to reflect how a user will
+typically use CHOLMOD.  Most users will find the Primary routines to be
+sufficient to use CHOLMOD in their programs.  Each Module exists as a
+sub-directory (a folder for Windows users) within the CHOLMOD directory
+(or folder).
+
+\vspace{0.1in}
+\noindent There are seven Modules that provide user-callable routines for CHOLMOD.
+    \begin{enumerate}
+    \item {\tt Core}: basic data structures and definitions
+    \item {\tt Check}: prints/checks each of CHOLMOD's objects
+    \item {\tt Cholesky}: sparse Cholesky factorization
+    \item {\tt Modify}: sparse Cholesky update/downdate and row-add/row-delete
+    \item {\tt MatrixOps}: sparse matrix operators (add, multiply, norm, scale)
+    \item {\tt Supernodal}: supernodal sparse Cholesky factorization
+    \item {\tt Partition}: graph-partitioning-based orderings
+    \end{enumerate}
+
+\noindent Two additional Modules are required to compile the CHOLMOD library:
+    \begin{enumerate}
+    \item {\tt Include}: include files for CHOLMOD and programs that use CHOLMOD
+    \item {\tt Lib}: where the CHOLMOD library is built
+    \end{enumerate}
+
+\noindent Five additional Modules provide support functions and documentation:
+    \begin{enumerate}
+    \item {\tt Demo}: simple programs that illustrate the use of CHOLMOD
+    \item {\tt Doc}: documentation (including this document)
+    \item {\tt MATLAB}: CHOLMOD's interface to MATLAB
+    \item {\tt Tcov}: an exhaustive test coverage (requires Linux or Solaris)
+    \item {\tt Valgrind}: runs the {\tt Tcov} test under {\tt valgrind} (requires Linux)
+    \end{enumerate}
+
+The following Modules are licensed under the GNU Lesser General Public
+License: {\tt Check}, {\tt Cholesky}, {\tt Core}, and {\tt Partition}.
+The following Modules are licensed under the GNU General Public
+License: {\tt Demo}, {\tt Modify}, {\tt MatrixOps}, {\tt Supernodal},
+the {\tt MATLAB} Module (not MATLAB itself!), {\tt Tcov}, and {\tt Valgrind}.
+The files in the {\tt Include} Module are licensed according to
+their respective Modules.  The {\tt Lib} and {\tt Doc} Modules need
+no license; the compiled binaries are licensed the same as their source code.
+
+%-------------------------------------------------------------------------------
+\newpage \subsection{{\tt Core} Module: basic data structures and definitions}
+%-------------------------------------------------------------------------------
+
+CHOLMOD includes five basic objects, defined in the {\tt Core} Module.
+The {\tt Core Module} provides basic operations for these objects
+and is required by all six other CHOLMOD library Modules:
+
+\subsubsection{{\tt cholmod\_common}: parameters, statistics, and workspace}
+    You must call {\tt cholmod\_start} before calling any other
+    CHOLMOD routine, and you must call {\tt cholmod\_finish} as your
+    last call to CHOLMOD (with the exception of
+    {\tt cholmod\_print\_common} and {\tt cholmod\_check\_common}
+    in the {\tt Check} Module).
+    Once the {\tt cholmod\_common} object is initialized,
+    the user may modify CHOLMOD's parameters held in this object,
+    and obtain statistics on CHOLMOD's activity.
+
+\vspace{0.1in}
+\noindent Primary routines for the {\tt cholmod\_common} object:
+% 2
+    \begin{itemize}
+    \item {\tt cholmod\_start}: the first call to CHOLMOD.
+    \item {\tt cholmod\_finish}: the last call to CHOLMOD (frees workspace in the {\tt cholmod\_common} object).
+    \end{itemize}
+
+\noindent Secondary routines for the {\tt cholmod\_common} object:
+% 9
+    \begin{itemize}
+    \item {\tt cholmod\_defaults}: restores default parameters
+    \item {\tt cholmod\_maxrank}: determine maximum rank for update/downdate.
+    \item {\tt cholmod\_allocate\_work}: allocate workspace.
+    \item {\tt cholmod\_free\_work}: free workspace.
+    \item {\tt cholmod\_clear\_flag}: clear {\tt Flag} array.
+    \item {\tt cholmod\_error}: called when CHOLMOD encounters and error.
+    \item {\tt cholmod\_dbound}: bounds the diagonal of $\m{L}$ or $\m{D}$.
+    \item {\tt cholmod\_hypot}: compute {\tt sqrt(x*x+y*y)} accurately.
+    \item {\tt cholmod\_divcomplex}: complex divide.
+    \end{itemize}
+
+%-------------------------------------------------------------------------------
+\newpage \subsubsection{{\tt cholmod\_sparse}: a sparse matrix in compressed column form}
+%-------------------------------------------------------------------------------
+    A sparse matrix {\tt A} is held in compressed column form.  In the basic
+    type (``packed,'' which corresponds to how MATLAB stores its sparse
+    matrices), and {\tt nrow}-by-{\tt ncol} matrix with {\tt nzmax} entries
+    is held in three arrays: {\tt p} of size {\tt ncol+1},
+    {\tt i} of size {\tt nzmax}, and {\tt x} of size {\tt nzmax}.
+    Row indices of nonzero entries in column {\tt j} are held in
+    {\tt i [p[j] ... p[j+1]-1]}, and their corresponding numerical values
+    are held in {\tt x [p[j] ... p[j+1]-1]}.  The first column starts at
+    location zero ({\tt p[0]=0}).
+    There may be no duplicate entries.  Row indices in each column may
+    be sorted or unsorted (the {\tt A->sorted} flag must be false if
+    the columns are unsorted).  The {\tt A->stype} determines the 
+    storage mode: 0 if the matrix is unsymmetric, 1 if the matrix is
+    symmetric with just the upper triangular part stored, and -1 if
+    the matrix is symmetric with just the lower triangular part stored.
+
+    In ``unpacked'' form, an additional array {\tt nz} of size {\tt ncol}
+    is used.  The end of column {\tt j} in {\tt i} and {\tt x}
+    is given by {\tt p[j]+nz[j]}.  Columns not need be in any particular
+    order ({\tt p[0]} need not be zero), and there may be gaps between
+    the columns.
+
+\vspace{0.1in}
+\noindent Primary routines for the {\tt cholmod\_sparse} object:
+% 2
+    \begin{itemize}
+    \item {\tt cholmod\_allocate\_sparse}: allocate a sparse matrix
+    \item {\tt cholmod\_free\_sparse}: free a sparse matrix
+    \end{itemize}
+
+\noindent Secondary routines for the {\tt cholmod\_sparse} object:
+% 16
+    \begin{itemize}
+    \item {\tt cholmod\_reallocate\_sparse}: change the size (number of entries) of a sparse matrix.
+    \item {\tt cholmod\_nnz}: number of nonzeros in a sparse matrix.
+    \item {\tt cholmod\_speye}: sparse identity matrix.
+    \item {\tt cholmod\_spzeros}: sparse zero matrix.
+    \item {\tt cholmod\_transpose}: transpose a sparse matrix.
+    \item {\tt cholmod\_ptranspose}: transpose/permute a sparse matrix.
+    \item {\tt cholmod\_transpose\_unsym}: transpose/permute an unsymmetric sparse matrix.
+    \item {\tt cholmod\_transpose\_sym}: transpose/permute a symmetric sparse matrix.
+    \item {\tt cholmod\_sort}: sort row indices in each column of a sparse matrix.
+    \item {\tt cholmod\_band}: extract a band of a sparse matrix.
+    \item {\tt cholmod\_band\_inplace}: remove entries not with a band.
+    \item {\tt cholmod\_aat}: {\tt C = A*A'}.
+    \item {\tt cholmod\_copy\_sparse}: {\tt C = A}, create an exact copy of a sparse matrix.
+    \item {\tt cholmod\_copy}: {\tt C = A}, with possible change of {\tt stype}.
+    \item {\tt cholmod\_add}: {\tt C = alpha*A + beta*B}.
+    \item {\tt cholmod\_sparse\_xtype}: change the {\tt xtype} of a sparse matrix.
+    \end{itemize}
+
+%-------------------------------------------------------------------------------
+\newpage \subsubsection{{\tt cholmod\_factor}: a symbolic or numeric factorization}
+%-------------------------------------------------------------------------------
+
+    A factor can be in $\m{LL}\tr$ or $\m{LDL}\tr$ form, and either supernodal
+    or simplicial form.  In simplicial form, this is very much like a
+    packed or unpacked {\tt cholmod\_sparse} matrix.  In supernodal
+    form, adjacent columns with similar nonzero pattern are stored as
+    a single block (a supernode).
+
+\vspace{0.1in}
+\noindent Primary routine for the {\tt cholmod\_factor} object:
+% 1
+    \begin{itemize}
+    \item {\tt cholmod\_free\_factor}: free a factor
+    \end{itemize}
+
+\noindent Secondary routines for the {\tt cholmod\_factor} object:
+% 8
+    \begin{itemize}
+    \item {\tt cholmod\_allocate\_factor}: allocate a factor.  You will normally use {\tt cholmod\_analyze} to create a factor.
+    \item {\tt cholmod\_reallocate\_factor}: change the number of entries in a factor.
+    \item {\tt cholmod\_change\_factor}: change the type of a factor ($\m{LDL}\tr$ to $\m{LL}\tr$, supernodal to simplicial, etc.).
+    \item {\tt cholmod\_pack\_factor}: pack the columns of a factor.
+    \item {\tt cholmod\_reallocate\_column}: resize a single column of a factor.
+    \item {\tt cholmod\_factor\_to\_sparse}: create a sparse matrix copy of a factor.
+    \item {\tt cholmod\_copy\_factor}: create a copy of a factor.
+    \item {\tt cholmod\_factor\_xtype}: change the xtype of a factor.
+    \end{itemize}
+
+%-------------------------------------------------------------------------------
+\subsubsection{{\tt cholmod\_dense}: a dense matrix}
+%-------------------------------------------------------------------------------
+    This consists of a dense array of numerical values and its dimensions.
+
+\vspace{0.1in}
+\noindent Primary routines for the {\tt cholmod\_dense} object:
+% 2
+    \begin{itemize}
+    \item {\tt cholmod\_allocate\_dense}: allocate a dense matrix.
+    \item {\tt cholmod\_free\_dense}: free a dense matrix.
+    \end{itemize}
+
+\vspace{0.1in}
+\noindent Secondary routines for the {\tt cholmod\_dense} object:
+% 8
+    \begin{itemize}
+    \item {\tt cholmod\_zeros}: allocate a dense matrix of all zeros.
+    \item {\tt cholmod\_ones}: allocate a dense matrix of all ones.
+    \item {\tt cholmod\_eye}: allocate a dense identity matrix .
+    \item {\tt cholmod\_sparse\_to\_dense}: create a dense matrix copy of a sparse matrix.
+    \item {\tt cholmod\_dense\_to\_sparse}: create a sparse matrix copy of a dense matrix.
+    \item {\tt cholmod\_copy\_dense}: create a copy of a dense matrix.
+    \item {\tt cholmod\_copy\_dense2}: copy a dense matrix (pre-allocated).
+    \item {\tt cholmod\_dense\_xtype}: change the {\tt xtype} of a dense matrix.
+    \end{itemize}
+
+%-------------------------------------------------------------------------------
+\newpage \subsubsection{{\tt cholmod\_triplet}: a sparse matrix in ``triplet'' form}
+%-------------------------------------------------------------------------------
+    The {\tt cholmod\_sparse} matrix is the basic sparse matrix used in
+    CHOLMOD, but it can be difficult for the user to construct.  It also
+    does not easily support the inclusion of new entries in the matrix.
+    The {\tt cholmod\_triplet} matrix is provided to address these issues.
+    A sparse matrix in triplet form consists of three arrays of size
+    {\tt nzmax}: {\tt i}, {\tt j}, and {\tt x}, and a {\tt z} array
+    for the zomplex case.
+
+\vspace{0.1in}
+\noindent Primary routines for the {\tt cholmod\_triplet} object:
+% 3
+    \begin{itemize}
+    \item {\tt cholmod\_allocate\_triplet}: allocate a triplet matrix.
+    \item {\tt cholmod\_free\_triplet}: free a triplet matrix.
+    \item {\tt cholmod\_triplet\_to\_sparse}: create a sparse matrix copy of a triplet matrix.
+    \end{itemize}
+
+\noindent Secondary routines for the {\tt cholmod\_triplet} object:
+% 4
+    \begin{itemize}
+    \item {\tt cholmod\_reallocate\_triplet}: change the number of entries in a triplet matrix.
+    \item {\tt cholmod\_sparse\_to\_triplet}: create a triplet matrix copy of a sparse matrix.
+    \item {\tt cholmod\_copy\_triplet}: create a copy of a triplet matrix.
+    \item {\tt cholmod\_triplet\_xtype}: change the {\tt xtype} of a triplet matrix.
+    \end{itemize}
+
+%-------------------------------------------------------------------------------
+\subsubsection{Memory management routines}
+%-------------------------------------------------------------------------------
+    By default, CHOLMOD uses the ANSI C {\tt malloc}, {\tt free},
+    {\tt calloc}, and {\tt realloc} routines.  You may use different
+    routines by modifying function pointers in the {\tt cholmod\_common} object.
+
+\vspace{0.1in}
+\noindent Primary routines:
+% 2
+    \begin{itemize}
+    \item {\tt cholmod\_malloc}: {\tt malloc} wrapper.
+    \item {\tt cholmod\_free}: {\tt free} wrapper.
+    \end{itemize}
+
+\noindent Secondary routines:
+% 3
+    \begin{itemize}
+    \item {\tt cholmod\_calloc}: {\tt calloc} wrapper.
+    \item {\tt cholmod\_realloc}: {\tt realloc} wrapper.
+    \item {\tt cholmod\_realloc\_multiple}: {\tt realloc} wrapper for multiple objects.
+    \end{itemize}
+
+%-------------------------------------------------------------------------------
+\newpage \subsection{{\tt Check} Module: print/check the CHOLMOD objects}
+%-------------------------------------------------------------------------------
+    The {\tt Check} Module contains routines that check and print the five
+    basic objects in CHOLMOD, and three kinds of integer vectors (a set,
+    a permutation, and a tree).  It also provides a routine to read a sparse
+    matrix from a file in Matrix Market format (http://www.nist.gov/MatrixMarket).
+    Requires the {\tt Core} Module.
+
+\vspace{0.1in}
+\noindent Primary routines:
+% 4
+    \begin{itemize}
+    \item {\tt cholmod\_print\_common}: print the {\tt cholmod\_common} object,
+	including statistics on CHOLMOD's behavior (fill-in, flop count,
+	ordering methods used, and so on).
+    \item {\tt cholmod\_write\_sparse}: write a sparse matrix to a file
+	in Matrix Market format.
+    \item {\tt cholmod\_write\_dense}: write a sparse matrix to a file
+	in Matrix Market format.
+    \item {\tt cholmod\_read\_matrix}: read a sparse or dense matrix from a file
+	in Matrix Market format.
+    \end{itemize}
+
+\vspace{0.1in}
+\noindent Secondary routines:
+% 18
+    \begin{itemize}
+    \item {\tt cholmod\_check\_common}: check the {\tt cholmod\_common} object
+    \item {\tt cholmod\_check\_sparse}: check a sparse matrix
+    \item {\tt cholmod\_print\_sparse}: print a sparse matrix
+    \item {\tt cholmod\_check\_dense}: check a dense matrix
+    \item {\tt cholmod\_print\_dense}: print a dense matrix
+    \item {\tt cholmod\_check\_factor}: check a Cholesky factorization
+    \item {\tt cholmod\_print\_factor}: print a Cholesky factorization
+    \item {\tt cholmod\_check\_triplet}: check a triplet matrix
+    \item {\tt cholmod\_print\_triplet}: print a triplet matrix
+    \item {\tt cholmod\_check\_subset}: check a subset (integer vector in given range)
+    \item {\tt cholmod\_print\_subset}: print a subset (integer vector in given range)
+    \item {\tt cholmod\_check\_perm}: check a permutation (an integer vector)
+    \item {\tt cholmod\_print\_perm}: print a permutation (an integer vector)
+    \item {\tt cholmod\_check\_parent}: check an elimination tree (an integer vector)
+    \item {\tt cholmod\_print\_parent}: print an elimination tree (an integer vector)
+    \item {\tt cholmod\_read\_triplet}: read a triplet matrix from a file
+    \item {\tt cholmod\_read\_sparse}: read a sparse matrix from a file
+    \item {\tt cholmod\_read\_dense}: read a dense matrix from a file
+    \end{itemize}
+
+%-------------------------------------------------------------------------------
+\newpage \subsection{{\tt Cholesky} Module: sparse Cholesky factorization}
+%-------------------------------------------------------------------------------
+
+The primary routines are all that a user requires to order, analyze, and
+factorize a sparse symmetric positive definite matrix $\m{A}$ (or $\m{AA}\tr$), and
+to solve $\m{Ax}=\m{b}$ (or $\m{AA}\tr\m{x}=\m{b}$).  The primary routines rely on the secondary
+routines, the {\tt Core} Module, and the AMD and COLAMD packages.  They
+make optional use of the {\tt Supernodal} and {\tt Partition} Modules, the
+METIS package, the CAMD package, and
+the CCOLAMD package.  The {\tt Cholesky} Module is
+required by the {\tt Partition} Module.
+
+\vspace{0.1in}
+\noindent Primary routines:
+% 4
+    \begin{itemize}
+    \item {\tt cholmod\_analyze}: order and analyze (simplicial or supernodal).
+    \item {\tt cholmod\_factorize}: simplicial or supernodal Cholesky factorization.
+    \item {\tt cholmod\_solve}: solve a linear system (simplicial or supernodal, dense $\m{x}$ and $\m{b}$).
+    \item {\tt cholmod\_spsolve}: solve a linear system (simplicial or supernodal, sparse $\m{x}$ and $\m{b}$ ).
+    \end{itemize}
+
+\noindent Secondary routines:
+% 15
+    \begin{itemize}
+    \item {\tt cholmod\_analyze\_p}: analyze, with user-provided permutation or $\m{f}$ set.
+    \item {\tt cholmod\_factorize\_p}: factorize, with user-provided permutation or $\m{f}$.
+    \item {\tt cholmod\_analyze\_ordering}:  analyze a permutation
+    \item {\tt cholmod\_etree}: find the elimination tree.
+    \item {\tt cholmod\_rowcolcounts}: compute the row/column counts of $\m{L}$.
+    \item {\tt cholmod\_amd}: order using AMD.
+    \item {\tt cholmod\_colamd}: order using COLAMD.
+    \item {\tt cholmod\_rowfac}: incremental simplicial factorization.
+    \item {\tt cholmod\_row\_subtree}: find the nonzero pattern of a row of $\m{L}$.
+    \item {\tt cholmod\_row\_lsubtree}: find the nonzero pattern of a row of $\m{L}$.
+    \item {\tt cholmod\_resymbol}: recompute the symbolic pattern of $\m{L}$.
+    \item {\tt cholmod\_resymbol\_noperm}: recompute the symbolic pattern of $\m{L}$, no permutation.
+    \item {\tt cholmod\_postorder}: postorder a tree.
+    \item {\tt cholmod\_rcond}: compute the reciprocal condition number estimate.
+    \item {\tt cholmod\_rowfac\_mask}: for use in LPDASA only.
+    \end{itemize}
+
+%-------------------------------------------------------------------------------
+\newpage \subsection{{\tt Modify} Module: update/downdate a sparse Cholesky factorization}
+%-------------------------------------------------------------------------------
+
+The {\tt Modify} Module contains sparse Cholesky modification routines:
+update, downdate, row-add, and row-delete.
+It can also modify a corresponding solution to $\m{Lx}=\m{b}$ when L is modified.
+This module is most useful when applied on a Cholesky factorization computed by
+the {\tt Cholesky} module, but it does not actually require the {\tt Cholesky} module.
+The {\tt Core} module can create an identity Cholesky factorization ($\m{LDL}\tr$ where
+$\m{L}=\m{D}=\m{I}$) that can then be modified by these routines.
+Requires the {\tt Core} module.  Not required by any other CHOLMOD Module.
+
+\vspace{0.1in}
+\noindent Primary routine:
+% 1
+    \begin{itemize}
+    \item {\tt cholmod\_updown}: multiple rank update/downdate
+    \end{itemize}
+
+\noindent Secondary routines:
+% 8
+    \begin{itemize}
+    \item {\tt cholmod\_updown\_solve}: update/downdate, and modify solution to $\m{Lx=b}$
+    \item {\tt cholmod\_updown\_mark}: update/downdate, and modify solution to partial $\m{Lx=b}$
+    \item {\tt cholmod\_updown\_mask}: for use in LPDASA only.
+    \item {\tt cholmod\_rowadd}: add a row to an $\m{LDL}\tr$ factorization
+    \item {\tt cholmod\_rowadd\_solve}: add a row, and update solution to $\m{Lx=b}$
+    \item {\tt cholmod\_rowadd\_mark}: add a row, and update solution to partial $\m{Lx=b}$
+    \item {\tt cholmod\_rowdel}: delete a row from an $\m{LDL}\tr$ factorization
+    \item {\tt cholmod\_rowdel\_solve}: delete a row, and downdate $\m{Lx=b}$
+    \item {\tt cholmod\_rowdel\_mark}: delete a row, and downdate solution to partial $\m{Lx=b}$
+    \end{itemize}
+
+%-------------------------------------------------------------------------------
+\subsection{{\tt MatrixOps} Module: basic sparse matrix operations}
+%-------------------------------------------------------------------------------
+
+The {\tt MatrixOps} Module provides
+basic operations on sparse and dense matrices.
+Requires the {\tt Core} module.  Not required by any other CHOLMOD module.
+In the descriptions below,
+{\tt A}, {\tt B}, and {\tt C:} are sparse matrices ({\tt cholmod\_sparse}),
+{\tt X} and {\tt Y} are dense matrices ({\tt cholmod\_dense}),
+{\tt s} is a scalar or vector, and
+{\tt alpha} {\tt beta} are scalars.
+
+% 10
+    \begin{itemize}
+    \item {\tt cholmod\_drop}: drop entries from A with absolute value $\ge$ a given tolerance.
+    \item {\tt cholmod\_norm\_dense}: {\tt s = norm (X)}, 1-norm, infinity-norm, or 2-norm
+    \item {\tt cholmod\_norm\_sparse}: {\tt s = norm (A)}, 1-norm or infinity-norm
+    \item {\tt cholmod\_horzcat}: {\tt C = [A,B]}
+    \item {\tt cholmod\_scale}: {\tt A = diag(s)*A}, {\tt A*diag(s)}, {\tt s*A} or {\tt diag(s)*A*diag(s)}.
+    \item {\tt cholmod\_sdmult}: {\tt Y = alpha*(A*X) + beta*Y} or {\tt alpha*(A'*X) + beta*Y}.
+    \item {\tt cholmod\_ssmult}: {\tt C = A*B}
+    \item {\tt cholmod\_submatrix}: {\tt C = A (i,j)}, where {\tt i} and {\tt j} are arbitrary integer vectors.
+    \item {\tt cholmod\_vertcat}: {\tt C = [A ; B]}.
+    \item {\tt cholmod\_symmetry}: determine symmetry of a matrix.
+    \end{itemize}
+
+%-------------------------------------------------------------------------------
+\newpage \subsection{{\tt Supernodal} Module: supernodal sparse Cholesky factorization}
+%-------------------------------------------------------------------------------
+
+The {\tt Supernodal} Module performs
+supernodal analysis, factorization, and solve.  The simplest way to use
+these routines is via the {\tt Cholesky} Module.  This Module does not provide any
+fill-reducing orderings.  It normally operates on matrices ordered by the
+{\tt Cholesky} Module.
+It does not require the {\tt Cholesky} Module itself, however.
+Requires the {\tt Core} Module, and two external packages: LAPACK and the BLAS.
+Optionally used by the {\tt Cholesky} Module.  All are secondary routines
+since these functions are more easily used via the {\tt Cholesky} Module.
+
+\vspace{0.1in}
+\noindent Secondary routines:
+% 4
+    \begin{itemize}
+    \item {\tt cholmod\_super\_symbolic}: supernodal symbolic analysis
+    \item {\tt cholmod\_super\_numeric}: supernodal numeric factorization
+    \item {\tt cholmod\_super\_lsolve}: supernodal $\m{Lx}=\m{b}$ solve
+    \item {\tt cholmod\_super\_ltsolve}: supernodal $\m{L}\tr\m{x}=\m{b}$ solve
+    \end{itemize}
+
+%-------------------------------------------------------------------------------
+\subsection{{\tt Partition} Module: graph-partitioning-based orderings}
+%-------------------------------------------------------------------------------
+
+The {\tt Partition} Module provides
+graph partitioning and graph-partition-based orderings.  It includes an
+interface to CAMD, CCOLAMD, and CSYMAMD, constrained minimum degree ordering
+methods which order a matrix following constraints determined via nested
+dissection.
+Requires the {\tt Core} and {\tt Cholesky} Modules, and two packages: {\tt METIS 4.0.1}, CAMD, and CCOLAMD.
+Optionally used by the {\tt Cholesky} Module.  All are secondary routines since
+these are more easily used by the {\tt Cholesky} Module.
+
+Note that METIS does not have a version that uses {\tt long} integers.  If you try to use
+these routines (except the CAMD, CCOLAMD, and CSYMAMD interfaces)
+on a matrix that is too large, an error code will be returned.
+
+\vspace{0.1in}
+\noindent Secondary routines:
+% 8
+    \begin{itemize}
+    \item {\tt cholmod\_nested\_dissection}: CHOLMOD nested dissection ordering
+    \item {\tt cholmod\_metis}: METIS nested dissection ordering ({\tt METIS\_NodeND})
+    \item {\tt cholmod\_camd}: interface to CAMD ordering
+    \item {\tt cholmod\_ccolamd}: interface to CCOLAMD ordering
+    \item {\tt cholmod\_csymamd}: interface to CSYMAMD ordering
+    \item {\tt cholmod\_bisect}: graph partitioner (currently based on METIS)
+    \item {\tt cholmod\_metis\_bisector}: direct interface to {\tt METIS\_NodeComputeSeparator}.
+    \item {\tt cholmod\_collapse\_septree}: pruned a separator tree from
+    {\tt cholmod\_nested\_dissection}.
+    \end{itemize}
+
+%-------------------------------------------------------------------------------
+\newpage \section{CHOLMOD naming convention, parameters, and return values}
+%-------------------------------------------------------------------------------
+
+All routine names, data types, and CHOLMOD library files use the
+{\tt cholmod\_} prefix.  All macros and other {\tt \#define} statements
+visible to the user program use the {\tt CHOLMOD} prefix.
+The {\tt cholmod.h} file must be included in user programs that use CHOLMOD:
+
+{\footnotesize
+\begin{verbatim}
+        #include "cholmod.h"
+\end{verbatim}
+}
+
+\noindent
+All CHOLMOD routines (in all modules) use the following protocol for return values:
+\begin{itemize}
+\item {\tt int}: {\tt TRUE} (1) if successful, or {\tt FALSE} (0) otherwise. (exception: {\tt cholmod\_divcomplex}).
+\item {\tt long}: a value $\ge 0$ if successful, or -1 otherwise.
+\item {\tt double}: a value $\ge 0$ if successful, or -1 otherwise.
+\item {\tt size\_t}: a value $>$ 0 if successful, or 0 otherwise.
+\item {\tt void *}: a non-{\tt NULL} pointer to newly allocated memory if successful, or {\tt NULL} otherwise.
+\item {\tt cholmod\_sparse *}:  a non-{\tt NULL} pointer to a newly allocated sparse matrix if successful, or {\tt NULL} otherwise.
+\item {\tt cholmod\_factor *}:  a non-{\tt NULL} pointer to a newly allocated factor if successful, or {\tt NULL} otherwise.
+\item {\tt cholmod\_triplet *}: a non-{\tt NULL} pointer to a newly allocated triplet matrix if successful, or {\tt NULL} otherwise.
+\item {\tt cholmod\_dense *}:   a non-{\tt NULL} pointer to a newly allocated dense matrix if successful, or {\tt NULL} otherwise.
+\end{itemize}
+
+{\tt TRUE} and {\tt FALSE} are not defined in {\tt cholmod.h},
+since they may conflict with the user program.  A routine that described
+here returning {\tt TRUE} or {\tt FALSE} returns 1 or 0, respectively.
+Any {\tt TRUE}/{\tt FALSE} parameter is true if nonzero, false if zero.
+
+\noindent
+Input, output, and input/output parameters:
+\begin{itemize}
+\item Input parameters appear first in the parameter lists of all CHOLMOD routines.
+They are not modified by CHOLMOD.
+\item Input/output parameters (except for {\tt Common}) appear next.
+They must be defined on input, and are modified on output.
+\item Output parameters are listed next.  If they are pointers, they must
+point to allocated space on input, but their contents are not defined on input.
+\item Workspace parameters appear next.  They are used in only two routines in the Supernodal module.
+\item The {\tt cholmod\_common *Common} parameter always appears as the last parameter
+(with two exceptions: {\tt cholmod\_hypot} and {\tt cholmod\_divcomplex}).
+It is always an input/output parameter.
+\end{itemize}
+
+A floating-point scalar is passed to CHOLMOD as a pointer to a {\tt double}
+array of size two.  The first entry in this array is the real part of the
+scalar, and the second entry is the imaginary part.  The imaginary part is
+only accessed if the other inputs are complex or zomplex.  In some cases
+the imaginary part is always ignored ({\tt cholmod\_factor\_p}, for example).
+
+%-------------------------------------------------------------------------------
+\newpage \section{{\tt Core} Module: {\tt cholmod\_common} object}
+\label{cholmod_common}
+%-------------------------------------------------------------------------------
+
+%---------------------------------------
+\subsection{Constant definitions}
+%---------------------------------------
+
+\input{_defn.tex}
+These definitions are used within the {\tt cholmod\_common} object,
+called {\tt Common} both here and throughout the code.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_common}: parameters, statistics, and workspace}
+%---------------------------------------
+
+\input{_common.tex}
+The {\tt cholmod\_common Common} object contains parameters, statistics, and
+workspace used within CHOLMOD.  The first call to CHOLMOD must be
+{\tt cholmod\_start}, which initializes this object.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_start}: start CHOLMOD}
+%---------------------------------------
+
+\input{_start.tex}
+Sets the default parameters, clears the statistics, and initializes all
+workspace pointers to {\tt NULL}.  The {\tt int}/{\tt long} type
+is set in {\tt Common->itype}.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_finish}: finish CHOLMOD}
+%---------------------------------------
+
+\input{_finish.tex}
+This must be the last call to CHOLMOD.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_defaults}: set default parameters}
+%---------------------------------------
+
+\input{_defaults.tex}
+Sets the default parameters.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_maxrank}: maximum update/downdate rank}
+%---------------------------------------
+
+\input{_maxrank.tex}
+Returns the maximum rank for an update/downdate.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_allocate\_work}: allocate workspace}
+%---------------------------------------
+
+\input{_allocate_work.tex}
+Allocates workspace in {\tt Common}.  The workspace consists
+of the integer {\tt Head}, {\tt Flag}, and {\tt Iwork} arrays,
+of size {\tt nrow+1}, {\tt nrow}, and {\tt iworksize},
+respectively, and a {\tt double} array {\tt Xwork} of size
+{\tt xworksize}.  The {\tt Head} array is normally equal to -1
+when it is cleared.  If the {\tt Flag} array is cleared,
+all entries are less than {\tt Common->mark}.  The {\tt Iwork} array is
+not kept in any particular state.
+The integer type is {\tt int} or {\tt long}, depending
+on whether the {\tt cholmod\_} or {\tt cholmod\_l\_} routines
+are used.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_free\_work}: free workspace}
+%---------------------------------------
+
+\input{_free_work.tex}
+Frees the workspace in {\tt Common}.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_clear\_flag}: clear Flag array}
+%---------------------------------------
+
+\input{_clear_flag.tex}
+Increments {\tt Common->mark} so that the {\tt Flag} array is now cleared.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_error}: report error}
+%---------------------------------------
+
+\input{_error.tex}
+This routine is called when CHOLMOD encounters an error.
+It prints a message (if printing is enabled), sets
+{\tt Common->status}.  It then calls the
+user error handler routine {\tt Common->error\_handler},
+if it is not {\tt NULL}.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_dbound}: bound diagonal of $\m{L}$}
+%---------------------------------------
+
+\input{_dbound.tex}
+Ensures that entries on the diagonal of $\m{L}$ for an $\m{LL}\tr$
+factorization are greater than or equal to {\tt Common->dbound}.
+For an $\m{LDL}\tr$ factorization, it ensures that the magnitude
+of the entries of $\m{D}$ are greater than or equal to {\tt Common->dbound}.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_hypot}: {\tt sqrt(x*x+y*y)}}
+%---------------------------------------
+
+\input{_hypot.tex}
+Computes the magnitude of a complex number.
+This routine is the default value for the {\tt Common->hypotenuse} function pointer.
+See also {\tt hypot}, in the standard {\tt math.h} header.  If you have
+the ANSI C99 {\tt hypot}, you can use {\tt Common->hypotenuse = hypot}.
+The {\tt cholmod\_hypot} routine is provided in case you are using the
+ANSI C89 standard, which does not have {\tt hypot}.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_divcomplex}: complex divide}
+%---------------------------------------
+
+\input{_divcomplex.tex}
+Divides two complex numbers.  It returns 1 if a divide-by-zero occurred, or 0 otherwise.
+This routine is the default value for the {\tt Common->complex\_divide} function pointer.
+This return value is the single exception to the CHOLMOD rule that states all {\tt int} return
+values are {\tt TRUE} if successful or {\tt FALSE} otherwise.
+The exception is made to match the return value of a different complex divide routine
+that is not a part of CHOLMOD, but can be used via the function pointer.
+
+%-------------------------------------------------------------------------------
+\newpage \section{{\tt Core} Module: {\tt cholmod\_sparse} object}
+\label{cholmod_sparse}
+%-------------------------------------------------------------------------------
+
+%---------------------------------------
+\subsection{{\tt cholmod\_sparse}: compressed-column sparse matrix}
+%---------------------------------------
+
+\input{_sparse.tex}
+Stores a sparse matrix in compressed-column form.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_allocate\_sparse}: allocate sparse matrix}
+%---------------------------------------
+
+\input{_allocate_sparse.tex}
+Allocates a sparse matrix.  {\tt A->i}, {\tt A->x}, and {\tt A->z} are not initialized.
+The matrix returned is all zero, but it contains space enough for {\tt nzmax} entries.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_free\_sparse}: free sparse matrix}
+%---------------------------------------
+
+\input{_free_sparse.tex}
+Frees a sparse matrix.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_reallocate\_sparse}: reallocate sparse matrix}
+%---------------------------------------
+
+\input{_reallocate_sparse.tex}
+Reallocates a sparse matrix, so that it can contain {\tt nznew} entries.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_nnz}: number of entries in sparse matrix}
+%---------------------------------------
+
+\input{_nnz.tex}
+Returns the number of entries in a sparse matrix.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_speye}: sparse identity matrix}
+%---------------------------------------
+
+\input{_speye.tex}
+Returns the sparse identity matrix.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_spzeros}: sparse zero matrix}
+%---------------------------------------
+
+\input{_spzeros.tex}
+Returns the sparse zero matrix.  This is another name
+for {\tt cholmod\_allocate\_sparse}, but with fewer parameters
+(the matrix is packed, sorted, and unsymmetric).
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_transpose}: transpose sparse matrix}
+%---------------------------------------
+
+\input{_transpose.tex}
+Returns the transpose or complex conjugate transpose of a sparse matrix.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_ptranspose}: transpose/permute sparse matrix}
+%---------------------------------------
+
+\input{_ptranspose.tex}
+Returns {\tt A'} or {\tt A(p,p)'} if {\tt A} is symmetric.
+Returns {\tt A'}, {\tt A(:,f)'}, or {\tt A(p,f)'} if {\tt A} is unsymmetric.
+See {\tt cholmod\_transpose\_unsym} for a discussion of how {\tt f} is used;
+this usage deviates from the MATLAB notation.
+Can also return the array transpose.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_sort}: sort columns of a sparse matrix}
+%---------------------------------------
+
+\input{_sort.tex}
+Sorts the columns of the matrix {\tt A}.  Returns  {\tt A} in packed form, even if it
+starts as unpacked.  Removes entries in the ignored part of a symmetric matrix.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_transpose\_unsym}: transpose/permute unsymmetric sparse matrix}
+%---------------------------------------
+
+\input{_transpose_unsym.tex}
+Transposes and optionally permutes an unsymmetric sparse matrix.
+The output matrix must be preallocated before calling this routine.
+
+Computes {\tt F=A'}, {\tt F=A(:,f)'} or {\tt F=A(p,f)'}, except that the
+indexing by {\tt f} does not work the same as the MATLAB notation (see below).
+{\tt A->stype} is zero, which denotes that both the upper and lower triangular
+parts of A are present (and used).  The matrix {\tt A} may in fact be symmetric in pattern
+and/or value; {\tt A->stype} just denotes which part of {\tt A} are stored.  {\tt A} may be
+rectangular.
+ 
+The integer vector
+{\tt p} is a permutation of {\tt 0:m-1}, and {\tt f} is a subset of {\tt 0:n-1},
+where A is {\tt m}-by-{\tt n}.
+There can be no duplicate entries in {\tt p} or {\tt f}.
+
+\noindent
+Three kinds of transposes are available, depending on the {\tt values} parameter:
+\begin{itemize}
+\item    0: do not transpose the numerical values; create a {\tt CHOLMOD\_PATTERN} matrix
+\item    1: array transpose
+\item    2: complex conjugate transpose (same as 2 if input is real or pattern)
+\end{itemize}
+
+\noindent
+The set {\tt f} is held in fset and fsize:
+\begin{itemize}
+\item  {\tt fset = NULL} means ``{\tt :}'' in MATLAB. {\tt fset} is ignored.
+\item  {\tt fset != NULL} means {\tt f = fset [0..fsize-1]}.
+\item  {\tt fset != NULL} and {\tt fsize = 0} means {\tt f} is the empty set.
+\end{itemize}
+ 
+Columns not in the set {\tt f} are considered to be zero.  That is,
+if {\tt A} is 5-by-10 then {\tt F=A(:,[3 4])'} is not 2-by-5, but 10-by-5,
+and rows 3 and 4 of {\tt F} are equal to columns 3 and 4 of {\tt A} (the other
+rows of {\tt F} are zero).  More precisely, in MATLAB notation:
+
+\begin{verbatim}
+        [m n] = size (A)
+        F = A
+        notf = ones (1,n)
+        notf (f) = 0
+        F (:, find (notf)) = 0
+        F = F'
+\end{verbatim}
+
+If you want the MATLAB equivalent {\tt F=A(p,f)} operation, use
+{\tt cholmod\_submatrix} instead (which does not compute the transpose).
+{\tt F->nzmax} must be large enough to hold the matrix {\tt F}.
+If {\tt F->nz} is present then {\tt F->nz [j]} is equal to the number of entries in column {\tt j} of {\tt F}.
+{\tt A} can be sorted or unsorted, with packed or unpacked columns.
+If {\tt f} is present and not sorted in ascending order, then {\tt F} is unsorted
+(that is, it may contain columns whose row indices do not appear in
+ascending order).  Otherwise, {\tt F} is sorted (the row indices in each
+column of {\tt F} appear in strictly ascending order).
+
+{\tt F} is returned in packed or unpacked form, depending on {\tt F->packed} on input.
+If {\tt F->packed} is {\tt FALSE}, then {\tt F} is returned in unpacked form ({\tt F->nz} must be
+present).  Each row {\tt i} of {\tt F} is large enough to hold all the entries in row {\tt i}
+of {\tt A}, even if {\tt f} is provided.  That is, {\tt F->i} and
+{\tt F->x [F->p [i] .. F->p [i] + F->nz [i] - 1]} contain all entries in {\tt A(i,f)},
+but {\tt F->p [i+1] - F->p [i]} is equal to the number of nonzeros in {\tt A (i,:)},
+not just {\tt A (i,f)}.
+The {\tt cholmod\_transpose\_unsym} routine is the only operation in CHOLMOD that
+can produce an unpacked matrix.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_transpose\_sym}: transpose/permute symmetric sparse matrix}
+%---------------------------------------
+
+\input{_transpose_sym.tex}
+Computes {\tt F = A'} or {\tt F = A(p,p)'}, the transpose or permuted transpose, where
+{\tt A->stype} is nonzero.  {\tt A} must be square and symmetric.
+If {\tt A->stype} $> 0$, then {\tt A} is a symmetric matrix where just the upper part
+of the matrix is stored.  Entries in the lower triangular part may be
+present, but are ignored.
+If {\tt A->stype} $< 0$, then {\tt A} is a symmetric matrix where just the lower part
+of the matrix is stored.  Entries in the upper triangular part may be present, but are ignored.
+If {\tt F=A'}, then {\tt F} is returned
+sorted; otherwise {\tt F} is unsorted for the {\tt F=A(p,p)'} case.
+There can be no duplicate entries in {\tt p}.
+
+Three kinds of transposes are available, depending on the {\tt values} parameter:
+\begin{itemize}
+\item    0: do not transpose the numerical values; create a {\tt CHOLMOD\_PATTERN} matrix
+\item    1: array transpose
+\item    2: complex conjugate transpose (same as 2 if input is real or pattern)
+\end{itemize}
+
+For {\tt cholmod\_transpose\_unsym} and {\tt cholmod\_transpose\_sym}, the output matrix
+{\tt F} must already be pre-allocated by the caller, with the correct dimensions.
+If {\tt F} is not valid or has the wrong dimensions, it is not modified.
+Otherwise, if {\tt F} is too small, the transpose is not computed; the contents
+of {\tt F->p} contain the column pointers of the resulting matrix, where
+{\tt F->p [F->ncol] > F->nzmax}.  In this case, the remaining contents of {\tt F} are
+not modified.  {\tt F} can still be properly freed with {\tt cholmod\_free\_sparse}.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_band}: extract band of a sparse matrix}
+%---------------------------------------
+
+\input{_band.tex}
+Returns {\tt C = tril (triu (A,k1), k2)}.
+{\tt C} is a matrix consisting of the diagonals of A from {\tt k1} to {\tt k2}.
+{\tt k=0} is the main diagonal of {\tt A}, {\tt k=1} is the superdiagonal, {\tt k=-1} is the
+subdiagonal, and so on.  If {\tt A} is {\tt m}-by-{\tt n}, then:
+\begin{itemize}
+\item {\tt k1=-m} means {\tt C = tril (A,k2)}
+\item {\tt k2=n} means {\tt C = triu (A,k1)}
+\item {\tt k1=0} and {\tt k2=0} means {\tt C = diag(A)}, except {\tt C} is a matrix, not a vector
+\end{itemize}
+Values of {\tt k1} and {\tt k2} less than {\tt -m} are treated as {\tt -m}, and values greater
+than {\tt n} are treated as {\tt n}.
+
+{\tt A} can be of any symmetry (upper, lower, or unsymmetric); {\tt C} is returned in
+the same form, and packed.  If {\tt A->stype} $> 0$, entries in the lower
+triangular part of {\tt A} are ignored, and the opposite is true if
+{\tt A->stype} $< 0$.  If {\tt A} has sorted columns, then so does {\tt C}.
+{\tt C} has the same size as {\tt A}.
+
+{\tt C} can be returned as a numerical valued matrix (if {\tt A} has numerical values
+and {\tt mode} $> 0$), as a pattern-only ({\tt mode} $=0$), or as a pattern-only but with
+the diagonal entries removed ({\tt mode} $< 0$).
+
+The xtype of {\tt A} can be pattern or real.  Complex or zomplex cases are supported only
+if {\tt mode} is $\le 0$ (in which case the numerical values are ignored).
+
+%---------------------------------------
+\subsection{{\tt cholmod\_band\_inplace}: extract band, in place}
+%---------------------------------------
+
+\input{_band_inplace.tex}
+Same as {\tt cholmod\_band}, except that it always operates in place.
+Only packed matrices can be converted in place.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_aat}: compute $\m{AA}\tr$}
+%---------------------------------------
+
+\input{_aat.tex}
+Computes {\tt C = A*A'} or {\tt C = A(:,f)*A(:,f)'}.
+{\tt A} can be packed or unpacked, sorted or unsorted, but must be stored with
+both upper and lower parts ({\tt A->stype} of zero).  {\tt C} is returned as packed,
+{\tt C->stype} of zero (both upper and lower parts present), and unsorted.  See
+{\tt cholmod\_ssmult} in the {\tt MatrixOps} Module for a more general matrix-matrix
+multiply.
+The xtype of {\tt A} can be pattern or real.  Complex or zomplex cases are supported only
+if {\tt mode} is $\le 0$ (in which case the numerical values are ignored).
+You can trivially convert {\tt C} to a symmetric upper/lower matrix
+by changing {\tt C->stype} to 1 or -1, respectively, after calling this routine.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_copy\_sparse}: copy sparse matrix}
+%---------------------------------------
+
+\input{_copy_sparse.tex}
+Returns an exact copy of the input sparse matrix {\tt A}.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_copy}: copy (and change) sparse matrix}
+%---------------------------------------
+
+\input{_copy.tex}
+{\tt C = A}, which allocates {\tt C} and copies {\tt A} into {\tt C}, with possible change of
+{\tt stype}.  The diagonal can optionally be removed.  The numerical entries
+can optionally be copied.  This routine differs from {\tt cholmod\_copy\_sparse},
+which makes an exact copy of a sparse matrix.
+
+{\tt A} can be of any type (packed/unpacked, upper/lower/unsymmetric).  {\tt C} is
+packed and can be of any stype (upper/lower/unsymmetric), except that if
+{\tt A} is rectangular {\tt C} can only be unsymmetric.  If the stype of A and C
+differ, then the appropriate conversion is made.
+
+\noindent
+There are three cases for {\tt A->stype}:
+\begin{itemize}
+\item $<0$,  lower: assume {\tt A} is symmetric with just {\tt tril(A)} stored; the rest of {\tt A} is ignored
+\item $ 0$,  unsymmetric: assume {\tt A} is unsymmetric; consider all entries in A
+\item $>0$,  upper: assume {\tt A} is symmetric with just {\tt triu(A)} stored; the rest of {\tt A} is ignored
+\end{itemize}
+
+\noindent
+There are three cases for the requested symmetry of {\tt C} ({\tt stype} parameter):
+\begin{itemize}
+\item $<0$,  lower: return just {\tt tril(C)}
+\item $0$,   unsymmetric: return all of {\tt C}
+\item $>0$,  upper: return just {\tt triu(C)}
+\end{itemize}
+
+\noindent
+This gives a total of nine combinations: \newline
+\begin{tabular}{ll}
+\hline
+Equivalent MATLAB statements			    & Using {\tt cholmod\_copy} \\
+\hline
+{\tt C = A ;						   }& {\tt A} unsymmetric, {\tt C} unsymmetric \\
+{\tt C = tril (A) ;					   }& {\tt A} unsymmetric, {\tt C} lower \\
+{\tt C = triu (A) ;					   }& {\tt A} unsymmetric, {\tt C} upper \\
+{\tt U = triu (A) ; L = tril (U',-1) ; C = L+U ;	   }& {\tt A} upper, {\tt C} unsymmetric \\
+{\tt C = triu (A)' ;					   }& {\tt A} upper, {\tt C} lower \\
+{\tt C = triu (A) ;					   }& {\tt A} upper, {\tt C} upper \\
+{\tt L = tril (A) ; U = triu (L',1) ; C = L+U ;		   }& {\tt A} lower, {\tt C} unsymmetric \\
+{\tt C = tril (A) ;					   }& {\tt A} lower, {\tt C} lower \\
+{\tt C = tril (A)' ;					   }& {\tt A} lower, {\tt C} upper \\
+\hline
+\end{tabular}
+
+\vspace{0.1in}
+The xtype of {\tt A} can be pattern or real.  Complex or zomplex cases are supported only
+if {\tt values} is {\tt FALSE} (in which case the numerical values are ignored).
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_add}: add sparse matrices}
+%---------------------------------------
+
+\input{_add.tex}
+Returns {\tt C = alpha*A + beta*B}.
+If the {\tt stype} of {\tt A} and {\tt B} match, then {\tt C} has
+the same {\tt stype}.  Otherwise, {\tt C->stype} is zero ({\tt C} is
+unsymmetric).
+
+%---------------------------------------
+\subsection{{\tt cholmod\_sparse\_xtype}: change sparse xtype}
+%---------------------------------------
+
+\input{_sparse_xtype.tex}
+Changes the {\tt xtype} of a sparse matrix, to pattern, real, complex, or zomplex.
+Changing from complex or zomplex to real discards the imaginary part.
+
+%-------------------------------------------------------------------------------
+\newpage \section{{\tt Core} Module: {\tt cholmod\_factor} object}
+\label{cholmod_factor}
+%-------------------------------------------------------------------------------
+
+%---------------------------------------
+\subsection{{\tt cholmod\_factor} object: a sparse Cholesky factorization}
+%---------------------------------------
+
+\input{_factor.tex}
+An $\m{LL}\tr$ or $\m{LDL}\tr$ factorization in simplicial or supernodal form.
+A simplicial factor is very similar to a {\tt cholmod\_sparse} matrix.
+For an $\m{LDL}\tr$ factorization, the diagonal matrix $\m{D}$ is stored
+as the diagonal of $\m{L}$; the unit-diagonal of $\m{L}$ is not stored.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_free\_factor}: free factor}
+%---------------------------------------
+
+\input{_free_factor.tex}
+Frees a factor.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_allocate\_factor}: allocate factor}
+%---------------------------------------
+
+\input{_allocate_factor.tex}
+Allocates a factor and sets it to identity.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_reallocate\_factor}: reallocate factor}
+%---------------------------------------
+
+\input{_reallocate_factor.tex}
+Reallocates a simplicial factor so that it can contain {\tt nznew} entries.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_change\_factor}: change factor}
+%---------------------------------------
+
+\input{_change_factor.tex}
+Change the numeric or symbolic, $\m{LL}\tr$ or $\m{LDL}\tr$, simplicial or super, packed or unpacked, and
+monotonic or non-monotonic status of a {\tt cholmod\_factor} object.
+
+There are four basic classes of factor types:
+\begin{enumerate}
+\item simplicial symbolic:  Consists of two size-{\tt n} arrays: the fill-reducing
+permutation ({\tt L->Perm}) and the nonzero count for each column of L
+({\tt L->ColCount}).  All other factor types also include this information.
+{\tt L->ColCount} may be exact (obtained from the analysis routines), or
+it may be a guess.  During factorization, and certainly after update/downdate,
+the columns of {\tt L} can have a different number of nonzeros.
+{\tt L->ColCount} is used to allocate space.  {\tt L->ColCount} is exact for the
+supernodal factorizations.  The nonzero pattern of {\tt L} is not kept.
+
+\item simplicial numeric:  These represent {\tt L} in a compressed column form.  The
+variants of this type are:
+
+\begin{itemize}
+\item $\m{LDL}\tr$:	{\tt L} is unit diagonal.  Row indices in column {\tt j} are located in
+    {\tt L->i [L->p [j] ... L->p [j] + L->nz [j]]}, and corresponding numeric
+    values are in the same locations in {\tt L->x}.  The total number of
+    entries is the sum of {\tt L->nz [j]}.  The unit diagonal is not stored;
+    {\tt D} is stored on the diagonal of {\tt L} instead.  {\tt L->p} may or may not be
+    monotonic.  The order of storage of the columns in {\tt L->i} and {\tt L->x} is
+    given by a doubly-linked list ({\tt L->prev} and {\tt L->next}).  {\tt L->p} is of
+    size {\tt n+1}, but only the first {\tt n} entries are used.
+
+    For the complex case, {\tt L->x} is stored interleaved with real and imaginary
+    parts, and is of size {\tt 2*lnz*sizeof(double)}.  For the zomplex case,
+    {\tt L->x} is of size {\tt lnz*sizeof(double)} and holds the real part; {\tt L->z}
+    is the same size and holds the imaginary part.
+
+\item $\m{LL}\tr$:  This is identical to the $\m{LDL}\tr$ form, except that the non-unit
+    diagonal of {\tt L} is stored as the first entry in each column of {\tt L}.
+\end{itemize}
+
+\item supernodal symbolic:  A representation of the nonzero pattern of the
+supernodes for a supernodal factorization.  There are {\tt L->nsuper}
+supernodes.  Columns {\tt L->super [k]} to {\tt L->super [k+1]-1} are in the {\tt k}th
+supernode.  The row indices for the {\tt k}th supernode are in
+{\tt L->s [L->pi [k] ... L->pi [k+1]-1]}.  The numerical values are not
+allocated ({\tt L->x}), but when they are they will be located in
+{\tt L->x [L->px [k] ... L->px [k+1]-1]}, and the {\tt L->px} array is defined
+in this factor type.
+
+For the complex case, {\tt L->x} is stored interleaved with real/imaginary parts,
+and is of size \newline
+{\tt 2*L->xsize*sizeof(double)}.  The zomplex supernodal case
+is not supported, since it is not compatible with LAPACK and the BLAS.
+
+\item supernodal numeric:  Always an $\m{LL}\tr$ factorization.  {\tt L} has a non-unit
+     diagonal.  {\tt L->x} contains the numerical values of the supernodes, as
+     described above for the supernodal symbolic factor.
+     For the complex case, {\tt L->x} is stored interleaved, and is of size
+     {\tt 2*L->xsize*sizeof(double)}.  The zomplex supernodal case is not
+     supported, since it is not compatible with LAPACK and the BLAS.
+\end{enumerate}
+
+
+In all cases, the row indices in each column ({\tt L->i} for simplicial {\tt L} and
+{\tt L->s} for supernodal {\tt L}) are kept sorted from low indices to high indices.
+This means the diagonal of {\tt L} (or {\tt D} for a $\m{LDL}\tr$ factorization) is always kept as the
+first entry in each column.  The elimination tree is not kept.  The parent
+of node {\tt j} can be found as the second row index in the {\tt j}th column.
+If column {\tt j} has no off-diagonal entries then node {\tt j} is a root
+of the elimination tree.
+
+The {\tt cholmod\_change\_factor} routine can do almost all possible conversions.
+It cannot do the following conversions:
+
+\begin{itemize}
+\item Simplicial numeric types cannot be converted to a supernodal
+    symbolic type.  This would simultaneously deallocate the
+    simplicial pattern and numeric values and reallocate uninitialized
+    space for the supernodal pattern.  This isn't useful for the user,
+    and not needed by CHOLMOD's own routines either.
+\item Only a symbolic factor (simplicial to supernodal) can be converted
+    to a supernodal numeric factor.
+\end{itemize}
+
+Some conversions are meant only to be used internally by other CHOLMOD
+routines, and should not be performed by the end user.  They allocate space
+whose contents are undefined:
+
+\begin{itemize}
+\item converting from simplicial symbolic to supernodal symbolic.
+\item converting any factor to supernodal numeric.
+\end{itemize}
+
+Supports all xtypes, except that there is no supernodal zomplex L.
+
+The {\tt to\_xtype} parameter is used only when converting from symbolic to numeric
+or numeric to symbolic.  It cannot be used to convert a numeric xtype (real,
+complex, or zomplex) to a different numeric xtype.  For that conversion,
+use {\tt cholmod\_factor\_xtype} instead.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_pack\_factor}: pack the columns of a factor}
+%---------------------------------------
+
+\input{_pack_factor.tex}
+Pack the columns of a simplicial $\m{LDL}\tr$ or $\m{LL}\tr$ factorization.  This can be followed
+by a call to {\tt cholmod\_reallocate\_factor} to reduce the size of {\tt L} to the exact
+size required by the factor, if desired.  Alternatively, you can leave the
+size of {\tt L->i} and {\tt L->x} the same, to allow space for future updates/rowadds.
+Each column is reduced in size so that it has at most {\tt Common->grow2} free
+space at the end of the column.
+Does nothing and returns silently if given any other type of factor.
+Does not force the columns of {\tt L} to be monotonic.  It thus differs from
+\begin{verbatim}
+    cholmod_change_factor (xtype, L->is_ll, FALSE, TRUE, TRUE, L, Common)
+\end{verbatim}
+which packs the columns and ensures that they appear in monotonic order.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_reallocate\_column}: reallocate one column of a factor}
+%---------------------------------------
+
+\input{_reallocate_column.tex}
+Reallocates the space allotted to a single column of $\m{L}$.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_factor\_to\_sparse}: sparse matrix copy of a factor}
+%---------------------------------------
+
+\input{_factor_to_sparse.tex}
+Returns a column-oriented sparse matrix containing the pattern and values
+of a simplicial or supernodal numerical factor, and then converts the factor
+into a simplicial symbolic factor.  If {\tt L} is already packed, monotonic,
+and simplicial (which is the case when {\tt cholmod\_factorize} uses the simplicial
+Cholesky factorization algorithm) then this routine requires only a small
+amount of time and memory, independent of {\tt n}.
+It only operates on numeric factors (real, complex, or zomplex).  It does not
+change {\tt L->xtype} (the resulting sparse matrix has the same {\tt xtype}
+as {\tt L}).  If this routine fails, {\tt L} is left unmodified.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_copy\_factor}: copy factor}
+%---------------------------------------
+
+\input{_copy_factor.tex}
+Returns an exact copy of a factor.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_factor\_xtype}: change factor xtype}
+%---------------------------------------
+
+\input{_factor_xtype.tex}
+Changes the {\tt xtype} of a factor, to pattern, real, complex, or zomplex.
+Changing from complex or zomplex to real discards the imaginary part.
+You cannot change a supernodal factor to the zomplex xtype.
+
+%-------------------------------------------------------------------------------
+\newpage \section{{\tt Core} Module: {\tt cholmod\_dense} object}
+\label{cholmod_dense}
+%-------------------------------------------------------------------------------
+
+%---------------------------------------
+\subsection{{\tt cholmod\_dense} object: a dense matrix}
+%---------------------------------------
+
+\input{_dense.tex}
+Contains a dense matrix.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_allocate\_dense}: allocate dense matrix}
+%---------------------------------------
+
+\input{_allocate_dense.tex}
+Allocates a dense matrix.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_free\_dense}: free dense matrix}
+%---------------------------------------
+
+\input{_free_dense.tex}
+Frees a dense matrix.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_zeros}: dense zero matrix}
+%---------------------------------------
+
+\input{_zeros.tex}
+Returns an all-zero dense matrix.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_ones}: dense matrix, all ones}
+%---------------------------------------
+
+\input{_ones.tex}
+Returns a dense matrix with each entry equal to one.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_eye}: dense identity matrix}
+%---------------------------------------
+
+\input{_eye.tex}
+Returns a dense identity matrix.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_sparse\_to\_dense}: dense matrix copy of a sparse matrix}
+%---------------------------------------
+
+\input{_sparse_to_dense.tex}
+Returns a dense copy of a sparse matrix.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_dense\_to\_sparse}: sparse matrix copy of a dense matrix}
+%---------------------------------------
+
+\input{_dense_to_sparse.tex}
+Returns a sparse copy of a dense matrix.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_copy\_dense}: copy dense matrix}
+%---------------------------------------
+
+\input{_copy_dense.tex}
+Returns a copy of a dense matrix.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_copy\_dense2}: copy dense matrix (preallocated)}
+%---------------------------------------
+
+\input{_copy_dense2.tex}
+Returns a copy of a dense matrix, placing the result in a preallocated matrix {\tt Y}.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_dense\_xtype}: change dense matrix xtype}
+%---------------------------------------
+
+\input{_dense_xtype.tex}
+Changes the {\tt xtype} of a dense matrix, to real, complex, or zomplex.
+Changing from complex or zomplex to real discards the imaginary part.
+
+%-------------------------------------------------------------------------------
+\newpage \section{{\tt Core} Module: {\tt cholmod\_triplet} object}
+\label{cholmod_triplet}
+%-------------------------------------------------------------------------------
+
+%---------------------------------------
+\subsection{{\tt cholmod\_triplet} object: sparse matrix in triplet form}
+%---------------------------------------
+
+\input{_triplet.tex}
+Contains a sparse matrix in triplet form.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_allocate\_triplet}: allocate triplet matrix}
+%---------------------------------------
+
+\input{_allocate_triplet.tex}
+Allocates a triplet matrix.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_free\_triplet}: free triplet matrix}
+%---------------------------------------
+
+\input{_free_triplet.tex}
+Frees a triplet matrix.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_reallocate\_triplet}: reallocate triplet matrix}
+%---------------------------------------
+
+\input{_reallocate_triplet.tex}
+Reallocates a triplet matrix so that it can hold {\tt nznew} entries.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_sparse\_to\_triplet}: triplet matrix copy of a sparse matrix}
+%---------------------------------------
+
+\input{_sparse_to_triplet.tex}
+Returns a triplet matrix copy of a sparse matrix.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_triplet\_to\_sparse}: sparse matrix copy of a triplet matrix}
+%---------------------------------------
+
+\input{_triplet_to_sparse.tex}
+Returns a sparse matrix copy of a triplet matrix.
+If the triplet matrix is symmetric with just the lower part present ({\tt T->stype} $< 0$),
+then entries in the upper part are transposed and placed in the lower part when
+converting to a sparse matrix.  Similarly,
+if the triplet matrix is symmetric with just the upper part present ({\tt T->stype} $> 0$),
+then entries in the lower part are transposed and placed in the upper part when
+converting to a sparse matrix.
+Any duplicate entries are summed.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_copy\_triplet}: copy triplet matrix}
+%---------------------------------------
+
+\input{_copy_triplet.tex}
+Returns an exact copy of a triplet matrix.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_triplet\_xtype}: change triplet xtype}
+%---------------------------------------
+
+\input{_triplet_xtype.tex}
+Changes the {\tt xtype} of a dense matrix, to real, complex, or zomplex.
+Changing from complex or zomplex to real discards the imaginary part.
+
+%-------------------------------------------------------------------------------
+\newpage \section{{\tt Core} Module: memory management}
+%-------------------------------------------------------------------------------
+
+%---------------------------------------
+\subsection{{\tt cholmod\_malloc}: allocate memory}
+%---------------------------------------
+
+\input{_malloc.tex}
+Allocates a block of memory of size {\tt n*size},
+using the {\tt Common->malloc\_memory}
+function pointer (default is to use the ANSI C {\tt malloc} routine).
+A value of {\tt n=0} is treated as {\tt n=1}.
+If not successful, {\tt NULL} is returned and {\tt Common->status} is set to {\tt CHOLMOD\_OUT\_OF\_MEMORY}.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_calloc}: allocate and clear memory}
+%---------------------------------------
+
+\input{_calloc.tex}
+Allocates a block of memory of size {\tt n*size},
+using the {\tt Common->calloc\_memory}
+function pointer (default is to use the ANSI C {\tt calloc} routine).
+A value of {\tt n=0} is treated as {\tt n=1}.
+If not successful, {\tt NULL} is returned and {\tt Common->status} is set to {\tt CHOLMOD\_OUT\_OF\_MEMORY}.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_free}: free memory}
+%---------------------------------------
+
+\input{_free.tex}
+Frees a block of memory of size {\tt n*size},
+using the {\tt Common->free\_memory}
+function pointer (default is to use the ANSI C {\tt free} routine).
+The size of the block ({\tt n} and {\tt size}) is only required so that CHOLMOD
+can keep track of its current and peak memory usage.  This is a useful statistic,
+and it can also help in tracking down memory leaks.  After the call to
+{\tt cholmod\_finish}, the count of allocated blocks ({\tt Common->malloc\_count})
+should be zero, and the count of bytes in use ({\tt Common->memory\_inuse}) also
+should be zero.  If you allocate a block with one size and free it with another,
+the {\tt Common->memory\_inuse} count will be wrong, but CHOLMOD will not
+have a memory leak.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_realloc}: reallocate memory}
+%---------------------------------------
+
+\input{_realloc.tex}
+Reallocates a block of memory whose current size {\tt n*size},
+and whose new size will be {\tt nnew*size} if successful,
+using the {\tt Common->calloc\_memory}
+function pointer (default is to use the ANSI C {\tt realloc} routine).
+If the reallocation is not successful, {\tt p} is returned unchanged
+and {\tt Common->status} is set to {\tt CHOLMOD\_OUT\_OF\_MEMORY}.
+The value of {\tt n} is set to {\tt nnew} if successful, or left
+unchanged otherwise.
+A value of {\tt nnew=0} is treated as {\tt nnew=1}.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_realloc\_multiple}: reallocate memory}
+%---------------------------------------
+
+\input{_realloc_multiple.tex}
+Reallocates multiple blocks of memory, all with the same number of items
+(but with different item sizes).  Either all reallocations succeed,
+or all are returned to their original size.
+
+%-------------------------------------------------------------------------------
+\newpage \section{{\tt Check} Module routines}
+%-------------------------------------------------------------------------------
+
+No CHOLMOD routines print anything, except for the {\tt cholmod\_print\_*}
+routines in the {\tt Check} Module, and the {\tt cholmod\_error} routine.  The
+{\tt Common->print\_function} is a pointer to {\tt printf} by default;
+you can redirect the output of CHOLMOD by redefining this pointer.
+If {\tt Common->print\_function} is {\tt NULL}, CHOLMOD does not print anything.
+
+The {\tt Common->print} parameter determines how much detail is printed.
+Each value of {\tt Common->print} listed below also prints the items listed
+for smaller values of {\tt Common->print}:
+\begin{itemize}
+\item 0: print nothing; check the data structures and return {\tt TRUE} or {\tt FALSE}.
+\item 1: print error messages.
+\item 2: print warning messages.
+\item 3: print a one-line summary of the object.
+\item 4: print a short summary of the object (first and last few entries).
+\item 5: print the entire contents of the object.
+\end{itemize}
+Values less than zero are treated as zero, and values greater than five are
+treated as five.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_check\_common}: check Common object}
+%---------------------------------------
+
+\input{_check_common.tex}
+Check if the {\tt Common} object is valid.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_print\_common}: print Common object}
+%---------------------------------------
+
+\input{_print_common.tex}
+Print the {\tt Common} object and check if it is valid.
+This prints the CHOLMOD parameters and statistics.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_check\_sparse}: check sparse matrix}
+%---------------------------------------
+
+\input{_check_sparse.tex}
+Check if a sparse matrix is valid.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_print\_sparse}: print sparse matrix}
+%---------------------------------------
+
+\input{_print_sparse.tex}
+Print a sparse matrix and check if it is valid.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_check\_dense}: check dense matrix}
+%---------------------------------------
+
+\input{_check_dense.tex}
+Check if a dense matrix is valid.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_print\_dense}: print dense matrix}
+%---------------------------------------
+
+\input{_print_dense.tex}
+Print a dense matrix and check if it is valid.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_check\_factor}: check factor}
+%---------------------------------------
+
+\input{_check_factor.tex}
+Check if a factor is valid.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_print\_factor}: print factor}
+%---------------------------------------
+
+\input{_print_factor.tex}
+Print a factor and check if it is valid.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_check\_triplet}: check triplet matrix}
+%---------------------------------------
+
+\input{_check_triplet.tex}
+Check if a triplet matrix is valid.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_print\_triplet}: print triplet matrix}
+%---------------------------------------
+
+\input{_print_triplet.tex}
+Print a triplet matrix and check if it is valid.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_check\_subset}: check subset}
+%---------------------------------------
+
+\input{_check_subset.tex}
+Check if a subset is valid.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_print\_subset}: print subset}
+%---------------------------------------
+
+\input{_print_subset.tex}
+Print a subset and check if it is valid.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_check\_perm}: check permutation}
+%---------------------------------------
+
+\input{_check_perm.tex}
+Check if a permutation is valid.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_print\_perm}: print permutation}
+%---------------------------------------
+
+\input{_print_perm.tex}
+Print a permutation and check if it is valid.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_check\_parent}: check elimination tree}
+%---------------------------------------
+
+\input{_check_parent.tex}
+Check if an elimination tree is valid.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_print\_parent}: print elimination tree}
+%---------------------------------------
+
+\input{_print_parent.tex}
+Print an elimination tree and check if it is valid.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_read\_triplet}: read triplet matrix from file}
+%---------------------------------------
+
+\input{_read_triplet.tex}
+Read a sparse matrix in triplet form, using the the {\tt coord} 
+Matrix Market format (http://www.nist.gov/MatrixMarket).
+Skew-symmetric and complex symmetric matrices are returned with
+both upper and lower triangular parts present (an stype of zero).
+Real symmetric and complex Hermitian matrices are returned with just
+their upper or lower triangular part, depending on their stype.
+The Matrix Market {\tt array} data type for dense matrices is not supported
+(use {\tt cholmod\_read\_dense} for that case).
+
+If the first line of the file starts with {\tt \%\%MatrixMarket}, then it is
+interpreted as a file in Matrix Market format.  The header line is optional.
+If present, this line must have the following format:
+\vspace{0.1in}
+
+        {\tt \%\%MatrixMarket matrix coord} {\em type storage}
+
+\vspace{0.1in}
+\noindent
+where {\em type} is one of: {\tt real}, {\tt complex}, {\tt pattern},
+or {\tt integer}, and {\em storage} is one of: {\tt general}, {\tt hermitian},
+{\tt symmetric}, or {\tt skew-symmetric}.
+In CHOLMOD, these roughly correspond to the {\tt xtype}
+(pattern, real, complex, or zomplex) and {\tt stype}
+(unsymmetric, symmetric/upper, and symmetric/lower).
+The strings are case-insensitive.  Only the first character (or the
+first two for skew-symmetric) is significant.
+The {\tt coord} token can be replaced with {\tt array} in the Matrix Market format, but
+this format not supported by {\tt cholmod\_read\_triplet}.
+The {\tt integer} type is converted to real.
+The {\em type} is ignored; the actual type (real, complex, or pattern) is
+inferred from the number of tokens in each line of the file (2: pattern,
+3: real, 4: complex).  This is compatible with the Matrix Market format.
+
+A storage of {\tt general} implies an stype of zero
+(see below).  A storage of {\tt symmetric} and {\tt hermitian} imply an stype of -1.
+Skew-symmetric and complex symmetric matrices are returned with an stype of 0.
+Blank lines, any other lines starting with ``{\tt \%}'' are treated as comments, and are ignored.
+
+The first non-comment line contains 3 or 4 integers:
+\vspace{0.1in}
+
+	{\em nrow ncol nnz stype}
+
+\vspace{0.1in}
+\noindent
+where {\em stype} is optional (stype does not appear in the Matrix Market format).
+The matrix is {\em nrow}-by-{\em ncol}.  The following {\em nnz} lines (excluding comments)
+each contain a single entry.  Duplicates are permitted, and are summed in
+the output matrix.
+
+If stype is present, it denotes the storage format for the matrix.
+\begin{itemize}
+\item stype = 0 denotes an unsymmetric matrix (same as Matrix Market {\tt general}).
+\item stype = -1 denotes a symmetric or Hermitian matrix whose lower triangular 
+	entries are stored.  Entries may be present in the upper triangular
+	part, but these are ignored (same as Matrix Market {\tt symmetric}
+	for the real case, {\tt hermitian} for the complex case).
+\item stype = 1 denotes a symmetric or Hermitian matrix whose upper triangular 
+	entries are stored.  Entries may be present in the lower triangular
+	part, but these are ignored.  This format is not available in the Matrix
+	Market format.
+\end{itemize}
+
+If neither the stype nor the Matrix Market header are present, then
+the stype is inferred from the rest of the data.  If the matrix is
+rectangular, or has
+entries in both the upper and lower triangular parts, then it is assumed to
+be unsymmetric (stype=0).  If only entries in the lower triangular part are
+present, the matrix is assumed to have stype = -1.  If only entries in the
+upper triangular part are present, the matrix is assumed to have stype = 1.
+
+Each nonzero consists of one line with 2, 3, or 4 entries.  All lines must
+have the same number of entries.  The first two entries are the row and
+column indices of the nonzero.  If 3 entries are present, the 3rd entry is
+the numerical value, and the matrix is real.  If 4 entries are present,
+the 3rd and 4th entries in the line are the real and imaginary parts of
+a complex value.
+
+The matrix can be either 0-based or 1-based.  It is first assumed to be
+one-based (compatible with Matrix Market), with row indices in the range
+1 to ncol and column indices in the range 1 to nrow.  If a row or column
+index of zero is found, the matrix is assumed to be zero-based (with row
+indices in the range 0 to ncol-1 and column indices in the range 0 to
+nrow-1).  This test correctly determines that all Matrix Market
+matrices are in 1-based form.
+
+For symmetric pattern-only matrices, the kth diagonal (if present) is set to
+one plus the degree of the row k or column k (whichever is larger), and the
+off-diagonals are set to -1.  A symmetric pattern-only matrix with a
+zero-free diagonal is thus converted into a symmetric positive definite
+matrix.  All entries are set to one for an unsymmetric pattern-only matrix.
+This differs from the MatrixMarket format ({\tt A = mmread ('file')} returns
+a binary pattern for A for symmetric pattern-only matrices).
+To return a binary format for all pattern-only matrices, use
+{\tt A = mread('file',1)}.
+
+Example matrices that follow this format can be found in the
+{\tt CHOLMOD/Demo/Matrix} and \newline
+{\tt CHOLMOD/Tcov/Matrix} directories.
+You can also try any of the matrices in the Matrix Market collection
+at http://www.nist.gov/MatrixMarket.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_read\_sparse}: read sparse matrix from file}
+%---------------------------------------
+
+\input{_read_sparse.tex}
+Read a sparse matrix in triplet form from a file (using {\tt cholmod\_read\_triplet})
+and convert to a CHOLMOD sparse matrix.
+The Matrix Market format is used.
+If {\tt Common->prefer\_upper} is {\tt TRUE} (the default case), a symmetric matrix is
+returned stored in upper-triangular form ({\tt A->stype} is 1).
+Otherwise, it is left in its original form, either upper or lower.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_read\_dense}: read dense matrix from file}
+%---------------------------------------
+
+\input{_read_dense.tex}
+Read a dense matrix from a file, using the the {\tt array} 
+Matrix Market format 
+\newline (http://www.nist.gov/MatrixMarket).
+
+%---------------------------------------
+\subsection{{\tt cholmod\_read\_matrix}: read a matrix from file}
+%---------------------------------------
+
+\input{_read_matrix.tex}
+Read a sparse or dense matrix from a file, in Matrix Market format.
+Returns a {\tt void} pointer to either a
+{\tt cholmod\_triplet},
+{\tt cholmod\_sparse}, or
+{\tt cholmod\_dense} object.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_write\_sparse}: write a sparse matrix to a file}
+%---------------------------------------
+
+\input{_write_sparse.tex}
+Write a sparse matrix to a file in Matrix Market format.   Optionally include
+comments, and print explicit zero entries given by the pattern of the {\tt Z}
+matrix.  If not NULL, the {\tt Z} matrix must have the same dimensions and stype
+as {\tt A}.
+
+Returns the symmetry in which the matrix was printed
+(1 to 7) or -1 on failure.  See the {\tt cholmod\_symmetry} function for
+a description of the return codes.
+
+If {\tt A} and {\tt Z} are sorted on input, and either unsymmetric (stype = 0) or
+symmetric-lower (stype < 0), and if {\tt A} and {\tt Z} do not overlap,
+then the triplets
+are sorted, first by column and then by row index within each column, with
+no duplicate entries.  If all the above holds except stype > 0, then the
+triplets are sorted by row first and then column.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_write\_dense}: write a dense matrix to a file}
+%---------------------------------------
+
+\input{_write_dense.tex}
+Write a dense matrix to a file in Matrix Market format.   Optionally include
+comments.  Returns > 0 if successful, -1 otherwise (1 if rectangular, 2 if
+square).
+A dense matrix is written in "general" format; symmetric formats in the
+Matrix Market standard are not exploited.
+
+%-------------------------------------------------------------------------------
+\newpage \section{{\tt Cholesky} Module routines}
+%-------------------------------------------------------------------------------
+
+%---------------------------------------
+\subsection{{\tt cholmod\_analyze}: symbolic factorization}
+%---------------------------------------
+
+\input{_analyze.tex}
+Orders and analyzes a matrix (either simplicial or supernodal), in preparation
+for numerical factorization via {\tt cholmod\_factorize} or via the ``expert''
+routines {\tt cholmod\_rowfac} and {\tt cholmod\_super\_numeric}.
+
+In the symmetric case, {\tt A} or {\tt A(p,p)} is analyzed,
+where {\tt p} is the fill-reducing ordering.
+In the unsymmetric case, {\tt A*A'} or {\tt A(p,:)*A(p,:)'} is analyzed.
+The {\tt cholmod\_analyze\_p} routine can be given a user-provided permutation {\tt p}
+(see below).
+
+The default ordering strategy is to first try AMD.
+The ordering quality is analyzed, and if AMD obtains an ordering where
+{\tt nnz(L)} is greater than or equal to {\tt 5*nnz(tril(A))}
+(or {\tt 5*nnz(tril(A*A'))} if {\tt A} is unsymmetric) and
+the floating-point operation count for the subsequent factorization is
+greater than or equal to {\tt 500*nnz(L)}, then METIS is tried (if installed).
+For {\tt cholmod\_analyze\_p}, the user-provided ordering is also tried.
+This default behavior is obtained when {\tt Common->nmethods} is zero.
+In this case, methods 0, 1, and 2 in {\tt Common->method[...]} are reset
+to user-provided, AMD, and METIS, respectively.
+The ordering with the smallest {\tt nnz(L)} is kept.
+
+If {\tt Common->default\_nesdis} is true (nonzero), then CHOLMOD's
+nested dissection (NESDIS) is used for the default strategy described
+above, in place of METIS.
+
+Other ordering options can be requested.  These include:
+\begin{enumerate}
+\item	natural:    A is not permuted to reduce fill-in.
+\item	user-provided:	    a permutation can be provided to {\tt cholmod\_analyze\_p}.
+\item	AMD:	    approximate minimum degree (AMD for the symmetric case, COLAMD for the {\tt A*A'} case).
+\item	METIS:	    nested dissection with {\tt METIS\_NodeND}
+\item	{\tt NESDIS}:	    CHOLMOD's nested dissection using
+    {\tt METIS\_NodeComputeSeparator},
+    followed by a constrained minimum degree
+    (CAMD or CSYMAMD for the symmetric case, CCOLAMD for the {\tt A*A'} case).
+    This is typically slower than METIS, but typically provides better orderings.
+\end{enumerate}
+
+Multiple ordering options can be tried (up to 9 of them), and the best one
+is selected (the one that gives the smallest number of nonzeros in the
+simplicial factor L).  If one method fails, {\tt cholmod\_analyze} keeps going, and
+picks the best among the methods that succeeded.  This routine fails (and
+returns {\tt NULL}) if either the initial memory allocation fails, all ordering methods
+fail, or the supernodal analysis (if requested) fails.  Change {\tt Common->nmethods} to the
+number of methods you wish to try.  By default, the 9 methods available are:
+
+\begin{enumerate}
+\item user-provided permutation (only for {\tt cholmod\_analyze\_p}).
+\item AMD with default parameters.
+\item METIS with default parameters.
+\item {\tt NESDIS} with default parameters: stopping the partitioning when
+	    the graph is of size {\tt nd\_small} = 200 or less, remove nodes with
+	    more than {\tt max (16, prune\_dense * sqrt (n))} nodes where
+	    {\tt prune\_dense} = 10, and follow partitioning with
+	    constrained minimum degree ordering
+	    (CAMD for the symmetric case,
+	    CCOLAMD for the unsymmetric case).
+\item natural ordering (with weighted postorder).
+\item NESDIS, {\tt nd\_small} = 20000, {\tt prune\_dense} = 10.
+\item NESDIS, {\tt nd\_small} =     4, {\tt prune\_dense} = 10,
+    no constrained minimum degree.
+\item NESDIS, {\tt nd\_small} =   200, {\tt prune\_dense} = 0.
+\item COLAMD for {\tt A*A'} or AMD for {\tt A}
+\end{enumerate}
+
+You can modify these 9 methods and the number of methods tried by changing
+parameters in the {\tt Common} argument.  If you know the best ordering for your
+matrix, set {\tt Common->nmethods} to 1 and set {\tt Common->method[0].ordering} to the
+requested ordering method.  Parameters for each method can also be modified
+(refer to the description of {\tt cholmod\_common} for details).
+
+Note that it is possible for METIS to terminate your program if it runs out
+of memory.  This is not the case for any CHOLMOD or minimum degree ordering
+routine (AMD, COLAMD, CAMD, CCOLAMD, or CSYMAMD).
+Since {\tt NESDIS} relies on METIS, it too can terminate your program.
+
+The selected ordering is followed by a weighted postorder of the elimination
+tree by default (see {\tt cholmod\_postorder} for details),
+unless {\tt Common->postorder} is set to {\tt FALSE}.
+The postorder does not change the number of nonzeros in $\m{L}$ or
+the floating-point operation count.  It does improve performance,
+particularly for the supernodal factorization.
+If you truly want the natural ordering with no postordering,
+you must set {\tt Common->postorder} to {\tt FALSE}.
+
+The factor {\tt L} is returned as simplicial symbolic if
+{\tt Common->supernodal} is {\tt CHOLMOD\_SIMPLICIAL} (zero) or as supernodal symbolic if
+{\tt Common->supernodal} is {\tt CHOLMOD\_SUPERNODAL} (two).  If \newline
+{\tt Common->supernodal} is {\tt CHOLMOD\_AUTO} (one),
+then {\tt L} is simplicial if the flop count per nonzero in {\tt L} is less than
+{\tt Common->supernodal\_switch} (default: 40), and
+supernodal otherwise.  In both cases, {\tt L->xtype} is {\tt CHOLMOD\_PATTERN}.
+A subsequent call to {\tt cholmod\_factorize} will perform a
+simplicial or supernodal factorization, depending on the type of {\tt L}.
+
+For the simplicial case, {\tt L} contains the fill-reducing permutation ({\tt L->Perm})
+and the counts of nonzeros in each column of {\tt L} ({\tt L->ColCount}).  For the
+supernodal case, {\tt L} also contains the nonzero pattern of each supernode.
+
+If a simplicial factorization is selected, it will be $\m{LDL}\tr$ by default, since
+this is the kind required by the {\tt Modify} Module.  CHOLMOD does not include a
+supernodal $\m{LDL}\tr$ factorization, so if a supernodal factorization is selected,
+it will be in the form $\m{LL}\tr$.  The $\m{LDL}\tr$ method can be used to
+factorize positive definite matrices and indefinite matrices whose leading minors
+are well-conditioned (2-by-2 pivoting is not supported).  The $\m{LL}\tr$ method
+is restricted to positive definite matrices.  To factorize a large indefinite matrix,
+set {\tt Common->supernodal} to {\tt CHOLMOD\_SIMPLICIAL}, and the simplicial 
+$\m{LDL}\tr$ method will always be used.  This will be significantly slower than
+a supernodal $\m{LL}\tr$ factorization, however.
+
+Refer to {\tt cholmod\_transpose\_unsym} for a description of {\tt f}.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_factorize}: numeric factorization}
+%---------------------------------------
+
+\input{_factorize.tex}
+Computes the numerical factorization of a symmetric matrix.  The % primary
+inputs to this routine are a sparse matrix {\tt A} and the symbolic factor {\tt L} from
+{\tt cholmod\_analyze} or a prior numerical factor {\tt L}.  If {\tt A} is symmetric, this
+routine factorizes {\tt A(p,p)}. %+beta*I (beta can be zero),
+where p is the fill-reducing permutation ({\tt L->Perm}).  If {\tt A} is unsymmetric,
+% either
+{\tt A(p,:)*A(p,:)'} % +beta*I  or A(p,f)*A(p,f)'+beta*I
+is factorized.  %  The set f and
+The nonzero pattern of the matrix {\tt A} must be the same as the matrix passed to
+{\tt cholmod\_analyze} for the supernodal case.  For the simplicial case, it can
+be different, but it should be the same for best performance. %  beta is real.
+
+A simplicial factorization or supernodal factorization is chosen, based on
+the type of the factor {\tt L}.  If {\tt L->is\_super} is {\tt TRUE}, a supernodal $\m{LL}\tr$
+factorization is computed.  Otherwise, a simplicial numeric factorization
+is computed, either $\m{LL}\tr$ or $\m{LDL}\tr$, depending on {\tt Common->final\_ll}
+(the default for the simplicial case is to compute an $\m{LDL}\tr$ factorization).
+
+Once the factorization is complete, it can be left as is or optionally
+converted into any simplicial numeric type, depending on the
+{\tt Common->final\_*} parameters.  If converted from a supernodal to simplicial
+type, and {\tt Common->final\_resymbol} is {\tt TRUE}, then numerically
+zero entries in {\tt L} due to relaxed supernodal amalgamation are removed from
+the simplicial factor (they are always left in the supernodal form of {\tt L}).
+Entries that are numerically zero but present in the simplicial symbolic
+pattern of {\tt L} are left in place (the graph of {\tt L} remains chordal).
+This is required for the update/downdate/rowadd/rowdel routines to work
+properly.
+
+If the matrix is not positive definite the routine returns {\tt TRUE}, but
+{\tt Common->status} is set to {\tt CHOLMOD\_NOT\_POSDEF} and {\tt L->minor} is set to the
+column at which the failure occurred.  Columns {\tt L->minor} to {\tt L->n-1}
+are set to zero.
+
+Supports any xtype (pattern, real, complex, or zomplex), except that the
+input matrix {\tt A} cannot be pattern-only.  If {\tt L} is simplicial, its numeric
+xtype matches {\tt A} on output.  If {\tt L} is supernodal, its xtype is real if {\tt A} is
+real, or complex if {\tt A} is complex or zomplex.  CHOLMOD does not provide
+a supernodal zomplex factor, since it is incompatible with how complex numbers are
+stored in LAPACK and the BLAS.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_analyze\_p}: symbolic factorization, given permutation}
+%---------------------------------------
+
+\input{_analyze_p.tex}
+Identical to {\tt cholmod\_analyze}, except that a user-provided
+permutation {\tt p} can be provided, and the set {\tt f} for the unsymmetric case
+can be provided.  The matrices {\tt A(:,f)*A(:,f)'} or {\tt A(p,f)*A(p,f)'}
+can be analyzed in the the unsymmetric case.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_factorize\_p}: numeric factorization, given permutation}
+%---------------------------------------
+
+\input{_factorize_p.tex}
+Identical to {\tt cholmod\_factorize}, but with additional options.
+The set {\tt f} can be provided for the unsymmetric case;
+{\tt A(p,f)*A(p,f)'} is factorized.  The term {\tt beta*I} can be added to
+the matrix before it is factorized, where {\tt beta} is real.
+Only the real part, {\tt beta[0]}, is used.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_solve}: solve a linear system}
+%---------------------------------------
+
+\input{_solve.tex}
+Returns a solution {\tt X} that solves one of the following systems:
+
+\begin{tabular}{ll|ll}
+	\hline
+	system			    & {\tt sys} parameter & system		    & {\tt sys} parameter \\
+	$\m{Ax}=\m{b}$		    & 0: {\tt CHOLMOD\_A}	&			    &			\\
+	$\m{LDL}\tr\m{x}=\m{b}$	    & 1: {\tt CHOLMOD\_LDLt}	& $\m{L}\tr\m{x}=\m{b}$	    & 5: {\tt CHOLMOD\_Lt}	\\
+	$\m{LDx}=\m{b}$		    & 2: {\tt CHOLMOD\_LD}	& $\m{Dx}=\m{b}$	    & 6: {\tt CHOLMOD\_D}	\\
+	$\m{DL}\tr\m{x}=\m{b}$	    & 3: {\tt CHOLMOD\_DLt}	& $\m{x}=\m{Pb}$	    & 7: {\tt CHOLMOD\_P}	\\
+	$\m{Lx}=\m{b}$		    & 4: {\tt CHOLMOD\_L}	& $\m{x}=\m{P}\tr\m{b}$	    & 8: {\tt CHOLMOD\_Pt}	\\
+	\hline
+\end{tabular}
+
+The factorization can be simplicial $\m{LDL}\tr$, simplicial $\m{LL}\tr$, or supernodal $\m{LL}\tr$.
+For an $\m{LL}\tr$ factorization, $\m{D}$ is the identity matrix.  Thus {\tt CHOLMOD\_LD} and
+{\tt CHOLMOD\_L} solve the same system if an $\m{LL}\tr$ factorization was performed,
+for example.
+This is one of the few routines in CHOLMOD for which the xtype of the input
+arguments need not match.
+If both {\tt L} and {\tt B} are real, then {\tt X} is returned real.  If either is complex
+or zomplex, {\tt X} is returned as either complex or zomplex, depending on the
+{\tt Common->prefer\_zomplex} parameter (default is complex).
+
+This routine does not check to see if the diagonal of $\m{L}$ or $\m{D}$ is zero,
+because sometimes a partial solve can be done with an indefinite or singular
+matrix.  If you wish to check in your own code, test {\tt L->minor}.  If
+{\tt L->minor == L->n}, then the matrix has no zero diagonal entries.
+If {\tt k = L->minor < L->n}, then {\tt L(k,k)} is zero for an $\m{LL}\tr$ factorization, or
+{\tt D(k,k)} is zero for an $\m{LDL}\tr$ factorization.
+
+Iterative refinement is not performed, but this can be easily done with
+the {\tt MatrixOps} Module.  See {\tt Demo/cholmod\_demo.c} for an example.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_spsolve}: solve a linear system}
+%---------------------------------------
+
+\input{_spsolve.tex}
+Identical to {\tt cholmod\_spsolve}, except that {\tt B} and {\tt X} are sparse.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_etree}: find elimination tree}
+%---------------------------------------
+
+\input{_etree.tex}
+Computes the elimination tree of {\tt A} or {\tt A'*A}.
+In the symmetric case, the upper triangular part of {\tt A} is used.  Entries not
+in this part of the matrix are ignored.  Computing the etree of a symmetric
+matrix from just its lower triangular entries is not supported.
+In the unsymmetric case, all of {\tt A} is used, and the etree of {\tt A'*A} is computed.
+Refer to \cite{Liu90a} for a discussion of the elimination tree
+and its use in sparse Cholesky factorization.
+% J. Liu, "The role of elimination trees in sparse factorization", SIAM J.
+% Matrix Analysis \& Applic., vol 11, 1990, pp. 134-172.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_rowcolcounts}: nonzeros counts of a factor}
+%---------------------------------------
+
+\input{_rowcolcounts.tex}
+Compute the row and column counts of the Cholesky factor {\tt L} of the matrix
+{\tt A} or {\tt A*A'}.  The etree and its postordering must already be computed (see
+{\tt cholmod\_etree} and {\tt cholmod\_postorder}) and given as inputs to this routine.
+For the symmetric case ($\m{LL}\tr=\m{A}$), {\tt A} must be stored in
+symmetric/lower form ({\tt A->stype = -1}).
+In the unsymmetric case, {\tt A*A'} or {\tt A(:,f)*A(:,f)'} can be analyzed.
+The fundamental floating-point operation count is returned in {\tt Common->fl}
+(this excludes extra flops due to relaxed supernodal amalgamation).
+Refer to {\tt cholmod\_transpose\_unsym} for a description of {\tt f}.
+The algorithm is described in \cite{GilbertLiNgPeyton01,GilbertNgPeyton94}.
+
+% J. Gilbert, E. Ng, B. Peyton, "An efficient algorithm to compute row and
+% column counts for sparse Cholesky factorization", SIAM J. Matrix Analysis \&
+% Applic., vol 15, 1994, pp. 1075-1091.
+% 
+% J. Gilbert, X. Li, E. Ng, B. Peyton, "Computing row and column counts for
+% sparse QR and LU factorization", BIT, vol 41, 2001, pp. 693-710.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_analyze\_ordering}: analyze a permutation}
+%---------------------------------------
+
+\input{_analyze_ordering.tex}
+Given a matrix {\tt A} and its fill-reducing permutation, compute the elimination
+tree, its (non-weighted) postordering, and the number of nonzeros in each
+column of {\tt L}.  Also computes the flop count, the total nonzeros in {\tt L}, and
+the nonzeros in {\tt tril(A)} ({\tt Common->fl}, {\tt Common->lnz}, and {\tt Common->anz}).
+In the unsymmetric case, {\tt A(p,f)*A(p,f)'} is analyzed, and {\tt Common->anz}
+is the number of nonzero entries in the lower triangular part of the product,
+not in {\tt A} itself.
+
+Refer to {\tt cholmod\_transpose\_unsym} for a description of {\tt f}.
+
+The column counts of {\tt L}, flop count, and other statistics from
+{\tt cholmod\_rowcolcounts} are not computed if {\tt ColCount} is {\tt NULL}.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_amd}: interface to AMD}
+%---------------------------------------
+
+\input{_amd.tex}
+CHOLMOD interface to the AMD ordering package.  Orders {\tt A} if the matrix is
+symmetric.  On output, {\tt Perm [k] = i} if row/column {\tt i} of {\tt A} is the {\tt k}th
+row/column of {\tt P*A*P'}.  This corresponds to {\tt A(p,p)} in MATLAB notation.
+If A is unsymmetric, {\tt cholmod\_amd} orders {\tt A*A'} or {\tt A(:,f)*A(:,f)'}.
+On output, {\tt Perm [k] = i} if
+row/column {\tt i} of {\tt A*A'} is the {\tt k}th row/column of {\tt P*A*A'*P'}.
+This corresponds to {\tt A(p,:)*A(p,:)'} in MATLAB notation.
+If {\tt f} is present, {\tt A(p,f)*A(p,f)'} is the permuted matrix.
+Refer to {\tt cholmod\_transpose\_unsym} for a description of {\tt f}.
+
+Computes the flop count for a subsequent $\m{LL}\tr$ factorization, the number
+of nonzeros in {\tt L}, and the number of nonzeros in the matrix ordered
+({\tt A}, {\tt A*A'} or {\tt A(:,f)*A(:,f)'}).
+These statistics are returned in
+{\tt Common->fl}, {\tt Common->lnz}, and {\tt Common->anz}, respectively.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_colamd}: interface to COLAMD}
+%---------------------------------------
+
+\input{_colamd.tex}
+CHOLMOD interface to the COLAMD ordering package.
+Finds a permutation {\tt p} such that the Cholesky factorization of {\tt P*A*A'*P'} is
+sparser than {\tt A*A'}, using COLAMD.  If the {\tt postorder} input parameter is {\tt TRUE},
+the column elimination tree is found and postordered, and the COLAMD ordering is then
+combined with its postordering (COLAMD itself does not perform this postordering).
+{\tt A} must be unsymmetric ({\tt A->stype = 0}).
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_rowfac}: row-oriented Cholesky factorization}
+%---------------------------------------
+
+\input{_rowfac.tex}
+Full or incremental numerical $\m{LDL}\tr$ or $\m{LL}\tr$ factorization (simplicial, not
+supernodal).  {\tt cholmod\_factorize} is the ``easy'' wrapper for this code, but it
+does not provide access to incremental factorization.
+The algorithm is the row-oriented, up-looking method described in \cite{Davis05}.
+See also \cite{Liu86c}.  No 2-by-2 pivoting (or any other pivoting) is performed.
+
+{\tt cholmod\_rowfac} computes the full or incremental $\m{LDL}\tr$ or $\m{LL}\tr$ factorization of
+{\tt A+beta*I} (where {\tt A} is symmetric) or {\tt A*F+beta*I}
+(where {\tt A} and {\tt F} are unsymmetric
+and only the upper triangular part of {\tt A*F+beta*I} is used).  It computes
+{\tt L} (and {\tt D}, for $\m{LDL}\tr$) one row at a time.
+The input scalar {\tt beta} is real; only the real part ({\tt beta[0]}) is used.
+
+{\tt L} can be a simplicial symbolic or numeric ({\tt L->is\_super} must be {\tt FALSE}).
+A symbolic factor is converted immediately into a numeric factor containing
+the identity matrix.
+
+For a full factorization, use {\tt kstart = 0} and {\tt kend = nrow}.  The existing nonzero
+entries (numerical values in {\tt L->x} and {\tt L->z} for the zomplex case, and indices
+in {\tt L->i}) are overwritten.
+
+To compute an incremental factorization, select {\tt kstart} and {\tt kend} as the range
+of rows of {\tt L} you wish to compute.    Rows {\tt kstart} to {\tt kend-1} of {\tt L}
+will be computed.  A correct factorization will be computed
+only if all descendants of all nodes {\tt kstart} to {\tt kend-1} in the elimination tree have
+been factorized by a prior call to this routine, and if rows {\tt kstart} to {\tt kend-1}
+have not been factorized.  This condition is {\bf not} checked on input.
+
+In the symmetric case, {\tt A} must be stored in upper form ({\tt A->stype} is greater than zero).
+The matrix {\tt F} is not accessed and may be {\tt NULL}.  Only
+columns {\tt kstart} to {\tt kend-1} of {\tt A} are accessed.
+
+In the unsymmetric case,
+	the typical case is {\tt F=A'}.  Alternatively, if {\tt F=A(:,f)'}, then this
+	routine factorizes the matrix {\tt S = beta*I + A(:,f)*A(:,f)'}.
+	The product {\tt A*F} is assumed to be symmetric;
+	only the upper triangular part of {\tt A*F} is used.
+	{\tt F} must be of size {\tt A->ncol} by {\tt A->nrow}.
+
+% J. Liu, "A compact row storage scheme for Cholesky factors", ACM Trans.
+% Math. Software, vol 12, 1986, pp. 127-148.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_rowfac\_mask}: row-oriented Cholesky factorization}
+%---------------------------------------
+
+\input{_rowfac_mask.tex}
+For use in LPDASA only.
+
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_row\_subtree}: pattern of row of a factor}
+%---------------------------------------
+
+\input{_row_subtree.tex}
+Compute the nonzero pattern of the solution to the lower triangular system
+\begin{verbatim}
+    L(0:k-1,0:k-1) * x = A (0:k-1,k)
+\end{verbatim}
+if {\tt A} is symmetric, or
+\begin{verbatim}
+    L(0:k-1,0:k-1) * x = A (0:k-1,:) * A (:,k)'
+\end{verbatim}
+if {\tt A} is unsymmetric.
+This gives the nonzero pattern of row {\tt k} of {\tt L} (excluding the diagonal).
+The pattern is returned postordered, according to the subtree of the elimination
+tree rooted at node {\tt k}.
+
+The symmetric case requires {\tt A} to be in symmetric-upper form.
+
+The result is returned in {\tt R}, a pre-allocated sparse matrix of size {\tt nrow}-by-1,
+with {\tt R->nzmax >= nrow}.  {\tt R} is assumed to be packed ({\tt Rnz [0]} is not updated);
+the number of entries in {\tt R} is given by {\tt Rp [0]}.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_row\_lsubtree}: pattern of row of a factor}
+%---------------------------------------
+
+\input{_row_lsubtree.tex}
+Identical to {\tt cholmod\_row\_subtree}, except the elimination tree is
+found from {\tt L} itself, not {\tt Parent}.  Also, {\tt F=A'} is not provided;
+the nonzero pattern of the {\tt k}th column of {\tt F} is given by 
+{\tt Fi} and {\tt fnz} instead.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_resymbol}: re-do symbolic factorization}
+%---------------------------------------
+
+\input{_resymbol.tex}
+Recompute the symbolic pattern of {\tt L}.  Entries not in the symbolic pattern
+of the factorization of {\tt A(p,p)} or {\tt F*F'}, where
+{\tt F=A(p,f)} or {\tt F=A(:,f)}, are dropped, where
+{\tt p = L->Perm} is used to permute the input matrix {\tt A}.
+
+Refer to {\tt cholmod\_transpose\_unsym} for a description of {\tt f}.
+
+If an entry in {\tt L} is kept, its numerical value does not change.
+
+This routine is used after a supernodal factorization is converted into
+a simplicial one, to remove zero entries that were added due to relaxed
+supernode amalgamation.  It can also be used after a series of downdates
+to remove entries that would no longer be present if the matrix were
+factorized from scratch.  A downdate ({\tt cholmod\_updown}) does not remove any
+entries from {\tt L}.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_resymbol\_noperm}: re-do symbolic factorization}
+%---------------------------------------
+
+\input{_resymbol_noperm.tex}
+Identical to {\tt cholmod\_resymbol}, except that the fill-reducing
+ordering {\tt L->Perm} is not used.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_postorder}: tree postorder}
+%---------------------------------------
+
+\input{_postorder.tex}
+Postorder a tree.  The tree is either an elimination tree (the output from
+{\tt cholmod\_etree}) or a component tree (from {\tt cholmod\_nested\_dissection}).
+
+An elimination tree is a complete tree of {\tt n} nodes with {\tt Parent [j] > j} or
+{\tt Parent [j] = -1} if j is a root.  On output {\tt Post [0..n-1]} is a complete
+permutation vector;
+{\tt Post [k] = j} if node {\tt j} is the {\tt k}th node in the
+postordered elimination tree, where {\tt k} is in the range 0 to {\tt n-1}.
+
+A component tree is a subset of {\tt 0:n-1}.  {\tt Parent [j] = -2} if node {\tt j} is not
+in the component tree.  {\tt Parent [j] = -1} if {\tt j} is a root of the component
+tree, and {\tt Parent [j]} is in the range 0 to {\tt n-1} if {\tt j} is in the component
+tree but not a root.  On output, {\tt Post [k]} is defined only for nodes in
+the component tree.  {\tt Post [k] = j} if node {\tt j} is the {\tt k}th node in the
+postordered component tree, where {\tt k} is in the range 0 to the number of
+components minus 1.
+Node {\tt j} is ignored and not included in the postorder if {\tt Parent [j] < -1}.
+As a result, {\tt cholmod\_check\_parent (Parent, ...)} and {\tt cholmod\_check\_perm (Post, ...)}
+fail if used for a component tree and its postordering.
+
+An optional node weight can be given.  When starting a postorder at node {\tt j},
+the children of {\tt j} are ordered in decreasing order of their weight.
+If no weights are given ({\tt Weight} is {\tt NULL}) then children are ordered in
+decreasing order of their node number.  The weight of a node must be in the
+range 0 to {\tt n-1}.  Weights outside that range are silently converted to that
+range (weights $<$ 0 are treated as zero, and weights $\ge$ {\tt n} are treated as {\tt n-1}).
+
+%---------------------------------------
+\subsection{{\tt cholmod\_rcond}: reciprocal condition number}
+%---------------------------------------
+
+\input{_rcond.tex}
+Returns a rough estimate of the reciprocal of the condition number:
+the minimum entry on the diagonal of {\tt L} (or absolute entry of {\tt D} for an $\m{LDL}\tr$
+factorization) divided by the maximum entry.  {\tt L} can be real, complex, or
+zomplex.  Returns -1 on error, 0 if the matrix is singular or has a zero or NaN
+entry on the diagonal of {\tt L}, 1 if the matrix is 0-by-0, or
+{\tt min(diag(L))/max(diag(L))} otherwise.  Never returns NaN; if {\tt L} has a NaN on
+the diagonal it returns zero instead.
+
+%-------------------------------------------------------------------------------
+\newpage \section{{\tt Modify} Module routines}
+%-------------------------------------------------------------------------------
+
+%---------------------------------------
+\subsection{{\tt cholmod\_updown}: update/downdate}
+%---------------------------------------
+
+\input{_updown.tex}
+Updates/downdates the $\m{LDL}\tr$ factorization (symbolic, then numeric), by
+computing a new factorization of
+\[
+\new{\m{L}}\new{\m{D}}\new{\m{L}}\tr = \m{LDL}\tr \pm \m{CC}\tr
+\]
+where $\new{\m{L}}$ denotes the new factor.
+{\tt C} must be sorted.  It can be either packed or unpacked.  As in all CHOLMOD
+routines, the columns of {\tt L} are sorted on input, and also on output.
+If {\tt L} does not contain a simplicial numeric $\m{LDL}\tr$ factorization, it
+is converted into one.  Thus, a supernodal $\m{LL}\tr$ factorization
+can be passed to {\tt cholmod\_updown}.
+A symbolic {\tt L} is converted into a numeric identity matrix.
+If the initial conversion fails, the factor is returned unchanged.
+
+If memory runs out during the update, the factor is returned as a simplicial
+symbolic factor.  That is, everything is freed except for the fill-reducing
+ordering and its corresponding column counts (typically computed by
+{\tt cholmod\_analyze}).
+
+Note that the fill-reducing permutation {\tt L->Perm} is not used.  The row
+indices of {\tt C} refer to the rows of {\tt L}, not {\tt A}.  If your original system is
+$\m{LDL}\tr = \m{PAP}\tr$ (where $\m{P} =$ {\tt L->Perm}), and you want to compute the $\m{LDL}\tr$
+factorization of $\m{A}+\m{CC}\tr$, then you must permute $\m{C}$ first.  That is,
+if
+\[
+    \m{PAP}\tr = \m{LDL}\tr
+\]
+is the initial factorization, then
+\[
+\m{P}(\m{A}+\m{CC}\tr)\m{P}\tr
+    = \m{PAP}\tr+\m{PCC}\tr\m{P}\tr
+    = \m{LDL}\tr + (\m{PC})(\m{PC})\tr
+    = \m{LDL}\tr + \new{\m{C}}\new{\m{C}}\tr
+\]
+where $\new{\m{C}} = \m{PC}$.
+
+You can use the {\tt cholmod\_submatrix} routine in the {\tt MatrixOps} Module
+to permute {\tt C}, with:
+\begin{verbatim}
+    Cnew = cholmod_submatrix (C, L->Perm, L->n, NULL, -1, TRUE, TRUE, Common) ;
+\end{verbatim}
+
+Note that the {\tt sorted} input parameter to {\tt cholmod\_submatrix} must be {\tt TRUE},
+because {\tt cholmod\_updown} requires {\tt C} with sorted columns.
+Only real matrices are supported.
+The algorithms are described in \cite{DavisHager99,DavisHager01}.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_updown\_solve}: update/downdate}
+%---------------------------------------
+
+\input{_updown_solve.tex}
+Identical to {\tt cholmod\_updown}, except
+the system $\m{Lx}=\m{b}$ is also updated/downdated.
+The new system is $\new{\m{L}}\new{\m{x}}=\m{b} + \Delta \m{b}$.  The old solution $\m{x}$ is overwritten
+with $\new{\m{x}}$.  Note that as in the update/downdate of $\m{L}$ itself, the fill-
+reducing permutation {\tt L->Perm} is not used.  The vectors $\m{x}$ and $\m{b}$ are in the permuted
+ordering, not your original ordering.  This routine does not handle multiple right-hand-sides.
+
+%---------------------------------------
+\newpage
+\subsection{{\tt cholmod\_updown\_mark}: update/downdate}
+%---------------------------------------
+
+\input{_updown_mark.tex}
+Identical to {\tt cholmod\_updown\_solve}, except that only part of $\m{L}$
+is used in the update of the solution to $\m{Lx}=\m{b}$.  For more details,
+see the source code file {\tt CHOLMOD/Modify/cholmod\_updown.c}.
+This routine is meant for use in the {\tt LPDASA} linear program solver only,
+by Hager and Davis.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_updown\_mask}: update/downdate}
+%---------------------------------------
+
+\input{_updown_mask.tex}
+For use in LPDASA only.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_rowadd}: add row to factor}
+%---------------------------------------
+
+\input{_rowadd.tex}
+Adds a row and column to an $\m{LDL}\tr$ factorization.  The {\tt k}th
+row and column of {\tt L} must be equal to the {\tt k}th row and
+column of the identity matrix on input.
+Only real matrices are supported.
+The algorithm is described in \cite{DavisHager05}.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_rowadd\_solve}: add row to factor}
+%---------------------------------------
+
+\input{_rowadd_solve.tex}
+Identical to {\tt cholmod\_rowadd}, except the system $\m{Lx}=\m{b}$ is also updated/downdated, just like {\tt cholmod\_updown\_solve}.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_rowdel}: delete row from factor}
+%---------------------------------------
+
+\input{_rowdel.tex}
+Deletes a row and column from an $\m{LDL}\tr$ factorization.  The {\tt k}th
+row and column of {\tt L} is equal to the {\tt k}th row and
+column of the identity matrix on output.
+Only real matrices are supported.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_rowdel\_solve}: delete row from factor}
+%---------------------------------------
+
+\input{_rowdel_solve.tex}
+Identical to {\tt cholmod\_rowdel}, except the system $\m{Lx}=\m{b}$ is also updated/downdated, just like {\tt cholmod\_updown\_solve}.
+When row/column $k$ of $\m{A}$ is deleted from the system $\m{Ay}=\m{b}$, this can induce
+a change to $\m{x}$, in addition to changes arising when $\m{L}$ and $\m{b}$ are modified.
+If this is the case, the kth entry of $\m{y}$ is required as input ({\tt yk}).
+The algorithm is described in \cite{DavisHager05}.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_rowadd\_mark}: add row to factor}
+%---------------------------------------
+
+\input{_rowadd_mark.tex}
+Identical to {\tt cholmod\_rowadd\_solve}, except that only part of $\m{L}$
+is used in the update of the solution to $\m{Lx}=\m{b}$.  For more details,
+see the source code file {\tt CHOLMOD/Modify/cholmod\_rowadd.c}.
+This routine is meant for use in the {\tt LPDASA} linear program solver only.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_rowdel\_mark}: delete row from factor}
+%---------------------------------------
+
+\input{_rowdel_mark.tex}
+Identical to {\tt cholmod\_rowadd\_solve}, except that only part of $\m{L}$
+is used in the update of the solution to $\m{Lx}=\m{b}$.  For more details,
+see the source code file {\tt CHOLMOD/Modify/cholmod\_rowdel.c}.
+This routine is meant for use in the {\tt LPDASA} linear program solver only.
+
+%-------------------------------------------------------------------------------
+\newpage \section{{\tt MatrixOps} Module routines}
+%-------------------------------------------------------------------------------
+
+%---------------------------------------
+\subsection{{\tt cholmod\_drop}: drop small entries}
+%---------------------------------------
+
+\input{_drop.tex}
+Drop small entries from {\tt A}, and entries in the ignored part of {\tt A} if {\tt A}
+is symmetric.  No CHOLMOD routine drops small numerical entries
+from a matrix, except for this one.  NaN's and Inf's are kept.
+
+Supports pattern and real matrices; complex and zomplex matrices are not supported.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_norm\_dense}: dense matrix norm}
+%---------------------------------------
+
+\input{_norm_dense.tex}
+Returns the infinity-norm, 1-norm, or 2-norm of a dense matrix.
+Can compute the 2-norm only for a dense column vector.
+All xtypes are supported.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_norm\_sparse}: sparse matrix norm}
+%---------------------------------------
+
+\input{_norm_sparse.tex}
+Returns the infinity-norm or 1-norm of a sparse matrix.
+All xtypes are supported.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_scale}: scale sparse matrix}
+%---------------------------------------
+
+\input{_scale.tex}
+Scales a matrix:  {\tt A = diag(s)*A}, {\tt A*diag(s)}, {\tt s*A}, or {\tt diag(s)*A*diag(s)}.
+
+{\tt A} can be of any type (packed/unpacked, upper/lower/unsymmetric).
+The symmetry of {\tt A} is ignored; all entries in the matrix are modified.
+
+If {\tt A} is {\tt m}-by-{\tt n} unsymmetric but scaled symmetrically, the result is
+\begin{verbatim}
+    A = diag (s (1:m)) * A * diag (s (1:n))
+\end{verbatim}
+
+Row or column scaling of a symmetric matrix still results in a symmetric
+matrix, since entries are still ignored by other routines.
+For example, when row-scaling a symmetric matrix where just the upper
+triangular part is stored (and lower triangular entries ignored)
+{\tt A = diag(s)*triu(A)} is performed, where the result {\tt A} is also
+symmetric-upper.  This has the effect of modifying the implicit lower
+triangular part.  In MATLAB notation:
+\begin{verbatim}
+    U = diag(s)*triu(A) ;
+    L = tril (U',-1)
+    A = L + U ;
+\end{verbatim}
+
+The scale parameter determines the kind of scaling to perform and the size of {\tt S}:
+
+\begin{tabular}{lll}
+\hline
+{\tt scale} & operation & size of {\tt S} \\
+\hline
+{\tt CHOLMOD\_SCALAR} & {\tt s[0]*A}		& 1 \\
+{\tt CHOLMOD\_ROW}    & {\tt diag(s)*A}		& {\tt nrow}-by-1 or 1-by-{\tt nrow} \\
+{\tt CHOLMOD\_COL}    & {\tt A*diag(s)}		& {\tt ncol}-by-1 or 1-by-{\tt ncol} \\
+{\tt CHOLMOD\_SYM}    & {\tt diag(s)*A*diag(s)}	& {\tt max(nrow,ncol)}-by-1, or 1-by-{\tt max(nrow,ncol)} \\
+\hline
+\end{tabular}
+
+Only real matrices are supported.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_sdmult}: sparse-times-dense matrix}
+%---------------------------------------
+
+\input{_sdmult.tex}
+Sparse matrix times dense matrix:
+{\tt Y = alpha*(A*X) + beta*Y} or {\tt Y = alpha*(A'*X) + beta*Y},
+where {\tt A} is sparse and {\tt X} and {\tt Y} are dense.
+When using {\tt A},  {\tt X} has {\tt A->ncol} columns and {\tt Y} has {\tt A->nrow} rows.
+When using {\tt A'}, {\tt X} has {\tt A->nrow} columns and {\tt Y} has {\tt A->ncol} rows.
+If {\tt transpose = 0}, then {\tt A} is used;
+otherwise, {\tt A'} is used (the complex conjugate transpose).
+The {\tt transpose} parameter is ignored if the matrix is symmetric or Hermitian.
+(the array transpose {\tt A.'} is not supported).
+Supports real, complex, and zomplex matrices, but the xtypes of {\tt A}, {\tt X}, and {\tt Y} must all match.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_ssmult}: sparse-times-sparse matrix}
+%---------------------------------------
+
+\input{_ssmult.tex}
+Computes {\tt C = A*B}; multiplying two sparse matrices.
+{\tt C} is returned as packed, and either unsorted or sorted, depending on the
+{\tt sorted} input parameter.  If {\tt C} is returned sorted, then either {\tt C = (B'*A')'}
+or {\tt C = (A*B)''} is computed, depending on the number of nonzeros in {\tt A}, {\tt B}, and {\tt C}.
+The stype of {\tt C} is determined by the {\tt stype} parameter.
+Only pattern and real matrices are supported.  Complex and zomplex matrices
+are supported only when the numerical values are not computed ({\tt values}
+is {\tt FALSE}).
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_submatrix}: sparse submatrix}
+%---------------------------------------
+
+\input{_submatrix.tex}
+Returns {\tt C = A (rset,cset)}, where {\tt C} becomes {\tt length(rset)}-by-{\tt length(cset)} in dimension.
+{\tt rset} and {\tt cset} can have duplicate entries.  {\tt A} must be unsymmetric.  {\tt C} unsymmetric and
+is packed.  If {\tt sorted} is {\tt TRUE} on input, or {\tt rset} is sorted and {\tt A} is
+sorted, then {\tt C} is sorted; otherwise {\tt C} is unsorted.
+
+If {\tt rset} is {\tt NULL}, it means ``{\tt [ ]}'' in MATLAB notation, the empty set.
+The number of rows in the result {\tt C} will be zero if {\tt rset} is {\tt NULL}.
+Likewise if {\tt cset} means the empty set; the number of columns in the result {\tt C} will be zero if {\tt cset} is {\tt NULL}.
+If {\tt rsize} or {\tt csize} is negative, it denotes ``{\tt :}'' in MATLAB notation.
+Thus, if both {\tt rsize} and {\tt csize} are negative {\tt C = A(:,:) = A} is returned.
+
+For permuting a matrix, this routine is an alternative to {\tt cholmod\_ptranspose}
+(which permutes and transposes a matrix and can work on symmetric matrices).
+
+The time taken by this routine is O({\tt A->nrow}) if the {\tt Common} workspace needs
+to be initialized, plus O({\tt C->nrow + C->ncol + nnz (A (:,cset))}).  Thus, if {\tt C}
+is small and the workspace is not initialized, the time can be dominated by
+the call to {\tt cholmod\_allocate\_work}.  However, once the workspace is
+allocated, subsequent calls take less time.
+
+Only pattern and real matrices are supported.  Complex and zomplex matrices
+are supported only when {\tt values} is {\tt FALSE}.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_horzcat}: horizontal concatenation}
+%---------------------------------------
+
+\input{_horzcat.tex}
+Horizontal concatenation, returns {\tt C = [A,B]} in MATLAB notation.
+{\tt A} and {\tt B} can have any stype.  {\tt C} is returned unsymmetric and packed.
+{\tt A} and {\tt B} must have the same number of rows.
+{\tt C} is sorted if both {\tt A} and {\tt B} are sorted.
+{\tt A} and {\tt B} must have the same numeric xtype, unless {\tt values} is {\tt FALSE}.
+{\tt A} and {\tt B} cannot be complex or zomplex, unless {\tt values} is {\tt FALSE}.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_vertcat}: vertical concatenation}
+%---------------------------------------
+
+\input{_vertcat.tex}
+Vertical concatenation, returns {\tt C = [A;B]} in MATLAB notation.
+{\tt A} and {\tt B} can have any stype.  {\tt C} is returned unsymmetric and packed.
+{\tt A} and {\tt B} must have the same number of columns.
+{\tt C} is sorted if both {\tt A} and {\tt B} are sorted.
+{\tt A} and {\tt B} must have the same numeric xtype, unless {\tt values} is {\tt FALSE}.
+{\tt A} and {\tt B} cannot be complex or zomplex, unless {\tt values} is {\tt FALSE}.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_symmetry}: compute the symmetry of a matrix}
+%---------------------------------------
+
+\input{_symmetry.tex}
+
+Determines if a sparse matrix is rectangular, unsymmetric, symmetric,
+skew-symmetric, or Hermitian.  It does so by looking at its numerical values
+of both upper and lower triangular parts of a CHOLMOD "unsymmetric"
+matrix, where A->stype == 0.  The transpose of A is NOT constructed.
+
+If not unsymmetric, it also determines if the matrix has a diagonal whose
+entries are all real and positive (and thus a candidate for sparse Cholesky
+if A->stype is changed to a nonzero value).
+
+Note that a Matrix Market "general" matrix is either rectangular or
+unsymmetric.
+
+The row indices in the column of each matrix MUST be sorted for this function
+to work properly (A->sorted must be TRUE).  This routine returns EMPTY if
+A->stype is not zero, or if A->sorted is FALSE.  The exception to this rule
+is if A is rectangular.
+
+If option == 0, then this routine returns immediately when it finds a
+non-positive diagonal entry (or one with nonzero imaginary part).   If the
+matrix is not a candidate for sparse Cholesky, it returns the value
+{\tt CHOLMOD\_MM\_UNSYMMETRIC}, even if the matrix might in fact be symmetric or
+Hermitian.
+
+This routine is useful inside the MATLAB backslash, which must look at an
+arbitrary matrix (A->stype == 0) and determine if it is a candidate for
+sparse Cholesky.  In that case, option should be 0.
+
+This routine is also useful when writing a MATLAB matrix to a file in
+Rutherford/Boeing or Matrix Market format.  Those formats require a
+determination as to the symmetry of the matrix, and thus this routine should
+not return upon encountering the first non-positive diagonal.  In this case,
+option should be 1.
+
+If option is 2, this function can be used to compute the numerical and
+pattern symmetry, where 0 is a completely unsymmetric matrix, and 1 is a
+perfectly symmetric matrix.  This option is used when computing the following
+statistics for the matrices in the UF Sparse Matrix Collection.
+
+	numerical symmetry: number of matched offdiagonal nonzeros over
+	the total number of offdiagonal entries.  A real entry $a_{ij}$,  $i \ne j$,
+	is matched if $a_{ji} = a_{ij}$, but this is only counted if both
+	$a_{ji}$ and $a_{ij}$ are nonzero.  This does not depend on {\tt Z}.
+	(If A is complex, then the above test is modified; $a_{ij}$ is matched
+	if $\mbox{conj}(a_{ji}) = a_{ij}$.
+
+	Then numeric symmetry = xmatched / nzoffdiag, or 1 if nzoffdiag = 0.
+ 
+	pattern symmetry: number of matched offdiagonal entries over the
+	total number of offdiagonal entries.  An entry $a_{ij}$, $i \ne j$, is
+	matched if $a_{ji}$ is also an entry.
+
+	Then pattern symmetry = pmatched / nzoffdiag, or 1 if nzoffdiag = 0.
+ 
+The symmetry of a matrix with no offdiagonal entries is equal to 1.
+
+A workspace of size ncol integers is allocated; EMPTY is returned if this
+allocation fails.
+
+Summary of return values:
+
+\begin{tabular}{ll}
+{\tt EMPTY (-1)}		    & out of memory, stype not zero, A not sorted \\
+{\tt CHOLMOD\_MM\_RECTANGULAR 1}    & A is rectangular \\
+{\tt CHOLMOD\_MM\_UNSYMMETRIC 2}    & A is unsymmetric \\
+{\tt CHOLMOD\_MM\_SYMMETRIC 3}	    & A is symmetric, but with non-pos. diagonal \\
+{\tt CHOLMOD\_MM\_HERMITIAN 4}	    & A is Hermitian, but with non-pos. diagonal \\
+{\tt CHOLMOD\_MM\_SKEW\_SYMMETRIC 5}    & A is skew symmetric \\
+{\tt CHOLMOD\_MM\_SYMMETRIC\_POSDIAG 6} & A is symmetric with positive diagonal \\
+{\tt CHOLMOD\_MM\_HERMITIAN\_POSDIAG 7} & A is Hermitian with positive diagonal \\
+\end{tabular}
+
+See also the {\tt spsym} mexFunction, which is a MATLAB interface for this code.
+
+If the matrix is a candidate for sparse Cholesky, it will return a result
+\newline
+{\tt CHOLMOD\_MM\_SYMMETRIC\_POSDIAG} if real, or {\tt CHOLMOD\_MM\_HERMITIAN\_POSDIAG} if
+complex.  Otherwise, it will return a value less than this.  This is true
+regardless of the value of the option parameter.
+
+
+
+%-------------------------------------------------------------------------------
+\newpage \section{{\tt Supernodal} Module routines}
+%-------------------------------------------------------------------------------
+
+%---------------------------------------
+\subsection{{\tt cholmod\_super\_symbolic}: supernodal symbolic factorization}
+%---------------------------------------
+
+\input{_super_symbolic.tex}
+Supernodal symbolic analysis of the $\m{LL}\tr$ factorization of {\tt A}, {\tt A*A'}, or {\tt A(:,f)*A(:,f)'}.
+This routine must be preceded by a simplicial symbolic analysis
+({\tt cholmod\_rowcolcounts}).  See {\tt Cholesky/cholmod\_analyze.c} for an example of how to use
+this routine.
+The user need not call this directly; {\tt cholmod\_analyze} is a ``simple'' wrapper for this routine.
+{\tt A} can be symmetric (upper), or unsymmetric.  The symmetric/lower form is not supported.
+In the unsymmetric case {\tt F} is the normally transpose of {\tt A}.
+Alternatively, if {\tt F=A(:,f)'} then {\tt F*F'} is analyzed.
+Requires {\tt Parent} and {\tt L->ColCount} to be defined on input; these are the
+simplicial {\tt Parent} and {\tt ColCount} arrays as computed by {\tt cholmod\_rowcolcounts}.
+Does not use {\tt L->Perm}; the input matrices {\tt A} and {\tt F} must already be properly
+permuted.  Allocates and computes the supernodal pattern of {\tt L}
+({\tt L->super}, {\tt L->pi}, {\tt L->px}, and {\tt L->s}).
+Does not allocate the real part ({\tt L->x}).
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_super\_numeric}: supernodal numeric factorization}
+%---------------------------------------
+
+\input{_super_numeric.tex}
+Computes the numerical Cholesky factorization of {\tt A+beta*I} or {\tt A*F+beta*I}.  Only the
+lower triangular part of {\tt A+beta*I} or {\tt A*F+beta*I} is accessed.  The
+matrices {\tt A} and {\tt F} must already be permuted according to the fill-reduction
+permutation {\tt L->Perm}.  {\tt cholmod\_factorize} is an "easy" wrapper for this code
+which applies that permutation.
+The input scalar {\tt beta} is real; only the real part ({\tt beta[0]} is used.
+
+Symmetric case: {\tt A} is a symmetric (lower) matrix.  {\tt F} is not accessed and may be {\tt NULL}.
+With a fill-reducing permutation, {\tt A(p,p)} should be passed for {\tt A}, where is
+{\tt p} is {\tt L->Perm}.
+
+Unsymmetric case: {\tt A} is unsymmetric, and {\tt F} must be present.  Normally, {\tt F=A'}.
+With a fill-reducing permutation, {\tt A(p,f)} and {\tt A(p,f)'} should be passed as the
+parameters {\tt A} and {\tt F}, respectively, where {\tt f} is a list of the subset of the columns of {\tt A}.
+
+The input factorization {\tt L} must be supernodal ({\tt L->is\_super} is {\tt TRUE}).  It can
+either be symbolic or numeric.  In the first case, {\tt L} has been analyzed by
+{\tt cholmod\_analyze} or {\tt cholmod\_super\_symbolic}, but the matrix has not yet been
+numerically factorized.  The numerical values are allocated here and the
+factorization is computed.  In the second case, a prior matrix has been
+analyzed and numerically factorized, and a new matrix is being factorized.
+The numerical values of {\tt L} are replaced with the new numerical factorization.
+
+{\tt L->is\_ll} is ignored on input, and set to {\tt TRUE} on output.  This routine always computes an $\m{LL}\tr$
+factorization.  Supernodal $\m{LDL}\tr$ factorization is not supported.
+
+If the matrix is not positive definite the routine returns {\tt TRUE}, but sets
+{\tt Common->status} to {\tt CHOLMOD\_NOT\_POSDEF} and {\tt L->minor} is set to the column at
+which the failure occurred.  Columns {\tt L->minor} to {\tt L->n-1} are set to zero.
+
+If {\tt L} is supernodal symbolic on input, it is converted to a supernodal numeric
+factor on output, with an xtype of real if {\tt A} is real, or complex if {\tt A} is
+complex or zomplex.  If {\tt L} is supernodal numeric on input, its xtype must
+match {\tt A} (except that {\tt L} can be complex and {\tt A} zomplex).  The xtype of {\tt A} and {\tt F}
+must match.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_super\_lsolve}: supernodal forward solve}
+%---------------------------------------
+
+\input{_super_lsolve.tex}
+Solve $\m{Lx}=\m{b}$ for a supernodal factorization.  This routine does not
+apply the permutation {\tt L->Perm}.  See {\tt cholmod\_solve} for a more general
+interface that performs that operation.
+Only real and complex xtypes are supported.
+{\tt L}, {\tt X}, and {\tt E} must have the same xtype.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_super\_ltsolve}: supernodal backsolve}
+%---------------------------------------
+
+\input{_super_ltsolve.tex}
+Solve $\m{L}\tr\m{x}=\m{b}$ for a supernodal factorization.  This routine does not
+apply the permutation {\tt L->Perm}.  See {\tt cholmod\_solve} for a more general
+interface that performs that operation.
+Only real and complex xtypes are supported.
+{\tt L}, {\tt X}, and {\tt E} must have the same xtype.
+
+%-------------------------------------------------------------------------------
+\newpage \section{{\tt Partition} Module routines}
+%-------------------------------------------------------------------------------
+
+%---------------------------------------
+\subsection{{\tt cholmod\_nested\_dissection}: nested dissection ordering}
+%---------------------------------------
+
+\input{_nested_dissection.tex}
+CHOLMOD's nested dissection algorithm:
+	using its own compression and connected-components
+	algorithms, an external graph partitioner (METIS), and a constrained
+	minimum degree ordering algorithm (CAMD, CCOLAMD, or CSYMAMD).  Typically
+	gives better orderings than {\tt METIS\_NodeND} (about 5\% to 10\% fewer
+	nonzeros in {\tt L}).
+
+This method uses a node bisector, applied recursively (but using a
+non-recursive implementation).  Once the graph is partitioned, it calls a
+constrained minimum degree code (CAMD or CSYMAMD for {\tt A+A'},
+and CCOLAMD for {\tt A*A'}) to
+order all the nodes in the graph - but obeying the constraints determined
+by the separators.  This routine is similar to {\tt METIS\_NodeND}, except for
+how
+it treats the leaf nodes.  {\tt METIS\_NodeND} orders the leaves of the separator
+tree with {\tt MMD}, ignoring the rest of the matrix when ordering a single leaf.
+This routine orders the whole matrix with CAMD, CSYMAMD, or CCOLAMD, all at once,
+when the graph partitioning is done.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_metis}: interface to METIS nested dissection}
+%---------------------------------------
+
+\input{_metis.tex}
+CHOLMOD wrapper for the {\tt METIS\_NodeND} ordering routine.  Creates {\tt A+A'},
+{\tt A*A'} or {\tt A(:,f)*A(:,f)'} and then calls {\tt METIS\_NodeND} on the resulting graph.
+This routine is comparable to {\tt cholmod\_nested\_dissection}, except that it
+calls {\tt METIS\_NodeND} directly, and it does not return the separator tree.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_camd}: interface to CAMD}
+%---------------------------------------
+
+\input{_camd.tex}
+CHOLMOD interface to the CAMD ordering routine.  Finds a permutation
+{\tt p} such that the Cholesky factorization of {\tt A(p,p)}
+is sparser than {\tt A}.  If {\tt A} is unsymmetric,
+{\tt A*A'} is ordered.
+If {\tt Cmember[i]=c} then node {\tt i} is in set {\tt c}.
+All nodes in set 0 are ordered first, followed by all nodes in set 1, and so on.
+
+%---------------------------------------
+\newpage \subsection{{\tt cholmod\_ccolamd}: interface to CCOLAMD}
+%---------------------------------------
+
+\input{_ccolamd.tex}
+CHOLMOD interface to the CCOLAMD ordering routine.  Finds a permutation
+{\tt p} such that the Cholesky factorization of {\tt A(p,:)*A(p,:)'} is sparser than {\tt A*A'}.
+The column elimination is found and postordered, and the CCOLAMD ordering is then
+combined with its postordering.  {\tt A} must be unsymmetric.
+If {\tt Cmember[i]=c} then node {\tt i} is in set {\tt c}.
+All nodes in set 0 are ordered first, followed by all nodes in set 1, and so on.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_csymamd}: interface to CSYMAMD}
+%---------------------------------------
+
+\input{_csymamd.tex}
+CHOLMOD interface to the CSYMAMD ordering routine.  Finds a permutation
+{\tt p} such that the Cholesky factorization of {\tt A(p,p)} is sparser than {\tt A}.
+The elimination tree is found and postordered, and the CSYMAMD
+ordering is then combined with its postordering.  If {\tt A} is unsymmetric,
+{\tt A+A'} is ordered ({\tt A} must be square).
+If {\tt Cmember[i]=c} then node {\tt i} is in set {\tt c}.
+All nodes in set 0 are ordered first, followed by all nodes in set 1, and so on.
+
+%---------------------------------------
+\newpage
+\subsection{{\tt cholmod\_bisect}: graph bisector}
+%---------------------------------------
+
+\input{_bisect.tex}
+Finds a node bisector of {\tt A}, {\tt A*A'}, {\tt A(:,f)*A(:,f)'}:
+a set of nodes that partitions the graph into two parts.
+Compresses the graph first, and then calls METIS.
+
+%---------------------------------------
+\subsection{{\tt cholmod\_metis\_bisector}: interface to METIS node bisector}
+%---------------------------------------
+
+\input{_metis_bisector.tex}
+Finds a set of nodes that bisects the graph of {\tt A} or {\tt A*A'} (a direct interface to \newline
+{\tt METIS\_NodeComputeSeparator}).
+
+The input matrix {\tt A} must be square, symmetric (with both upper and lower
+parts present) and with no diagonal entries.  These conditions are not
+checked.
+
+%---------------------------------------
+\newpage
+\subsection{{\tt cholmod\_collapse\_septree}: prune a separator tree}
+%---------------------------------------
+
+\input{_collapse_septree.tex}
+Prunes a separator tree obtained from {\tt cholmod\_nested\_dissection}.
+
+\newpage
+\bibliographystyle{plain}
+\bibliography{UserGuide}
+\end{document}
diff --git a/src/C/SuiteSparse/CHOLMOD/Doc/footer.tex b/src/C/SuiteSparse/CHOLMOD/Doc/footer.tex
new file mode 100644
index 0000000..112a2d1
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Doc/footer.tex
@@ -0,0 +1,6 @@
+\end{verbatim}
+}
+\noindent\hspace{0.85in}\rule[0.25in]{5.2in}{1pt}
+\vspace{-0.15in}
+
+\noindent {\bf Purpose:}
diff --git a/src/C/SuiteSparse/CHOLMOD/Doc/getmproto b/src/C/SuiteSparse/CHOLMOD/Doc/getmproto
new file mode 100755
index 0000000..644a48c
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Doc/getmproto
@@ -0,0 +1,4 @@
+#!/bin/sh
+cat mheader.tex
+expand -8 $1 | awk -f mfile.awk
+cat mfooter.tex
diff --git a/src/C/SuiteSparse/CHOLMOD/Doc/getproto b/src/C/SuiteSparse/CHOLMOD/Doc/getproto
new file mode 100755
index 0000000..b3b30a6
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Doc/getproto
@@ -0,0 +1,6 @@
+#!/bin/sh
+echo -n $1 > _temp.awk
+cat rule.awk >> _temp.awk
+cat header.tex
+expand -8 $2 | awk -f _temp.awk
+cat footer.tex
diff --git a/src/C/SuiteSparse/CHOLMOD/Doc/header.tex b/src/C/SuiteSparse/CHOLMOD/Doc/header.tex
new file mode 100644
index 0000000..4f28f1b
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Doc/header.tex
@@ -0,0 +1,4 @@
+\noindent\hspace{0.85in}\rule[0.05in]{5.2in}{1pt}
+\vspace{-0.15in}
+{\footnotesize
+\begin{verbatim}
diff --git a/src/C/SuiteSparse/CHOLMOD/Doc/mfile.awk b/src/C/SuiteSparse/CHOLMOD/Doc/mfile.awk
new file mode 100644
index 0000000..5106442
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Doc/mfile.awk
@@ -0,0 +1 @@
+/^%/ { print "            ", substr ($0,2) }
diff --git a/src/C/SuiteSparse/CHOLMOD/Doc/mfooter.tex b/src/C/SuiteSparse/CHOLMOD/Doc/mfooter.tex
new file mode 100644
index 0000000..4bce503
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Doc/mfooter.tex
@@ -0,0 +1,4 @@
+\end{verbatim}
+}
+\noindent\hspace{0.85in}\rule[0.25in]{5.2in}{1pt}
+\vspace{-0.15in}
diff --git a/src/C/SuiteSparse/CHOLMOD/Doc/mheader.tex b/src/C/SuiteSparse/CHOLMOD/Doc/mheader.tex
new file mode 100644
index 0000000..90d3203
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Doc/mheader.tex
@@ -0,0 +1,5 @@
+
+\noindent\hspace{0.85in}\rule[0.05in]{5.2in}{1pt}
+\vspace{-0.15in}
+{\footnotesize
+\begin{verbatim}
diff --git a/src/C/SuiteSparse/CHOLMOD/Doc/rule.awk b/src/C/SuiteSparse/CHOLMOD/Doc/rule.awk
new file mode 100644
index 0000000..16e6ac1
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Doc/rule.awk
@@ -0,0 +1 @@
+{ print "            ", $0 }
diff --git a/src/C/SuiteSparse/CHOLMOD/Include/License.txt b/src/C/SuiteSparse/CHOLMOD/Include/License.txt
new file mode 100644
index 0000000..cfca615
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Include/License.txt
@@ -0,0 +1,9 @@
+CHOLMOD/Include/* files.
+Copyright (C) 2005-2006, either Univ. of Florida or T. Davis,
+depending on the file.
+http://www.cise.ufl.edu/research/sparse
+
+Refer to each include file in this directory; each file is licensed
+separately, according to the Module for which it contains definitions
+and prototypes.
+
diff --git a/src/C/SuiteSparse/CHOLMOD/Include/README.txt b/src/C/SuiteSparse/CHOLMOD/Include/README.txt
new file mode 100644
index 0000000..387eb6e
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Include/README.txt
@@ -0,0 +1,25 @@
+CHOLMOD: a sparse Cholesky factorization package.
+
+The Include/*.h files in this directory provide a basic documentation of all
+user-callable routines and user-visible data structures in the CHOLMOD
+package.  Start with cholmod.h, which describes the general structure of
+the parameter lists of CHOLMOD routines.  cholmod_core.h describes the
+data structures and basic operations on them (creating and deleting them).
+
+cholmod.h		single include file for all user programs
+cholmod_config.h	CHOLMOD compile-time configuration
+
+cholmod_core.h		Core module: data structures and basic support routines
+cholmod_check.h		Check module: check/print CHOLMOD data structures
+cholmod_cholesky.h	Cholesky module: LL' and LDL' factorization
+cholmod_matrixops.h	MatrixOps module: sparse matrix operators (add, mult,..)
+cholmod_modify.h	Modify module: update/downdate/...
+cholmod_partition.h	Partition module: nested dissection ordering
+cholmod_supernodal.h	Supernodal module: supernodal Cholesky
+
+These include files are not used in user programs, but in CHOLMOD only:
+
+cholmod_blas.h		BLAS definitions
+cholmod_complexity.h	complex arithmetic
+cholmod_template.h	complex arithmetic for template routines
+cholmod_internal.h	internal definitions, not visible to user program
diff --git a/src/C/SuiteSparse/CHOLMOD/Include/cholmod.h b/src/C/SuiteSparse/CHOLMOD/Include/cholmod.h
new file mode 100644
index 0000000..1332516
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Include/cholmod.h
@@ -0,0 +1,122 @@
+/* ========================================================================== */
+/* === Include/cholmod.h ==================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod.h.
+ * Copyright (C) 2005-2006, Univ. of Florida.  Author: Timothy A. Davis
+ * CHOLMOD/Include/cholmod.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ *
+ * Portions of CHOLMOD (the Core and Partition Modules) are copyrighted by the
+ * University of Florida.  The Modify Module is co-authored by William W.
+ * Hager, Univ. of Florida.
+ *
+ * Acknowledgements:  this work was supported in part by the National Science
+ * Foundation (NFS CCR-0203270 and DMS-9803599), and a grant from Sandia
+ * National Laboratories (Dept. of Energy) which supported the development of
+ * CHOLMOD's Partition Module.
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD include file, for inclusion user programs.
+ *
+ * The include files listed below include a short description of each user-
+ * callable routine.  Each routine in CHOLMOD has a consistent interface.
+ * More details about the CHOLMOD data types is in the cholmod_core.h file.
+ *
+ * Naming convention:
+ * ------------------
+ *
+ *	All routine names, data types, and CHOLMOD library files use the
+ *	cholmod_ prefix.  All macros and other #define's use the CHOLMOD
+ *	prefix.
+ * 
+ * Return value:
+ * -------------
+ *
+ *	Most CHOLMOD routines return an int (TRUE (1) if successful, or FALSE
+ *	(0) otherwise.  A UF_long or double return value is >= 0 if successful,
+ *	or -1 otherwise.  A size_t return value is > 0 if successful, or 0
+ *	otherwise.
+ *
+ *	If a routine returns a pointer, it is a pointer to a newly allocated
+ *	object or NULL if a failure occured, with one exception.  cholmod_free
+ *	always returns NULL.
+ *
+ * "Common" parameter:
+ * ------------------
+ *
+ *	The last parameter in all CHOLMOD routines is a pointer to the CHOLMOD
+ *	"Common" object.  This contains control parameters, statistics, and
+ *	workspace used between calls to CHOLMOD.  It is always an input/output
+ *	parameter.
+ *
+ * Input, Output, and Input/Output parameters:
+ * -------------------------------------------
+ *
+ *	Input parameters are listed first.  They are not modified by CHOLMOD.
+ *
+ *	Input/output are listed next.  They must be defined on input, and
+ *	are modified on output.
+ *
+ *	Output parameters are listed next.  If they are pointers, they must
+ *	point to allocated space on input, but their contents are not defined
+ *	on input.
+ *
+ *	Workspace parameters appear next.  They are used in only two routines
+ *	in the Supernodal module.
+ *
+ *	The cholmod_common *Common parameter always appears as the last
+ *	parameter.  It is always an input/output parameter.
+ */
+
+#ifndef CHOLMOD_H
+#define CHOLMOD_H
+
+/* make it easy for C++ programs to include CHOLMOD */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* assume large file support.  If problems occur, compile with -DNLARGEFILE */
+#include "cholmod_io64.h"
+
+/* define UF_long */
+#include "UFconfig.h"
+
+#include "cholmod_config.h"
+
+/* CHOLMOD always includes the Core module. */
+#include "cholmod_core.h"
+
+#ifndef NCHECK
+#include "cholmod_check.h"
+#endif
+
+#ifndef NCHOLESKY
+#include "cholmod_cholesky.h"
+#endif
+
+#ifndef NMATRIXOPS
+#include "cholmod_matrixops.h"
+#endif
+
+#ifndef NMODIFY
+#include "cholmod_modify.h"
+#endif
+
+#ifndef NPARTITION
+#include "cholmod_partition.h"
+#endif
+
+#ifndef NSUPERNODAL
+#include "cholmod_supernodal.h"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Include/cholmod_blas.h b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_blas.h
new file mode 100644
index 0000000..7d2b051
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_blas.h
@@ -0,0 +1,451 @@
+/* ========================================================================== */
+/* === Include/cholmod_blas.h =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_blas.h.
+ * Copyright (C) 2005-2006, Univ. of Florida.  Author: Timothy A. Davis
+ * CHOLMOD/Include/cholmod_blas.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* This does not need to be included in the user's program. */
+
+#ifndef CHOLMOD_BLAS_H
+#define CHOLMOD_BLAS_H
+
+/* ========================================================================== */
+/* === Architecture ========================================================= */
+/* ========================================================================== */
+
+#if defined (__sun) || defined (MSOL2) || defined (ARCH_SOL2)
+#define CHOLMOD_SOL2
+#define CHOLMOD_ARCHITECTURE "Sun Solaris"
+
+#elif defined (__sgi) || defined (MSGI) || defined (ARCH_SGI)
+#define CHOLMOD_SGI
+#define CHOLMOD_ARCHITECTURE "SGI Irix"
+
+#elif defined (__linux) || defined (MGLNX86) || defined (ARCH_GLNX86)
+#define CHOLMOD_LINUX
+#define CHOLMOD_ARCHITECTURE "Linux"
+
+#elif defined (_AIX) || defined (MIBM_RS) || defined (ARCH_IBM_RS)
+#define CHOLMOD_AIX
+#define CHOLMOD_ARCHITECTURE "IBM AIX"
+#define BLAS_NO_UNDERSCORE
+
+#elif defined (__alpha) || defined (MALPHA) || defined (ARCH_ALPHA)
+#define CHOLMOD_ALPHA
+#define CHOLMOD_ARCHITECTURE "Compaq Alpha"
+
+#elif defined (_WIN32) || defined (WIN32) || defined (_WIN64) || defined (WIN64)
+#if defined (__MINGW32__) || defined (__MINGW32__)
+#define CHOLMOD_MINGW
+#elif defined (__CYGWIN32__) || defined (__CYGWIN32__)
+#define CHOLMOD_CYGWIN
+#else
+#define CHOLMOD_WINDOWS
+#define BLAS_NO_UNDERSCORE
+#endif
+#define CHOLMOD_ARCHITECTURE "Microsoft Windows"
+
+#elif defined (__hppa) || defined (__hpux) || defined (MHPUX) || defined (ARCH_HPUX)
+#define CHOLMOD_HP
+#define CHOLMOD_ARCHITECTURE "HP Unix"
+#define BLAS_NO_UNDERSCORE
+
+#elif defined (__hp700) || defined (MHP700) || defined (ARCH_HP700)
+#define CHOLMOD_HP
+#define CHOLMOD_ARCHITECTURE "HP 700 Unix"
+#define BLAS_NO_UNDERSCORE
+
+#else
+/* If the architecture is unknown, and you call the BLAS, you may need to */
+/* define BLAS_BY_VALUE, BLAS_NO_UNDERSCORE, and/or BLAS_CHAR_ARG yourself. */
+#define CHOLMOD_ARCHITECTURE "unknown"
+#endif
+
+
+/* ========================================================================== */
+/* === BLAS and LAPACK names ================================================ */
+/* ========================================================================== */
+
+/* Prototypes for the various versions of the BLAS.  */
+
+/* Determine if the 64-bit Sun Performance BLAS is to be used */
+#if defined(CHOLMOD_SOL2) && !defined(NSUNPERF) && defined(LONG) && defined(LONGBLAS)
+#define SUN64
+#endif
+
+#ifdef SUN64
+
+#define BLAS_DTRSV dtrsv_64_
+#define BLAS_DGEMV dgemv_64_
+#define BLAS_DTRSM dtrsm_64_
+#define BLAS_DGEMM dgemm_64_
+#define BLAS_DSYRK dsyrk_64_
+#define BLAS_DGER  dger_64_
+#define BLAS_DSCAL dscal_64_
+#define LAPACK_DPOTRF dpotrf_64_
+
+#define BLAS_ZTRSV ztrsv_64_
+#define BLAS_ZGEMV zgemv_64_
+#define BLAS_ZTRSM ztrsm_64_
+#define BLAS_ZGEMM zgemm_64_
+#define BLAS_ZHERK zherk_64_
+#define BLAS_ZGER  zgeru_64_
+#define BLAS_ZSCAL zscal_64_
+#define LAPACK_ZPOTRF zpotrf_64_
+
+#elif defined (BLAS_NO_UNDERSCORE)
+
+#define BLAS_DTRSV dtrsv
+#define BLAS_DGEMV dgemv
+#define BLAS_DTRSM dtrsm
+#define BLAS_DGEMM dgemm
+#define BLAS_DSYRK dsyrk
+#define BLAS_DGER  dger
+#define BLAS_DSCAL dscal
+#define LAPACK_DPOTRF dpotrf
+
+#define BLAS_ZTRSV ztrsv
+#define BLAS_ZGEMV zgemv
+#define BLAS_ZTRSM ztrsm
+#define BLAS_ZGEMM zgemm
+#define BLAS_ZHERK zherk
+#define BLAS_ZGER  zgeru
+#define BLAS_ZSCAL zscal
+#define LAPACK_ZPOTRF zpotrf
+
+#else
+
+#define BLAS_DTRSV dtrsv_
+#define BLAS_DGEMV dgemv_
+#define BLAS_DTRSM dtrsm_
+#define BLAS_DGEMM dgemm_
+#define BLAS_DSYRK dsyrk_
+#define BLAS_DGER  dger_
+#define BLAS_DSCAL dscal_
+#define LAPACK_DPOTRF dpotrf_
+
+#define BLAS_ZTRSV ztrsv_
+#define BLAS_ZGEMV zgemv_
+#define BLAS_ZTRSM ztrsm_
+#define BLAS_ZGEMM zgemm_
+#define BLAS_ZHERK zherk_
+#define BLAS_ZGER  zgeru_
+#define BLAS_ZSCAL zscal_
+#define LAPACK_ZPOTRF zpotrf_
+
+#endif
+
+/* ========================================================================== */
+/* === BLAS and LAPACK integer arguments ==================================== */
+/* ========================================================================== */
+
+/* CHOLMOD can be compiled with -D'LONGBLAS=long' for the Sun Performance
+ * Library, or -D'LONGBLAS=long long' for SGI's SCSL BLAS.  This defines the
+ * integer used in the BLAS for the cholmod_l_* routines.
+ *
+ * The "int" version of CHOLMOD always uses the "int" version of the BLAS.
+ */
+
+#if defined (LONGBLAS) && defined (LONG)
+#define BLAS_INT LONGBLAS
+#else
+#define BLAS_INT int
+#endif
+
+/* If the BLAS integer is smaller than the basic CHOLMOD integer, then we need
+ * to check for integer overflow when converting from one to the other.  If
+ * any integer overflows, the externally-defined blas_ok variable is set to
+ * FALSE.  blas_ok should be set to TRUE before calling any BLAS_* macro.
+ */
+
+#define CHECK_BLAS_INT (sizeof (BLAS_INT) < sizeof (Int))
+#define EQ(K,k) (((BLAS_INT) K) == ((Int) k))
+
+/* ========================================================================== */
+/* === BLAS and LAPACK prototypes and macros ================================ */
+/* ========================================================================== */
+
+void BLAS_DGEMV (char *trans, BLAS_INT *m, BLAS_INT *n, double *alpha,
+	double *A, BLAS_INT *lda, double *X, BLAS_INT *incx, double *beta,
+	double *Y, BLAS_INT *incy) ;
+
+#define BLAS_dgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) \
+		&& EQ (INCY,incy) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_DGEMV (trans, &M, &N, alpha, A, &LDA, X, &INCX, beta, Y, &INCY) ; \
+    } \
+}
+
+void BLAS_ZGEMV (char *trans, BLAS_INT *m, BLAS_INT *n, double *alpha,
+	double *A, BLAS_INT *lda, double *X, BLAS_INT *incx, double *beta,
+	double *Y, BLAS_INT *incy) ;
+
+#define BLAS_zgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) \
+		&& EQ (INCY,incy) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_ZGEMV (trans, &M, &N, alpha, A, &LDA, X, &INCX, beta, Y, &INCY) ; \
+    } \
+}
+
+void BLAS_DTRSV (char *uplo, char *trans, char *diag, BLAS_INT *n, double *A,
+	BLAS_INT *lda, double *X, BLAS_INT *incx) ;
+
+#define BLAS_dtrsv(uplo,trans,diag,n,A,lda,X,incx) \
+{ \
+    BLAS_INT N = n, LDA = lda, INCX = incx ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_DTRSV (uplo, trans, diag, &N, A, &LDA, X, &INCX) ; \
+    } \
+}
+
+void BLAS_ZTRSV (char *uplo, char *trans, char *diag, BLAS_INT *n, double *A,
+	BLAS_INT *lda, double *X, BLAS_INT *incx) ;
+
+#define BLAS_ztrsv(uplo,trans,diag,n,A,lda,X,incx) \
+{ \
+    BLAS_INT N = n, LDA = lda, INCX = incx ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_ZTRSV (uplo, trans, diag, &N, A, &LDA, X, &INCX) ; \
+    } \
+}
+
+void BLAS_DTRSM (char *side, char *uplo, char *transa, char *diag, BLAS_INT *m,
+	BLAS_INT *n, double *alpha, double *A, BLAS_INT *lda, double *B,
+	BLAS_INT *ldb) ;
+
+#define BLAS_dtrsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, LDB = ldb ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (LDB,ldb) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_DTRSM (side, uplo, transa, diag, &M, &N, alpha, A, &LDA, B, &LDB);\
+    } \
+}
+
+void BLAS_ZTRSM (char *side, char *uplo, char *transa, char *diag, BLAS_INT *m,
+	BLAS_INT *n, double *alpha, double *A, BLAS_INT *lda, double *B,
+	BLAS_INT *ldb) ;
+
+#define BLAS_ztrsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, LDB = ldb ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (LDB,ldb) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_ZTRSM (side, uplo, transa, diag, &M, &N, alpha, A, &LDA, B, &LDB);\
+    } \
+}
+
+void BLAS_DGEMM (char *transa, char *transb, BLAS_INT *m, BLAS_INT *n,
+	BLAS_INT *k, double *alpha, double *A, BLAS_INT *lda, double *B,
+	BLAS_INT *ldb, double *beta, double *C, BLAS_INT *ldc) ;
+
+#define BLAS_dgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta,C,ldc) \
+{ \
+    BLAS_INT M = m, N = n, K = k, LDA = lda, LDB = ldb, LDC = ldc ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (M,m) && EQ (N,n) && EQ (K,k) && EQ (LDA,lda) \
+		&& EQ (LDB,ldb) && EQ (LDC,ldc) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_DGEMM (transa, transb, &M, &N, &K, alpha, A, &LDA, B, &LDB, beta, \
+	    C, &LDC) ; \
+    } \
+}
+
+void BLAS_ZGEMM (char *transa, char *transb, BLAS_INT *m, BLAS_INT *n,
+	BLAS_INT *k, double *alpha, double *A, BLAS_INT *lda, double *B,
+	BLAS_INT *ldb, double *beta, double *C, BLAS_INT *ldc) ;
+
+#define BLAS_zgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta,C,ldc) \
+{ \
+    BLAS_INT M = m, N = n, K = k, LDA = lda, LDB = ldb, LDC = ldc ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (M,m) && EQ (N,n) && EQ (K,k) && EQ (LDA,lda) \
+		&& EQ (LDB,ldb) && EQ (LDC,ldc) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_ZGEMM (transa, transb, &M, &N, &K, alpha, A, &LDA, B, &LDB, beta, \
+	    C, &LDC) ; \
+    } \
+}
+
+void BLAS_DSYRK (char *uplo, char *trans, BLAS_INT *n, BLAS_INT *k,
+	double *alpha, double *A, BLAS_INT *lda, double *beta, double *C,
+	BLAS_INT *ldc) ;
+
+#define BLAS_dsyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc) \
+{ \
+    BLAS_INT N = n, K = k, LDA = lda, LDC = ldc ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (N,n) && EQ (K,k) && EQ (LDA,lda) && EQ (LDC,ldc) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_DSYRK (uplo, trans, &N, &K, alpha, A, &LDA, beta, C, &LDC) ; \
+    } \
+} \
+
+void BLAS_ZHERK (char *uplo, char *trans, BLAS_INT *n, BLAS_INT *k,
+	double *alpha, double *A, BLAS_INT *lda, double *beta, double *C,
+	BLAS_INT *ldc) ;
+
+#define BLAS_zherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc) \
+{ \
+    BLAS_INT N = n, K = k, LDA = lda, LDC = ldc ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (N,n) && EQ (K,k) && EQ (LDA,lda) && EQ (LDC,ldc) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_ZHERK (uplo, trans, &N, &K, alpha, A, &LDA, beta, C, &LDC) ; \
+    } \
+} \
+
+void LAPACK_DPOTRF (char *uplo, BLAS_INT *n, double *A, BLAS_INT *lda,
+	BLAS_INT *info) ;
+
+#define LAPACK_dpotrf(uplo,n,A,lda,info) \
+{ \
+    BLAS_INT N = n, LDA = lda, INFO = 1 ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (N,n) && EQ (LDA,lda) ; \
+    } \
+    if (blas_ok) \
+    { \
+	LAPACK_DPOTRF (uplo, &N, A, &LDA, &INFO) ; \
+    } \
+    info = INFO ; \
+}
+
+void LAPACK_ZPOTRF (char *uplo, BLAS_INT *n, double *A, BLAS_INT *lda,
+	BLAS_INT *info) ;
+
+#define LAPACK_zpotrf(uplo,n,A,lda,info) \
+{ \
+    BLAS_INT N = n, LDA = lda, INFO = 1 ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (N,n) && EQ (LDA,lda) ; \
+    } \
+    if (blas_ok) \
+    { \
+	LAPACK_ZPOTRF (uplo, &N, A, &LDA, &INFO) ; \
+    } \
+    info = INFO ; \
+}
+
+/* ========================================================================== */
+
+void BLAS_DSCAL (BLAS_INT *n, double *alpha, double *Y, BLAS_INT *incy) ;
+
+#define BLAS_dscal(n,alpha,Y,incy) \
+{ \
+    BLAS_INT N = n, INCY = incy ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (N,n) && EQ (INCY,incy) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_DSCAL (&N, alpha, Y, &INCY) ; \
+    } \
+}
+
+void BLAS_ZSCAL (BLAS_INT *n, double *alpha, double *Y, BLAS_INT *incy) ;
+
+#define BLAS_zscal(n,alpha,Y,incy) \
+{ \
+    BLAS_INT N = n, INCY = incy ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (N,n) && EQ (INCY,incy) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_ZSCAL (&N, alpha, Y, &INCY) ; \
+    } \
+}
+
+void BLAS_DGER (BLAS_INT *m, BLAS_INT *n, double *alpha,
+	double *X, BLAS_INT *incx, double *Y, BLAS_INT *incy,
+	double *A, BLAS_INT *lda) ;
+
+#define BLAS_dger(m,n,alpha,X,incx,Y,incy,A,lda) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) \
+		&& EQ (INCY,incy) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_DGER (&M, &N, alpha, X, &INCX, Y, &INCY, A, &LDA) ; \
+    } \
+}
+
+void BLAS_ZGERU (BLAS_INT *m, BLAS_INT *n, double *alpha,
+	double *X, BLAS_INT *incx, double *Y, BLAS_INT *incy,
+	double *A, BLAS_INT *lda) ;
+
+#define BLAS_zgeru(m,n,alpha,X,incx,Y,incy,A,lda) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) \
+		&& EQ (INCY,incy) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_ZGER (&M, &N, alpha, X, &INCX, Y, &INCY, A, &LDA) ; \
+    } \
+}
+
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Include/cholmod_check.h b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_check.h
new file mode 100644
index 0000000..58e4ad0
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_check.h
@@ -0,0 +1,417 @@
+/* ========================================================================== */
+/* === Include/cholmod_check.h ============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_check.h.  Copyright (C) 2005-2006, Timothy A. Davis
+ * CHOLMOD/Include/cholmod_check.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD Check module.
+ *
+ * Routines that check and print the 5 basic data types in CHOLMOD, and 3 kinds
+ * of integer vectors (subset, perm, and parent), and read in matrices from a
+ * file:
+ *
+ * cholmod_check_common	    check/print the Common object
+ * cholmod_print_common
+ *
+ * cholmod_check_sparse	    check/print a sparse matrix in column-oriented form
+ * cholmod_print_sparse
+ *
+ * cholmod_check_dense	    check/print a dense matrix
+ * cholmod_print_dense
+ *
+ * cholmod_check_factor	    check/print a Cholesky factorization
+ * cholmod_print_factor
+ *
+ * cholmod_check_triplet    check/print a sparse matrix in triplet form
+ * cholmod_print_triplet
+ *
+ * cholmod_check_subset	    check/print a subset (integer vector in given range)
+ * cholmod_print_subset
+ *
+ * cholmod_check_perm	    check/print a permutation (an integer vector)
+ * cholmod_print_perm
+ *
+ * cholmod_check_parent	    check/print an elimination tree (an integer vector)
+ * cholmod_print_parent
+ *
+ * cholmod_read_triplet	    read a matrix in triplet form (any Matrix Market
+ *			    "coordinate" format, or a generic triplet format).
+ *
+ * cholmod_read_sparse	    read a matrix in sparse form (same file format as
+ *			    cholmod_read_triplet).
+ *
+ * cholmod_read_dense	    read a dense matrix (any Matrix Market "array"
+ *			    format, or a generic dense format).
+ *
+ * cholmod_write_sparse	    write a sparse matrix to a Matrix Market file.
+ *
+ * cholmod_write_dense	    write a dense matrix to a Matrix Market file.
+ *
+ * cholmod_print_common and cholmod_check_common are the only two routines that
+ * you may call after calling cholmod_finish.
+ *
+ * Requires the Core module.  Not required by any CHOLMOD module, except when
+ * debugging is enabled (in which case all modules require the Check module).
+ *
+ * See cholmod_read.c for a description of the file formats supported by the
+ * cholmod_read_* routines.
+ */
+
+#ifndef CHOLMOD_CHECK_H
+#define CHOLMOD_CHECK_H
+
+#include "cholmod_core.h"
+#include <stdio.h>
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_check_common:  check the Common object */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_check_common
+(
+    cholmod_common *Common
+) ;
+
+int cholmod_l_check_common (cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_print_common:  print the Common object */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_print_common
+(
+    /* ---- input ---- */
+    char *name,		/* printed name of Common object */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_print_common (char *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_check_sparse:  check a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_check_sparse
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* sparse matrix to check */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_check_sparse (cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_print_sparse */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_print_sparse
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* sparse matrix to print */
+    char *name,		/* printed name of sparse matrix */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_print_sparse (cholmod_sparse *, char *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_check_dense:  check a dense matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_check_dense
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* dense matrix to check */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_check_dense (cholmod_dense *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_print_dense:  print a dense matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_print_dense
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* dense matrix to print */
+    char *name,		/* printed name of dense matrix */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_print_dense (cholmod_dense *, char *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_check_factor:  check a factor */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_check_factor
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to check */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_check_factor (cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_print_factor:  print a factor */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_print_factor
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to print */
+    char *name,		/* printed name of factor */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_print_factor (cholmod_factor *, char *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_check_triplet:  check a sparse matrix in triplet form */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_check_triplet
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* triplet matrix to check */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_check_triplet (cholmod_triplet *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_print_triplet:  print a triplet matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_print_triplet
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* triplet matrix to print */
+    char *name,		/* printed name of triplet matrix */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_print_triplet (cholmod_triplet *, char *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_check_subset:  check a subset */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_check_subset
+(
+    /* ---- input ---- */
+    int *Set,		/* Set [0:len-1] is a subset of 0:n-1.  Duplicates OK */
+    UF_long len,	/* size of Set (an integer array) */
+    size_t n,		/* 0:n-1 is valid range */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_check_subset (UF_long *, UF_long, size_t, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_print_subset:  print a subset */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_print_subset
+(
+    /* ---- input ---- */
+    int *Set,		/* Set [0:len-1] is a subset of 0:n-1.  Duplicates OK */
+    UF_long len,	/* size of Set (an integer array) */
+    size_t n,		/* 0:n-1 is valid range */
+    char *name,		/* printed name of Set */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_print_subset (UF_long *, UF_long, size_t, char *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_check_perm:  check a permutation */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_check_perm
+(
+    /* ---- input ---- */
+    int *Perm,		/* Perm [0:len-1] is a permutation of subset of 0:n-1 */
+    size_t len,		/* size of Perm (an integer array) */
+    size_t n,		/* 0:n-1 is valid range */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_check_perm (UF_long *, size_t, size_t, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_print_perm:  print a permutation vector */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_print_perm
+(
+    /* ---- input ---- */
+    int *Perm,		/* Perm [0:len-1] is a permutation of subset of 0:n-1 */
+    size_t len,		/* size of Perm (an integer array) */
+    size_t n,		/* 0:n-1 is valid range */
+    char *name,		/* printed name of Perm */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_print_perm (UF_long *, size_t, size_t, char *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_check_parent:  check an elimination tree */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_check_parent
+(
+    /* ---- input ---- */
+    int *Parent,	/* Parent [0:n-1] is an elimination tree */
+    size_t n,		/* size of Parent */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_check_parent (UF_long *, size_t, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_print_parent */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_print_parent
+(
+    /* ---- input ---- */
+    int *Parent,	/* Parent [0:n-1] is an elimination tree */
+    size_t n,		/* size of Parent */
+    char *name,		/* printed name of Parent */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_print_parent (UF_long *, size_t, char *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_read_sparse: read a sparse matrix from a file */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_read_sparse
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from, must already be open */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_read_sparse (FILE *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_read_triplet: read a triplet matrix from a file */
+/* -------------------------------------------------------------------------- */
+
+cholmod_triplet *cholmod_read_triplet
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from, must already be open */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_triplet *cholmod_l_read_triplet (FILE *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_read_dense: read a dense matrix from a file */
+/* -------------------------------------------------------------------------- */
+
+cholmod_dense *cholmod_read_dense
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from, must already be open */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_dense *cholmod_l_read_dense (FILE *, cholmod_common *) ; 
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_read_matrix: read a sparse or dense matrix from a file */
+/* -------------------------------------------------------------------------- */
+
+void *cholmod_read_matrix
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from, must already be open */
+    int prefer,		/* If 0, a sparse matrix is always return as a
+			 *	cholmod_triplet form.  It can have any stype
+			 *	(symmetric-lower, unsymmetric, or
+			 *	symmetric-upper).
+			 * If 1, a sparse matrix is returned as an unsymmetric
+			 *	cholmod_sparse form (A->stype == 0), with both
+			 *	upper and lower triangular parts present.
+			 *	This is what the MATLAB mread mexFunction does,
+			 *	since MATLAB does not have an stype.
+			 * If 2, a sparse matrix is returned with an stype of 0
+			 *	or 1 (unsymmetric, or symmetric with upper part
+			 *	stored).
+			 * This argument has no effect for dense matrices.
+			 */
+    /* ---- output---- */
+    int *mtype,		/* CHOLMOD_TRIPLET, CHOLMOD_SPARSE or CHOLMOD_DENSE */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+void *cholmod_l_read_matrix (FILE *, int, int *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_write_sparse: write a sparse matrix to a file */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_write_sparse
+(
+    /* ---- input ---- */
+    FILE *f,		    /* file to write to, must already be open */
+    cholmod_sparse *A,	    /* matrix to print */
+    cholmod_sparse *Z,	    /* optional matrix with pattern of explicit zeros */
+    char *comments,	    /* optional filename of comments to include */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_write_sparse (FILE *, cholmod_sparse *, cholmod_sparse *,
+    char *c, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_write_dense: write a dense matrix to a file */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_write_dense
+(
+    /* ---- input ---- */
+    FILE *f,		    /* file to write to, must already be open */
+    cholmod_dense *X,	    /* matrix to print */
+    char *comments,	    /* optional filename of comments to include */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_write_dense (FILE *, cholmod_dense *, char *, cholmod_common *) ;
+
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Include/cholmod_cholesky.h b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_cholesky.h
new file mode 100644
index 0000000..7388afb
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_cholesky.h
@@ -0,0 +1,498 @@
+/* ========================================================================== */
+/* === Include/cholmod_cholesky.h =========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_cholesky.h. Copyright (C) 2005-2006, Timothy A. Davis
+ * CHOLMOD/Include/cholmod_cholesky.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD Cholesky module.
+ *
+ * Sparse Cholesky routines: analysis, factorization, and solve.
+ *
+ * The primary routines are all that a user requires to order, analyze, and
+ * factorize a sparse symmetric positive definite matrix A (or A*A'), and
+ * to solve Ax=b (or A*A'x=b).  The primary routines rely on the secondary
+ * routines, the CHOLMOD Core module, and the AMD and COLAMD packages.  They
+ * make optional use of the CHOLMOD Supernodal and Partition modules, the
+ * METIS package, and the CCOLAMD package.
+ *
+ * Primary routines:
+ * -----------------
+ *
+ * cholmod_analyze		order and analyze (simplicial or supernodal)
+ * cholmod_factorize		simplicial or supernodal Cholesky factorization
+ * cholmod_solve		solve a linear system (simplicial or supernodal)
+ * cholmod_spsolve		solve a linear system (sparse x and b)
+ *
+ * Secondary routines:
+ * ------------------
+ *
+ * cholmod_analyze_p		analyze, with user-provided permutation or f set
+ * cholmod_factorize_p		factorize, with user-provided permutation or f
+ * cholmod_analyze_ordering	analyze a fill-reducing ordering
+ * cholmod_etree		find the elimination tree
+ * cholmod_rowcolcounts		compute the row/column counts of L
+ * cholmod_amd			order using AMD
+ * cholmod_colamd		order using COLAMD
+ * cholmod_rowfac		incremental simplicial factorization
+ * cholmod_rowfac_mask		rowfac, specific to LPDASA
+ * cholmod_row_subtree		find the nonzero pattern of a row of L
+ * cholmod_resymbol		recompute the symbolic pattern of L
+ * cholmod_resymbol_noperm	recompute the symbolic pattern of L, no L->Perm
+ * cholmod_postorder		postorder a tree
+ *
+ * Requires the Core module, and two packages: AMD and COLAMD.
+ * Optionally uses the Supernodal and Partition modules.
+ * Required by the Partition module.
+ */
+
+#ifndef CHOLMOD_CHOLESKY_H
+#define CHOLMOD_CHOLESKY_H
+
+#include "cholmod_config.h"
+#include "cholmod_core.h"
+
+#ifndef NPARTITION
+#include "cholmod_partition.h"
+#endif
+
+#ifndef NSUPERNODAL
+#include "cholmod_supernodal.h"
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_analyze:  order and analyze (simplicial or supernodal) */
+/* -------------------------------------------------------------------------- */
+
+/* Orders and analyzes A, AA', PAP', or PAA'P' and returns a symbolic factor
+ * that can later be passed to cholmod_factorize. */
+
+cholmod_factor *cholmod_analyze 
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order and analyze */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_factor *cholmod_l_analyze (cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_analyze_p:  analyze, with user-provided permutation or f set */
+/* -------------------------------------------------------------------------- */
+
+/* Orders and analyzes A, AA', PAP', PAA'P', FF', or PFF'P and returns a
+ * symbolic factor that can later be passed to cholmod_factorize, where
+ * F = A(:,fset) if fset is not NULL and A->stype is zero.
+ * UserPerm is tried if non-NULL.  */
+
+cholmod_factor *cholmod_analyze_p
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order and analyze */
+    int *UserPerm,	/* user-provided permutation, size A->nrow */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_factor *cholmod_l_analyze_p (cholmod_sparse *, UF_long *, UF_long *,
+    size_t, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_factorize:  simplicial or supernodal Cholesky factorization */
+/* -------------------------------------------------------------------------- */
+
+/* Factorizes PAP' (or PAA'P' if A->stype is 0), using a factor obtained
+ * from cholmod_analyze.  The analysis can be re-used simply by calling this
+ * routine a second time with another matrix.  A must have the same nonzero
+ * pattern as that passed to cholmod_analyze. */
+
+int cholmod_factorize 
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* resulting factorization */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_factorize (cholmod_sparse *, cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_factorize_p:  factorize, with user-provided permutation or fset */
+/* -------------------------------------------------------------------------- */
+
+/* Same as cholmod_factorize, but with more options. */
+
+int cholmod_factorize_p
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    double beta [2],	/* factorize beta*I+A or beta*I+A'*A */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* resulting factorization */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_factorize_p (cholmod_sparse *, double *, UF_long *, size_t,
+    cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_solve:  solve a linear system (simplicial or supernodal) */
+/* -------------------------------------------------------------------------- */
+
+/* Solves one of many linear systems with a dense right-hand-side, using the
+ * factorization from cholmod_factorize (or as modified by any other CHOLMOD
+ * routine).  D is identity for LL' factorizations. */
+
+#define CHOLMOD_A    0		/* solve Ax=b */
+#define CHOLMOD_LDLt 1		/* solve LDL'x=b */
+#define CHOLMOD_LD   2		/* solve LDx=b */
+#define CHOLMOD_DLt  3		/* solve DL'x=b */
+#define CHOLMOD_L    4		/* solve Lx=b */
+#define CHOLMOD_Lt   5		/* solve L'x=b */
+#define CHOLMOD_D    6		/* solve Dx=b */
+#define CHOLMOD_P    7		/* permute x=Px */
+#define CHOLMOD_Pt   8		/* permute x=P'x */
+
+cholmod_dense *cholmod_solve	/* returns the solution X */
+(
+    /* ---- input ---- */
+    int sys,		/* system to solve */
+    cholmod_factor *L,	/* factorization to use */
+    cholmod_dense *B,	/* right-hand-side */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_dense *cholmod_l_solve (int, cholmod_factor *, cholmod_dense *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_spsolve:  solve a linear system with a sparse right-hand-side */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_spsolve
+(
+    /* ---- input ---- */
+    int sys,		/* system to solve */
+    cholmod_factor *L,	/* factorization to use */
+    cholmod_sparse *B,	/* right-hand-side */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_spsolve (int, cholmod_factor *, cholmod_sparse *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_etree: find the elimination tree of A or A'*A */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_etree
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,
+    /* ---- output --- */
+    int *Parent,	/* size ncol.  Parent [j] = p if p is the parent of j */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_etree (cholmod_sparse *, UF_long *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowcolcounts: compute the row/column counts of L */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_rowcolcounts
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int *Parent,	/* size nrow.  Parent [i] = p if p is the parent of i */
+    int *Post,		/* size nrow.  Post [k] = i if i is the kth node in
+			 * the postordered etree. */
+    /* ---- output --- */
+    int *RowCount,	/* size nrow. RowCount [i] = # entries in the ith row of
+			 * L, including the diagonal. */
+    int *ColCount,	/* size nrow. ColCount [i] = # entries in the ith
+			 * column of L, including the diagonal. */
+    int *First,		/* size nrow.  First [i] = k is the least postordering
+			 * of any descendant of i. */
+    int *Level,		/* size nrow.  Level [i] is the length of the path from
+			 * i to the root, with Level [root] = 0. */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowcolcounts (cholmod_sparse *, UF_long *, size_t, UF_long *,
+    UF_long *, UF_long *, UF_long *, UF_long *, UF_long *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_analyze_ordering:  analyze a fill-reducing ordering */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_analyze_ordering
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    int ordering,	/* ordering method used */
+    int *Perm,		/* size n, fill-reducing permutation to analyze */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- output --- */
+    int *Parent,	/* size n, elimination tree */
+    int *Post,		/* size n, postordering of elimination tree */
+    int *ColCount,	/* size n, nnz in each column of L */
+    /* ---- workspace  */
+    int *First,		/* size nworkspace for cholmod_postorder */
+    int *Level,		/* size n workspace for cholmod_postorder */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_analyze_ordering (cholmod_sparse *, int, UF_long *, UF_long *,
+    size_t, UF_long *, UF_long *, UF_long *, UF_long *, UF_long *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_amd:  order using AMD */
+/* -------------------------------------------------------------------------- */
+
+/* Finds a permutation P to reduce fill-in in the factorization of P*A*P'
+ * or P*A*A'P' */
+
+int cholmod_amd
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- output --- */
+    int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_amd (cholmod_sparse *, UF_long *, size_t, UF_long *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_colamd:  order using COLAMD */
+/* -------------------------------------------------------------------------- */
+
+/* Finds a permutation P to reduce fill-in in the factorization of P*A*A'*P'.
+ * Orders F*F' where F = A (:,fset) if fset is not NULL */
+
+int cholmod_colamd
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int postorder,	/* if TRUE, follow with a coletree postorder */
+    /* ---- output --- */
+    int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_colamd (cholmod_sparse *, UF_long *, size_t, int, UF_long *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowfac:  incremental simplicial factorization */
+/* -------------------------------------------------------------------------- */
+
+/* Partial or complete simplicial factorization.  Rows and columns kstart:kend-1
+ * of L and D must be initially equal to rows/columns kstart:kend-1 of the
+ * identity matrix.   Row k can only be factorized if all descendants of node
+ * k in the elimination tree have been factorized. */
+
+int cholmod_rowfac
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    cholmod_sparse *F,	/* used for A*A' case only. F=A' or A(:,fset)' */
+    double beta [2],	/* factorize beta*I+A or beta*I+A'*A */
+    size_t kstart,	/* first row to factorize */
+    size_t kend,	/* last row to factorize is kend-1 */
+    /* ---- in/out --- */
+    cholmod_factor *L,
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowfac (cholmod_sparse *, cholmod_sparse *, double *, size_t,
+    size_t, cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowfac_mask:  incremental simplicial factorization */
+/* -------------------------------------------------------------------------- */
+
+/* cholmod_rowfac_mask is a version of cholmod_rowfac that is specific to
+ * LPDASA.  It is unlikely to be needed by any other application. */
+
+int cholmod_rowfac_mask
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    cholmod_sparse *F,	/* used for A*A' case only. F=A' or A(:,fset)' */
+    double beta [2],	/* factorize beta*I+A or beta*I+A'*A */
+    size_t kstart,	/* first row to factorize */
+    size_t kend,	/* last row to factorize is kend-1 */
+    int *mask,		/* if mask[i] >= 0, then set row i to zero */
+    int *RLinkUp,	/* link list of rows to compute */
+    /* ---- in/out --- */
+    cholmod_factor *L,
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowfac_mask (cholmod_sparse *, cholmod_sparse *, double *, size_t,
+    size_t, UF_long *, UF_long *, cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_row_subtree:  find the nonzero pattern of a row of L */
+/* -------------------------------------------------------------------------- */
+
+/* Find the nonzero pattern of x for the system Lx=b where L = (0:k-1,0:k-1)
+ * and b = kth column of A or A*A' (rows 0 to k-1 only) */
+
+int cholmod_row_subtree
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    cholmod_sparse *F,	/* used for A*A' case only. F=A' or A(:,fset)' */
+    size_t k,		/* row k of L */
+    int *Parent,	/* elimination tree */
+    /* ---- output --- */
+    cholmod_sparse *R,	/* pattern of L(k,:), 1-by-n with R->nzmax >= n */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_row_subtree (cholmod_sparse *, cholmod_sparse *, size_t,
+    UF_long *, cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_row_lsubtree:  find the nonzero pattern of a row of L */
+/* -------------------------------------------------------------------------- */
+
+/* Identical to cholmod_row_subtree, except that it finds the elimination tree
+ * from L itself. */
+
+int cholmod_row_lsubtree
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    int *Fi, size_t fnz,    /* nonzero pattern of kth row of A', not required
+			     * for the symmetric case.  Need not be sorted. */
+    size_t k,		/* row k of L */
+    cholmod_factor *L,	/* the factor L from which parent(i) is derived */
+    /* ---- output --- */
+    cholmod_sparse *R,	/* pattern of L(k,:), 1-by-n with R->nzmax >= n */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_row_lsubtree (cholmod_sparse *, UF_long *, size_t,
+    size_t, cholmod_factor *, cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_resymbol:  recompute the symbolic pattern of L */
+/* -------------------------------------------------------------------------- */
+
+/* Remove entries from L that are not in the factorization of P*A*P', P*A*A'*P',
+ * or P*F*F'*P' (depending on A->stype and whether fset is NULL or not).
+ *
+ * cholmod_resymbol is the same as cholmod_resymbol_noperm, except that it
+ * first permutes A according to L->Perm.  A can be upper/lower/unsymmetric,
+ * in contrast to cholmod_resymbol_noperm (which can be lower or unsym). */
+
+int cholmod_resymbol 
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int pack,		/* if TRUE, pack the columns of L */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factorization, entries pruned on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_resymbol (cholmod_sparse *, UF_long *, size_t, int,
+    cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_resymbol_noperm:  recompute the symbolic pattern of L, no L->Perm */
+/* -------------------------------------------------------------------------- */
+
+/* Remove entries from L that are not in the factorization of A, A*A',
+ * or F*F' (depending on A->stype and whether fset is NULL or not). */
+
+int cholmod_resymbol_noperm
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int pack,		/* if TRUE, pack the columns of L */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factorization, entries pruned on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_resymbol_noperm (cholmod_sparse *, UF_long *, size_t, int,
+    cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rcond:  compute rough estimate of reciprocal of condition number */
+/* -------------------------------------------------------------------------- */
+
+double cholmod_rcond	    /* return min(diag(L)) / max(diag(L)) */
+(
+    /* ---- input ---- */
+    cholmod_factor *L,
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+double cholmod_l_rcond (cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_postorder: Compute the postorder of a tree */
+/* -------------------------------------------------------------------------- */
+
+UF_long cholmod_postorder	/* return # of nodes postordered */
+(
+    /* ---- input ---- */
+    int *Parent,	/* size n. Parent [j] = p if p is the parent of j */
+    size_t n,
+    int *Weight_p,	/* size n, optional. Weight [j] is weight of node j */
+    /* ---- output --- */
+    int *Post,		/* size n. Post [k] = j is kth in postordered tree */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+UF_long cholmod_l_postorder (UF_long *, size_t, UF_long *, UF_long *,
+    cholmod_common *) ;
+
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Include/cholmod_complexity.h b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_complexity.h
new file mode 100644
index 0000000..a84583a
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_complexity.h
@@ -0,0 +1,264 @@
+/* ========================================================================== */
+/* === Include/cholmod_complexity.h ========================================= */
+/* ========================================================================== */
+
+/* Define operations on pattern, real, complex, and zomplex objects.
+ *
+ * The xtype of an object defines it numerical type.  A qttern object has no
+ * numerical values (A->x and A->z are NULL).  A real object has no imaginary
+ * qrt (A->x is used, A->z is NULL).  A complex object has an imaginary qrt
+ * that is stored interleaved with its real qrt (A->x is of size 2*nz, A->z
+ * is NULL).  A zomplex object has both real and imaginary qrts, which are
+ * stored seqrately, as in MATLAB (A->x and A->z are both used).
+ *
+ * XTYPE is CHOLMOD_PATTERN, _REAL, _COMPLEX or _ZOMPLEX, and is the xtype of
+ * the template routine under construction.  XTYPE2 is equal to XTYPE, except
+ * if XTYPE is CHOLMOD_PATTERN, in which case XTYPE is CHOLMOD_REAL.
+ * XTYPE and XTYPE2 are defined in cholmod_template.h.  
+ */
+
+/* -------------------------------------------------------------------------- */
+/* pattern */
+/* -------------------------------------------------------------------------- */
+
+#define P_TEMPLATE(name)		p_ ## name
+#define P_ASSIGN2(x,z,p,ax,az,q)	x [p] = 1
+#define P_PRINT(k,x,z,p)		PRK(k, ("1"))
+
+/* -------------------------------------------------------------------------- */
+/* real */
+/* -------------------------------------------------------------------------- */
+
+#define R_TEMPLATE(name)			r_ ## name
+#define R_ASSEMBLE(x,z,p,ax,az,q)		x [p] += ax [q]
+#define R_ASSIGN(x,z,p,ax,az,q)			x [p]  = ax [q]
+#define R_ASSIGN_CONJ(x,z,p,ax,az,q)		x [p]  = ax [q]
+#define R_ASSIGN_REAL(x,p,ax,q)			x [p]  = ax [q]
+#define R_XTYPE_OK(type)			((type) == CHOLMOD_REAL)
+#define R_IS_NONZERO(ax,az,q)			IS_NONZERO (ax [q])
+#define R_IS_ZERO(ax,az,q)			IS_ZERO (ax [q])
+#define R_IS_ONE(ax,az,q)			(ax [q] == 1)
+#define R_MULT(x,z,p, ax,az,q, bx,bz,r)		x [p]  = ax [q] * bx [r]
+#define R_MULTADD(x,z,p, ax,az,q, bx,bz,r)	x [p] += ax [q] * bx [r]
+#define R_MULTSUB(x,z,p, ax,az,q, bx,bz,r)	x [p] -= ax [q] * bx [r]
+#define R_MULTADDCONJ(x,z,p, ax,az,q, bx,bz,r)	x [p] += ax [q] * bx [r]
+#define R_MULTSUBCONJ(x,z,p, ax,az,q, bx,bz,r)	x [p] -= ax [q] * bx [r]
+#define R_ADD(x,z,p, ax,az,q, bx,bz,r)		x [p]  = ax [q] + bx [r]
+#define R_ADD_REAL(x,p, ax,q, bx,r)		x [p]  = ax [q] + bx [r]
+#define R_CLEAR(x,z,p)				x [p]  = 0
+#define R_CLEAR_IMAG(x,z,p)
+#define R_DIV(x,z,p,ax,az,q)			x [p] /= ax [q]
+#define R_LLDOT(x,p, ax,az,q)			x [p] -= ax [q] * ax [q]
+#define R_PRINT(k,x,z,p)			PRK(k, ("%24.16e", x [p]))
+
+#define R_DIV_REAL(x,z,p, ax,az,q, bx,r)	x [p] = ax [q] / bx [r]
+#define R_MULT_REAL(x,z,p, ax,az,q, bx,r)	x [p] = ax [q] * bx [r]
+
+#define R_LDLDOT(x,p, ax,az,q, bx,r)		x [p] -=(ax[q] * ax[q])/ bx[r]
+
+/* -------------------------------------------------------------------------- */
+/* complex */
+/* -------------------------------------------------------------------------- */
+
+#define C_TEMPLATE(name)		c_ ## name
+#define CT_TEMPLATE(name)		ct_ ## name
+
+#define C_ASSEMBLE(x,z,p,ax,az,q) \
+    x [2*(p)  ] += ax [2*(q)  ] ; \
+    x [2*(p)+1] += ax [2*(q)+1]
+
+#define C_ASSIGN(x,z,p,ax,az,q) \
+    x [2*(p)  ] = ax [2*(q)  ] ; \
+    x [2*(p)+1] = ax [2*(q)+1]
+
+#define C_ASSIGN_REAL(x,p,ax,q)			x [2*(p)]  = ax [2*(q)]
+
+#define C_ASSIGN_CONJ(x,z,p,ax,az,q) \
+    x [2*(p)  ] =  ax [2*(q)  ] ; \
+    x [2*(p)+1] = -ax [2*(q)+1]
+
+#define C_XTYPE_OK(type)		((type) == CHOLMOD_COMPLEX)
+
+#define C_IS_NONZERO(ax,az,q) \
+    (IS_NONZERO (ax [2*(q)]) || IS_NONZERO (ax [2*(q)+1]))
+
+#define C_IS_ZERO(ax,az,q) \
+    (IS_ZERO (ax [2*(q)]) && IS_ZERO (ax [2*(q)+1]))
+
+#define C_IS_ONE(ax,az,q) \
+    ((ax [2*(q)] == 1) && IS_ZERO (ax [2*(q)+1]))
+
+#define C_IMAG_IS_NONZERO(ax,az,q)  (IS_NONZERO (ax [2*(q)+1]))
+
+#define C_MULT(x,z,p, ax,az,q, bx,bz,r) \
+x [2*(p)  ] = ax [2*(q)  ] * bx [2*(r)] - ax [2*(q)+1] * bx [2*(r)+1] ; \
+x [2*(p)+1] = ax [2*(q)+1] * bx [2*(r)] + ax [2*(q)  ] * bx [2*(r)+1]
+
+#define C_MULTADD(x,z,p, ax,az,q, bx,bz,r) \
+x [2*(p)  ] += ax [2*(q)  ] * bx [2*(r)] - ax [2*(q)+1] * bx [2*(r)+1] ; \
+x [2*(p)+1] += ax [2*(q)+1] * bx [2*(r)] + ax [2*(q)  ] * bx [2*(r)+1]
+
+#define C_MULTSUB(x,z,p, ax,az,q, bx,bz,r) \
+x [2*(p)  ] -= ax [2*(q)  ] * bx [2*(r)] - ax [2*(q)+1] * bx [2*(r)+1] ; \
+x [2*(p)+1] -= ax [2*(q)+1] * bx [2*(r)] + ax [2*(q)  ] * bx [2*(r)+1]
+
+/* s += conj(a)*b */
+#define C_MULTADDCONJ(x,z,p, ax,az,q, bx,bz,r) \
+x [2*(p)  ] +=   ax [2*(q)  ]  * bx [2*(r)] + ax [2*(q)+1] * bx [2*(r)+1] ; \
+x [2*(p)+1] += (-ax [2*(q)+1]) * bx [2*(r)] + ax [2*(q)  ] * bx [2*(r)+1]
+
+/* s -= conj(a)*b */
+#define C_MULTSUBCONJ(x,z,p, ax,az,q, bx,bz,r) \
+x [2*(p)  ] -=   ax [2*(q)  ]  * bx [2*(r)] + ax [2*(q)+1] * bx [2*(r)+1] ; \
+x [2*(p)+1] -= (-ax [2*(q)+1]) * bx [2*(r)] + ax [2*(q)  ] * bx [2*(r)+1]
+
+#define C_ADD(x,z,p, ax,az,q, bx,bz,r) \
+    x [2*(p)  ] = ax [2*(q)  ] + bx [2*(r)  ] ; \
+    x [2*(p)+1] = ax [2*(q)+1] + bx [2*(r)+1]
+
+#define C_ADD_REAL(x,p, ax,q, bx,r) \
+    x [2*(p)] = ax [2*(q)] + bx [2*(r)]
+
+#define C_CLEAR(x,z,p) \
+    x [2*(p)  ] = 0 ; \
+    x [2*(p)+1] = 0
+
+#define C_CLEAR_IMAG(x,z,p) \
+    x [2*(p)+1] = 0
+
+/* s = s / a */
+#define C_DIV(x,z,p,ax,az,q) \
+    Common->complex_divide ( \
+	      x [2*(p)],  x [2*(p)+1], \
+	     ax [2*(q)], ax [2*(q)+1], \
+	     &x [2*(p)], &x [2*(p)+1])
+
+/* s -= conj(a)*a ; note that the result of conj(a)*a is real */
+#define C_LLDOT(x,p, ax,az,q) \
+    x [2*(p)] -= ax [2*(q)] * ax [2*(q)] + ax [2*(q)+1] * ax [2*(q)+1]
+
+#define C_PRINT(k,x,z,p) PRK(k, ("(%24.16e,%24.16e)", x [2*(p)], x [2*(p)+1]))
+
+#define C_DIV_REAL(x,z,p, ax,az,q, bx,r) \
+    x [2*(p)  ] = ax [2*(q)  ] / bx [2*(r)] ; \
+    x [2*(p)+1] = ax [2*(q)+1] / bx [2*(r)]
+
+#define C_MULT_REAL(x,z,p, ax,az,q, bx,r) \
+    x [2*(p)  ] = ax [2*(q)  ] * bx [2*(r)] ; \
+    x [2*(p)+1] = ax [2*(q)+1] * bx [2*(r)]
+
+/* s -= conj(a)*a/t */
+#define C_LDLDOT(x,p, ax,az,q, bx,r) \
+    x [2*(p)] -= (ax [2*(q)] * ax [2*(q)] + ax [2*(q)+1] * ax [2*(q)+1]) / bx[r]
+
+/* -------------------------------------------------------------------------- */
+/* zomplex */
+/* -------------------------------------------------------------------------- */
+
+#define Z_TEMPLATE(name)		z_ ## name
+#define ZT_TEMPLATE(name)		zt_ ## name
+
+#define Z_ASSEMBLE(x,z,p,ax,az,q) \
+    x [p] += ax [q] ; \
+    z [p] += az [q]
+
+#define Z_ASSIGN(x,z,p,ax,az,q) \
+    x [p] = ax [q] ; \
+    z [p] = az [q]
+
+#define Z_ASSIGN_REAL(x,p,ax,q)			x [p]  = ax [q]
+
+#define Z_ASSIGN_CONJ(x,z,p,ax,az,q) \
+    x [p] =  ax [q] ; \
+    z [p] = -az [q]
+
+#define Z_XTYPE_OK(type)		((type) == CHOLMOD_ZOMPLEX)
+
+#define Z_IS_NONZERO(ax,az,q) \
+    (IS_NONZERO (ax [q]) || IS_NONZERO (az [q]))
+
+#define Z_IS_ZERO(ax,az,q) \
+    (IS_ZERO (ax [q]) && IS_ZERO (az [q]))
+
+#define Z_IS_ONE(ax,az,q) \
+    ((ax [q] == 1) && IS_ZERO (az [q]))
+
+#define Z_IMAG_IS_NONZERO(ax,az,q)  (IS_NONZERO (az [q]))
+
+#define Z_MULT(x,z,p, ax,az,q, bx,bz,r) \
+    x [p] = ax [q] * bx [r] - az [q] * bz [r] ; \
+    z [p] = az [q] * bx [r] + ax [q] * bz [r]
+
+#define Z_MULTADD(x,z,p, ax,az,q, bx,bz,r) \
+    x [p] += ax [q] * bx [r] - az [q] * bz [r] ; \
+    z [p] += az [q] * bx [r] + ax [q] * bz [r]
+
+#define Z_MULTSUB(x,z,p, ax,az,q, bx,bz,r) \
+    x [p] -= ax [q] * bx [r] - az [q] * bz [r] ; \
+    z [p] -= az [q] * bx [r] + ax [q] * bz [r]
+
+#define Z_MULTADDCONJ(x,z,p, ax,az,q, bx,bz,r) \
+    x [p] +=   ax [q]  * bx [r] + az [q] * bz [r] ; \
+    z [p] += (-az [q]) * bx [r] + ax [q] * bz [r]
+
+#define Z_MULTSUBCONJ(x,z,p, ax,az,q, bx,bz,r) \
+    x [p] -=   ax [q]  * bx [r] + az [q] * bz [r] ; \
+    z [p] -= (-az [q]) * bx [r] + ax [q] * bz [r]
+
+#define Z_ADD(x,z,p, ax,az,q, bx,bz,r) \
+	x [p] = ax [q] + bx [r] ; \
+	z [p] = az [q] + bz [r]
+
+#define Z_ADD_REAL(x,p, ax,q, bx,r) \
+	x [p] = ax [q] + bx [r]
+
+#define Z_CLEAR(x,z,p) \
+    x [p] = 0 ; \
+    z [p] = 0
+
+#define Z_CLEAR_IMAG(x,z,p) \
+    z [p] = 0
+
+/* s = s/a */
+#define Z_DIV(x,z,p,ax,az,q) \
+    Common->complex_divide (x [p], z [p], ax [q], az [q], &x [p], &z [p])
+
+/* s -= conj(a)*a ; note that the result of conj(a)*a is real */
+#define Z_LLDOT(x,p, ax,az,q) \
+    x [p] -= ax [q] * ax [q] + az [q] * az [q]
+
+#define Z_PRINT(k,x,z,p)	PRK(k, ("(%24.16e,%24.16e)", x [p], z [p]))
+
+#define Z_DIV_REAL(x,z,p, ax,az,q, bx,r) \
+    x [p] = ax [q] / bx [r] ; \
+    z [p] = az [q] / bx [r]
+
+#define Z_MULT_REAL(x,z,p, ax,az,q, bx,r) \
+    x [p] = ax [q] * bx [r] ; \
+    z [p] = az [q] * bx [r]
+
+/* s -= conj(a)*a/t */
+#define Z_LDLDOT(x,p, ax,az,q, bx,r) \
+    x [p] -= (ax [q] * ax [q] + az [q] * az [q]) / bx[r]
+
+/* -------------------------------------------------------------------------- */
+/* all classes */
+/* -------------------------------------------------------------------------- */
+
+/* Check if A->xtype and the two arrays A->x and A->z are valid.  Set status to
+ * invalid, unless status is already "out of memory".  A can be a sparse matrix,
+ * dense matrix, factor, or triplet. */
+
+#define RETURN_IF_XTYPE_INVALID(A,xtype1,xtype2,result) \
+{ \
+    if ((A)->xtype < (xtype1) || (A)->xtype > (xtype2) || \
+        ((A)->xtype != CHOLMOD_PATTERN && ((A)->x) == NULL) || \
+	((A)->xtype == CHOLMOD_ZOMPLEX && ((A)->z) == NULL)) \
+    { \
+	if (Common->status != CHOLMOD_OUT_OF_MEMORY) \
+	{ \
+	    ERROR (CHOLMOD_INVALID, "invalid xtype") ; \
+	} \
+	return (result) ; \
+    } \
+}
diff --git a/src/C/SuiteSparse/CHOLMOD/Include/cholmod_config.h b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_config.h
new file mode 100644
index 0000000..b9de51b
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_config.h
@@ -0,0 +1,83 @@
+/* ========================================================================== */
+/* === Include/cholmod_config.h ============================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_config.h.
+ * Copyright (C) 2005-2006, Univ. of Florida.  Author: Timothy A. Davis
+ * CHOLMOD/Include/cholmod_config.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD configuration file, for inclusion in user programs.
+ *
+ * You do not have to edit any CHOLMOD files to compile and install CHOLMOD.
+ * However, if you do not use all of CHOLMOD's modules, you need to compile
+ * with the appropriate flag, or edit this file to add the appropriate #define.
+ *
+ * If you wish to use CHOLMOD under the GNU LGPL license only, then you must
+ * compile CHOLMOD with -DNMATRIXOPS -DNSUPERNODAL and -DNMODIFY.  This can
+ * be done using just -DNGPL.
+ *
+ * Compiler flags for CHOLMOD:
+ *
+ * -DNCHECK	    do not include the Check module.        License: GNU LGPL
+ * -DNCHOLESKY	    do not include the Cholesky module.     License: GNU LGPL
+ * -DNPARTITION	    do not include the Partition module.    License: GNU LGPL
+ *
+ * -DNGPL	    do not include any GNU GPL Modules in the CHOLMOD library.
+ * -DNMATRIXOPS	    do not include the MatrixOps module.    License: GNU GPL
+ * -DNMODIFY	    do not include the Modify module.       License: GNU GPL
+ * -DNSUPERNODAL    do not include the Supernodal module.   License: GNU GPL
+ *
+ * -DNPRINT	    do not print anything
+ *
+ * -D'LONGBLAS=long' or -DLONGBLAS='long long' defines the integers used by
+ *		    LAPACK and the BLAS.  Use LONGBLAS=long on Solaris to use
+ *		    the 64-bit Sun Performance BLAS in cholmod_l_* routines.
+ *		    You may need to use -D'LONGBLAS=long long' on the SGI
+ *		    (this is not tested).
+ *
+ * -DNSUNPERF	    for Solaris only.  If defined, do not use the Sun
+ *		    Performance Library.  The default is to use SunPerf.
+ *		    You must compile CHOLMOD with -xlic_lib=sunperf.
+ *
+ * The Core Module (License GNU LGPL) is always included in the CHOLMOD library.
+ */
+
+#ifndef CHOLMOD_CONFIG_H
+#define CHOLMOD_CONFIG_H
+
+/* Use the compiler flag, or uncomment the definition(s), if you want to use
+ * one or more non-default installation options: */
+
+/*
+#define NCHECK
+#define NCHOLESKY
+#define NPARTITION
+
+#define NGPL  
+#define NMATRIXOPS
+#define NMODIFY
+#define NSUPERNODAL
+
+#define NPRINT
+
+#define LONGBLAS long
+#define LONGBLAS long long
+#define NSUNPERF
+*/
+
+/* -------------------------------------------------------------------------- */
+/* if NGPL is defined, disable all GNU GPL Modules */
+/* -------------------------------------------------------------------------- */
+
+#ifdef NGPL
+#define NMATRIXOPS
+#define NMODIFY
+#define NSUPERNODAL
+#endif
+
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Include/cholmod_core.h b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_core.h
new file mode 100644
index 0000000..65cf0c0
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_core.h
@@ -0,0 +1,2257 @@
+/* ========================================================================== */
+/* === Include/cholmod_core.h =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_core.h.
+ * Copyright (C) 2005-2006, Univ. of Florida.  Author: Timothy A. Davis
+ * CHOLMOD/Include/cholmod_core.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD Core module: basic CHOLMOD objects and routines.
+ * Required by all CHOLMOD modules.  Requires no other module or package.
+ *
+ * The CHOLMOD modules are:
+ *
+ * Core		basic data structures and definitions
+ * Check	check/print the 5 CHOLMOD objects, & 3 types of integer vectors
+ * Cholesky	sparse Cholesky factorization
+ * Modify	sparse Cholesky update/downdate/row-add/row-delete
+ * MatrixOps	sparse matrix functions (add, multiply, norm, ...)
+ * Supernodal	supernodal sparse Cholesky factorization
+ * Partition	graph-partitioning based orderings
+ *
+ * The CHOLMOD objects:
+ * --------------------
+ *
+ * cholmod_common   parameters, statistics, and workspace
+ * cholmod_sparse   a sparse matrix in compressed column form
+ * cholmod_factor   an LL' or LDL' factorization
+ * cholmod_dense    a dense matrix
+ * cholmod_triplet  a sparse matrix in "triplet" form
+ *
+ * The Core module described here defines the CHOLMOD data structures, and
+ * basic operations on them.  To create and solve a sparse linear system Ax=b,
+ * the user must create A and b, populate them with values, and then pass them
+ * to the routines in the CHOLMOD Cholesky module.  There are two primary
+ * methods for creating A: (1) allocate space for a column-oriented sparse
+ * matrix and fill it with pattern and values, or (2) create a triplet form
+ * matrix and convert it to a sparse matrix.  The latter option is simpler.
+ *
+ * The matrices b and x are typically dense matrices, but can also be sparse.
+ * You can allocate and free them as dense matrices with the
+ * cholmod_allocate_dense and cholmod_free_dense routines.
+ *
+ * The cholmod_factor object contains the symbolic and numeric LL' or LDL'
+ * factorization of sparse symmetric matrix.  The matrix must be positive
+ * definite for an LL' factorization.  It need only be symmetric and have well-
+ * conditioned leading submatrices for it to have an LDL' factorization
+ * (CHOLMOD does not pivot for numerical stability).  It is typically created
+ * with the cholmod_factorize routine in the Cholesky module, but can also
+ * be initialized to L=D=I in the Core module and then modified by the Modify
+ * module.  It must be freed with cholmod_free_factor, defined below.
+ *
+ * The Core routines for each object are described below.  Each list is split
+ * into two parts: the primary routines and secondary routines.
+ *
+ * ============================================================================
+ * === cholmod_common =========================================================
+ * ============================================================================
+ *
+ * The Common object contains control parameters, statistics, and
+ * You must call cholmod_start before calling any other CHOLMOD routine, and
+ * must call cholmod_finish as your last call to CHOLMOD, with two exceptions:
+ * you may call cholmod_print_common and cholmod_check_common in the Check
+ * module after calling cholmod_finish.
+ *
+ * cholmod_start		first call to CHOLMOD
+ * cholmod_finish		last call to CHOLMOD
+ * -----------------------------
+ * cholmod_defaults		restore default parameters
+ * cholmod_maxrank		maximum rank for update/downdate
+ * cholmod_allocate_work	allocate workspace in Common
+ * cholmod_free_work		free workspace in Common
+ * cholmod_clear_flag		clear Flag workspace in Common
+ * cholmod_error		called when CHOLMOD encounters an error
+ * cholmod_dbound		for internal use in CHOLMOD only
+ * cholmod_hypot		compute sqrt (x*x + y*y) accurately
+ * cholmod_divcomplex		complex division, c = a/b
+ *
+ * ============================================================================
+ * === cholmod_sparse =========================================================
+ * ============================================================================
+ *
+ * A sparse matrix is held in compressed column form.  In the basic type
+ * ("packed", which corresponds to a MATLAB sparse matrix), an n-by-n matrix
+ * with nz entries is held in three arrays: p of size n+1, i of size nz, and x
+ * of size nz.  Row indices of column j are held in i [p [j] ... p [j+1]-1] and
+ * in the same locations in x.  There may be no duplicate entries in a column.
+ * Row indices in each column may be sorted or unsorted (CHOLMOD keeps track).
+ * A->stype determines the storage mode: 0 if both upper/lower parts are stored,
+ * -1 if A is symmetric and just tril(A) is stored, +1 if symmetric and triu(A)
+ * is stored.
+ *
+ * cholmod_allocate_sparse	allocate a sparse matrix
+ * cholmod_free_sparse		free a sparse matrix
+ * -----------------------------
+ * cholmod_reallocate_sparse	change the size (# entries) of sparse matrix
+ * cholmod_nnz			number of nonzeros in a sparse matrix
+ * cholmod_speye		sparse identity matrix
+ * cholmod_spzeros		sparse zero matrix
+ * cholmod_transpose		transpose a sparse matrix
+ * cholmod_ptranspose		transpose/permute a sparse matrix
+ * cholmod_transpose_unsym	transpose/permute an unsymmetric sparse matrix
+ * cholmod_transpose_sym	transpose/permute a symmetric sparse matrix
+ * cholmod_sort			sort row indices in each column of sparse matrix
+ * cholmod_band			C = tril (triu (A,k1), k2)
+ * cholmod_band_inplace		A = tril (triu (A,k1), k2)
+ * cholmod_aat			C = A*A'
+ * cholmod_copy_sparse		C = A, create an exact copy of a sparse matrix
+ * cholmod_copy			C = A, with possible change of stype
+ * cholmod_add			C = alpha*A + beta*B
+ * cholmod_sparse_xtype		change the xtype of a sparse matrix
+ *
+ * ============================================================================
+ * === cholmod_factor =========================================================
+ * ============================================================================
+ *
+ * The data structure for an LL' or LDL' factorization is too complex to
+ * describe in one sentence.  This object can hold the symbolic analysis alone,
+ * or in combination with a "simplicial" (similar to a sparse matrix) or
+ * "supernodal" form of the numerical factorization.  Only the routine to free
+ * a factor is primary, since a factor object is created by the factorization
+ * routine (cholmod_factorize).  It must be freed with cholmod_free_factor.
+ *
+ * cholmod_free_factor		free a factor
+ * -----------------------------
+ * cholmod_allocate_factor	allocate a factor (LL' or LDL')
+ * cholmod_reallocate_factor	change the # entries in a factor
+ * cholmod_change_factor	change the type of factor (e.g., LDL' to LL')
+ * cholmod_pack_factor		pack the columns of a factor
+ * cholmod_reallocate_column	resize a single column of a factor
+ * cholmod_factor_to_sparse	create a sparse matrix copy of a factor
+ * cholmod_copy_factor		create a copy of a factor
+ * cholmod_factor_xtype		change the xtype of a factor
+ *
+ * Note that there is no cholmod_sparse_to_factor routine to create a factor
+ * as a copy of a sparse matrix.  It could be done, after a fashion, but a
+ * lower triangular sparse matrix would not necessarily have a chordal graph,
+ * which would break the many CHOLMOD routines that rely on this property.
+ *
+ * ============================================================================
+ * === cholmod_dense ==========================================================
+ * ============================================================================
+ *
+ * The solve routines and some of the MatrixOps and Modify routines use dense
+ * matrices as inputs.  These are held in column-major order.  With a leading
+ * dimension of d, the entry in row i and column j is held in x [i+j*d].
+ *
+ * cholmod_allocate_dense	allocate a dense matrix
+ * cholmod_free_dense		free a dense matrix
+ * -----------------------------
+ * cholmod_zeros		allocate a dense matrix of all zeros
+ * cholmod_ones			allocate a dense matrix of all ones
+ * cholmod_eye			allocate a dense identity matrix
+ * cholmod_sparse_to_dense	create a dense matrix copy of a sparse matrix
+ * cholmod_dense_to_sparse	create a sparse matrix copy of a dense matrix
+ * cholmod_copy_dense		create a copy of a dense matrix
+ * cholmod_copy_dense2		copy a dense matrix (pre-allocated)
+ * cholmod_dense_xtype		change the xtype of a dense matrix
+ *
+ * ============================================================================
+ * === cholmod_triplet ========================================================
+ * ============================================================================
+ *
+ * A sparse matrix held in triplet form is the simplest one for a user to
+ * create.  It consists of a list of nz entries in arbitrary order, held in
+ * three arrays: i, j, and x, each of length nk.  The kth entry is in row i[k],
+ * column j[k], with value x[k].  There may be duplicate values; if A(i,j)
+ * appears more than once, its value is the sum of the entries with those row
+ * and column indices.
+ *
+ * cholmod_allocate_triplet	allocate a triplet matrix
+ * cholmod_triplet_to_sparse	create a sparse matrix copy of a triplet matrix
+ * cholmod_free_triplet		free a triplet matrix
+ * -----------------------------
+ * cholmod_reallocate_triplet	change the # of entries in a triplet matrix
+ * cholmod_sparse_to_triplet	create a triplet matrix copy of a sparse matrix
+ * cholmod_copy_triplet		create a copy of a triplet matrix
+ * cholmod_triplet_xtype	change the xtype of a triplet matrix
+ *
+ * ============================================================================
+ * === memory management ======================================================
+ * ============================================================================
+ *
+ * cholmod_malloc		malloc wrapper
+ * cholmod_calloc		calloc wrapper
+ * cholmod_free			free wrapper
+ * cholmod_realloc		realloc wrapper
+ * cholmod_realloc_multiple	realloc wrapper for multiple objects
+ *
+ * ============================================================================
+ * === Core CHOLMOD prototypes ================================================
+ * ============================================================================
+ *
+ * All CHOLMOD routines (in all modules) use the following protocol for return
+ * values, with one exception:
+ *
+ * int			TRUE (1) if successful, or FALSE (0) otherwise.
+ *			(exception: cholmod_divcomplex)
+ * UF_long		a value >= 0 if successful, or -1 otherwise.
+ * double		a value >= 0 if successful, or -1 otherwise.
+ * size_t		a value > 0 if successful, or 0 otherwise.
+ * void *		a non-NULL pointer to newly allocated memory if
+ *			successful, or NULL otherwise.
+ * cholmod_sparse *	a non-NULL pointer to a newly allocated matrix
+ *			if successful, or NULL otherwise.
+ * cholmod_factor *	a non-NULL pointer to a newly allocated factor
+ *			if successful, or NULL otherwise.
+ * cholmod_triplet *	a non-NULL pointer to a newly allocated triplet
+ *			matrix if successful, or NULL otherwise.
+ * cholmod_dense *	a non-NULL pointer to a newly allocated triplet
+ *			matrix if successful, or NULL otherwise.
+ *
+ * The last parameter to all routines is always a pointer to the CHOLMOD
+ * Common object.
+ *
+ * TRUE and FALSE are not defined here, since they may conflict with the user
+ * program.  A routine that described here returning TRUE or FALSE returns 1
+ * or 0, respectively.  Any TRUE/FALSE parameter is true if nonzero, false if
+ * zero.
+ */
+
+#ifndef CHOLMOD_CORE_H
+#define CHOLMOD_CORE_H
+
+/* ========================================================================== */
+/* === CHOLMOD version ====================================================== */
+/* ========================================================================== */
+
+/* All versions of CHOLMOD will include the following definitions.
+ * As an example, to test if the version you are using is 1.3 or later:
+ *
+ *	if (CHOLMOD_VERSION >= CHOLMOD_VER_CODE (1,3)) ...
+ *
+ * This also works during compile-time:
+ *
+ *	#if CHOLMOD_VERSION >= CHOLMOD_VER_CODE (1,3)
+ *	    printf ("This is version 1.3 or later\n") ;
+ *	#else
+ *	    printf ("This is version is earlier than 1.3\n") ;
+ *	#endif
+ */
+
+#define CHOLMOD_DATE "Dec 12, 2006"
+#define CHOLMOD_VER_CODE(main,sub) ((main) * 1000 + (sub))
+#define CHOLMOD_MAIN_VERSION 1
+#define CHOLMOD_SUB_VERSION 4
+#define CHOLMOD_SUBSUB_VERSION 0
+#define CHOLMOD_VERSION \
+    CHOLMOD_VER_CODE(CHOLMOD_MAIN_VERSION,CHOLMOD_SUB_VERSION)
+
+
+/* ========================================================================== */
+/* === non-CHOLMOD include files ============================================ */
+/* ========================================================================== */
+
+/* This is the only non-CHOLMOD include file imposed on the user program.
+ * It required for size_t definition used here.  CHOLMOD itself includes other
+ * ANSI C89 standard #include files, but does not expose them to the user.
+ *
+ * CHOLMOD assumes that your C compiler is ANSI C89 compliant.  It does not make
+ * use of ANSI C99 features.
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+
+/* ========================================================================== */
+/* === CHOLMOD objects ====================================================== */
+/* ========================================================================== */
+
+/* Each CHOLMOD object has its own type code. */
+
+#define CHOLMOD_COMMON 0
+#define CHOLMOD_SPARSE 1
+#define CHOLMOD_FACTOR 2
+#define CHOLMOD_DENSE 3
+#define CHOLMOD_TRIPLET 4
+
+/* ========================================================================== */
+/* === CHOLMOD Common ======================================================= */
+/* ========================================================================== */
+
+/* itype defines the types of integer used: */
+#define CHOLMOD_INT 0		/* all integer arrays are int */
+#define CHOLMOD_INTLONG 1	/* most are int, some are UF_long */
+#define CHOLMOD_LONG 2		/* all integer arrays are UF_long */
+
+/* The itype of all parameters for all CHOLMOD routines must match.
+ * FUTURE WORK: CHOLMOD_INTLONG is not yet supported.
+ */
+
+/* dtype defines what the numerical type is (double or float): */
+#define CHOLMOD_DOUBLE 0	/* all numerical values are double */
+#define CHOLMOD_SINGLE 1	/* all numerical values are float */
+
+/* The dtype of all parameters for all CHOLMOD routines must match.
+ *
+ * Scalar floating-point values are always passed as double arrays of size 2
+ * (for the real and imaginary parts).  They are typecast to float as needed.
+ * FUTURE WORK: the float case is not supported yet.
+ */
+
+/* xtype defines the kind of numerical values used: */
+#define CHOLMOD_PATTERN 0	/* pattern only, no numerical values */
+#define CHOLMOD_REAL 1		/* a real matrix */
+#define CHOLMOD_COMPLEX 2	/* a complex matrix (ANSI C99 compatible) */
+#define CHOLMOD_ZOMPLEX 3	/* a complex matrix (MATLAB compatible) */
+
+/* The xtype of all parameters for all CHOLMOD routines must match.
+ *
+ * CHOLMOD_PATTERN: x and z are ignored.
+ * CHOLMOD_DOUBLE:  x is non-null of size nzmax, z is ignored.
+ * CHOLMOD_COMPLEX: x is non-null of size 2*nzmax doubles, z is ignored.
+ * CHOLMOD_ZOMPLEX: x and z are non-null of size nzmax
+ *
+ * In the real case, z is ignored.  The kth entry in the matrix is x [k].
+ * There are two methods for the complex case.  In the ANSI C99-compatible
+ * CHOLMOD_COMPLEX case, the real and imaginary parts of the kth entry
+ * are in x [2*k] and x [2*k+1], respectively.  z is ignored.  In the
+ * MATLAB-compatible CHOLMOD_ZOMPLEX case, the real and imaginary
+ * parts of the kth entry are in x [k] and z [k].
+ *
+ * Scalar floating-point values are always passed as double arrays of size 2
+ * (real and imaginary parts).  The imaginary part of a scalar is ignored if
+ * the routine operates on a real matrix.
+ *
+ * These Modules support complex and zomplex matrices, with a few exceptions:
+ *
+ *	Check	    all routines
+ *	Cholesky    all routines
+ *	Core	    all except cholmod_aat, add, band, copy
+ *	Demo	    all routines
+ *	Partition   all routines
+ *	Supernodal  all routines support any real, complex, or zomplex input.
+ *			There will never be a supernodal zomplex L; a complex
+ *			supernodal L is created if A is zomplex.
+ *	Tcov	    all routines
+ *	Valgrind    all routines
+ *
+ * These Modules provide partial support for complex and zomplex matrices:
+ *
+ *	MATLAB	    all routines support real and zomplex only, not complex,
+ *			with the exception of ldlupdate, which supports
+ *			real matrices only.  This is a minor constraint since
+ *			MATLAB's matrices are all real or zomplex.
+ *	MatrixOps   only norm_dense, norm_sparse, and sdmult support complex
+ *			and zomplex
+ *
+ * These Modules do not support complex and zomplex matrices at all:
+ *
+ *	Modify	    all routines support real matrices only
+ */
+
+/* Definitions for cholmod_common: */
+#define CHOLMOD_MAXMETHODS 9	/* maximum number of different methods that
+				 * cholmod_analyze can try. Must be >= 9. */
+
+/* Common->status values.  zero means success, negative means a fatal error,
+ * positive is a warning. */
+#define CHOLMOD_OK 0			/* success */
+#define CHOLMOD_NOT_INSTALLED (-1)	/* failure: method not installed */
+#define CHOLMOD_OUT_OF_MEMORY (-2)	/* failure: out of memory */
+#define CHOLMOD_TOO_LARGE (-3)		/* failure: integer overflow occured */
+#define CHOLMOD_INVALID (-4)		/* failure: invalid input */
+#define CHOLMOD_NOT_POSDEF (1)		/* warning: matrix not pos. def. */
+#define CHOLMOD_DSMALL (2)		/* warning: D for LDL'  or diag(L) or
+					 * LL' has tiny absolute value */
+
+/* ordering method (also used for L->ordering) */
+#define CHOLMOD_NATURAL 0	/* use natural ordering */
+#define CHOLMOD_GIVEN 1		/* use given permutation */
+#define CHOLMOD_AMD 2		/* use minimum degree (AMD) */
+#define CHOLMOD_METIS 3		/* use METIS' nested dissection */
+#define CHOLMOD_NESDIS 4	/* use CHOLMOD's version of nested dissection:
+				 * node bisector applied recursively, followed
+				 * by constrained minimum degree (CSYMAMD or
+				 * CCOLAMD) */
+#define CHOLMOD_COLAMD 5	/* use AMD for A, COLAMD for A*A' */
+
+/* POSTORDERED is not a method, but a result of natural ordering followed by a
+ * weighted postorder.  It is used for L->ordering, not method [ ].ordering. */
+#define CHOLMOD_POSTORDERED 6	/* natural ordering, postordered. */
+
+/* supernodal strategy (for Common->supernodal) */
+#define CHOLMOD_SIMPLICIAL 0	/* always do simplicial */
+#define CHOLMOD_AUTO 1		/* select simpl/super depending on matrix */
+#define CHOLMOD_SUPERNODAL 2	/* always do supernodal */
+
+typedef struct cholmod_common_struct
+{
+    /* ---------------------------------------------------------------------- */
+    /* parameters for symbolic/numeric factorization and update/downdate */
+    /* ---------------------------------------------------------------------- */
+
+    double dbound ;	/* Smallest absolute value of diagonal entries of D
+			 * for LDL' factorization and update/downdate/rowadd/
+	* rowdel, or the diagonal of L for an LL' factorization.
+	* Entries in the range 0 to dbound are replaced with dbound.
+	* Entries in the range -dbound to 0 are replaced with -dbound.  No
+	* changes are made to the diagonal if dbound <= 0.  Default: zero */
+
+    double grow0 ;	/* For a simplicial factorization, L->i and L->x can
+			 * grow if necessary.  grow0 is the factor by which
+	* it grows.  For the initial space, L is of size MAX (1,grow0) times
+	* the required space.  If L runs out of space, the new size of L is
+	* MAX(1.2,grow0) times the new required space.   If you do not plan on
+	* modifying the LDL' factorization in the Modify module, set grow0 to
+	* zero (or set grow2 to 0, see below).  Default: 1.2 */
+
+    double grow1 ;
+
+    size_t grow2 ;	/* For a simplicial factorization, each column j of L
+			 * is initialized with space equal to
+	* grow1*L->ColCount[j] + grow2.  If grow0 < 1, grow1 < 1, or grow2 == 0,
+	* then the space allocated is exactly equal to L->ColCount[j].  If the
+	* column j runs out of space, it increases to grow1*need + grow2 in
+	* size, where need is the total # of nonzeros in that column.  If you do
+	* not plan on modifying the factorization in the Modify module, set
+	* grow2 to zero.  Default: grow1 = 1.2, grow2 = 5. */
+
+    size_t maxrank ;	/* rank of maximum update/downdate.  Valid values:
+			 * 2, 4, or 8.  A value < 2 is set to 2, and a
+	* value > 8 is set to 8.  It is then rounded up to the next highest
+	* power of 2, if not already a power of 2.  Workspace (Xwork, below) of
+	* size nrow-by-maxrank double's is allocated for the update/downdate.
+	* If an update/downdate of rank-k is requested, with k > maxrank,
+	* it is done in steps of maxrank.  Default: 8, which is fastest.
+	* Memory usage can be reduced by setting maxrank to 2 or 4.
+	*/
+
+    double supernodal_switch ;	/* supernodal vs simplicial factorization */
+    int supernodal ;		/* If Common->supernodal <= CHOLMOD_SIMPLICIAL
+				 * (0) then cholmod_analyze performs a
+	* simplicial analysis.  If >= CHOLMOD_SUPERNODAL (2), then a supernodal
+	* analysis is performed.  If == CHOLMOD_AUTO (1) and
+	* flop/nnz(L) < Common->supernodal_switch, then a simplicial analysis
+	* is done.  A supernodal analysis done otherwise.
+	* Default:  CHOLMOD_AUTO.  Default supernodal_switch = 40 */
+
+    int final_asis ;	/* If TRUE, then ignore the other final_* parameters
+			 * (except for final_pack).
+			 * The factor is left as-is when done.  Default: TRUE.*/
+
+    int final_super ;	/* If TRUE, leave a factor in supernodal form when
+			 * supernodal factorization is finished.  If FALSE,
+			 * then convert to a simplicial factor when done.
+			 * Default: TRUE */
+
+    int final_ll ;	/* If TRUE, leave factor in LL' form when done.
+			 * Otherwise, leave in LDL' form.  Default: FALSE */
+
+    int final_pack ;	/* If TRUE, pack the columns when done.  If TRUE, and
+			 * cholmod_factorize is called with a symbolic L, L is
+	* allocated with exactly the space required, using L->ColCount.  If you
+	* plan on modifying the factorization, set Common->final_pack to FALSE,
+	* and each column will be given a little extra slack space for future
+	* growth in fill-in due to updates.  Default: TRUE */
+
+    int final_monotonic ;   /* If TRUE, ensure columns are monotonic when done.
+			 * Default: TRUE */
+
+    int final_resymbol ;/* if cholmod_factorize performed a supernodal
+			 * factorization, final_resymbol is true, and
+	* final_super is FALSE (convert a simplicial numeric factorization),
+	* then numerically zero entries that resulted from relaxed supernodal
+	* amalgamation are removed.  This does not remove entries that are zero
+	* due to exact numeric cancellation, since doing so would break the
+	* update/downdate rowadd/rowdel routines.  Default: FALSE. */
+
+    /* supernodal relaxed amalgamation parameters: */
+    double zrelax [3] ;
+    size_t nrelax [3] ;
+
+	/* Let ns be the total number of columns in two adjacent supernodes.
+	 * Let z be the fraction of zero entries in the two supernodes if they
+	 * are merged (z includes zero entries from prior amalgamations).  The
+	 * two supernodes are merged if:
+	 *    (ns <= nrelax [0]) || (no new zero entries added) ||
+	 *    (ns <= nrelax [1] && z < zrelax [0]) ||
+	 *    (ns <= nrelax [2] && z < zrelax [1]) || (z < zrelax [2])
+	 *
+	 * Default parameters result in the following rule:
+	 *    (ns <= 4) || (no new zero entries added) ||
+	 *    (ns <= 16 && z < 0.8) || (ns <= 48 && z < 0.1) || (z < 0.05)
+	 */
+
+    int prefer_zomplex ;    /* X = cholmod_solve (sys, L, B, Common) computes
+			     * x=A\b or solves a related system.  If L and B are
+	 * both real, then X is real.  Otherwise, X is returned as
+	 * CHOLMOD_COMPLEX if Common->prefer_zomplex is FALSE, or
+	 * CHOLMOD_ZOMPLEX if Common->prefer_zomplex is TRUE.  This parameter
+	 * is needed because there is no supernodal zomplex L.  Suppose the
+	 * caller wants all complex matrices to be stored in zomplex form
+	 * (MATLAB, for example).  A supernodal L is returned in complex form
+	 * if A is zomplex.  B can be real, and thus X = cholmod_solve (L,B)
+	 * should return X as zomplex.  This cannot be inferred from the input
+	 * arguments L and B.  Default: FALSE, since all data types are
+	 * supported in CHOLMOD_COMPLEX form and since this is the native type
+	 * of LAPACK and the BLAS.  Note that the MATLAB/cholmod.c mexFunction
+	 * sets this parameter to TRUE, since MATLAB matrices are in
+	 * CHOLMOD_ZOMPLEX form.
+	 */
+
+    int prefer_upper ;	    /* cholmod_analyze and cholmod_factorize work
+			     * fastest when a symmetric matrix is stored in
+	 * upper triangular form when a fill-reducing ordering is used.  In
+	 * MATLAB, this corresponds to how x=A\b works.  When the matrix is
+	 * ordered as-is, they work fastest when a symmetric matrix is in lower
+	 * triangular form.  In MATLAB, R=chol(A) does the opposite.  This
+	 * parameter affects only how cholmod_read returns a symmetric matrix.
+	 * If TRUE (the default case), a symmetric matrix is always returned in
+	 * upper-triangular form (A->stype = 1).  */
+
+    int quick_return_if_not_posdef ;	/* if TRUE, the supernodal numeric
+					 * factorization will return quickly if
+	* the matrix is not positive definite.  Default: FALSE. */
+
+    /* ---------------------------------------------------------------------- */
+    /* printing and error handling options */
+    /* ---------------------------------------------------------------------- */
+
+    int print ;		/* print level. Default: 3 */
+    int precise ;	/* if TRUE, print 16 digits.  Otherwise print 5 */
+    int (*print_function) (const char *, ...) ;	/* pointer to printf */
+
+    int try_catch ;	/* if TRUE, then ignore errors; CHOLMOD is in the middle
+			 * of a try/catch block.  No error message is printed
+	 * and the Common->error_handler function is not called. */
+
+    void (*error_handler) (int status, char *file, int line, char *message) ;
+
+	/* Common->error_handler is the user's error handling routine.  If not
+	 * NULL, this routine is called if an error occurs in CHOLMOD.  status
+	 * can be CHOLMOD_OK (0), negative for a fatal error, and positive for
+	 * a warning. file is a string containing the name of the source code
+	 * file where the error occured, and line is the line number in that
+	 * file.  message is a string describing the error in more detail. */
+
+    /* ---------------------------------------------------------------------- */
+    /* ordering options */
+    /* ---------------------------------------------------------------------- */
+
+    /* The cholmod_analyze routine can try many different orderings and select
+     * the best one.  It can also try one ordering method multiple times, with
+     * different parameter settings.  The default is to use three orderings,
+     * the user's permutation (if provided), AMD which is the fastest ordering
+     * and generally gives good fill-in, and METIS.  CHOLMOD's nested dissection
+     * (METIS with a constrained AMD) usually gives a better ordering than METIS
+     * alone (by about 5% to 10%) but it takes more time.
+     *
+     * If you know the method that is best for your matrix, set Common->nmethods
+     * to 1 and set Common->method [0] to the set of parameters for that method.
+     * If you set it to 1 and do not provide a permutation, then only AMD will
+     * be called.
+     *
+     * If METIS is not available, the default # of methods tried is 2 (the user
+     * permutation, if any, and AMD).
+     *
+     * To try other methods, set Common->nmethods to the number of methods you
+     * want to try.  The suite of default methods and their parameters is
+     * described in the cholmod_defaults routine, and summarized here:
+     *
+     *	    Common->method [i]:
+     *	    i = 0: user-provided ordering (cholmod_analyze_p only)
+     *	    i = 1: AMD (for both A and A*A')
+     *	    i = 2: METIS
+     *	    i = 3: CHOLMOD's nested dissection (NESDIS), default parameters
+     *	    i = 4: natural
+     *	    i = 5: NESDIS with nd_small = 20000
+     *	    i = 6: NESDIS with nd_small = 4, no constrained minimum degree
+     *	    i = 7: NESDIS with no dense node removal
+     *	    i = 8: AMD for A, COLAMD for A*A'
+     *
+     * You can modify the suite of methods you wish to try by modifying
+     * Common.method [...] after calling cholmod_start or cholmod_defaults.
+     *
+     * For example, to use AMD, followed by a weighted postordering:
+     *
+     *	    Common->nmethods = 1 ;
+     *	    Common->method [0].ordering = CHOLMOD_AMD ;
+     *	    Common->postorder = TRUE ;
+     *
+     * To use the natural ordering (with no postordering):
+     *
+     *	    Common->nmethods = 1 ;
+     *	    Common->method [0].ordering = CHOLMOD_NATURAL ;
+     *	    Common->postorder = FALSE ;
+     *
+     * If you are going to factorize hundreds or more matrices with the same
+     * nonzero pattern, you may wish to spend a great deal of time finding a
+     * good permutation.  In this case, try setting Common->nmethods to 9.
+     * The time spent in cholmod_analysis will be very high, but you need to
+     * call it only once.
+     *
+     * cholmod_analyze sets Common->current to a value between 0 and nmethods-1.
+     * Each ordering method uses the set of options defined by this parameter.
+     */
+
+    int nmethods ;	/* The number of ordering methods to try.  Default: 0.
+			 * nmethods = 0 is a special case.  cholmod_analyze
+	* will try the user-provided ordering (if given) and AMD.  Let fl and
+	* lnz be the flop count and nonzeros in L from AMD's ordering.  Let
+	* anz be the number of nonzeros in the upper or lower triangular part
+	* of the symmetric matrix A.  If fl/lnz < 500 or lnz/anz < 5, then this
+	* is a good ordering, and METIS is not attempted.  Otherwise, METIS is
+	* tried.   The best ordering found is used.  If nmethods > 0, the
+	* methods used are given in the method[ ] array, below.  The first
+	* three methods in the default suite of orderings is (1) use the given
+	* permutation (if provided), (2) use AMD, and (3) use METIS.  Maximum
+	* allowed value is CHOLMOD_MAXMETHODS.  */
+
+    int current ;	/* The current method being tried.  Default: 0.  Valid
+			 * range is 0 to nmethods-1. */
+
+    int selected ;	/* The best method found. */
+
+    /* The suite of ordering methods and parameters: */
+
+    struct cholmod_method_struct
+    {
+	/* statistics for this method */
+	double lnz ;	    /* nnz(L) excl. zeros from supernodal amalgamation,
+			     * for a "pure" L */
+
+	double fl ;	    /* flop count for a "pure", real simplicial LL'
+			     * factorization, with no extra work due to
+	    * amalgamation.  Subtract n to get the LDL' flop count.   Multiply
+	    * by about 4 if the matrix is complex or zomplex. */
+
+	/* ordering method parameters */
+	double prune_dense ;/* dense row/col control for AMD, SYMAMD, CSYMAMD,
+			     * and NESDIS (cholmod_nested_dissection).  For a
+	    * symmetric n-by-n matrix, rows/columns with more than
+	    * MAX (16, prune_dense * sqrt (n)) entries are removed prior to
+	    * ordering.  They appear at the end of the re-ordered matrix.
+	    *
+	    * If prune_dense < 0, only completely dense rows/cols are removed.
+	    *
+	    * This paramater is also the dense column control for COLAMD and
+	    * CCOLAMD.  For an m-by-n matrix, columns with more than
+	    * MAX (16, prune_dense * sqrt (MIN (m,n))) entries are removed prior
+	    * to ordering.  They appear at the end of the re-ordered matrix.
+	    * CHOLMOD factorizes A*A', so it calls COLAMD and CCOLAMD with A',
+	    * not A.  Thus, this parameter affects the dense *row* control for
+	    * CHOLMOD's matrix, and the dense *column* control for COLAMD and
+	    * CCOLAMD.
+	    *
+	    * Removing dense rows and columns improves the run-time of the
+	    * ordering methods.  It has some impact on ordering quality
+	    * (usually minimal, sometimes good, sometimes bad).
+	    *
+	    * Default: 10. */
+
+	double prune_dense2 ;/* dense row control for COLAMD and CCOLAMD.
+			    *  Rows with more than MAX (16, dense2 * sqrt (n))
+	    * for an m-by-n matrix are removed prior to ordering.  CHOLMOD's
+	    * matrix is transposed before ordering it with COLAMD or CCOLAMD,
+	    * so this controls the dense *columns* of CHOLMOD's matrix, and
+	    * the dense *rows* of COLAMD's or CCOLAMD's matrix.
+	    *
+	    * If prune_dense2 < 0, only completely dense rows/cols are removed.
+	    *
+	    * Default: -1.  Note that this is not the default for COLAMD and
+	    * CCOLAMD.  -1 is best for Cholesky.  10 is best for LU.  */
+
+	double nd_oksep ;   /* in NESDIS, when a node separator is computed, it
+			     * discarded if nsep >= nd_oksep*n, where nsep is
+	    * the number of nodes in the separator, and n is the size of the
+	    * graph being cut.  Valid range is 0 to 1.  If 1 or greater, the
+	    * separator is discarded if it consists of the entire graph.
+	    * Default: 1 */
+
+	double other1 [4] ; /* future expansion */
+
+	size_t nd_small ;    /* do not partition graphs with fewer nodes than
+			     * nd_small, in NESDIS.  Default: 200 (same as
+			     * METIS) */
+
+	size_t other2 [4] ; /* future expansion */
+
+	int aggressive ;    /* Aggresive absorption in AMD, COLAMD, SYMAMD,
+			     * CCOLAMD, and CSYMAMD.  Default: TRUE */
+
+	int order_for_lu ;  /* CCOLAMD can be optimized to produce an ordering
+			     * for LU or Cholesky factorization.  CHOLMOD only
+	    * performs a Cholesky factorization.  However, you may wish to use
+	    * CHOLMOD as an interface for CCOLAMD but use it for your own LU
+	    * factorization.  In this case, order_for_lu should be set to FALSE.
+	    * When factorizing in CHOLMOD itself, you should *** NEVER *** set
+	    * this parameter FALSE.  Default: TRUE. */
+
+	int nd_compress ;   /* If TRUE, compress the graph and subgraphs before
+			     * partitioning them in NESDIS.  Default: TRUE */
+
+	int nd_camd ;	    /* If 1, follow the nested dissection ordering
+			     * with a constrained minimum degree ordering that
+	    * respects the partitioning just found (using CAMD).  If 2, use
+	    * CSYMAMD instead.  If you set nd_small very small, you may not need
+	    * this ordering, and can save time by setting it to zero (no
+	    * constrained minimum degree ordering).  Default: 1. */
+
+	int nd_components ; /* The nested dissection ordering finds a node
+			     * separator that splits the graph into two parts,
+	    * which may be unconnected.  If nd_components is TRUE, each of
+	    * these connected components is split independently.  If FALSE,
+	    * each part is split as a whole, even if it consists of more than
+	    * one connected component.  Default: FALSE */
+
+	/* fill-reducing ordering to use */
+	int ordering ;
+
+	size_t other3 [4] ; /* future expansion */
+
+    } method [CHOLMOD_MAXMETHODS + 1] ;
+
+    int postorder ;	/* If TRUE, cholmod_analyze follows the ordering with a
+			 * weighted postorder of the elimination tree.  Improves
+	* supernode amalgamation.  Does not affect fundamental nnz(L) and
+	* flop count.  Default: TRUE. */
+
+    /* ---------------------------------------------------------------------- */
+    /* memory management routines */
+    /* ---------------------------------------------------------------------- */
+
+    void *(*malloc_memory) (size_t) ;		/* pointer to malloc */
+    void *(*realloc_memory) (void *, size_t) ;  /* pointer to realloc */
+    void (*free_memory) (void *) ;		/* pointer to free */
+    void *(*calloc_memory) (size_t, size_t) ;	/* pointer to calloc */
+
+    /* ---------------------------------------------------------------------- */
+    /* routines for complex arithmetic */
+    /* ---------------------------------------------------------------------- */
+
+    int (*complex_divide) (double ax, double az, double bx, double bz,
+	    double *cx, double *cz) ;
+
+	/* flag = complex_divide (ax, az, bx, bz, &cx, &cz) computes the complex
+	 * division c = a/b, where ax and az hold the real and imaginary part
+	 * of a, and b and c are stored similarly.  flag is returned as 1 if
+	 * a divide-by-zero occurs, or 0 otherwise.  By default, the function
+	 * pointer Common->complex_divide is set equal to cholmod_divcomplex.
+	 */
+
+    double (*hypotenuse) (double x, double y) ;
+
+	/* s = hypotenuse (x,y) computes s = sqrt (x*x + y*y), but does so more
+	 * accurately.  By default, the function pointer Common->hypotenuse is
+	 * set equal to cholmod_hypot.  See also the hypot function in the C99
+	 * standard, which has an identical syntax and function.  If you have
+	 * a C99-compliant compiler, you can set Common->hypotenuse = hypot.  */
+
+    /* ---------------------------------------------------------------------- */
+    /* METIS workarounds */
+    /* ---------------------------------------------------------------------- */
+
+    double metis_memory ;   /* This is a parameter for CHOLMOD's interface to
+			     * METIS, not a parameter to METIS itself.  METIS
+	* uses an amount of memory that is difficult to estimate precisely
+	* beforehand.  If it runs out of memory, it terminates your program.
+	* All routines in CHOLMOD except for CHOLMOD's interface to METIS
+	* return an error status and safely return to your program if they run
+	* out of memory.  To mitigate this problem, the CHOLMOD interface
+	* can allocate a single block of memory equal in size to an empirical
+	* upper bound of METIS's memory usage times the Common->metis_memory
+	* parameter, and then immediately free it.  It then calls METIS.  If
+	* this pre-allocation fails, it is possible that METIS will fail as
+	* well, and so CHOLMOD returns with an out-of-memory condition without
+	* calling METIS.
+	*
+	* METIS_NodeND (used in the CHOLMOD_METIS ordering option) with its
+	* default parameter settings typically uses about (4*nz+40n+4096)
+	* times sizeof(int) memory, where nz is equal to the number of entries
+	* in A for the symmetric case or AA' if an unsymmetric matrix is
+	* being ordered (where nz includes both the upper and lower parts
+	* of A or AA').  The observed "upper bound" (with 2 exceptions),
+	* measured in an instrumented copy of METIS 4.0.1 on thousands of
+	* matrices, is (10*nz+50*n+4096) * sizeof(int).  Two large matrices
+	* exceeded this bound, one by almost a factor of 2 (Gupta/gupta2).
+	*
+	* If your program is terminated by METIS, try setting metis_memory to
+	* 2.0, or even higher if needed.  By default, CHOLMOD assumes that METIS
+	* does not have this problem (so that CHOLMOD will work correctly when
+	* this issue is fixed in METIS).  Thus, the default value is zero.
+	* This work-around is not guaranteed anyway.
+	*
+	* If a matrix exceeds this predicted memory usage, AMD is attempted
+	* instead.  It, too, may run out of memory, but if it does so it will
+	* not terminate your program.
+	*/
+
+    double metis_dswitch ;	/* METIS_NodeND in METIS 4.0.1 gives a seg */
+    size_t metis_nswitch ;	/* fault with one matrix of order n = 3005 and
+				 * nz = 6,036,025.  This is a very dense graph.
+     * The workaround is to use AMD instead of METIS for matrices of dimension
+     * greater than Common->metis_nswitch (default 3000) or more and with
+     * density of Common->metis_dswitch (default 0.66) or more.
+     * cholmod_nested_dissection has no problems with the same matrix, even
+     * though it uses METIS_NodeComputeSeparator on this matrix.  If this
+     * seg fault does not affect you, set metis_nswitch to zero or less,
+     * and CHOLMOD will not switch to AMD based just on the density of the
+     * matrix (it will still switch to AMD if the metis_memory parameter
+     * causes the switch).
+     */
+
+    /* ---------------------------------------------------------------------- */
+    /* workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* CHOLMOD has several routines that take less time than the size of
+     * workspace they require.  Allocating and initializing the workspace would
+     * dominate the run time, unless workspace is allocated and initialized
+     * just once.  CHOLMOD allocates this space when needed, and holds it here
+     * between calls to CHOLMOD.  cholmod_start sets these pointers to NULL
+     * (which is why it must be the first routine called in CHOLMOD).
+     * cholmod_finish frees the workspace (which is why it must be the last
+     * call to CHOLMOD).
+     */
+
+    size_t nrow ;	/* size of Flag and Head */
+    UF_long mark ;	/* mark value for Flag array */
+    size_t iworksize ;	/* size of Iwork.  Upper bound: 6*nrow+ncol */
+    size_t xworksize ;	/* size of Xwork,  in bytes.
+			 * maxrank*nrow*sizeof(double) for update/downdate.
+			 * 2*nrow*sizeof(double) otherwise */
+
+    /* initialized workspace: contents needed between calls to CHOLMOD */
+    void *Flag ;	/* size nrow, an integer array.  Kept cleared between
+			 * calls to cholmod rouines (Flag [i] < mark) */
+
+    void *Head ;	/* size nrow+1, an integer array. Kept cleared between
+			 * calls to cholmod routines (Head [i] = EMPTY) */
+
+    void *Xwork ; 	/* a double array.  Its size varies.  It is nrow for
+			 * most routines (cholmod_rowfac, cholmod_add,
+	* cholmod_aat, cholmod_norm, cholmod_ssmult) for the real case, twice
+	* that when the input matrices are complex or zomplex.  It is of size
+	* 2*nrow for cholmod_rowadd and cholmod_rowdel.  For cholmod_updown,
+	* its size is maxrank*nrow where maxrank is 2, 4, or 8.  Kept cleared
+	* between calls to cholmod (set to zero). */
+
+    /* uninitialized workspace, contents not needed between calls to CHOLMOD */
+    void *Iwork ;	/* size iworksize, 2*nrow+ncol for most routines,
+			 * up to 6*nrow+ncol for cholmod_analyze. */
+
+    int itype ;		/* If CHOLMOD_LONG, Flag, Head, and Iwork are UF_long.
+			 * Otherwise all three arrays are int. */
+
+    int dtype ;		/* double or float */
+
+	/* Common->itype and Common->dtype are used to define the types of all
+	 * sparse matrices, triplet matrices, dense matrices, and factors
+	 * created using this Common struct.  The itypes and dtypes of all
+	 * parameters to all CHOLMOD routines must match.  */
+
+    int no_workspace_reallocate ;   /* this is an internal flag, used as a
+	* precaution by cholmod_analyze.  It is normally false.  If true,
+	* cholmod_allocate_work is not allowed to reallocate any workspace;
+	* they must use the existing workspace in Common (Iwork, Flag, Head,
+	* and Xwork).  Added for CHOLMOD v1.1 */
+
+    /* ---------------------------------------------------------------------- */
+    /* statistics */
+    /* ---------------------------------------------------------------------- */
+
+    /* fl and lnz are set only in cholmod_analyze and cholmod_rowcolcounts,
+     * in the Cholesky modudle.  modfl is set only in the Modify module. */
+
+    int status ;	    /* error code */
+    double fl ;		    /* LL' flop count from most recent analysis */
+    double lnz ;	    /* fundamental nz in L */
+    double anz ;	    /* nonzeros in tril(A) if A is symmetric/lower,
+			     * triu(A) if symmetric/upper, or tril(A*A') if
+			     * unsymmetric, in last call to cholmod_analyze. */
+    double modfl ;	    /* flop count from most recent update/downdate/
+			     * rowadd/rowdel (excluding flops to modify the
+			     * solution to Lx=b, if computed) */
+    size_t malloc_count ;   /* # of objects malloc'ed minus the # free'd*/
+    size_t memory_usage ;   /* peak memory usage in bytes */
+    size_t memory_inuse ;   /* current memory usage in bytes */
+
+    double nrealloc_col ;   /* # of column reallocations */
+    double nrealloc_factor ;/* # of factor reallocations due to col. reallocs */
+    double ndbounds_hit ;   /* # of times diagonal modified by dbound */
+
+    double rowfacfl ;	    /* # of flops in last call to cholmod_rowfac */
+    double aatfl ;	    /* # of flops to compute A(:,f)*A(:,f)' */
+
+    /* ---------------------------------------------------------------------- */
+    /* future expansion */
+    /* ---------------------------------------------------------------------- */
+
+    /* To allow CHOLMOD to be updated without recompiling the user application,
+     * additional space is set aside here for future statistics, parameters,
+     * and workspace.  Note:  additional entries were added in v1.1 to the
+     * method array, above, and thus v1.0 and v1.1 are not binary compatible.
+     *
+     * v1.1 to the current version are binary compatible.
+     */
+
+    double  other1 [16] ;
+    UF_long other2 [16] ;
+    int     other3 [13] ;   /* reduced from size 16 in v1.1. */
+
+    int prefer_binary ;	    /* cholmod_read_triplet converts a symmetric
+			     * pattern-only matrix into a real matrix.  If
+	* prefer_binary is FALSE, the diagonal entries are set to 1 + the degree
+	* of the row/column, and off-diagonal entries are set to -1 (resulting
+	* in a positive definite matrix if the diagonal is zero-free).  Most
+	* symmetric patterns are the pattern a positive definite matrix.  If
+	* this parameter is TRUE, then the matrix is returned with a 1 in each
+	* entry, instead.  Default: FALSE.  Added in v1.3. */
+
+    /* control parameter (added for v1.2): */
+    int default_nesdis ;    /* Default: FALSE.  If FALSE, then the default
+			     * ordering strategy (when Common->nmethods == 0)
+	* is to try the given ordering (if present), AMD, and then METIS if AMD
+	* reports high fill-in.  If Common->default_nesdis is TRUE then NESDIS
+	* is used instead in the default strategy. */
+
+    /* statistic (added for v1.2): */
+    int called_nd ;	    /* TRUE if the last call to
+			     * cholmod_analyze called NESDIS or METIS. */
+
+    size_t  other4 [16] ;
+    void   *other5 [16] ;
+
+} cholmod_common ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_start:  first call to CHOLMOD */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_start
+(
+    cholmod_common *Common
+) ;
+
+int cholmod_l_start (cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_finish:  last call to CHOLMOD */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_finish
+(
+    cholmod_common *Common
+) ;
+
+int cholmod_l_finish (cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_defaults:  restore default parameters */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_defaults
+(
+    cholmod_common *Common
+) ;
+
+int cholmod_l_defaults (cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_maxrank:  return valid maximum rank for update/downdate */
+/* -------------------------------------------------------------------------- */
+
+size_t cholmod_maxrank	/* returns validated value of Common->maxrank */
+(
+    /* ---- input ---- */
+    size_t n,		/* A and L will have n rows */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+size_t cholmod_l_maxrank (size_t, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_allocate_work:  allocate workspace in Common */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_allocate_work
+(
+    /* ---- input ---- */
+    size_t nrow,	/* size: Common->Flag (nrow), Common->Head (nrow+1) */
+    size_t iworksize,	/* size of Common->Iwork */
+    size_t xworksize,	/* size of Common->Xwork */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_allocate_work (size_t, size_t, size_t, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_free_work:  free workspace in Common */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_free_work
+(
+    cholmod_common *Common
+) ;
+
+int cholmod_l_free_work (cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_clear_flag:  clear Flag workspace in Common */
+/* -------------------------------------------------------------------------- */
+
+UF_long cholmod_clear_flag
+(
+    cholmod_common *Common
+) ;
+
+UF_long cholmod_l_clear_flag (cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_error:  called when CHOLMOD encounters an error */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_error
+(
+    /* ---- input ---- */
+    int status,		/* error status */
+    char *file,		/* name of source code file where error occured */
+    int line,		/* line number in source code file where error occured*/
+    char *message,	/* error message */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_error (int, char *, int, char *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_dbound:  for internal use in CHOLMOD only */
+/* -------------------------------------------------------------------------- */
+
+double cholmod_dbound	/* returns modified diagonal entry of D or L */
+(
+    /* ---- input ---- */
+    double dj,		/* diagonal entry of D for LDL' or L for LL' */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+double cholmod_l_dbound (double, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_hypot:  compute sqrt (x*x + y*y) accurately */
+/* -------------------------------------------------------------------------- */
+
+double cholmod_hypot
+(
+    /* ---- input ---- */
+    double x, double y
+) ;
+
+double cholmod_l_hypot (double, double) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_divcomplex:  complex division, c = a/b */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_divcomplex		/* return 1 if divide-by-zero, 0 otherise */
+(
+    /* ---- input ---- */
+    double ar, double ai,	/* real and imaginary parts of a */
+    double br, double bi,	/* real and imaginary parts of b */
+    /* ---- output --- */
+    double *cr, double *ci	/* real and imaginary parts of c */
+) ;
+
+int cholmod_l_divcomplex (double, double, double, double, double *, double *) ;
+
+
+/* ========================================================================== */
+/* === Core/cholmod_sparse ================================================== */
+/* ========================================================================== */
+
+/* A sparse matrix stored in compressed-column form. */
+
+typedef struct cholmod_sparse_struct
+{
+    size_t nrow ;	/* the matrix is nrow-by-ncol */
+    size_t ncol ;
+    size_t nzmax ;	/* maximum number of entries in the matrix */
+
+    /* pointers to int or UF_long: */
+    void *p ;		/* p [0..ncol], the column pointers */
+    void *i ;		/* i [0..nzmax-1], the row indices */
+
+    /* for unpacked matrices only: */
+    void *nz ;		/* nz [0..ncol-1], the # of nonzeros in each col.  In
+			 * packed form, the nonzero pattern of column j is in
+	* A->i [A->p [j] ... A->p [j+1]-1].  In unpacked form, column j is in
+	* A->i [A->p [j] ... A->p [j]+A->nz[j]-1] instead.  In both cases, the
+	* numerical values (if present) are in the corresponding locations in
+	* the array x (or z if A->xtype is CHOLMOD_ZOMPLEX). */
+
+    /* pointers to double or float: */
+    void *x ;		/* size nzmax or 2*nzmax, if present */
+    void *z ;		/* size nzmax, if present */
+
+    int stype ;		/* Describes what parts of the matrix are considered:
+			 *
+	* 0:  matrix is "unsymmetric": use both upper and lower triangular parts
+	*     (the matrix may actually be symmetric in pattern and value, but
+	*     both parts are explicitly stored and used).  May be square or
+	*     rectangular.
+	* >0: matrix is square and symmetric, use upper triangular part.
+	*     Entries in the lower triangular part are ignored.
+	* <0: matrix is square and symmetric, use lower triangular part.
+	*     Entries in the upper triangular part are ignored.
+	*
+	* Note that stype>0 and stype<0 are different for cholmod_sparse and
+	* cholmod_triplet.  See the cholmod_triplet data structure for more
+	* details.
+	*/
+
+    int itype ;		/* CHOLMOD_INT:     p, i, and nz are int.
+			 * CHOLMOD_INTLONG: p is UF_long, i and nz are int.
+			 * CHOLMOD_LONG:    p, i, and nz are UF_long.  */
+
+    int xtype ;		/* pattern, real, complex, or zomplex */
+    int dtype ;		/* x and z are double or float */
+    int sorted ;	/* TRUE if columns are sorted, FALSE otherwise */
+    int packed ;	/* TRUE if packed (nz ignored), FALSE if unpacked
+			 * (nz is required) */
+
+} cholmod_sparse ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_allocate_sparse:  allocate a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_allocate_sparse
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of A */
+    size_t ncol,	/* # of columns of A */
+    size_t nzmax,	/* max # of nonzeros of A */
+    int sorted,		/* TRUE if columns of A sorted, FALSE otherwise */
+    int packed,		/* TRUE if A will be packed, FALSE otherwise */
+    int stype,		/* stype of A */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_allocate_sparse (size_t, size_t, size_t, int, int,
+    int, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_free_sparse:  free a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_free_sparse
+(
+    /* ---- in/out --- */
+    cholmod_sparse **A,	/* matrix to deallocate, NULL on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_free_sparse (cholmod_sparse **, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_reallocate_sparse:  change the size (# entries) of sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_reallocate_sparse
+(
+    /* ---- input ---- */
+    size_t nznew,	/* new # of entries in A */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix to reallocate */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_reallocate_sparse ( size_t, cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_nnz:  return number of nonzeros in a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+UF_long cholmod_nnz
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+UF_long cholmod_l_nnz (cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_speye:  sparse identity matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_speye
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of A */
+    size_t ncol,	/* # of columns of A */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_speye (size_t, size_t, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_spzeros:  sparse zero matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_spzeros
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of A */
+    size_t ncol,	/* # of columns of A */
+    size_t nzmax,	/* max # of nonzeros of A */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_spzeros (size_t, size_t, size_t, int,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_transpose:  transpose a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+/* Return A' or A.'  The "values" parameter is 0, 1, or 2 to denote the pattern
+ * transpose, the array transpose (A.'), and the complex conjugate transpose
+ * (A').
+ */
+
+cholmod_sparse *cholmod_transpose
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    int values,		/* 0: pattern, 1: array transpose, 2: conj. transpose */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_transpose (cholmod_sparse *, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_transpose_unsym:  transpose an unsymmetric sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+/* Compute F = A', A (:,f)', or A (p,f)', where A is unsymmetric and F is
+ * already allocated.  See cholmod_transpose for a simpler routine. */
+
+int cholmod_transpose_unsym
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    int values,		/* 0: pattern, 1: array transpose, 2: conj. transpose */
+    int *Perm,		/* size nrow, if present (can be NULL) */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- output --- */
+    cholmod_sparse *F,	/* F = A', A(:,f)', or A(p,f)' */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_transpose_unsym (cholmod_sparse *, int, UF_long *, UF_long *,
+    size_t, cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_transpose_sym:  transpose a symmetric sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+/* Compute F = A' or A (p,p)', where A is symmetric and F is already allocated.
+ * See cholmod_transpose for a simpler routine. */
+
+int cholmod_transpose_sym
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    int values,		/* 0: pattern, 1: array transpose, 2: conj. transpose */
+    int *Perm,		/* size nrow, if present (can be NULL) */
+    /* ---- output --- */
+    cholmod_sparse *F,	/* F = A' or A(p,p)' */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_transpose_sym (cholmod_sparse *, int, UF_long *, cholmod_sparse *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_ptranspose:  transpose a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+/* Return A' or A(p,p)' if A is symmetric.  Return A', A(:,f)', or A(p,f)' if
+ * A is unsymmetric. */
+
+cholmod_sparse *cholmod_ptranspose
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    int values,		/* 0: pattern, 1: array transpose, 2: conj. transpose */
+    int *Perm,		/* if non-NULL, F = A(p,f) or A(p,p) */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_ptranspose (cholmod_sparse *, int, UF_long *,
+    UF_long *, size_t, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_sort:  sort row indices in each column of sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_sort
+(
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix to sort */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_sort (cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_band:  C = tril (triu (A,k1), k2) */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_band
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to extract band matrix from */
+    UF_long k1,		/* ignore entries below the k1-st diagonal */
+    UF_long k2,		/* ignore entries above the k2-nd diagonal */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag) */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_band (cholmod_sparse *, UF_long, UF_long, int,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_band_inplace:  A = tril (triu (A,k1), k2) */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_band_inplace
+(
+    /* ---- input ---- */
+    UF_long k1,		/* ignore entries below the k1-st diagonal */
+    UF_long k2,		/* ignore entries above the k2-nd diagonal */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag) */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix from which entries not in band are removed */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_band_inplace (UF_long, UF_long, int, cholmod_sparse *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_aat:  C = A*A' or A(:,f)*A(:,f)' */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_aat
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* input matrix; C=A*A' is constructed */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag),
+			 * -2: pattern only, no diagonal, add 50%+n extra
+			 * space to C */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_aat (cholmod_sparse *, UF_long *, size_t, int,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_copy_sparse:  C = A, create an exact copy of a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_copy_sparse
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_copy_sparse (cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_copy:  C = A, with possible change of stype */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_copy 
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    int stype,		/* requested stype of C */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag) */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_copy (cholmod_sparse *, int, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_add: C = alpha*A + beta*B */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_add
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	    /* matrix to add */
+    cholmod_sparse *B,	    /* matrix to add */
+    double alpha [2],	    /* scale factor for A */
+    double beta [2],	    /* scale factor for B */
+    int values,		    /* if TRUE compute the numerical values of C */
+    int sorted,		    /* if TRUE, sort columns of C */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_add (cholmod_sparse *, cholmod_sparse *, double *,
+    double *, int, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_sparse_xtype: change the xtype of a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_sparse_xtype
+(
+    /* ---- input ---- */
+    int to_xtype,	/* requested xtype (pattern, real, complex, zomplex) */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* sparse matrix to change */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_sparse_xtype (int, cholmod_sparse *, cholmod_common *) ;
+
+
+/* ========================================================================== */
+/* === Core/cholmod_factor ================================================== */
+/* ========================================================================== */
+
+/* A symbolic and numeric factorization, either simplicial or supernodal.
+ * In all cases, the row indices in the columns of L are kept sorted. */
+
+typedef struct cholmod_factor_struct
+{
+    /* ---------------------------------------------------------------------- */
+    /* for both simplicial and supernodal factorizations */
+    /* ---------------------------------------------------------------------- */
+
+    size_t n ;		/* L is n-by-n */
+
+    size_t minor ;	/* If the factorization failed, L->minor is the column
+			 * at which it failed (in the range 0 to n-1).  A value
+			 * of n means the factorization was successful or
+			 * the matrix has not yet been factorized. */
+
+    /* ---------------------------------------------------------------------- */
+    /* symbolic ordering and analysis */
+    /* ---------------------------------------------------------------------- */
+
+    void *Perm ;	/* size n, permutation used */
+    void *ColCount ;	/* size n, column counts for simplicial L */
+
+    /* ---------------------------------------------------------------------- */
+    /* simplicial factorization */
+    /* ---------------------------------------------------------------------- */
+
+    size_t nzmax ;	/* size of i and x */
+
+    void *p ;		/* p [0..ncol], the column pointers */
+    void *i ;		/* i [0..nzmax-1], the row indices */
+    void *x ;		/* x [0..nzmax-1], the numerical values */
+    void *z ;
+    void *nz ;		/* nz [0..ncol-1], the # of nonzeros in each column.
+			 * i [p [j] ... p [j]+nz[j]-1] contains the row indices,
+			 * and the numerical values are in the same locatins
+			 * in x. The value of i [p [k]] is always k. */
+
+    void *next ;	/* size ncol+2. next [j] is the next column in i/x */
+    void *prev ;	/* size ncol+2. prev [j] is the prior column in i/x.
+			 * head of the list is ncol+1, and the tail is ncol. */
+
+    /* ---------------------------------------------------------------------- */
+    /* supernodal factorization */
+    /* ---------------------------------------------------------------------- */
+
+    /* Note that L->x is shared with the simplicial data structure.  L->x has
+     * size L->nzmax for a simplicial factor, and size L->xsize for a supernodal
+     * factor. */
+
+    size_t nsuper ;	/* number of supernodes */
+    size_t ssize ;	/* size of s, integer part of supernodes */
+    size_t xsize ;	/* size of x, real part of supernodes */
+    size_t maxcsize ;	/* size of largest update matrix */
+    size_t maxesize ;	/* max # of rows in supernodes, excl. triangular part */
+
+    void *super ;	/* size nsuper+1, first col in each supernode */
+    void *pi ;		/* size nsuper+1, pointers to integer patterns */
+    void *px ;		/* size nsuper+1, pointers to real parts */
+    void *s ;		/* size ssize, integer part of supernodes */
+
+    /* ---------------------------------------------------------------------- */
+    /* factorization type */
+    /* ---------------------------------------------------------------------- */
+
+    int ordering ;	/* ordering method used */
+
+    int is_ll ;		/* TRUE if LL', FALSE if LDL' */
+    int is_super ;	/* TRUE if supernodal, FALSE if simplicial */
+    int is_monotonic ;	/* TRUE if columns of L appear in order 0..n-1.
+			 * Only applicable to simplicial numeric types. */
+
+    /* There are 8 types of factor objects that cholmod_factor can represent
+     * (only 6 are used):
+     *
+     * Numeric types (xtype is not CHOLMOD_PATTERN)
+     * --------------------------------------------
+     *
+     * simplicial LDL':  (is_ll FALSE, is_super FALSE).  Stored in compressed
+     *	    column form, using the simplicial components above (nzmax, p, i,
+     *	    x, z, nz, next, and prev).  The unit diagonal of L is not stored,
+     *	    and D is stored in its place.  There are no supernodes.
+     *
+     * simplicial LL': (is_ll TRUE, is_super FALSE).  Uses the same storage
+     *	    scheme as the simplicial LDL', except that D does not appear.
+     *	    The first entry of each column of L is the diagonal entry of
+     *	    that column of L.
+     *
+     * supernodal LDL': (is_ll FALSE, is_super TRUE).  Not used.
+     *	    FUTURE WORK:  add support for supernodal LDL'
+     *
+     * supernodal LL': (is_ll TRUE, is_super TRUE).  A supernodal factor,
+     *	    using the supernodal components described above (nsuper, ssize,
+     *	    xsize, maxcsize, maxesize, super, pi, px, s, x, and z).
+     *
+     *
+     * Symbolic types (xtype is CHOLMOD_PATTERN)
+     * -----------------------------------------
+     *
+     * simplicial LDL': (is_ll FALSE, is_super FALSE).  Nothing is present
+     *	    except Perm and ColCount.
+     *
+     * simplicial LL': (is_ll TRUE, is_super FALSE).  Identical to the
+     *	    simplicial LDL', except for the is_ll flag.
+     *
+     * supernodal LDL': (is_ll FALSE, is_super TRUE).  Not used.
+     *	    FUTURE WORK:  add support for supernodal LDL'
+     *
+     * supernodal LL': (is_ll TRUE, is_super TRUE).  A supernodal symbolic
+     *	    factorization.  The simplicial symbolic information is present
+     *	    (Perm and ColCount), as is all of the supernodal factorization
+     *	    except for the numerical values (x and z).
+     */
+
+    int itype ;		/* The integer arrays are Perm, ColCount, p, i, nz,
+			 * next, prev, super, pi, px, and s.  If itype is
+			 * CHOLMOD_INT, all of these are int arrays.
+			 * CHOLMOD_INTLONG: p, pi, px are UF_long, others int.
+			 * CHOLMOD_LONG:    all integer arrays are UF_long. */
+    int xtype ;		/* pattern, real, complex, or zomplex */
+    int dtype ;		/* x and z double or float */
+
+} cholmod_factor ;
+
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_allocate_factor: allocate a factor (symbolic LL' or LDL') */
+/* -------------------------------------------------------------------------- */
+
+cholmod_factor *cholmod_allocate_factor
+(
+    /* ---- input ---- */
+    size_t n,		/* L is n-by-n */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_factor *cholmod_l_allocate_factor (size_t, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_free_factor:  free a factor */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_free_factor
+(
+    /* ---- in/out --- */
+    cholmod_factor **L,	/* factor to free, NULL on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_free_factor (cholmod_factor **, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_reallocate_factor:  change the # entries in a factor */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_reallocate_factor
+(
+    /* ---- input ---- */
+    size_t nznew,	/* new # of entries in L */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_reallocate_factor (size_t, cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_change_factor:  change the type of factor (e.g., LDL' to LL') */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_change_factor
+(
+    /* ---- input ---- */
+    int to_xtype,	/* to CHOLMOD_PATTERN, _REAL, _COMPLEX, _ZOMPLEX */
+    int to_ll,		/* TRUE: convert to LL', FALSE: LDL' */
+    int to_super,	/* TRUE: convert to supernodal, FALSE: simplicial */
+    int to_packed,	/* TRUE: pack simplicial columns, FALSE: do not pack */
+    int to_monotonic,	/* TRUE: put simplicial columns in order, FALSE: not */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_change_factor ( int, int, int, int, int, cholmod_factor *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_pack_factor:  pack the columns of a factor */
+/* -------------------------------------------------------------------------- */
+
+/* Pack the columns of a simplicial factor.  Unlike cholmod_change_factor,
+ * it can pack the columns of a factor even if they are not stored in their
+ * natural order (non-monotonic). */
+
+int cholmod_pack_factor
+(
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_pack_factor (cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_reallocate_column:  resize a single column of a factor */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_reallocate_column
+(
+    /* ---- input ---- */
+    size_t j,		/* the column to reallocate */
+    size_t need,	/* required size of column j */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_reallocate_column (size_t, size_t, cholmod_factor *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_factor_to_sparse:  create a sparse matrix copy of a factor */
+/* -------------------------------------------------------------------------- */
+
+/* Only operates on numeric factors, not symbolic ones */
+
+cholmod_sparse *cholmod_factor_to_sparse
+(
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to copy, converted to symbolic on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_factor_to_sparse (cholmod_factor *,
+	cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_copy_factor:  create a copy of a factor */
+/* -------------------------------------------------------------------------- */
+
+cholmod_factor *cholmod_copy_factor
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to copy */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_factor *cholmod_l_copy_factor (cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_factor_xtype: change the xtype of a factor */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_factor_xtype
+(
+    /* ---- input ---- */
+    int to_xtype,	/* requested xtype (real, complex, or zomplex) */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to change */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_factor_xtype (int, cholmod_factor *, cholmod_common *) ;
+
+
+/* ========================================================================== */
+/* === Core/cholmod_dense =================================================== */
+/* ========================================================================== */
+
+/* A dense matrix in column-oriented form.  It has no itype since it contains
+ * no integers.  Entry in row i and column j is located in x [i+j*d].
+ */
+
+typedef struct cholmod_dense_struct
+{
+    size_t nrow ;	/* the matrix is nrow-by-ncol */
+    size_t ncol ;
+    size_t nzmax ;	/* maximum number of entries in the matrix */
+    size_t d ;		/* leading dimension (d >= nrow must hold) */
+    void *x ;		/* size nzmax or 2*nzmax, if present */
+    void *z ;		/* size nzmax, if present */
+    int xtype ;		/* pattern, real, complex, or zomplex */
+    int dtype ;		/* x and z double or float */
+
+} cholmod_dense ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_allocate_dense:  allocate a dense matrix (contents uninitialized) */
+/* -------------------------------------------------------------------------- */
+
+cholmod_dense *cholmod_allocate_dense
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    size_t d,		/* leading dimension */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_dense *cholmod_l_allocate_dense (size_t, size_t, size_t, int,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_zeros: allocate a dense matrix and set it to zero */
+/* -------------------------------------------------------------------------- */
+
+cholmod_dense *cholmod_zeros
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_dense *cholmod_l_zeros (size_t, size_t, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_ones: allocate a dense matrix and set it to all ones */
+/* -------------------------------------------------------------------------- */
+
+cholmod_dense *cholmod_ones
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_dense *cholmod_l_ones (size_t, size_t, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_eye: allocate a dense matrix and set it to the identity matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_dense *cholmod_eye
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_dense *cholmod_l_eye (size_t, size_t, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_free_dense:  free a dense matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_free_dense
+(
+    /* ---- in/out --- */
+    cholmod_dense **X,	/* dense matrix to deallocate, NULL on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_free_dense (cholmod_dense **, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_sparse_to_dense:  create a dense matrix copy of a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_dense *cholmod_sparse_to_dense
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_dense *cholmod_l_sparse_to_dense (cholmod_sparse *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_dense_to_sparse:  create a sparse matrix copy of a dense matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_dense_to_sparse
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to copy */
+    int values,		/* TRUE if values to be copied, FALSE otherwise */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_dense_to_sparse (cholmod_dense *, int,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_copy_dense:  create a copy of a dense matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_dense *cholmod_copy_dense
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_dense *cholmod_l_copy_dense (cholmod_dense *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_copy_dense2:  copy a dense matrix (pre-allocated) */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_copy_dense2
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to copy */
+    /* ---- output --- */
+    cholmod_dense *Y,	/* copy of matrix X */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_copy_dense2 (cholmod_dense *, cholmod_dense *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_dense_xtype: change the xtype of a dense matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_dense_xtype
+(
+    /* ---- input ---- */
+    int to_xtype,	/* requested xtype (real, complex,or zomplex) */
+    /* ---- in/out --- */
+    cholmod_dense *X,	/* dense matrix to change */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_dense_xtype (int, cholmod_dense *, cholmod_common *) ;
+
+
+/* ========================================================================== */
+/* === Core/cholmod_triplet ================================================= */
+/* ========================================================================== */
+
+/* A sparse matrix stored in triplet form. */
+
+typedef struct cholmod_triplet_struct
+{
+    size_t nrow ;	/* the matrix is nrow-by-ncol */
+    size_t ncol ;
+    size_t nzmax ;	/* maximum number of entries in the matrix */
+    size_t nnz ;	/* number of nonzeros in the matrix */
+
+    void *i ;		/* i [0..nzmax-1], the row indices */
+    void *j ;		/* j [0..nzmax-1], the column indices */
+    void *x ;		/* size nzmax or 2*nzmax, if present */
+    void *z ;		/* size nzmax, if present */
+
+    int stype ;		/* Describes what parts of the matrix are considered:
+			 *
+	* 0:  matrix is "unsymmetric": use both upper and lower triangular parts
+	*     (the matrix may actually be symmetric in pattern and value, but
+	*     both parts are explicitly stored and used).  May be square or
+	*     rectangular.
+	* >0: matrix is square and symmetric.  Entries in the lower triangular
+	*     part are transposed and added to the upper triangular part when
+	*     the matrix is converted to cholmod_sparse form.
+	* <0: matrix is square and symmetric.  Entries in the upper triangular
+	*     part are transposed and added to the lower triangular part when
+	*     the matrix is converted to cholmod_sparse form.
+	*
+	* Note that stype>0 and stype<0 are different for cholmod_sparse and
+	* cholmod_triplet.  The reason is simple.  You can permute a symmetric
+	* triplet matrix by simply replacing a row and column index with their
+	* new row and column indices, via an inverse permutation.  Suppose
+	* P = L->Perm is your permutation, and Pinv is an array of size n.
+	* Suppose a symmetric matrix A is represent by a triplet matrix T, with
+	* entries only in the upper triangular part.  Then the following code:
+	*
+	*	Ti = T->i ;
+	*	Tj = T->j ;
+	*	for (k = 0 ; k < n  ; k++) Pinv [P [k]] = k ;
+	*	for (k = 0 ; k < nz ; k++) Ti [k] = Pinv [Ti [k]] ;
+	*	for (k = 0 ; k < nz ; k++) Tj [k] = Pinv [Tj [k]] ;
+	*
+	* creates the triplet form of C=P*A*P'.  However, if T initially
+	* contains just the upper triangular entries (T->stype = 1), after
+	* permutation it has entries in both the upper and lower triangular
+	* parts.  These entries should be transposed when constructing the
+	* cholmod_sparse form of A, which is what cholmod_triplet_to_sparse
+	* does.  Thus:
+	*
+	*	C = cholmod_triplet_to_sparse (T, 0, &Common) ;
+	*
+	* will return the matrix C = P*A*P'.
+	*
+	* Since the triplet matrix T is so simple to generate, it's quite easy
+	* to remove entries that you do not want, prior to converting T to the
+	* cholmod_sparse form.  So if you include these entries in T, CHOLMOD
+	* assumes that there must be a reason (such as the one above).  Thus,
+	* no entry in a triplet matrix is ever ignored.
+	*/
+
+    int itype ;		/* CHOLMOD_LONG: i and j are UF_long.  Otherwise int. */
+    int xtype ;		/* pattern, real, complex, or zomplex */
+    int dtype ;		/* x and z are double or float */
+
+} cholmod_triplet ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_allocate_triplet:  allocate a triplet matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_triplet *cholmod_allocate_triplet
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of T */
+    size_t ncol,	/* # of columns of T */
+    size_t nzmax,	/* max # of nonzeros of T */
+    int stype,		/* stype of T */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_triplet *cholmod_l_allocate_triplet (size_t, size_t, size_t, int, int,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_free_triplet:  free a triplet matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_free_triplet
+(
+    /* ---- in/out --- */
+    cholmod_triplet **T,    /* triplet matrix to deallocate, NULL on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_free_triplet (cholmod_triplet **, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_reallocate_triplet:  change the # of entries in a triplet matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_reallocate_triplet
+(
+    /* ---- input ---- */
+    size_t nznew,	/* new # of entries in T */
+    /* ---- in/out --- */
+    cholmod_triplet *T,	/* triplet matrix to modify */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_reallocate_triplet (size_t, cholmod_triplet *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_sparse_to_triplet:  create a triplet matrix copy of a sparse matrix*/
+/* -------------------------------------------------------------------------- */
+
+cholmod_triplet *cholmod_sparse_to_triplet
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_triplet *cholmod_l_sparse_to_triplet (cholmod_sparse *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_triplet_to_sparse:  create a sparse matrix copy of a triplet matrix*/
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_triplet_to_sparse
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* matrix to copy */
+    size_t nzmax,	/* allocate at least this much space in output matrix */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_triplet_to_sparse (cholmod_triplet *, size_t,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_copy_triplet:  create a copy of a triplet matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_triplet *cholmod_copy_triplet
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_triplet *cholmod_l_copy_triplet (cholmod_triplet *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_triplet_xtype: change the xtype of a triplet matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_triplet_xtype
+(
+    /* ---- input ---- */
+    int to_xtype,	/* requested xtype (pattern, real, complex,or zomplex)*/
+    /* ---- in/out --- */
+    cholmod_triplet *T,	/* triplet matrix to change */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_triplet_xtype (int, cholmod_triplet *, cholmod_common *) ;
+
+
+/* ========================================================================== */
+/* === Core/cholmod_memory ================================================== */
+/* ========================================================================== */
+
+/* The user may make use of these, just like malloc and free.  You can even
+ * malloc an object and safely free it with cholmod_free, and visa versa
+ * (except that the memory usage statistics will be corrupted).  These routines
+ * do differ from malloc and free.  If cholmod_free is given a NULL pointer,
+ * for example, it does nothing (unlike the ANSI free).  cholmod_realloc does
+ * not return NULL if given a non-NULL pointer and a nonzero size, even if it
+ * fails (it returns the original pointer and sets an error code in
+ * Common->status instead).
+ *
+ * CHOLMOD keeps track of the amount of memory it has allocated, and so the
+ * cholmod_free routine also takes the size of the object being freed.  This
+ * is only used for statistics.  If you, the user of CHOLMOD, pass the wrong
+ * size, the only consequence is that the memory usage statistics will be
+ * corrupted.
+ */
+
+void *cholmod_malloc	/* returns pointer to the newly malloc'd block */
+(
+    /* ---- input ---- */
+    size_t n,		/* number of items */
+    size_t size,	/* size of each item */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+void *cholmod_l_malloc (size_t, size_t, cholmod_common *) ;
+
+void *cholmod_calloc	/* returns pointer to the newly calloc'd block */
+(
+    /* ---- input ---- */
+    size_t n,		/* number of items */
+    size_t size,	/* size of each item */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+void *cholmod_l_calloc (size_t, size_t, cholmod_common *) ;
+
+void *cholmod_free	/* always returns NULL */
+(
+    /* ---- input ---- */
+    size_t n,		/* number of items */
+    size_t size,	/* size of each item */
+    /* ---- in/out --- */
+    void *p,		/* block of memory to free */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+void *cholmod_l_free (size_t, size_t, void *, cholmod_common *) ;
+
+void *cholmod_realloc	/* returns pointer to reallocated block */
+(
+    /* ---- input ---- */
+    size_t nnew,	/* requested # of items in reallocated block */
+    size_t size,	/* size of each item */
+    /* ---- in/out --- */
+    void *p,		/* block of memory to realloc */
+    size_t *n,		/* current size on input, nnew on output if successful*/
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+void *cholmod_l_realloc (size_t, size_t, void *, size_t *, cholmod_common *) ;
+
+int cholmod_realloc_multiple
+(
+    /* ---- input ---- */
+    size_t nnew,	/* requested # of items in reallocated blocks */
+    int nint,		/* number of int/UF_long blocks */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* ---- in/out --- */
+    void **I,		/* int or UF_long block */
+    void **J,		/* int or UF_long block */
+    void **X,		/* complex, double, or float block */
+    void **Z,		/* zomplex case only: double or float block */
+    size_t *n,		/* current size of the I,J,X,Z blocks on input,
+			 * nnew on output if successful */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_realloc_multiple (size_t, int, int, void **, void **, void **,
+    void **, size_t *, cholmod_common *) ;
+
+/* ========================================================================== */
+/* === symmetry types ======================================================= */
+/* ========================================================================== */
+
+#define CHOLMOD_MM_RECTANGULAR 1
+#define CHOLMOD_MM_UNSYMMETRIC 2
+#define CHOLMOD_MM_SYMMETRIC 3
+#define CHOLMOD_MM_HERMITIAN 4
+#define CHOLMOD_MM_SKEW_SYMMETRIC 5
+#define CHOLMOD_MM_SYMMETRIC_POSDIAG 6
+#define CHOLMOD_MM_HERMITIAN_POSDIAG 7
+
+/* ========================================================================== */
+/* === Numerical relop macros =============================================== */
+/* ========================================================================== */
+
+/* These macros correctly handle the NaN case.
+ *
+ *  CHOLMOD_IS_NAN(x):
+ *	True if x is NaN.  False otherwise.  The commonly-existing isnan(x)
+ *	function could be used, but it's not in Kernighan & Ritchie 2nd edition
+ *	(ANSI C89).  It may appear in <math.h>, but I'm not certain about
+ *	portability.  The expression x != x is true if and only if x is NaN,
+ *	according to the IEEE 754 floating-point standard.
+ *
+ *  CHOLMOD_IS_ZERO(x):
+ *	True if x is zero.  False if x is nonzero, NaN, or +/- Inf.
+ *	This is (x == 0) if the compiler is IEEE 754 compliant.
+ *
+ *  CHOLMOD_IS_NONZERO(x):
+ *	True if x is nonzero, NaN, or +/- Inf.  False if x zero.
+ *	This is (x != 0) if the compiler is IEEE 754 compliant.
+ *
+ *  CHOLMOD_IS_LT_ZERO(x):
+ *	True if x is < zero or -Inf.  False if x is >= 0, NaN, or +Inf.
+ *	This is (x < 0) if the compiler is IEEE 754 compliant.
+ *
+ *  CHOLMOD_IS_GT_ZERO(x):
+ *	True if x is > zero or +Inf.  False if x is <= 0, NaN, or -Inf.
+ *	This is (x > 0) if the compiler is IEEE 754 compliant.
+ *
+ *  CHOLMOD_IS_LE_ZERO(x):
+ *	True if x is <= zero or -Inf.  False if x is > 0, NaN, or +Inf.
+ *	This is (x <= 0) if the compiler is IEEE 754 compliant.
+ */
+
+#ifdef CHOLMOD_WINDOWS
+
+/* Yes, this is exceedingly ugly.  Blame Microsoft, which hopelessly */
+/* violates the IEEE 754 floating-point standard in a bizarre way. */
+/* If you're using an IEEE 754-compliant compiler, then x != x is true */
+/* iff x is NaN.  For Microsoft, (x < x) is true iff x is NaN. */
+/* So either way, this macro safely detects a NaN. */
+#define CHOLMOD_IS_NAN(x)	(((x) != (x)) || (((x) < (x))))
+#define CHOLMOD_IS_ZERO(x)	(((x) == 0.) && !CHOLMOD_IS_NAN(x))
+#define CHOLMOD_IS_NONZERO(x)	(((x) != 0.) || CHOLMOD_IS_NAN(x))
+#define CHOLMOD_IS_LT_ZERO(x)	(((x) < 0.) && !CHOLMOD_IS_NAN(x))
+#define CHOLMOD_IS_GT_ZERO(x)	(((x) > 0.) && !CHOLMOD_IS_NAN(x))
+#define CHOLMOD_IS_LE_ZERO(x)	(((x) <= 0.) && !CHOLMOD_IS_NAN(x))
+
+#else
+
+/* These all work properly, according to the IEEE 754 standard ... except on */
+/* a PC with windows.  Works fine in Linux on the same PC... */
+#define CHOLMOD_IS_NAN(x)	((x) != (x))
+#define CHOLMOD_IS_ZERO(x)	((x) == 0.)
+#define CHOLMOD_IS_NONZERO(x)	((x) != 0.)
+#define CHOLMOD_IS_LT_ZERO(x)	((x) < 0.)
+#define CHOLMOD_IS_GT_ZERO(x)	((x) > 0.)
+#define CHOLMOD_IS_LE_ZERO(x)	((x) <= 0.)
+
+#endif
+
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Include/cholmod_internal.h b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_internal.h
new file mode 100644
index 0000000..0cabd5a
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_internal.h
@@ -0,0 +1,385 @@
+/* ========================================================================== */
+/* === Include/cholmod_internal.h =========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_internal.h.
+ * Copyright (C) 2005-2006, Univ. of Florida.  Author: Timothy A. Davis
+ * CHOLMOD/Include/cholmod_internal.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD internal include file.
+ *
+ * This file contains internal definitions for CHOLMOD, not meant to be included
+ * in user code.  They define macros that are not prefixed with CHOLMOD_.  This
+ * file can safely #include'd in user code if you want to make use of the
+ * macros defined here, and don't mind the possible name conflicts with your
+ * code, however.
+ *
+ * Required by all CHOLMOD routines.  Not required by any user routine that
+ * uses CHOLMOMD.  Unless debugging is enabled, this file does not require any
+ * CHOLMOD module (not even the Core module).
+ *
+ * If debugging is enabled, all CHOLMOD modules require the Check module.
+ * Enabling debugging requires that this file be editted.  Debugging cannot be
+ * enabled with a compiler flag.  This is because CHOLMOD is exceedingly slow
+ * when debugging is enabled.  Debugging is meant for development of CHOLMOD
+ * itself, not by users of CHOLMOD.
+ */
+
+#ifndef CHOLMOD_INTERNAL_H
+#define CHOLMOD_INTERNAL_H
+
+/* ========================================================================== */
+/* === large file I/O ======================================================= */
+/* ========================================================================== */
+
+/* Definitions for large file I/O must come before any other #includes.  If
+ * this causes problems (may not be portable to all platforms), then compile
+ * CHOLMOD with -DNLARGEFILE.  You must do this for MATLAB 6.5 and earlier,
+ * for example. */
+
+#include "cholmod_io64.h"
+
+/* ========================================================================== */
+/* === debugging and basic includes ========================================= */
+/* ========================================================================== */
+
+/* turn off debugging */
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+
+/* Uncomment this line to enable debugging.  CHOLMOD will be very slow.
+#undef NDEBUG
+ */
+
+#if !defined(NPRINT) || !defined(NDEBUG)
+#include <stdio.h>
+#endif
+
+#include <stddef.h>
+#include <math.h>
+#include <limits.h>
+#include <float.h>
+#include <stdlib.h>
+
+/* ========================================================================== */
+/* === basic definitions ==================================================== */
+/* ========================================================================== */
+
+/* Some non-conforming compilers insist on defining TRUE and FALSE. */
+#undef TRUE
+#undef FALSE
+#define TRUE 1
+#define FALSE 0
+#define BOOLEAN(x) ((x) ? TRUE : FALSE)
+
+/* NULL should already be defined, but ensure it is here. */
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+/* FLIP is a "negation about -1", and is used to mark an integer i that is
+ * normally non-negative.  FLIP (EMPTY) is EMPTY.  FLIP of a number > EMPTY
+ * is negative, and FLIP of a number < EMTPY is positive.  FLIP (FLIP (i)) = i
+ * for all integers i.  UNFLIP (i) is >= EMPTY. */
+#define EMPTY (-1)
+#define FLIP(i) (-(i)-2)
+#define UNFLIP(i) (((i) < EMPTY) ? FLIP (i) : (i))
+
+/* MAX and MIN are not safe to use for NaN's */
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MAX3(a,b,c) (((a) > (b)) ? (MAX (a,c)) : (MAX (b,c)))
+#define MAX4(a,b,c,d) (((a) > (b)) ? (MAX3 (a,c,d)) : (MAX3 (b,c,d)))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define IMPLIES(p,q) (!(p) || (q))
+
+/* find the sign: -1 if x < 0, 1 if x > 0, zero otherwise.
+ * Not safe for NaN's */
+#define SIGN(x) (((x) < 0) ? (-1) : (((x) > 0) ? 1 : 0))
+
+/* round up an integer x to a multiple of s */
+#define ROUNDUP(x,s) ((s) * (((x) + ((s) - 1)) / (s)))
+
+#define ERROR(status,msg) \
+    CHOLMOD(error) (status, __FILE__, __LINE__, msg, Common)
+
+/* Check a pointer and return if null.  Set status to invalid, unless the
+ * status is already "out of memory" */
+#define RETURN_IF_NULL(A,result) \
+{ \
+    if ((A) == NULL) \
+    { \
+	if (Common->status != CHOLMOD_OUT_OF_MEMORY) \
+	{ \
+	    ERROR (CHOLMOD_INVALID, "argument missing") ; \
+	} \
+	return (result) ; \
+    } \
+}
+
+/* Return if Common is NULL or invalid */
+#define RETURN_IF_NULL_COMMON(result) \
+{ \
+    if (Common == NULL) \
+    { \
+	return (result) ; \
+    } \
+    if (Common->itype != ITYPE || Common->dtype != DTYPE) \
+    { \
+	Common->status = CHOLMOD_INVALID ; \
+	return (result) ; \
+    } \
+}
+
+#define IS_NAN(x)	CHOLMOD_IS_NAN(x)
+#define IS_ZERO(x)	CHOLMOD_IS_ZERO(x)
+#define IS_NONZERO(x)	CHOLMOD_IS_NONZERO(x)
+#define IS_LT_ZERO(x)	CHOLMOD_IS_LT_ZERO(x)
+#define IS_GT_ZERO(x)	CHOLMOD_IS_GT_ZERO(x)
+#define IS_LE_ZERO(x)	CHOLMOD_IS_LE_ZERO(x)
+
+/* 1e308 is a huge number that doesn't take many characters to print in a
+ * file, in CHOLMOD/Check/cholmod_read and _write.  Numbers larger than this
+ * are interpretted as Inf, since sscanf doesn't read in Inf's properly.
+ * This assumes IEEE double precision arithmetic.  DBL_MAX would be a little
+ * better, except that it takes too many digits to print in a file. */
+#define HUGE_DOUBLE 1e308
+
+/* ========================================================================== */
+/* === int/UF_long and double/float definitions ============================= */
+/* ========================================================================== */
+
+/* CHOLMOD is designed for 3 types of integer variables:
+ *
+ *	(1) all integers are int
+ *	(2) most integers are int, some are UF_long
+ *	(3) all integers are UF_long
+ *
+ * and two kinds of floating-point values:
+ *
+ *	(1) double
+ *	(2) float
+ *
+ * the complex types (ANSI-compatible complex, and MATLAB-compatable zomplex)
+ * are based on the double or float type, and are not selected here.  They
+ * are typically selected via template routines.
+ *
+ * This gives 6 different modes in which CHOLMOD can be compiled (only the
+ * first two are currently supported):
+ *
+ *	DINT	double, int			prefix: cholmod_
+ *	DLONG	double, UF_long			prefix: cholmod_l_
+ *	DMIX	double, mixed int/UF_long	prefix: cholmod_m_
+ *	SINT	float, int			prefix: cholmod_si_
+ *	SLONG	float, UF_long			prefix: cholmod_sl_
+ *	SMIX	float, mixed int/log		prefix: cholmod_sm_
+ *
+ * These are selected with compile time flags (-DDLONG, for example).  If no
+ * flag is selected, the default is DINT.
+ *
+ * All six versions use the same include files.  The user-visible include files
+ * are completely independent of which int/UF_long/double/float version is being
+ * used.  The integer / real types in all data structures (sparse, triplet,
+ * dense, common, and triplet) are defined at run-time, not compile-time, so
+ * there is only one "cholmod_sparse" data type.  Void pointers are used inside
+ * that data structure to point to arrays of the proper type.  Each data
+ * structure has an itype and dtype field which determines the kind of basic
+ * types used.  These are defined in Include/cholmod_core.h.
+ *
+ * FUTURE WORK: support all six types (float, and mixed int/UF_long)
+ *
+ * UF_long is normally defined as long.  However, for WIN64 it is __int64.
+ * It can also be redefined for other platforms, by modifying UFconfig.h.
+ */
+
+#include "UFconfig.h"
+
+/* -------------------------------------------------------------------------- */
+/* Size_max: the largest value of size_t */
+/* -------------------------------------------------------------------------- */
+
+#define Size_max ((size_t) (-1))
+
+/* routines for doing arithmetic on size_t, and checking for overflow */
+size_t cholmod_add_size_t (size_t a, size_t b, int *ok) ;
+size_t cholmod_mult_size_t (size_t a, size_t k, int *ok) ;
+size_t cholmod_l_add_size_t (size_t a, size_t b, int *ok) ;
+size_t cholmod_l_mult_size_t (size_t a, size_t k, int *ok) ;
+
+/* -------------------------------------------------------------------------- */
+/* double, UF_long */
+/* -------------------------------------------------------------------------- */
+
+#ifdef DLONG
+#define Real double
+#define Int UF_long
+#define Int_max UF_long_max
+#define CHOLMOD(name) cholmod_l_ ## name
+#define LONG
+#define DOUBLE
+#define ITYPE CHOLMOD_LONG
+#define DTYPE CHOLMOD_DOUBLE
+#define ID UF_long_id
+
+/* -------------------------------------------------------------------------- */
+/* double, int/UF_long */
+/* -------------------------------------------------------------------------- */
+
+#elif defined (DMIX)
+#error "mixed int/UF_long not yet supported"
+
+/* -------------------------------------------------------------------------- */
+/* single, int */
+/* -------------------------------------------------------------------------- */
+
+#elif defined (SINT)
+#error "single-precision not yet supported"
+
+/* -------------------------------------------------------------------------- */
+/* single, UF_long */
+/* -------------------------------------------------------------------------- */
+
+#elif defined (SLONG)
+#error "single-precision not yet supported"
+
+/* -------------------------------------------------------------------------- */
+/* single, int/UF_long */
+/* -------------------------------------------------------------------------- */
+
+#elif defined (SMIX)
+#error "single-precision not yet supported"
+
+/* -------------------------------------------------------------------------- */
+/* double, int: this is the default */
+/* -------------------------------------------------------------------------- */
+
+#else
+
+#ifndef DINT
+#define DINT
+#endif
+#define INT
+#define DOUBLE
+
+#define Real double
+#define Int int
+#define Int_max INT_MAX
+#define CHOLMOD(name) cholmod_ ## name
+#define ITYPE CHOLMOD_INT
+#define DTYPE CHOLMOD_DOUBLE
+#define ID "%d"
+
+#endif
+
+
+/* ========================================================================== */
+/* === real/complex arithmetic ============================================== */
+/* ========================================================================== */
+
+#include "cholmod_complexity.h"
+
+/* ========================================================================== */
+/* === Architecture and BLAS ================================================ */
+/* ========================================================================== */
+
+#include "cholmod_blas.h"
+
+/* ========================================================================== */
+/* === debugging definitions ================================================ */
+/* ========================================================================== */
+
+#ifndef NDEBUG
+
+#include <assert.h>
+#include "cholmod.h"
+
+/* The cholmod_dump routines are in the Check module.  No CHOLMOD routine
+ * calls the cholmod_check_* or cholmod_print_* routines in the Check module,
+ * since they use Common workspace that may already be in use.  Instead, they
+ * use the cholmod_dump_* routines defined there, which allocate their own
+ * workspace if they need it. */
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+/* double, int */
+EXTERN int cholmod_dump ;
+EXTERN int cholmod_dump_malloc ;
+UF_long cholmod_dump_sparse (cholmod_sparse  *, char *, cholmod_common *) ;
+int  cholmod_dump_factor (cholmod_factor  *, char *, cholmod_common *) ;
+int  cholmod_dump_triplet (cholmod_triplet *, char *, cholmod_common *) ;
+int  cholmod_dump_dense (cholmod_dense   *, char *, cholmod_common *) ;
+int  cholmod_dump_subset (int *, size_t, size_t, char *, cholmod_common *) ;
+int  cholmod_dump_perm (int *, size_t, size_t, char *, cholmod_common *) ;
+int  cholmod_dump_parent (int *, size_t, char *, cholmod_common *) ;
+void cholmod_dump_init (char *, cholmod_common *) ;
+int  cholmod_dump_mem (char *, UF_long, cholmod_common *) ;
+void cholmod_dump_real (char *, Real *, UF_long, UF_long, int, int,
+	cholmod_common *) ;
+void cholmod_dump_super (UF_long, int *, int *, int *, int *, double *, int,
+	cholmod_common *) ;
+int  cholmod_dump_partition (UF_long, int *, int *, int *, int *, UF_long,
+	cholmod_common *) ;
+int  cholmod_dump_work(int, int, UF_long, cholmod_common *) ;
+
+/* double, UF_long */
+EXTERN int cholmod_l_dump ;
+EXTERN int cholmod_l_dump_malloc ;
+UF_long cholmod_l_dump_sparse (cholmod_sparse  *, char *, cholmod_common *) ;
+int  cholmod_l_dump_factor (cholmod_factor  *, char *, cholmod_common *) ;
+int  cholmod_l_dump_triplet (cholmod_triplet *, char *, cholmod_common *) ;
+int  cholmod_l_dump_dense (cholmod_dense   *, char *, cholmod_common *) ;
+int  cholmod_l_dump_subset (UF_long *, size_t, size_t, char *,
+    cholmod_common *) ;
+int  cholmod_l_dump_perm (UF_long *, size_t, size_t, char *, cholmod_common *) ;
+int  cholmod_l_dump_parent (UF_long *, size_t, char *, cholmod_common *) ;
+void cholmod_l_dump_init (char *, cholmod_common *) ;
+int  cholmod_l_dump_mem (char *, UF_long, cholmod_common *) ;
+void cholmod_l_dump_real (char *, Real *, UF_long, UF_long, int, int,
+	cholmod_common *) ;
+void cholmod_l_dump_super (UF_long, UF_long *, UF_long *, UF_long *, UF_long *,
+        double *, int, cholmod_common *) ;
+int  cholmod_l_dump_partition (UF_long, UF_long *, UF_long *, UF_long *,
+	UF_long *, UF_long, cholmod_common *) ;
+int  cholmod_l_dump_work(int, int, UF_long, cholmod_common *) ;
+
+#define DEBUG_INIT(s)  { CHOLMOD(dump_init)(s, Common) ; }
+#define ASSERT(expression) (assert (expression))
+
+#define PRK(k,params) \
+{ \
+    if (CHOLMOD(dump) >= (k) && Common->print_function != NULL) \
+    { \
+	(Common->print_function) params ; \
+    } \
+}
+
+#define PRINT0(params) PRK (0, params)
+#define PRINT1(params) PRK (1, params)
+#define PRINT2(params) PRK (2, params)
+#define PRINT3(params) PRK (3, params)
+#define PRINTM(params) PRK (CHOLMOD(dump_malloc), params)
+
+#define DEBUG(statement) statement
+
+#else
+
+/* Debugging disabled (the normal case) */
+#define PRK(k,params)
+#define DEBUG_INIT(s)
+#define PRINT0(params)
+#define PRINT1(params)
+#define PRINT2(params)
+#define PRINT3(params)
+#define PRINTM(params)
+#define ASSERT(expression)
+#define DEBUG(statement)
+#endif
+
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Include/cholmod_io64.h b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_io64.h
new file mode 100644
index 0000000..98bf2b3
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_io64.h
@@ -0,0 +1,46 @@
+/* ========================================================================== */
+/* === Include/cholmod_io64 ================================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_io64.h.
+ * Copyright (C) 2005-2006, Univ. of Florida.  Author: Timothy A. Davis
+ * CHOLMOD/Include/cholmod_io64.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Definitions required for large file I/O, which must come before any other
+ * #includes.  These are not used if -DNLARGEFILE is defined at compile time.
+ * Large file support may not be portable across all platforms and compilers;
+ * if you encounter an error here, compile your code with -DNLARGEFILE.  In
+ * particular, you must use -DNLARGEFILE for MATLAB 6.5 or earlier (which does
+ * not have the io64.h include file).
+ */
+
+#ifndef CHOLMOD_IO_H
+#define CHOLMOD_IO_H
+
+/* skip all of this if NLARGEFILE is defined at the compiler command line */
+#ifndef NLARGEFILE
+
+#if defined(MATLAB_MEX_FILE) || defined(MATHWORKS)
+
+/* CHOLMOD is being compiled as a MATLAB MEX file, or for use inside MATLAB */
+#include "io64.h"
+
+#else
+
+/* CHOLMOD is being compiled in a stand-alone library */
+#undef  _LARGEFILE64_SOURCE
+#define _LARGEFILE64_SOURCE
+#undef  _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 64
+
+#endif
+
+#endif
+
+#endif
+
diff --git a/src/C/SuiteSparse/CHOLMOD/Include/cholmod_matrixops.h b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_matrixops.h
new file mode 100644
index 0000000..59f19da
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_matrixops.h
@@ -0,0 +1,235 @@
+/* ========================================================================== */
+/* === Include/cholmod_matrixops.h ========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_matrixops.h.
+ * Copyright (C) 2005-2006, Timothy A. Davis
+ * CHOLMOD/Include/cholmod_matrixops.h is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD MatrixOps module.
+ *
+ * Basic operations on sparse and dense matrices.
+ *
+ * cholmod_drop		    A = entries in A with abs. value >= tol
+ * cholmod_norm_dense	    s = norm (X), 1-norm, inf-norm, or 2-norm
+ * cholmod_norm_sparse	    s = norm (A), 1-norm or inf-norm
+ * cholmod_horzcat	    C = [A,B]
+ * cholmod_scale	    A = diag(s)*A, A*diag(s), s*A or diag(s)*A*diag(s)
+ * cholmod_sdmult	    Y = alpha*(A*X) + beta*Y or alpha*(A'*X) + beta*Y
+ * cholmod_ssmult	    C = A*B
+ * cholmod_submatrix	    C = A (i,j), where i and j are arbitrary vectors
+ * cholmod_vertcat	    C = [A ; B]
+ *
+ * A, B, C: sparse matrices (cholmod_sparse)
+ * X, Y: dense matrices (cholmod_dense)
+ * s: scalar or vector
+ *
+ * Requires the Core module.  Not required by any other CHOLMOD module.
+ */
+
+#ifndef CHOLMOD_MATRIXOPS_H
+#define CHOLMOD_MATRIXOPS_H
+
+#include "cholmod_core.h"
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_drop:  drop entries with small absolute value */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_drop
+(
+    /* ---- input ---- */
+    double tol,		/* keep entries with absolute value > tol */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix to drop entries from */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_drop (double, cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_norm_dense:  s = norm (X), 1-norm, inf-norm, or 2-norm */
+/* -------------------------------------------------------------------------- */
+
+double cholmod_norm_dense
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to compute the norm of */
+    int norm,		/* type of norm: 0: inf. norm, 1: 1-norm, 2: 2-norm */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+double cholmod_l_norm_dense (cholmod_dense *, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_norm_sparse:  s = norm (A), 1-norm or inf-norm */
+/* -------------------------------------------------------------------------- */
+
+double cholmod_norm_sparse
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to compute the norm of */
+    int norm,		/* type of norm: 0: inf. norm, 1: 1-norm */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+double cholmod_l_norm_sparse (cholmod_sparse *, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_horzcat:  C = [A,B] */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_horzcat
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* left matrix to concatenate */
+    cholmod_sparse *B,	/* right matrix to concatenate */
+    int values,		/* if TRUE compute the numerical values of C */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_horzcat (cholmod_sparse *, cholmod_sparse *, int,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_scale:  A = diag(s)*A, A*diag(s), s*A or diag(s)*A*diag(s) */
+/* -------------------------------------------------------------------------- */
+
+/* scaling modes, selected by the scale input parameter: */
+#define CHOLMOD_SCALAR 0	/* A = s*A */
+#define CHOLMOD_ROW 1		/* A = diag(s)*A */
+#define CHOLMOD_COL 2		/* A = A*diag(s) */
+#define CHOLMOD_SYM 3		/* A = diag(s)*A*diag(s) */
+
+int cholmod_scale
+(
+    /* ---- input ---- */
+    cholmod_dense *S,	/* scale factors (scalar or vector) */
+    int scale,		/* type of scaling to compute */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix to scale */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_scale (cholmod_dense *, int, cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_sdmult:  Y = alpha*(A*X) + beta*Y or alpha*(A'*X) + beta*Y */
+/* -------------------------------------------------------------------------- */
+
+/* Sparse matrix times dense matrix */
+
+int cholmod_sdmult
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* sparse matrix to multiply */
+    int transpose,	/* use A if 0, or A' if 1, or A.' if -1 */
+    double alpha [2],   /* scale factor for A */
+    double beta [2],    /* scale factor for Y */
+    cholmod_dense *X,	/* dense matrix to multiply */
+    /* ---- in/out --- */
+    cholmod_dense *Y,	/* resulting dense matrix */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_sdmult (cholmod_sparse *, int, double *, double *,
+    cholmod_dense *, cholmod_dense *Y, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_ssmult:  C = A*B */
+/* -------------------------------------------------------------------------- */
+
+/* Sparse matrix times sparse matrix */
+
+cholmod_sparse *cholmod_ssmult
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* left matrix to multiply */
+    cholmod_sparse *B,	/* right matrix to multiply */
+    int stype,		/* requested stype of C */
+    int values,		/* TRUE: do numerical values, FALSE: pattern only */
+    int sorted,		/* if TRUE then return C with sorted columns */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_ssmult (cholmod_sparse *, cholmod_sparse *, int, int,
+    int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_submatrix:  C = A (r,c), where i and j are arbitrary vectors */
+/* -------------------------------------------------------------------------- */
+
+/* rsize < 0 denotes ":" in MATLAB notation, or more precisely 0:(A->nrow)-1.
+ * In this case, r can be NULL.  An rsize of zero, or r = NULL and rsize >= 0,
+ * denotes "[ ]" in MATLAB notation (the empty set).
+ * Similar rules hold for csize.
+ */
+
+cholmod_sparse *cholmod_submatrix
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to subreference */
+    int *rset,		/* set of row indices, duplicates OK */
+    UF_long rsize,	/* size of r; rsize < 0 denotes ":" */
+    int *cset,		/* set of column indices, duplicates OK */
+    UF_long csize,	/* size of c; csize < 0 denotes ":" */
+    int values,		/* if TRUE compute the numerical values of C */
+    int sorted,		/* if TRUE then return C with sorted columns */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_submatrix (cholmod_sparse *, UF_long *, UF_long,
+    UF_long *, UF_long, int, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_vertcat:  C = [A ; B] */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_vertcat
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* left matrix to concatenate */
+    cholmod_sparse *B,	/* right matrix to concatenate */
+    int values,		/* if TRUE compute the numerical values of C */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_vertcat (cholmod_sparse *, cholmod_sparse *, int,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_symmetry: determine if a sparse matrix is symmetric */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_symmetry
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,
+    int option,
+    /* ---- output ---- */
+    int *xmatched,
+    int *pmatched,
+    int *nzoffdiag,
+    int *nzdiag,
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_symmetry (cholmod_sparse *, int, UF_long *, UF_long *, UF_long *,
+    UF_long *, cholmod_common *) ;
+
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Include/cholmod_modify.h b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_modify.h
new file mode 100644
index 0000000..bb7dd5a
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_modify.h
@@ -0,0 +1,304 @@
+/* ========================================================================== */
+/* === Include/cholmod_modify.h ============================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_modify.h.
+ * Copyright (C) 2005-2006, Timothy A. Davis and William W. Hager
+ * CHOLMOD/Include/cholmod_modify.h is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD Modify module.
+ *
+ * Sparse Cholesky modification routines: update / downdate / rowadd / rowdel.
+ * Can also modify a corresponding solution to Lx=b when L is modified.  This
+ * module is most useful when applied on a Cholesky factorization computed by
+ * the Cholesky module, but it does not actually require the Cholesky module.
+ * The Core module can create an identity Cholesky factorization (LDL' where
+ * L=D=I) that can then by modified by these routines.
+ *
+ * Primary routines:
+ * -----------------
+ *
+ * cholmod_updown	    multiple rank update/downdate
+ * cholmod_rowadd	    add a row to an LDL' factorization
+ * cholmod_rowdel	    delete a row from an LDL' factorization
+ *
+ * Secondary routines:
+ * -------------------
+ *
+ * cholmod_updown_solve	    update/downdate, and modify solution to Lx=b
+ * cholmod_updown_mark	    update/downdate, and modify solution to partial Lx=b
+ * cholmod_updown_mask	    update/downdate for LPDASA
+ * cholmod_rowadd_solve	    add a row, and update solution to Lx=b
+ * cholmod_rowadd_mark	    add a row, and update solution to partial Lx=b
+ * cholmod_rowdel_solve	    delete a row, and downdate Lx=b
+ * cholmod_rowdel_mark	    delete a row, and downdate solution to partial Lx=b
+ *
+ * Requires the Core module.  Not required by any other CHOLMOD module.
+ */
+
+#ifndef CHOLMOD_MODIFY_H
+#define CHOLMOD_MODIFY_H
+
+#include "cholmod_core.h"
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_updown:  multiple rank update/downdate */
+/* -------------------------------------------------------------------------- */
+
+/* Compute the new LDL' factorization of LDL'+CC' (an update) or LDL'-CC'
+ * (a downdate).  The factor object L need not be an LDL' factorization; it
+ * is converted to one if it isn't. */
+
+int cholmod_updown 
+(
+    /* ---- input ---- */
+    int update,		/* TRUE for update, FALSE for downdate */
+    cholmod_sparse *C,	/* the incoming sparse update */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_updown (int, cholmod_sparse *, cholmod_factor *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_updown_solve:  update/downdate, and modify solution to Lx=b */
+/* -------------------------------------------------------------------------- */
+
+/* Does the same as cholmod_updown, except that it also updates/downdates the
+ * solution to Lx=b+DeltaB.  x and b must be n-by-1 dense matrices.  b is not
+ * need as input to this routine, but a sparse change to b is (DeltaB).  Only
+ * entries in DeltaB corresponding to columns modified in L are accessed; the
+ * rest must be zero. */
+
+int cholmod_updown_solve
+(
+    /* ---- input ---- */
+    int update,		/* TRUE for update, FALSE for downdate */
+    cholmod_sparse *C,	/* the incoming sparse update */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_updown_solve (int, cholmod_sparse *, cholmod_factor *,
+    cholmod_dense *, cholmod_dense *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_updown_mark:  update/downdate, and modify solution to partial Lx=b */
+/* -------------------------------------------------------------------------- */
+
+/* Does the same as cholmod_updown_solve, except only part of L is used in
+ * the update/downdate of the solution to Lx=b.  This routine is an "expert"
+ * routine.  It is meant for use in LPDASA only.  See cholmod_updown.c for
+ * a description of colmark. */
+
+int cholmod_updown_mark
+(
+    /* ---- input ---- */
+    int update,		/* TRUE for update, FALSE for downdate */
+    cholmod_sparse *C,	/* the incoming sparse update */
+    int *colmark,	/* int array of size n.  See cholmod_updown.c */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_updown_mark (int, cholmod_sparse *, UF_long *, cholmod_factor *,
+    cholmod_dense *, cholmod_dense *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_updown_mask:  update/downdate, for LPDASA */
+/* -------------------------------------------------------------------------- */
+
+/* Does the same as cholmod_updown_mark, except has an additional "mask"
+ * argument.  This routine is an "expert" routine.  It is meant for use in
+ * LPDASA only.  See cholmod_updown.c for a description of mask. */
+
+int cholmod_updown_mask
+(
+    /* ---- input ---- */
+    int update,		/* TRUE for update, FALSE for downdate */
+    cholmod_sparse *C,	/* the incoming sparse update */
+    int *colmark,	/* int array of size n.  See cholmod_updown.c */
+    int *mask,		/* size n */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_updown_mask (int, cholmod_sparse *, UF_long *, UF_long *,
+    cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowadd:  add a row to an LDL' factorization (a rank-2 update) */
+/* -------------------------------------------------------------------------- */
+
+/* cholmod_rowadd adds a row to the LDL' factorization.  It computes the kth
+ * row and kth column of L, and then updates the submatrix L (k+1:n,k+1:n)
+ * accordingly.  The kth row and column of L must originally be equal to the
+ * kth row and column of the identity matrix.  The kth row/column of L is
+ * computed as the factorization of the kth row/column of the matrix to
+ * factorize, which is provided as a single n-by-1 sparse matrix R. */
+
+int cholmod_rowadd 
+(
+    /* ---- input ---- */
+    size_t k,		/* row/column index to add */
+    cholmod_sparse *R,	/* row/column of matrix to factorize (n-by-1) */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowadd (size_t, cholmod_sparse *, cholmod_factor *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowadd_solve:  add a row, and update solution to Lx=b */
+/* -------------------------------------------------------------------------- */
+
+/* Does the same as cholmod_rowadd, and also updates the solution to Lx=b
+ * See cholmod_updown for a description of how Lx=b is updated.  There is on
+ * additional parameter:  bk specifies the new kth entry of b. */
+
+int cholmod_rowadd_solve
+(
+    /* ---- input ---- */
+    size_t k,		/* row/column index to add */
+    cholmod_sparse *R,	/* row/column of matrix to factorize (n-by-1) */
+    double bk [2],	/* kth entry of the right-hand-side b */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowadd_solve (size_t, cholmod_sparse *, double *,
+    cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowadd_mark:  add a row, and update solution to partial Lx=b */
+/* -------------------------------------------------------------------------- */
+
+/* Does the same as cholmod_rowadd_solve, except only part of L is used in
+ * the update/downdate of the solution to Lx=b.  This routine is an "expert"
+ * routine.  It is meant for use in LPDASA only.  */
+
+int cholmod_rowadd_mark
+(
+    /* ---- input ---- */
+    size_t k,		/* row/column index to add */
+    cholmod_sparse *R,	/* row/column of matrix to factorize (n-by-1) */
+    double bk [2],	/* kth entry of the right hand side, b */
+    int *colmark,	/* int array of size n.  See cholmod_updown.c */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowadd_mark (size_t, cholmod_sparse *, double *, UF_long *,
+    cholmod_factor *, cholmod_dense *, cholmod_dense *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowdel:  delete a row from an LDL' factorization (a rank-2 update) */
+/* -------------------------------------------------------------------------- */
+
+/* Sets the kth row and column of L to be the kth row and column of the identity
+ * matrix, and updates L(k+1:n,k+1:n) accordingly.   To reduce the running time,
+ * the caller can optionally provide the nonzero pattern (or an upper bound) of
+ * kth row of L, as the sparse n-by-1 vector R.  Provide R as NULL if you want
+ * CHOLMOD to determine this itself, which is easier for the caller, but takes
+ * a little more time.
+ */
+
+int cholmod_rowdel 
+(
+    /* ---- input ---- */
+    size_t k,		/* row/column index to delete */
+    cholmod_sparse *R,	/* NULL, or the nonzero pattern of kth row of L */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowdel (size_t, cholmod_sparse *, cholmod_factor *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowdel_solve:  delete a row, and downdate Lx=b */
+/* -------------------------------------------------------------------------- */
+
+/* Does the same as cholmod_rowdel, but also downdates the solution to Lx=b.
+ * When row/column k of A is "deleted" from the system A*y=b, this can induce
+ * a change to x, in addition to changes arising when L and b are modified.
+ * If this is the case, the kth entry of y is required as input (yk) */
+
+int cholmod_rowdel_solve
+(
+    /* ---- input ---- */
+    size_t k,		/* row/column index to delete */
+    cholmod_sparse *R,	/* NULL, or the nonzero pattern of kth row of L */
+    double yk [2],	/* kth entry in the solution to A*y=b */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowdel_solve (size_t, cholmod_sparse *, double *,
+    cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowdel_mark:  delete a row, and downdate solution to partial Lx=b */
+/* -------------------------------------------------------------------------- */
+
+/* Does the same as cholmod_rowdel_solve, except only part of L is used in
+ * the update/downdate of the solution to Lx=b.  This routine is an "expert"
+ * routine.  It is meant for use in LPDASA only.  */
+
+int cholmod_rowdel_mark
+(
+    /* ---- input ---- */
+    size_t k,		/* row/column index to delete */
+    cholmod_sparse *R,	/* NULL, or the nonzero pattern of kth row of L */
+    double yk [2],	/* kth entry in the solution to A*y=b */
+    int *colmark,	/* int array of size n.  See cholmod_updown.c */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowdel_mark (size_t, cholmod_sparse *, double *, UF_long *,
+    cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ;
+
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Include/cholmod_partition.h b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_partition.h
new file mode 100644
index 0000000..1adbc46
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_partition.h
@@ -0,0 +1,233 @@
+/* ========================================================================== */
+/* === Include/cholmod_partition.h ========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_partition.h.
+ * Copyright (C) 2005-2006, Univ. of Florida.  Author: Timothy A. Davis
+ * CHOLMOD/Include/cholmod_partition.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD Partition module.
+ *
+ * Graph partitioning and graph-partition-based orderings.  Includes an
+ * interface to CCOLAMD and CSYMAMD, constrained minimum degree ordering
+ * methods which order a matrix following constraints determined via nested
+ * dissection.
+ *
+ * cholmod_nested_dissection	CHOLMOD nested dissection ordering
+ * cholmod_metis		METIS nested dissection ordering (METIS_NodeND)
+ * cholmod_ccolamd		interface to CCOLAMD ordering
+ * cholmod_csymamd		interface to CSYMAMD ordering
+ * cholmod_camd			interface to CAMD ordering
+ * cholmod_bisect		graph partitioner (currently based on METIS)
+ * cholmod_metis_bisector	direct interface to METIS_NodeComputeSeparator
+ *
+ * Requires the Core and Cholesky modules, and three packages: METIS, CAMD,
+ * and CCOLAMD.  Optionally used by the Cholesky module.
+ *
+ * Note that METIS does not have a version that uses UF_long integers.  If you
+ * try to use cholmod_nested_dissection, cholmod_metis, cholmod_bisect, or
+ * cholmod_metis_bisector on a matrix that is too large, an error code will be
+ * returned.  METIS does have an "idxtype", which could be redefined as UF_long,
+ * if you wish to edit METIS or use compile-time flags to redefine idxtype.
+ */
+
+#ifndef CHOLMOD_PARTITION_H
+#define CHOLMOD_PARTITION_H
+
+#include "cholmod_core.h"
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_nested_dissection */
+/* -------------------------------------------------------------------------- */
+
+/* Order A, AA', or A(:,f)*A(:,f)' using CHOLMOD's nested dissection method
+ * (METIS's node bisector applied recursively to compute the separator tree
+ * and constraint sets, followed by CCOLAMD using the constraints).  Usually
+ * finds better orderings than METIS_NodeND, but takes longer.
+ */
+
+UF_long cholmod_nested_dissection	/* returns # of components */
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- output --- */
+    int *Perm,		/* size A->nrow, output permutation */
+    int *CParent,	/* size A->nrow.  On output, CParent [c] is the parent
+			 * of component c, or EMPTY if c is a root, and where
+			 * c is in the range 0 to # of components minus 1 */
+    int *Cmember,	/* size A->nrow.  Cmember [j] = c if node j of A is
+			 * in component c */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+UF_long cholmod_l_nested_dissection (cholmod_sparse *, UF_long *, size_t,
+    UF_long *, UF_long *, UF_long *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_metis */
+/* -------------------------------------------------------------------------- */
+
+/* Order A, AA', or A(:,f)*A(:,f)' using METIS_NodeND. */
+
+int cholmod_metis
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int postorder,	/* if TRUE, follow with etree or coletree postorder */
+    /* ---- output --- */
+    int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_metis (cholmod_sparse *, UF_long *, size_t, int, UF_long *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_ccolamd */
+/* -------------------------------------------------------------------------- */
+
+/* Order AA' or A(:,f)*A(:,f)' using CCOLAMD. */
+
+int cholmod_ccolamd
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int *Cmember,	/* size A->nrow.  Cmember [i] = c if row i is in the
+			 * constraint set c.  c must be >= 0.  The # of
+			 * constraint sets is max (Cmember) + 1.  If Cmember is
+			 * NULL, then it is interpretted as Cmember [i] = 0 for
+			 * all i */
+    /* ---- output --- */
+    int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_ccolamd (cholmod_sparse *, UF_long *, size_t, UF_long *,
+    UF_long *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_csymamd */
+/* -------------------------------------------------------------------------- */
+
+/* Order A using CSYMAMD. */
+
+int cholmod_csymamd
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    /* ---- output --- */
+    int *Cmember,	/* size nrow.  see cholmod_ccolamd above */
+    int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_csymamd (cholmod_sparse *, UF_long *, UF_long *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_camd */
+/* -------------------------------------------------------------------------- */
+
+/* Order A using CAMD. */
+
+int cholmod_camd
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- output --- */
+    int *Cmember,	/* size nrow.  see cholmod_ccolamd above */
+    int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_camd (cholmod_sparse *, UF_long *, size_t, UF_long *, UF_long *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_bisect */
+/* -------------------------------------------------------------------------- */
+
+/* Finds a node bisector of A, A*A', A(:,f)*A(:,f)'. */
+
+UF_long cholmod_bisect	/* returns # of nodes in separator */
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to bisect */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int compress,	/* if TRUE, compress the graph first */
+    /* ---- output --- */
+    int *Partition,	/* size A->nrow.  Node i is in the left graph if
+			 * Partition [i] = 0, the right graph if 1, and in the
+			 * separator if 2. */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+UF_long cholmod_l_bisect (cholmod_sparse *, UF_long *, size_t, int, UF_long *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_metis_bisector */
+/* -------------------------------------------------------------------------- */
+
+/* Find a set of nodes that bisects the graph of A or AA' (direct interface
+ * to METIS_NodeComputeSeparator). */
+
+UF_long cholmod_metis_bisector	/* returns separator size */
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to bisect */
+    int *Anw,		/* size A->nrow, node weights */
+    int *Aew,		/* size nz, edge weights */
+    /* ---- output --- */
+    int *Partition,	/* size A->nrow.  see cholmod_bisect above. */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+UF_long cholmod_l_metis_bisector (cholmod_sparse *, UF_long *, UF_long *,
+    UF_long *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_collapse_septree */
+/* -------------------------------------------------------------------------- */
+
+/* Collapse nodes in a separator tree. */
+
+UF_long cholmod_collapse_septree
+(
+    /* ---- input ---- */
+    size_t n,		/* # of nodes in the graph */
+    size_t ncomponents,	/* # of nodes in the separator tree (must be <= n) */
+    double nd_oksep,    /* collapse if #sep >= nd_oksep * #nodes in subtree */
+    size_t nd_small,    /* collapse if #nodes in subtree < nd_small */
+    /* ---- in/out --- */
+    int *CParent,	/* size ncomponents; from cholmod_nested_dissection */
+    int *Cmember,	/* size n; from cholmod_nested_dissection */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+UF_long cholmod_l_collapse_septree (size_t, size_t, double, size_t, UF_long *,
+    UF_long *, cholmod_common *) ;
+
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Include/cholmod_supernodal.h b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_supernodal.h
new file mode 100644
index 0000000..cfb483e
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_supernodal.h
@@ -0,0 +1,147 @@
+/* ========================================================================== */
+/* === Include/cholmod_supernodal.h ========================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_supernodal.h.
+ * Copyright (C) 2005-2006, Timothy A. Davis
+ * CHOLMOD/Include/cholmod_supernodal.h is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD Supernodal module.
+ *
+ * Supernodal analysis, factorization, and solve.  The simplest way to use
+ * these routines is via the Cholesky module.  It does not provide any
+ * fill-reducing orderings, but does accept the orderings computed by the
+ * Cholesky module.  It does not require the Cholesky module itself, however.
+ *
+ * Primary routines:
+ * -----------------
+ * cholmod_super_symbolic	supernodal symbolic analysis
+ * cholmod_super_numeric	supernodal numeric factorization
+ * cholmod_super_lsolve		supernodal Lx=b solve
+ * cholmod_super_ltsolve	supernodal L'x=b solve
+ *
+ * Prototypes for the BLAS and LAPACK routines that CHOLMOD uses are listed
+ * below, including how they are used in CHOLMOD.
+ *
+ * BLAS routines:
+ * --------------
+ * dtrsv	solve Lx=b or L'x=b, L non-unit diagonal, x and b stride-1
+ * dtrsm	solve LX=B or L'X=b, L non-unit diagonal
+ * dgemv	y=y-A*x or y=y-A'*x (x and y stride-1)
+ * dgemm	C=A*B', C=C-A*B, or C=C-A'*B
+ * dsyrk	C=tril(A*A')
+ *
+ * LAPACK routines:
+ * ----------------
+ * dpotrf	LAPACK: A=chol(tril(A))
+ *
+ * Requires the Core module, and two external packages: LAPACK and the BLAS.
+ * Optionally used by the Cholesky module.
+ */
+
+#ifndef CHOLMOD_SUPERNODAL_H
+#define CHOLMOD_SUPERNODAL_H
+
+#include "cholmod_core.h"
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_super_symbolic */
+/* -------------------------------------------------------------------------- */
+
+/* Analyzes A, AA', or A(:,f)*A(:,f)' in preparation for a supernodal numeric
+ * factorization.  The user need not call this directly; cholmod_analyze is
+ * a "simple" wrapper for this routine.
+ */
+
+int cholmod_super_symbolic
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    cholmod_sparse *F,	/* F = A' or A(:,f)' */
+    int *Parent,	/* elimination tree */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* simplicial symbolic on input,
+			 * supernodal symbolic on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_super_symbolic (cholmod_sparse *, cholmod_sparse *, UF_long *,
+    cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_super_numeric */
+/* -------------------------------------------------------------------------- */
+
+/* Computes the numeric LL' factorization of A, AA', or A(:,f)*A(:,f)' using
+ * a BLAS-based supernodal method.  The user need not call this directly;
+ * cholmod_factorize is a "simple" wrapper for this routine.
+ */
+
+int cholmod_super_numeric
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    cholmod_sparse *F,	/* F = A' or A(:,f)' */
+    double beta [2],	/* beta*I is added to diagonal of matrix to factorize */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factorization */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_super_numeric (cholmod_sparse *, cholmod_sparse *, double *,
+    cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_super_lsolve */
+/* -------------------------------------------------------------------------- */
+
+/* Solve Lx=b where L is from a supernodal numeric factorization.  The user
+ * need not call this routine directly.  cholmod_solve is a "simple" wrapper
+ * for this routine. */
+
+int cholmod_super_lsolve
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to use for the forward solve */
+    /* ---- output ---- */
+    cholmod_dense *X,	/* b on input, solution to Lx=b on output */
+    /* ---- workspace   */
+    cholmod_dense *E,	/* workspace of size nrhs*(L->maxesize) */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_super_lsolve (cholmod_factor *, cholmod_dense *, cholmod_dense *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_super_ltsolve */
+/* -------------------------------------------------------------------------- */
+
+/* Solve L'x=b where L is from a supernodal numeric factorization.  The user
+ * need not call this routine directly.  cholmod_solve is a "simple" wrapper
+ * for this routine. */
+
+int cholmod_super_ltsolve
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to use for the backsolve */
+    /* ---- output ---- */
+    cholmod_dense *X,	/* b on input, solution to L'x=b on output */
+    /* ---- workspace   */
+    cholmod_dense *E,	/* workspace of size nrhs*(L->maxesize) */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_super_ltsolve (cholmod_factor *, cholmod_dense *, cholmod_dense *,
+    cholmod_common *) ;
+
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Include/cholmod_template.h b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_template.h
new file mode 100644
index 0000000..aa45b4d
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Include/cholmod_template.h
@@ -0,0 +1,238 @@
+/* ========================================================================== */
+/* === Include/cholmod_template.h =========================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* undefine current xtype macros, and then define macros for current type */
+/* -------------------------------------------------------------------------- */
+
+#undef TEMPLATE
+#undef XTYPE
+#undef XTYPE2
+#undef XTYPE_OK
+#undef ENTRY_IS_NONZERO
+#undef ENTRY_IS_ZERO
+#undef ENTRY_IS_ONE
+#undef IMAG_IS_NONZERO
+
+#undef ASSEMBLE
+#undef ASSIGN
+#undef ASSIGN_CONJ
+#undef ASSIGN2
+#undef ASSIGN2_CONJ
+#undef ASSIGN_REAL
+#undef MULT
+#undef MULTADD
+#undef ADD
+#undef ADD_REAL
+#undef MULTSUB
+#undef MULTADDCONJ
+#undef MULTSUBCONJ
+#undef LLDOT
+#undef CLEAR
+#undef DIV
+#undef DIV_REAL
+#undef MULT_REAL
+#undef CLEAR_IMAG
+#undef LDLDOT
+#undef PREFIX
+
+#undef ENTRY_SIZE
+
+#undef XPRINT0
+#undef XPRINT1
+#undef XPRINT2
+#undef XPRINT3
+
+/* -------------------------------------------------------------------------- */
+/* pattern */
+/* -------------------------------------------------------------------------- */
+
+
+#ifdef PATTERN
+
+#define PREFIX				    p_
+#define TEMPLATE(name)			    P_TEMPLATE(name)
+#define XTYPE				    CHOLMOD_PATTERN
+#define XTYPE2				    CHOLMOD_REAL
+#define XTYPE_OK(type)			    (TRUE)
+#define ENTRY_IS_NONZERO(ax,az,q)	    (TRUE)
+#define ENTRY_IS_ZERO(ax,az,q)		    (FALSE)
+#define ENTRY_IS_ONE(ax,az,q)		    (TRUE)
+#define IMAG_IS_NONZERO(ax,az,q)	    (FALSE)
+#define ENTRY_SIZE			    0
+
+#define ASSEMBLE(x,z,p,ax,az,q)
+#define ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN_CONJ(x,z,p,ax,az,q)
+#define ASSIGN2(x,z,p,ax,az,q)		    P_ASSIGN2(x,z,p,ax,az,q)
+#define ASSIGN2_CONJ(x,z,p,ax,az,q)	    P_ASSIGN2(x,z,p,ax,az,q)
+#define ASSIGN_REAL(x,p,ax,q)
+#define MULT(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTADD(x,z,p,ax,az,q,bx,bz,pb)
+#define ADD(x,z,p,ax,az,q,bx,bz,pb)
+#define ADD_REAL(x,p, ax,q, bx,r)
+#define MULTSUB(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb)
+#define LLDOT(x,p,ax,az,q)
+#define CLEAR(x,z,p)
+#define CLEAR_IMAG(x,z,p)
+#define DIV(x,z,p,ax,az,q)
+#define DIV_REAL(x,z,p, ax,az,q, bx,r)
+#define MULT_REAL(x,z,p, ax,az,q, bx,r)
+#define LDLDOT(x,p, ax,az,q, bx,r)
+
+#define XPRINT0(x,z,p)			    P_PRINT(0,x,z,p)
+#define XPRINT1(x,z,p)			    P_PRINT(1,x,z,p)
+#define XPRINT2(x,z,p)			    P_PRINT(2,x,z,p)
+#define XPRINT3(x,z,p)			    P_PRINT(3,x,z,p)
+
+/* -------------------------------------------------------------------------- */
+/* real */
+/* -------------------------------------------------------------------------- */
+
+#elif defined (REAL)
+
+#define PREFIX				    r_
+#define TEMPLATE(name)			    R_TEMPLATE(name)
+#define XTYPE				    CHOLMOD_REAL
+#define XTYPE2				    CHOLMOD_REAL
+#define XTYPE_OK(type)			    R_XTYPE_OK(type)
+#define ENTRY_IS_NONZERO(ax,az,q)	    R_IS_NONZERO(ax,az,q)
+#define ENTRY_IS_ZERO(ax,az,q)		    R_IS_ZERO(ax,az,q)
+#define ENTRY_IS_ONE(ax,az,q)		    R_IS_ONE(ax,az,q)
+#define IMAG_IS_NONZERO(ax,az,q)	    (FALSE)
+#define ENTRY_SIZE			    1
+
+#define ASSEMBLE(x,z,p,ax,az,q)		    R_ASSEMBLE(x,z,p,ax,az,q) 
+#define ASSIGN(x,z,p,ax,az,q)		    R_ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN_CONJ(x,z,p,ax,az,q)	    R_ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN2(x,z,p,ax,az,q)		    R_ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN2_CONJ(x,z,p,ax,az,q)	    R_ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN_REAL(x,p,ax,q)		    R_ASSIGN_REAL(x,p,ax,q)
+#define MULT(x,z,p,ax,az,q,bx,bz,pb)	    R_MULT(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTADD(x,z,p,ax,az,q,bx,bz,pb)     R_MULTADD(x,z,p,ax,az,q,bx,bz,pb)
+#define ADD(x,z,p,ax,az,q,bx,bz,pb)	    R_ADD(x,z,p,ax,az,q,bx,bz,pb)
+#define ADD_REAL(x,p, ax,q, bx,r)	    R_ADD_REAL(x,p, ax,q, bx,r)
+#define MULTSUB(x,z,p,ax,az,q,bx,bz,pb)     R_MULTSUB(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb) \
+    R_MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) \
+    R_MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb)
+#define LLDOT(x,p,ax,az,q)		    R_LLDOT(x,p,ax,az,q)
+#define CLEAR(x,z,p)			    R_CLEAR(x,z,p) 
+#define CLEAR_IMAG(x,z,p)		    R_CLEAR_IMAG(x,z,p) 
+#define DIV(x,z,p,ax,az,q)		    R_DIV(x,z,p,ax,az,q)
+#define DIV_REAL(x,z,p, ax,az,q, bx,r)	    R_DIV_REAL(x,z,p, ax,az,q, bx,r)
+#define MULT_REAL(x,z,p, ax,az,q, bx,r)	    R_MULT_REAL(x,z,p, ax,az,q, bx,r)
+#define LDLDOT(x,p, ax,az,q, bx,r)	    R_LDLDOT(x,p, ax,az,q, bx,r)
+
+#define XPRINT0(x,z,p)			    R_PRINT(0,x,z,p)
+#define XPRINT1(x,z,p)			    R_PRINT(1,x,z,p)
+#define XPRINT2(x,z,p)			    R_PRINT(2,x,z,p)
+#define XPRINT3(x,z,p)			    R_PRINT(3,x,z,p)
+
+/* -------------------------------------------------------------------------- */
+/* complex */
+/* -------------------------------------------------------------------------- */
+
+#elif defined (COMPLEX)
+
+#define PREFIX				    c_
+
+#ifdef NCONJUGATE
+#define TEMPLATE(name)			    CT_TEMPLATE(name)
+#else
+#define TEMPLATE(name)			    C_TEMPLATE(name)
+#endif
+
+#define ASSEMBLE(x,z,p,ax,az,q)		    C_ASSEMBLE(x,z,p,ax,az,q) 
+#define ASSIGN(x,z,p,ax,az,q)		    C_ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN_CONJ(x,z,p,ax,az,q)	    C_ASSIGN_CONJ(x,z,p,ax,az,q)
+#define ASSIGN2(x,z,p,ax,az,q)		    C_ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN2_CONJ(x,z,p,ax,az,q)	    C_ASSIGN_CONJ(x,z,p,ax,az,q)
+#define ASSIGN_REAL(x,p,ax,q)		    C_ASSIGN_REAL(x,p,ax,q)
+#define XTYPE				    CHOLMOD_COMPLEX
+#define XTYPE2				    CHOLMOD_COMPLEX
+#define XTYPE_OK(type)			    C_XTYPE_OK(type)
+#define ENTRY_IS_NONZERO(ax,az,q)	    C_IS_NONZERO(ax,az,q)
+#define ENTRY_IS_ZERO(ax,az,q)		    C_IS_ZERO(ax,az,q)
+#define ENTRY_IS_ONE(ax,az,q)		    C_IS_ONE(ax,az,q)
+#define IMAG_IS_NONZERO(ax,az,q)	    C_IMAG_IS_NONZERO(ax,az,q)
+#define ENTRY_SIZE			    2
+
+#define MULTADD(x,z,p,ax,az,q,bx,bz,pb)     C_MULTADD(x,z,p,ax,az,q,bx,bz,pb)
+#define MULT(x,z,p,ax,az,q,bx,bz,pb)	    C_MULT(x,z,p,ax,az,q,bx,bz,pb)
+#define ADD(x,z,p,ax,az,q,bx,bz,pb)	    C_ADD(x,z,p,ax,az,q,bx,bz,pb)
+#define ADD_REAL(x,p, ax,q, bx,r)	    C_ADD_REAL(x,p, ax,q, bx,r)
+#define MULTSUB(x,z,p,ax,az,q,bx,bz,pb)     C_MULTSUB(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb) \
+    C_MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) \
+    C_MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb)
+#define LLDOT(x,p,ax,az,q)		    C_LLDOT(x,p,ax,az,q)
+#define CLEAR(x,z,p)			    C_CLEAR(x,z,p) 
+#define CLEAR_IMAG(x,z,p)		    C_CLEAR_IMAG(x,z,p) 
+#define DIV(x,z,p,ax,az,q)		    C_DIV(x,z,p,ax,az,q)
+#define DIV_REAL(x,z,p, ax,az,q, bx,r)	    C_DIV_REAL(x,z,p, ax,az,q, bx,r)
+#define MULT_REAL(x,z,p, ax,az,q, bx,r)	    C_MULT_REAL(x,z,p, ax,az,q, bx,r)
+#define LDLDOT(x,p, ax,az,q, bx,r)	    C_LDLDOT(x,p, ax,az,q, bx,r)
+
+#define XPRINT0(x,z,p)			    C_PRINT(0,x,z,p)
+#define XPRINT1(x,z,p)			    C_PRINT(1,x,z,p)
+#define XPRINT2(x,z,p)			    C_PRINT(2,x,z,p)
+#define XPRINT3(x,z,p)			    C_PRINT(3,x,z,p)
+
+/* -------------------------------------------------------------------------- */
+/* zomplex */
+/* -------------------------------------------------------------------------- */
+
+#elif defined (ZOMPLEX)
+
+#define PREFIX				    z_
+
+#ifdef NCONJUGATE
+#define TEMPLATE(name)			    ZT_TEMPLATE(name)
+#else
+#define TEMPLATE(name)			    Z_TEMPLATE(name)
+#endif
+
+#define ASSEMBLE(x,z,p,ax,az,q)		    Z_ASSEMBLE(x,z,p,ax,az,q) 
+#define ASSIGN(x,z,p,ax,az,q)		    Z_ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN_CONJ(x,z,p,ax,az,q)	    Z_ASSIGN_CONJ(x,z,p,ax,az,q)
+#define ASSIGN2(x,z,p,ax,az,q)		    Z_ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN2_CONJ(x,z,p,ax,az,q)	    Z_ASSIGN_CONJ(x,z,p,ax,az,q)
+#define ASSIGN_REAL(x,p,ax,q)		    Z_ASSIGN_REAL(x,p,ax,q)
+#define XTYPE				    CHOLMOD_ZOMPLEX
+#define XTYPE2				    CHOLMOD_ZOMPLEX
+#define XTYPE_OK(type)			    Z_XTYPE_OK(type)
+#define ENTRY_IS_NONZERO(ax,az,q)	    Z_IS_NONZERO(ax,az,q)
+#define ENTRY_IS_ZERO(ax,az,q)		    Z_IS_ZERO(ax,az,q)
+#define ENTRY_IS_ONE(ax,az,q)		    Z_IS_ONE(ax,az,q)
+#define IMAG_IS_NONZERO(ax,az,q)	    Z_IMAG_IS_NONZERO(ax,az,q)
+#define ENTRY_SIZE			    1
+
+#define MULTADD(x,z,p,ax,az,q,bx,bz,pb)     Z_MULTADD(x,z,p,ax,az,q,bx,bz,pb)
+#define MULT(x,z,p,ax,az,q,bx,bz,pb)	    Z_MULT(x,z,p,ax,az,q,bx,bz,pb)
+#define ADD(x,z,p,ax,az,q,bx,bz,pb)	    Z_ADD(x,z,p,ax,az,q,bx,bz,pb)
+#define ADD_REAL(x,p, ax,q, bx,r)	    Z_ADD_REAL(x,p, ax,q, bx,r)
+#define MULTSUB(x,z,p,ax,az,q,bx,bz,pb)     Z_MULTSUB(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb) \
+    Z_MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) \
+    Z_MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb)
+#define LLDOT(x,p,ax,az,q)		    Z_LLDOT(x,p,ax,az,q)
+#define CLEAR(x,z,p)			    Z_CLEAR(x,z,p) 
+#define CLEAR_IMAG(x,z,p)		    Z_CLEAR_IMAG(x,z,p) 
+#define DIV(x,z,p,ax,az,q)		    Z_DIV(x,z,p,ax,az,q)
+#define DIV_REAL(x,z,p, ax,az,q, bx,r)	    Z_DIV_REAL(x,z,p, ax,az,q, bx,r)
+#define MULT_REAL(x,z,p, ax,az,q, bx,r)	    Z_MULT_REAL(x,z,p, ax,az,q, bx,r)
+#define LDLDOT(x,p, ax,az,q, bx,r)	    Z_LDLDOT(x,p, ax,az,q, bx,r)
+
+#define XPRINT0(x,z,p)			    Z_PRINT(0,x,z,p)
+#define XPRINT1(x,z,p)			    Z_PRINT(1,x,z,p)
+#define XPRINT2(x,z,p)			    Z_PRINT(2,x,z,p)
+#define XPRINT3(x,z,p)			    Z_PRINT(3,x,z,p)
+
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Lib/Makefile b/src/C/SuiteSparse/CHOLMOD/Lib/Makefile
new file mode 100644
index 0000000..117f869
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Lib/Makefile
@@ -0,0 +1,473 @@
+#===============================================================================
+# CHOLOMD/Lib/Makefile: for compiling the CHOLMOD library
+#===============================================================================
+
+default: all
+
+ccode: all
+
+include ../../UFconfig/UFconfig.mk
+
+C = $(CC) $(CFLAGS) $(CHOLMOD_CONFIG)
+
+all: libcholmod.a
+
+library: libcholmod.a
+
+purge: distclean
+
+distclean: clean
+	- $(RM) libcholmod.a
+
+clean:
+	- $(RM) $(CLEAN)
+
+#-------------------------------------------------------------------------------
+# ../Include/ directory contains all include files:
+#-------------------------------------------------------------------------------
+
+INC =   ../Include/cholmod.h \
+	../Include/cholmod_blas.h \
+	../Include/cholmod_check.h \
+	../Include/cholmod_cholesky.h \
+	../Include/cholmod_complexity.h \
+	../Include/cholmod_config.h \
+	../Include/cholmod_core.h \
+	../Include/cholmod_internal.h \
+	../Include/cholmod_matrixops.h \
+	../Include/cholmod_modify.h \
+	../Include/cholmod_partition.h \
+	../Include/cholmod_supernodal.h \
+	../Include/cholmod_template.h
+
+#-------------------------------------------------------------------------------
+# The 7 CHOLMOD library modules (int, double)
+#-------------------------------------------------------------------------------
+
+CORE = cholmod_aat.o cholmod_add.o cholmod_band.o \
+	cholmod_change_factor.o cholmod_common.o cholmod_complex.o \
+	cholmod_copy.o cholmod_dense.o cholmod_error.o cholmod_factor.o \
+	cholmod_memory.o cholmod_sparse.o \
+	cholmod_transpose.o cholmod_triplet.o
+
+CHECK = cholmod_check.o cholmod_read.o cholmod_write.o
+
+CHOLESKY = cholmod_amd.o cholmod_analyze.o cholmod_colamd.o \
+	cholmod_etree.o cholmod_factorize.o cholmod_postorder.o \
+	cholmod_rcond.o cholmod_resymbol.o cholmod_rowcolcounts.o \
+	cholmod_rowfac.o cholmod_solve.o cholmod_spsolve.o
+
+MATRIXOPS = cholmod_drop.o cholmod_horzcat.o cholmod_norm.o \
+	cholmod_scale.o cholmod_sdmult.o cholmod_ssmult.o \
+	cholmod_submatrix.o cholmod_vertcat.o cholmod_symmetry.o
+
+PARTITION = cholmod_ccolamd.o cholmod_csymamd.o \
+	cholmod_metis.o cholmod_nesdis.o cholmod_camd.o
+
+MODIFY = cholmod_rowadd.o cholmod_rowdel.o cholmod_updown.o
+
+SUPERNODAL = cholmod_super_numeric.o cholmod_super_solve.o \
+	cholmod_super_symbolic.o
+
+DI = $(CORE) $(CHECK) $(CHOLESKY) $(MATRIXOPS) $(MODIFY) $(SUPERNODAL) \
+	$(PARTITION)
+
+#-------------------------------------------------------------------------------
+# CHOLMOD library modules (long, double)
+#-------------------------------------------------------------------------------
+
+LCORE = cholmod_l_aat.o cholmod_l_add.o cholmod_l_band.o \
+	cholmod_l_change_factor.o cholmod_l_common.o cholmod_l_complex.o \
+	cholmod_l_copy.o cholmod_l_dense.o cholmod_l_error.o \
+	cholmod_l_factor.o cholmod_l_memory.o \
+	cholmod_l_sparse.o cholmod_l_transpose.o cholmod_l_triplet.o
+
+LCHECK = cholmod_l_check.o cholmod_l_read.o cholmod_l_write.o
+
+LCHOLESKY = cholmod_l_amd.o cholmod_l_analyze.o cholmod_l_colamd.o \
+	cholmod_l_etree.o cholmod_l_factorize.o cholmod_l_postorder.o \
+	cholmod_l_rcond.o cholmod_l_resymbol.o cholmod_l_rowcolcounts.o \
+	cholmod_l_rowfac.o cholmod_l_solve.o cholmod_l_spsolve.o
+
+LMATRIXOPS = cholmod_l_drop.o cholmod_l_horzcat.o cholmod_l_norm.o \
+	cholmod_l_scale.o cholmod_l_sdmult.o cholmod_l_ssmult.o \
+	cholmod_l_submatrix.o cholmod_l_vertcat.o cholmod_l_symmetry.o
+
+LPARTITION = cholmod_l_ccolamd.o cholmod_l_csymamd.o \
+	cholmod_l_metis.o cholmod_l_nesdis.o cholmod_l_camd.o
+
+LMODIFY = cholmod_l_rowadd.o cholmod_l_rowdel.o cholmod_l_updown.o
+
+LSUPERNODAL = cholmod_l_super_numeric.o cholmod_l_super_solve.o \
+	cholmod_l_super_symbolic.o
+
+DL = $(LCORE) $(LCHECK) $(LCHOLESKY) $(LMATRIXOPS) $(LMODIFY) $(LSUPERNODAL) \
+	$(LPARTITION)
+
+#-------------------------------------------------------------------------------
+
+# to compile just the double/int version, use OBJ = $(DI)
+OBJ = $(DI) $(DL)
+
+libcholmod.a: $(OBJ)
+	$(AR) libcholmod.a $(OBJ)
+	$(RANLIB) libcholmod.a
+
+$(OBJ): $(INC)
+
+I = -I../../AMD/Include -I../../AMD/Source -I../../COLAMD \
+	-I$(METIS_PATH)/Lib -I../../CCOLAMD -I../../CAMD/Include -I../Include \
+	-I../../UFconfig
+
+
+#-------------------------------------------------------------------------------
+# Check Module:
+#-------------------------------------------------------------------------------
+
+cholmod_check.o: ../Check/cholmod_check.c
+	$(C) -c $(I) $<
+
+cholmod_read.o: ../Check/cholmod_read.c
+	$(C) -c $(I) $<
+
+cholmod_write.o: ../Check/cholmod_write.c
+	$(C) -c $(I) $<
+
+#-------------------------------------------------------------------------------
+
+cholmod_l_check.o: ../Check/cholmod_check.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_read.o: ../Check/cholmod_read.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_write.o: ../Check/cholmod_write.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+
+#-------------------------------------------------------------------------------
+# Core Module:
+#-------------------------------------------------------------------------------
+
+cholmod_common.o: ../Core/cholmod_common.c
+	$(C) -c $(I) $<
+
+cholmod_dense.o: ../Core/cholmod_dense.c ../Core/t_cholmod_dense.c
+	$(C) -c $(I) $<
+
+cholmod_factor.o: ../Core/cholmod_factor.c
+	$(C) -c $(I) $<
+
+cholmod_change_factor.o: ../Core/cholmod_change_factor.c \
+	../Core/t_cholmod_change_factor.c
+	$(C) -c $(I) $<
+
+cholmod_memory.o: ../Core/cholmod_memory.c
+	$(C) -c $(I) $<
+
+cholmod_sparse.o: ../Core/cholmod_sparse.c
+	$(C) -c $(I) $<
+
+cholmod_complex.o: ../Core/cholmod_complex.c
+	$(C) -c $(I) $<
+
+cholmod_transpose.o: ../Core/cholmod_transpose.c ../Core/t_cholmod_transpose.c
+	$(C) -c $(I) $<
+
+cholmod_band.o: ../Core/cholmod_band.c
+	$(C) -c $(I) $<
+
+cholmod_copy.o: ../Core/cholmod_copy.c
+	$(C) -c $(I) $<
+
+cholmod_triplet.o: ../Core/cholmod_triplet.c ../Core/t_cholmod_triplet.c
+	$(C) -c $(I) $<
+
+cholmod_error.o: ../Core/cholmod_error.c
+	$(C) -c $(I) $<
+
+cholmod_aat.o: ../Core/cholmod_aat.c
+	$(C) -c $(I) $<
+
+cholmod_add.o: ../Core/cholmod_add.c
+	$(C) -c $(I) $<
+
+#-------------------------------------------------------------------------------
+
+cholmod_l_common.o: ../Core/cholmod_common.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_dense.o: ../Core/cholmod_dense.c ../Core/t_cholmod_dense.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_factor.o: ../Core/cholmod_factor.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_change_factor.o: ../Core/cholmod_change_factor.c \
+	../Core/t_cholmod_change_factor.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_memory.o: ../Core/cholmod_memory.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_sparse.o: ../Core/cholmod_sparse.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_complex.o: ../Core/cholmod_complex.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_transpose.o: ../Core/cholmod_transpose.c ../Core/t_cholmod_transpose.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_band.o: ../Core/cholmod_band.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_copy.o: ../Core/cholmod_copy.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_triplet.o: ../Core/cholmod_triplet.c ../Core/t_cholmod_triplet.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_error.o: ../Core/cholmod_error.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_aat.o: ../Core/cholmod_aat.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_add.o: ../Core/cholmod_add.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+
+#-------------------------------------------------------------------------------
+# Cholesky Module:
+#-------------------------------------------------------------------------------
+
+cholmod_amd.o: ../Cholesky/cholmod_amd.c
+	$(C) -c $(I) $<
+
+cholmod_analyze.o: ../Cholesky/cholmod_analyze.c
+	$(C) -c $(I) $<
+
+cholmod_colamd.o: ../Cholesky/cholmod_colamd.c
+	$(C) -c $(I) $<
+
+cholmod_etree.o: ../Cholesky/cholmod_etree.c
+	$(C) -c $(I) $<
+
+cholmod_factorize.o: ../Cholesky/cholmod_factorize.c
+	$(C) -c $(I) $<
+
+cholmod_postorder.o: ../Cholesky/cholmod_postorder.c
+	$(C) -c $(I) $<
+
+cholmod_rcond.o: ../Cholesky/cholmod_rcond.c
+	$(C) -c $(I) $<
+
+cholmod_resymbol.o: ../Cholesky/cholmod_resymbol.c
+	$(C) -c $(I) $<
+
+cholmod_rowcolcounts.o: ../Cholesky/cholmod_rowcolcounts.c
+	$(C) -c $(I) $<
+
+cholmod_solve.o: ../Cholesky/cholmod_solve.c ../Cholesky/t_cholmod_lsolve.c \
+	../Cholesky/t_cholmod_ltsolve.c ../Cholesky/t_cholmod_solve.c
+	$(C) -c $(I) $<
+
+cholmod_spsolve.o: ../Cholesky/cholmod_spsolve.c
+	$(C) -c $(I) $<
+
+cholmod_rowfac.o: ../Cholesky/cholmod_rowfac.c ../Cholesky/t_cholmod_rowfac.c
+	$(C) -c $(I) $<
+
+#-------------------------------------------------------------------------------
+
+cholmod_l_amd.o: ../Cholesky/cholmod_amd.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_analyze.o: ../Cholesky/cholmod_analyze.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_colamd.o: ../Cholesky/cholmod_colamd.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_etree.o: ../Cholesky/cholmod_etree.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_factorize.o: ../Cholesky/cholmod_factorize.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_postorder.o: ../Cholesky/cholmod_postorder.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_rcond.o: ../Cholesky/cholmod_rcond.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_resymbol.o: ../Cholesky/cholmod_resymbol.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_rowcolcounts.o: ../Cholesky/cholmod_rowcolcounts.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_solve.o: ../Cholesky/cholmod_solve.c ../Cholesky/t_cholmod_lsolve.c \
+	../Cholesky/t_cholmod_ltsolve.c ../Cholesky/t_cholmod_solve.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_spsolve.o: ../Cholesky/cholmod_spsolve.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_rowfac.o: ../Cholesky/cholmod_rowfac.c ../Cholesky/t_cholmod_rowfac.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+#-------------------------------------------------------------------------------
+# Partition Module:
+#-------------------------------------------------------------------------------
+
+cholmod_ccolamd.o: ../Partition/cholmod_ccolamd.c
+	$(C) -c $(I) $<
+
+cholmod_csymamd.o: ../Partition/cholmod_csymamd.c
+	$(C) -c $(I) $<
+
+cholmod_camd.o: ../Partition/cholmod_camd.c
+	$(C) -c $(I) $<
+
+cholmod_metis.o: ../Partition/cholmod_metis.c
+	$(C) -c $(I) $<
+
+cholmod_nesdis.o: ../Partition/cholmod_nesdis.c
+	$(C) -c $(I) $<
+
+#-------------------------------------------------------------------------------
+
+cholmod_l_ccolamd.o: ../Partition/cholmod_ccolamd.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_csymamd.o: ../Partition/cholmod_csymamd.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_camd.o: ../Partition/cholmod_camd.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_metis.o: ../Partition/cholmod_metis.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_nesdis.o: ../Partition/cholmod_nesdis.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+
+#-------------------------------------------------------------------------------
+# MatrixOps Module:
+#-------------------------------------------------------------------------------
+
+cholmod_horzcat.o: ../MatrixOps/cholmod_horzcat.c
+	$(C) -c $(I) $<
+
+cholmod_norm.o: ../MatrixOps/cholmod_norm.c
+	$(C) -c $(I) $<
+
+cholmod_scale.o: ../MatrixOps/cholmod_scale.c
+	$(C) -c $(I) $<
+
+cholmod_drop.o: ../MatrixOps/cholmod_drop.c
+	$(C) -c $(I) $<
+
+cholmod_sdmult.o: ../MatrixOps/cholmod_sdmult.c \
+	../MatrixOps/t_cholmod_sdmult.c
+	$(C) -c $(I) $<
+
+cholmod_ssmult.o: ../MatrixOps/cholmod_ssmult.c
+	$(C) -c $(I) $<
+
+cholmod_submatrix.o: ../MatrixOps/cholmod_submatrix.c
+	$(C) -c $(I) $<
+
+cholmod_vertcat.o: ../MatrixOps/cholmod_vertcat.c
+	$(C) -c $(I) $<
+
+cholmod_symmetry.o: ../MatrixOps/cholmod_symmetry.c
+	$(C) -c $(I) $<
+
+#-------------------------------------------------------------------------------
+
+cholmod_l_horzcat.o: ../MatrixOps/cholmod_horzcat.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_norm.o: ../MatrixOps/cholmod_norm.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_scale.o: ../MatrixOps/cholmod_scale.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_drop.o: ../MatrixOps/cholmod_drop.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_sdmult.o: ../MatrixOps/cholmod_sdmult.c \
+	../MatrixOps/t_cholmod_sdmult.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_ssmult.o: ../MatrixOps/cholmod_ssmult.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_submatrix.o: ../MatrixOps/cholmod_submatrix.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_vertcat.o: ../MatrixOps/cholmod_vertcat.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_symmetry.o: ../MatrixOps/cholmod_symmetry.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+#-------------------------------------------------------------------------------
+# Modify Module:
+#-------------------------------------------------------------------------------
+
+cholmod_rowadd.o: ../Modify/cholmod_rowadd.c
+	$(C) -c $(I) $<
+
+cholmod_rowdel.o: ../Modify/cholmod_rowdel.c
+	$(C) -c $(I) $<
+
+cholmod_updown.o: ../Modify/cholmod_updown.c \
+	../Modify/t_cholmod_updown.c ../Modify/t_cholmod_updown_numkr.c
+	$(C) -c $(I) $<
+
+#-------------------------------------------------------------------------------
+
+cholmod_l_rowadd.o: ../Modify/cholmod_rowadd.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_rowdel.o: ../Modify/cholmod_rowdel.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_updown.o: ../Modify/cholmod_updown.c \
+	../Modify/t_cholmod_updown.c ../Modify/t_cholmod_updown_numkr.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+
+#-------------------------------------------------------------------------------
+# Supernodal Module:
+#-------------------------------------------------------------------------------
+
+cholmod_super_numeric.o: ../Supernodal/cholmod_super_numeric.c \
+	../Supernodal/t_cholmod_super_numeric.c
+	$(C) -c $(I) $<
+
+cholmod_super_symbolic.o: ../Supernodal/cholmod_super_symbolic.c
+	$(C) -c $(I) $<
+
+cholmod_super_solve.o: ../Supernodal/cholmod_super_solve.c \
+	../Supernodal/t_cholmod_super_solve.c
+	$(C) -c $(I) $<
+
+#-------------------------------------------------------------------------------
+
+cholmod_l_super_numeric.o: ../Supernodal/cholmod_super_numeric.c \
+	../Supernodal/t_cholmod_super_numeric.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_super_symbolic.o: ../Supernodal/cholmod_super_symbolic.c
+	$(C) -DDLONG -c $(I) $< -o $@
+
+cholmod_l_super_solve.o: ../Supernodal/cholmod_super_solve.c \
+	../Supernodal/t_cholmod_super_solve.c
+	$(C) -DDLONG -c $(I) $< -o $@
diff --git a/src/C/SuiteSparse/CHOLMOD/Makefile b/src/C/SuiteSparse/CHOLMOD/Makefile
new file mode 100644
index 0000000..1916688
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Makefile
@@ -0,0 +1,59 @@
+#-------------------------------------------------------------------------------
+# CHOLMOD Makefile
+#-------------------------------------------------------------------------------
+
+# Note: If you do not have METIS, or do not wish to use it in CHOLMOD, you must
+# compile CHOLMOD with the -DNPARTITION flag.  See ../UFconfig/UFconfig.mk.
+
+default: all
+
+include ../UFconfig/UFconfig.mk
+
+# Compile the C-callable libraries and the Demo programs.
+all:
+	( cd Lib ; $(MAKE) )
+	( cd Demo ; $(MAKE) )
+
+# Compile the C-callable libraries only.
+library:
+	( cd Lib ; $(MAKE) )
+
+# Remove all files not in the original distribution
+purge:
+	( cd MATLAB ; $(MAKE) purge )
+	( cd Tcov ; $(MAKE) purge )
+	( cd Lib ; $(MAKE) purge )
+#	( cd Valgrind ; $(MAKE) purge )
+	( cd Demo ; $(MAKE) purge )
+	( cd Doc ; $(MAKE) purge )
+
+# Remove all files not in the original distribution, except keep the 
+# compiled libraries.
+clean:
+	( cd MATLAB ; $(MAKE) clean )
+	( cd Tcov ; $(MAKE) clean )
+	( cd Lib ; $(MAKE) clean )
+	( cd Valgrind ; $(MAKE) clean )
+	( cd Demo ; $(MAKE) clean )
+
+distclean: purge
+
+ccode: all
+
+# Compile the MATLAB mexFunctions (you can also use cholmod_make.m in MATLAB)
+mex:
+	( cd MATLAB ; $(MAKE) )
+
+# Run the test coverage suite.  Takes about 40 minutes on a 3.2GHz Pentium.
+# Requires Linux (gcc, gcov).
+cov:
+	( cd Tcov ; $(MAKE) go )
+
+# Run the test coverage suite using Valgrind.  This takes a *** long *** time.
+valgrind:
+	( cd Valgrind ; $(MAKE) )
+
+# Compile the C-callable libraries and the Demo programs.
+demo:
+	( cd Demo ; $(MAKE) )
+
diff --git a/src/C/SuiteSparse/CHOLMOD/README.txt b/src/C/SuiteSparse/CHOLMOD/README.txt
new file mode 100644
index 0000000..61f0131
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/README.txt
@@ -0,0 +1,76 @@
+CHOLMOD: a sparse CHOLesky MODification package 
+-----------------------------------------------
+
+    CHOLMOD is a set of routines for factorizing sparse symmetric positive
+    definite matrices of the form A or AA', updating/downdating a sparse
+    Cholesky factorization, solving linear systems, updating/downdating
+    the solution to the triangular system Lx=b, and many other sparse matrix
+    functions for both symmetric and unsymmetric matrices.  Its supernodal
+    Cholesky factorization relies on LAPACK and the Level-3 BLAS, and obtains
+    a substantial fraction of the peak performance of the BLAS.  Both real and
+    complex matrices are supported.  CHOLMOD is written in ANSI/ISO C, with both
+    C and MATLAB interfaces.  This code works on Microsoft Windows and many
+    versions of Unix and Linux.
+
+Version 1.4, Dec 12, 2006.  Copyright (c) 2005-2006.
+
+Some Modules of CHOLMOD are copyrighted by the University of Florida (the
+Core and Partition Modules).  The rest are copyrighted by the authors:
+Timothy A. Davis (all of them), and William W. Hager (the Modify Module).
+
+CHOLMOD relies on several other packages:  AMD, CAMD, COLAMD, CCOLAMD, UFconfig,
+METIS, the BLAS, and LAPACK.  All but METIS, the BLAS, and LAPACK are part of
+SuiteSparse.
+
+AMD is authored by T. Davis, Iain Duff, and Patrick Amestoy.
+COLAMD is authored by T. Davis and Stefan Larimore, with algorithmic design
+in collaboration with John Gilbert and Esmond Ng.
+CCOLAMD is authored by T. Davis and Siva Rajamanickam.
+CAMD is authored by T. Davis and Y. Chen.
+
+LAPACK and the BLAS are authored by Jack Dongarra and many others.
+LAPACK is available at http://www.netlib.org/lapack
+
+METIS is authored by George Karypis, Univ. of Minnesota.  Its use in CHOLMOD
+is optional.  See http://www-users.cs.umn.edu/~karypis/metis.
+Place a copy of the metis-4.0 directory in the same directory that
+contains the CHOLMOD, AMD, COLAMD, and CCOLAMD directories.  Then do:
+    cd metis-4.0 ; make
+You may then compile CHOLMOD.
+
+The CHOLMOD, AMD, COLAMD, CCOLAMD, and UFconfig directories must all reside
+in a common parent directory.  To compile all these libraries,
+edit UFconfig/UFconfig.mk to reflect your environment (C compiler, location
+of the BLAS, and so on) and then type "make" in either the CHOLMOD directory
+or in the parent directory of CHOLMOD.  See each package for more details on
+how to compile them.
+
+For use in MATLAB (on any system, including Windows):  start MATLAB,
+cd to the CHOLMOD/MATLAB directory, and type cholmod_make in the MATLAB
+Command Window.  This is the best way to compile CHOLMOD for MATLAB; it
+provides a workaround for a METIS design feature, in which METIS terminates
+your program (and thus MATLAB) if it runs out of memory.  Using cholmod_make
+also ensures your mexFunctions are compiled with -fexceptions, so that
+exceptions are handled properly (when hitting control-C in the MATLAB command
+window, for example).
+
+    NOTE: DO NOT ATTEMPT TO USE THIS CODE IN 64-BIT MATLAB (v7.3).
+    It is not yet ported to that version of MATLAB.
+
+On the Pentium, do NOT use the Intel MKL BLAS prior to MKL Version 8.0 with
+CHOLMOD.  Older versions (prior to 8.0) have a bug in dgemm when computing
+A*B'.  The bug generates a NaN result, when the inputs are well-defined.  Use
+the Goto BLAS or the MKL v8.0 BLAS instead.  The Goto BLAS is faster and more
+reliable.  See http://www.tacc.utexas.edu/~kgoto/ or
+http://www.cs.utexas.edu/users/flame/goto/.
+Sadly, the Intel MKL BLAS 7.x is the default for MATLAB 7.0.4.  See
+http://www.mathworks.com/support/bugreports/details.html?rp=252103 for more
+details.  To workaround this problem on Linux, set environment variable
+BLAS_VERSION to libmkl_p3.so:libguide.so. On Windows, set environment variable
+BLAS_VERSION to mkl_p3.dll.  Better yet, get MATLAB 7sp3 (MATLAB 7.1) or later.
+
+Acknowledgements:  this work was supported in part by the National Science
+Foundation (NFS CCR-0203270 and DMS-9803599), and a grant from Sandia National
+Laboratories (Dept. of Energy) which supported the development of CHOLMOD's
+Partition Module.
+
diff --git a/src/C/SuiteSparse/CHOLMOD/Supernodal/License.txt b/src/C/SuiteSparse/CHOLMOD/Supernodal/License.txt
new file mode 100644
index 0000000..668c929
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Supernodal/License.txt
@@ -0,0 +1,25 @@
+CHOLMOD/Supernodal Module.
+Copyright (C) 2005-2006, Timothy A. Davis
+CHOLMOD is also available under other licenses; contact authors for details.
+http://www.cise.ufl.edu/research/sparse
+
+Note that this license is for the CHOLMOD/Supernodal module only.
+All CHOLMOD modules are licensed separately.
+
+
+--------------------------------------------------------------------------------
+
+
+This Module is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This Module is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this Module; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
diff --git a/src/C/SuiteSparse/CHOLMOD/Supernodal/cholmod_super_numeric.c b/src/C/SuiteSparse/CHOLMOD/Supernodal/cholmod_super_numeric.c
new file mode 100644
index 0000000..28c6abc
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Supernodal/cholmod_super_numeric.c
@@ -0,0 +1,295 @@
+/* ========================================================================== */
+/* === Supernodal/cholmod_super_numeric ===================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Supernodal Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Supernodal Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Computes the Cholesky factorization of A+beta*I or A*F+beta*I.  Only the
+ * the lower triangular part of A+beta*I or A*F+beta*I is accessed.  The
+ * matrices A and F must already be permuted according to the fill-reduction
+ * permutation L->Perm.  cholmod_factorize is an "easy" wrapper for this code
+ * which applies that permutation.  beta is real.
+ *
+ * Symmetric case: A is a symmetric (lower) matrix.  F is not accessed.
+ * With a fill-reducing permutation, A(p,p) should be passed instead, where is
+ * p is L->Perm.
+ *
+ * Unsymmetric case: A is unsymmetric, and F must be present.  Normally, F=A'.
+ * With a fill-reducing permutation, A(p,f) and A(p,f)' should be passed as A
+ * and F, respectively, where f is a list of the subset of the columns of A.
+ *
+ * The input factorization L must be supernodal (L->is_super is TRUE).  It can
+ * either be symbolic or numeric.  In the first case, L has been analyzed by
+ * cholmod_analyze or cholmod_super_symbolic, but the matrix has not yet been
+ * numerically factorized.  The numerical values are allocated here and the
+ * factorization is computed.  In the second case, a prior matrix has been
+ * analyzed and numerically factorized, and a new matrix is being factorized.
+ * The numerical values of L are replaced with the new numerical factorization.
+ *
+ * L->is_ll is ignored, and set to TRUE.  This routine always computes an LL'
+ * factorization.  Supernodal LDL' factorization is not (yet) supported.
+ * FUTURE WORK: perform a supernodal LDL' factorization if L->is_ll is FALSE.
+ *
+ * Uses BLAS routines dsyrk, dgemm, dtrsm, and the LAPACK routine dpotrf.
+ * The supernodal solver uses BLAS routines dtrsv, dgemv, dtrsm, and dgemm.
+ *
+ * If the matrix is not positive definite the routine returns TRUE, but sets
+ * Common->status to CHOLMOD_NOT_POSDEF and L->minor is set to the column at
+ * which the failure occurred.  The supernode containing the non-positive
+ * diagonal entry is set to zero (this includes columns to the left of L->minor
+ * in the same supernode), as are all subsequent supernodes.
+ *
+ * workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow + 4*nsuper).
+ *	Allocates temporary space of size L->maxcsize * sizeof(double)
+ *	(twice that for the complex/zomplex case).
+ *
+ * If L is supernodal symbolic on input, it is converted to a supernodal numeric
+ * factor on output, with an xtype of real if A is real, or complex if A is
+ * complex or zomplex.  If L is supernodal numeric on input, its xtype must
+ * match A (except that L can be complex and A zomplex).  The xtype of A and F
+ * must match.
+ */
+
+#ifndef NSUPERNODAL
+
+#include "cholmod_internal.h"
+#include "cholmod_supernodal.h"
+
+/* ========================================================================== */
+/* === TEMPLATE ============================================================= */
+/* ========================================================================== */
+
+#define REAL
+#include "t_cholmod_super_numeric.c"
+#define COMPLEX
+#include "t_cholmod_super_numeric.c"
+#define ZOMPLEX
+#include "t_cholmod_super_numeric.c"
+
+/* ========================================================================== */
+/* === cholmod_super_numeric ================================================ */
+/* ========================================================================== */
+
+/* Returns TRUE if successful, or if the matrix is not positive definite.
+ * Returns FALSE if out of memory, inputs are invalid, or other fatal error
+ * occurs.
+ */
+
+int CHOLMOD(super_numeric)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    cholmod_sparse *F,	/* F = A' or A(:,f)' */
+    double beta [2],	/* beta*I is added to diagonal of matrix to factorize */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factorization */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *C ;
+    Int *Super, *Map, *SuperMap ;
+    size_t maxcsize ;
+    Int nsuper, n, i, k, s, stype, nrow ;
+    int ok = TRUE, symbolic ;
+    size_t t, w ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_COMPLEX, FALSE) ;
+    stype = A->stype ;
+    if (stype < 0)
+    {
+	if (A->nrow != A->ncol || A->nrow != L->n)
+	{
+	    ERROR (CHOLMOD_INVALID, "invalid dimensions") ;
+	    return (FALSE) ;
+	}
+    }
+    else if (stype == 0)
+    {
+	if (A->nrow != L->n)
+	{
+	    ERROR (CHOLMOD_INVALID, "invalid dimensions") ;
+	    return (FALSE) ;
+	}
+	RETURN_IF_NULL (F, FALSE) ;
+	RETURN_IF_XTYPE_INVALID (F, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+	if (A->nrow != F->ncol || A->ncol != F->nrow || F->stype != 0)
+	{
+	    ERROR (CHOLMOD_INVALID, "F invalid") ;
+	    return (FALSE) ;
+	}
+	if (A->xtype != F->xtype)
+	{
+	    ERROR (CHOLMOD_INVALID, "A and F must have same xtype") ;
+	    return (FALSE) ;
+	}
+    }
+    else
+    {
+	/* symmetric upper case not suppored */
+	ERROR (CHOLMOD_INVALID, "symmetric upper case not supported") ;
+	return (FALSE) ;
+    }
+    if (!(L->is_super))
+    {
+	ERROR (CHOLMOD_INVALID, "L not supernodal") ;
+	return (FALSE) ;
+    }
+    if (L->xtype != CHOLMOD_PATTERN)
+    {
+	if (! ((A->xtype == CHOLMOD_REAL    && L->xtype == CHOLMOD_REAL)
+	    || (A->xtype == CHOLMOD_COMPLEX && L->xtype == CHOLMOD_COMPLEX)
+	    || (A->xtype == CHOLMOD_ZOMPLEX && L->xtype == CHOLMOD_COMPLEX)))
+	{
+	    ERROR (CHOLMOD_INVALID, "complex type mismatch") ;
+	    return (FALSE) ;
+	}
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace in Common */
+    /* ---------------------------------------------------------------------- */
+
+    nsuper = L->nsuper ;
+    maxcsize = L->maxcsize ;
+    nrow = A->nrow ;
+    n = nrow ;
+
+    PRINT1 (("nsuper "ID" maxcsize %g\n", nsuper, (double) maxcsize)) ;
+    ASSERT (nsuper >= 0 && maxcsize > 0) ;
+
+    /* w = 2*n + 4*nsuper */
+    w = CHOLMOD(mult_size_t) (n, 2, &ok) ;
+    t = CHOLMOD(mult_size_t) (nsuper, 4, &ok) ;
+    w = CHOLMOD(add_size_t) (w, t, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (n, w, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get the current factor L and allocate numerical part, if needed */
+    /* ---------------------------------------------------------------------- */
+
+    Super = L->super ;
+    symbolic = (L->xtype == CHOLMOD_PATTERN) ;
+    if (symbolic)
+    {
+	/* convert to supernodal numeric by allocating L->x */
+	CHOLMOD(change_factor) (
+		(A->xtype == CHOLMOD_REAL) ? CHOLMOD_REAL : CHOLMOD_COMPLEX,
+		TRUE, TRUE, TRUE, TRUE, L, Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* the factor L remains in symbolic supernodal form */
+	    return (FALSE) ;
+	}
+    }
+    ASSERT (L->dtype == DTYPE) ;
+    ASSERT (L->xtype == CHOLMOD_REAL || L->xtype == CHOLMOD_COMPLEX) ;
+
+    /* supernodal LDL' is not supported */
+    L->is_ll = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get more workspace */
+    /* ---------------------------------------------------------------------- */
+
+    C = CHOLMOD(allocate_dense) (maxcsize, 1, maxcsize, L->xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	int status = Common->status ;
+	if (symbolic)
+	{
+	    /* Change L back to symbolic, since the numeric values are not
+	     * initialized.  This cannot fail. */
+	    CHOLMOD(change_factor) (CHOLMOD_PATTERN, TRUE, TRUE, TRUE, TRUE,
+		    L, Common) ;
+	}
+	/* the factor L is now back to the form it had on input */
+	Common->status = status ;
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    SuperMap = Common->Iwork ;		/* size n (i/i/l) */
+    Map = Common->Flag ;    /* size n, use Flag as workspace for Map array */
+    for (i = 0 ; i < n ; i++)
+    {
+	Map [i] = EMPTY ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* find the mapping of nodes to relaxed supernodes */
+    /* ---------------------------------------------------------------------- */
+
+    /* SuperMap [k] = s if column k is contained in supernode s */
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	PRINT1 (("Super ["ID"] "ID" ncols "ID"\n",
+		    s, Super[s], Super[s+1]-Super[s]));
+	for (k = Super [s] ; k < Super [s+1] ; k++)
+	{
+	    SuperMap [k] = s ;
+	    PRINT2 (("relaxed SuperMap ["ID"] = "ID"\n", k, SuperMap [k])) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* supernodal numerical factorization, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (A->xtype)
+    {
+	case CHOLMOD_REAL:
+	    ok = r_cholmod_super_numeric (A, F, beta, L, C, Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    ok = c_cholmod_super_numeric (A, F, beta, L, C, Common) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    /* This operates on complex L, not zomplex */
+	    ok = z_cholmod_super_numeric (A, F, beta, L, C, Common) ;
+	    break ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* clear Common workspace, free temp workspace C, and return */
+    /* ---------------------------------------------------------------------- */
+
+    /* Flag array was used as workspace, clear it */
+    Common->mark = EMPTY ;
+    CHOLMOD(clear_flag) (Common) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+    CHOLMOD(free_dense) (&C, Common) ;
+    return (ok) ;
+}
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Supernodal/cholmod_super_solve.c b/src/C/SuiteSparse/CHOLMOD/Supernodal/cholmod_super_solve.c
new file mode 100644
index 0000000..58191f0
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Supernodal/cholmod_super_solve.c
@@ -0,0 +1,221 @@
+/* ========================================================================== */
+/* === Supernodal/cholmod_super_solve ======================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Supernodal Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Supernodal Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Solve Lx=b or L'x=b for a supernodal factorization.  These routines do not
+ * apply the permutation L->Perm.  See cholmod_solve for a more general
+ * interface that performs that operation.
+ */
+
+#ifndef NSUPERNODAL
+
+#include "cholmod_internal.h"
+#include "cholmod_supernodal.h"
+
+/* ========================================================================== */
+/* === TEMPLATE ============================================================= */
+/* ========================================================================== */
+
+#define REAL
+#include "t_cholmod_super_solve.c"
+#define COMPLEX
+#include "t_cholmod_super_solve.c"
+
+/* ========================================================================== */
+/* === cholmod_super_lsolve ================================================= */
+/* ========================================================================== */
+
+/* Solve Lx=b where x and b are of size n-by-nrhs.  b is overwritten by the
+ * solution x.  On input, b is stored in col-major order with leading dimension
+ * of d, and on output x is stored in the same manner.
+ *
+ * The contents of the workspace E are undefined on both input and output.
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(super_lsolve)
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to use for the forward solve */
+    /* ---- output ---- */
+    cholmod_dense *X,	/* b on input, solution to Lx=b on output */
+    /* ---- workspace ---- */
+    cholmod_dense *E,	/* workspace of size nrhs*(L->maxesize) */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_NULL (X, FALSE) ;
+    RETURN_IF_NULL (E, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (E, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ;
+    if (L->xtype != X->xtype)
+    {
+	ERROR (CHOLMOD_INVALID, "L and X must have the same xtype") ;
+	return (FALSE) ;
+    }
+    if (L->xtype != E->xtype)
+    {
+	ERROR (CHOLMOD_INVALID, "L and E must have the same xtype") ;
+	return (FALSE) ;
+    }
+    if (X->d < X->nrow || L->n != X->nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "X and L dimensions must match") ;
+	return (FALSE) ;
+    }
+    if (E->nzmax < X->ncol * (L->maxesize))
+    {
+	ERROR (CHOLMOD_INVALID, "workspace E not large enough") ;
+	return (FALSE) ;
+    }
+    if (!(L->is_ll) || !(L->is_super))
+    {
+	ERROR (CHOLMOD_INVALID, "L not supernodal") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+    ASSERT (IMPLIES (L->n == 0, L->nsuper == 0)) ;
+    if (L->n == 0 || X->ncol == 0)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* solve Lx=b using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (L->xtype)
+    {
+
+	case CHOLMOD_REAL:
+	    ok = r_cholmod_super_lsolve (L, X, E, Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    ok = c_cholmod_super_lsolve (L, X, E, Common) ;
+	    break ;
+    }
+
+    if (CHECK_BLAS_INT && !ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large for the BLAS") ;
+    }
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_super_ltsolve ================================================ */
+/* ========================================================================== */
+
+/* Solve L'x=b where x and b are of size n-by-nrhs.  b is overwritten by the
+ * solution x.  On input, b is stored in col-major order with leading dimension
+ * of d, and on output x is stored in the same manner.
+ *
+ * The contents of the workspace E are undefined on both input and output.
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(super_ltsolve)
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to use for the backsolve */
+    /* ---- output ---- */
+    cholmod_dense *X,	/* b on input, solution to L'x=b on output */
+    /* ---- workspace ---- */
+    cholmod_dense *E,	/* workspace of size nrhs*(L->maxesize) */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_NULL (X, FALSE) ;
+    RETURN_IF_NULL (E, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (E, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ;
+    if (L->xtype != X->xtype)
+    {
+	ERROR (CHOLMOD_INVALID, "L and X must have the same xtype") ;
+	return (FALSE) ;
+    }
+    if (L->xtype != E->xtype)
+    {
+	ERROR (CHOLMOD_INVALID, "L and E must have the same xtype") ;
+	return (FALSE) ;
+    }
+    if (X->d < X->nrow || L->n != X->nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "X and L dimensions must match") ;
+	return (FALSE) ;
+    }
+    if (E->nzmax < X->ncol * (L->maxesize))
+    {
+	ERROR (CHOLMOD_INVALID, "workspace E not large enough") ;
+	return (FALSE) ;
+    }
+    if (!(L->is_ll) || !(L->is_super))
+    {
+	ERROR (CHOLMOD_INVALID, "L not supernodal") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+    ASSERT (IMPLIES (L->n == 0, L->nsuper == 0)) ;
+    if (L->n == 0 || X->ncol == 0)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* solve Lx=b using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (L->xtype)
+    {
+
+	case CHOLMOD_REAL:
+	    ok = r_cholmod_super_ltsolve (L, X, E, Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    ok = c_cholmod_super_ltsolve (L, X, E, Common) ;
+	    break ;
+    }
+
+    if (CHECK_BLAS_INT && !ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large for the BLAS") ;
+    }
+
+    return (ok) ;
+}
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Supernodal/cholmod_super_symbolic.c b/src/C/SuiteSparse/CHOLMOD/Supernodal/cholmod_super_symbolic.c
new file mode 100644
index 0000000..d41aa60
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Supernodal/cholmod_super_symbolic.c
@@ -0,0 +1,794 @@
+/* ========================================================================== */
+/* === Supernodal/cholmod_super_symbolic ==================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Supernodal Module. Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Supernodal Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Supernodal symbolic analysis of the LL' factorization of A, A*A',
+ * A(:,f)*A(:,f)'.
+ *
+ * This routine must be preceded by a simplicial symbolic analysis
+ * (cholmod_rowcolcounts).  See cholmod_analyze.c for an example of how to use
+ * this routine.
+ *
+ * The user need not call this directly; cholmod_analyze is a "simple" wrapper
+ * for this routine.
+ *
+ * Symmetric case:
+ *
+ *	A is stored in column form, with entries stored in the upper triangular
+ *	part.  Entries in the lower triangular part are ignored.
+ *
+ * Unsymmetric case:
+ *
+ *	A is stored in column form.  If F is equal to the transpose of A, then
+ *	A*A' is analyzed.  F can include a subset of the columns of A
+ *	(F=A(:,f)'), in which case F*F' is analyzed.
+ *
+ * Requires Parent and L->ColCount to be defined on input; these are the
+ * simplicial Parent and ColCount arrays as computed by cholmod_rowcolcounts.
+ * Does not use L->Perm; the input matrices A and F must already be properly
+ * permuted.  Allocates and computes the supernodal pattern of L (L->super,
+ * L->pi, L->px, and L->s).  Does not allocate the real part (L->x).
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex).
+ */
+
+#ifndef NSUPERNODAL
+
+#include "cholmod_internal.h"
+#include "cholmod_supernodal.h"
+
+
+/* ========================================================================== */
+/* === subtree ============================================================== */
+/* ========================================================================== */
+
+/* In the symmetric case, traverse the kth row subtree from the nonzeros in
+ * A (0:k,k) and add the new entries found to the pattern of the kth row of L.
+ *
+ * In the unsymmetric case, the nonzero pattern of A*F is computed one column at
+ * one column at a time.  The kth column is A*F(:,k), or the set union of all
+ * columns A(:,j) for which F(j,k) is nonzero.  This routine is called once
+ * for each entry j.  Only the upper triangular part is needed, so only
+ * A (0:k,j) is accessed.
+ *
+ * Only adds column indices corresponding to the leading columns of each
+ * relaxed supernode.
+ */
+
+static void subtree
+(
+    /* inputs, not modified: */
+    Int j,		/* j = k for symmetric case */
+    Int k,
+    Int Ap [ ],
+    Int Ai [ ],
+    Int Anz [ ],
+    Int SuperMap [ ],
+    Int Sparent [ ],
+    Int mark,
+
+    /* input/output: */
+    Int Flag [ ],
+    Int Ls [ ],
+    Int Lpi2 [ ]
+)
+{
+    Int p, pend, i, si ;
+    p = Ap [j] ;
+    pend = (Anz == NULL) ? (Ap [j+1]) : (p + Anz [j]) ;
+    for ( ; p < pend ; p++)
+    {
+	i = Ai [p] ;
+	if (i < k)
+	{
+	    /* (i,k) is an entry in the upper triangular part of A or A*F'.
+	     * symmetric case:   A(i,k) is nonzero (j=k).
+	     * unsymmetric case: A(i,j) and F(j,k) are both nonzero.
+	     *
+	     * Column i is in supernode si = SuperMap [i].  Follow path from si
+	     * to root of supernodal etree, stopping at the first flagged
+	     * supernode.  The root of the row subtree is supernode SuperMap[k],
+	     * which is flagged already. This traversal will stop there, or it
+	     * might stop earlier if supernodes have been flagged by previous
+	     * calls to this routine for the same k. */
+	    for (si = SuperMap [i] ; Flag [si] < mark ; si = Sparent [si])
+	    {
+		ASSERT (si <= SuperMap [k]) ;
+		Ls [Lpi2 [si]++] = k ;
+		Flag [si] = mark ;
+	    }
+	}
+    }
+}
+
+
+/* clear workspace used by cholmod_super_symbolic */
+#define FREE_WORKSPACE \
+{ \
+    CHOLMOD(clear_flag) (Common) ; \
+    for (k = 0 ; k <= nfsuper ; k++) \
+    { \
+	Head [k] = EMPTY ; \
+    } \
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; \
+} \
+
+
+/* ========================================================================== */
+/* === cholmod_super_symbolic =============================================== */
+/* ========================================================================== */
+
+/* Analyzes A, AA', or A(:,f)*A(:,f)' in preparation for a supernodal numeric
+ * factorization.  The user need not call this directly; cholmod_analyze is
+ * a "simple" wrapper for this routine.
+ *
+ * workspace: Flag (nrow), Head (nrow), Iwork (2*nrow),
+ * and temporary space of size 3*nfsuper*sizeof(Int), where nfsuper <= n
+ * is the number of fundamental supernodes.
+ */
+
+int CHOLMOD(super_symbolic)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    cholmod_sparse *F,	/* F = A' or A(:,f)' */
+    Int *Parent,	/* elimination tree */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* simplicial symbolic on input,
+			 * supernodal symbolic on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double zrelax0, zrelax1, zrelax2, xxsize ;
+    Int *Wi, *Wj, *Super, *Snz, *Ap, *Ai, *Flag, *Head, *Ls, *Lpi, *Lpx, *Fnz,
+	*Sparent, *Anz, *SuperMap, *Merged, *Nscol, *Zeros, *Fp, *Fj,
+	*ColCount, *Lpi2, *Lsuper, *Iwork ;
+    Int nsuper, d, n, j, k, s, mark, parent, p, pend, k1, k2, packed, nscol,
+	nsrow, ndrow1, ndrow2, stype, ssize, xsize, sparent, plast, slast,
+	csize, maxcsize, ss, nscol0, nscol1, ns, nfsuper, newzeros, totzeros,
+	merge, snext, esize, maxesize, nrelax0, nrelax1, nrelax2 ;
+    size_t w ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_NULL (Parent, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_PATTERN, FALSE) ;
+    stype = A->stype ;
+    if (stype < 0)
+    {
+	/* invalid symmetry; symmetric lower form not supported */
+	ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ;
+	return (FALSE) ;
+    }
+    if (stype == 0)
+    {
+	/* F must be present in the unsymmetric case */
+	RETURN_IF_NULL (F, FALSE) ;
+	ASSERT (CHOLMOD(dump_sparse) (F, "Fsup", Common) >= 0) ;
+    }
+    if (L->is_super)
+    {
+	/* L must be a simplicial symbolic factor */
+	ERROR (CHOLMOD_INVALID, "L must be symbolic on input") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    ASSERT (CHOLMOD(dump_sparse) (A, "Asup", Common) >= 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    n = A->nrow ;
+
+    /* w = 5*n */
+    w = CHOLMOD(mult_size_t) (n, 5, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (n, w, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	return (FALSE) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    /* A is now either A or triu(A(p,p)) for the symmetric case.  It is either
+     * A or A(p,f) for the unsymmetric case (both in column form).  It can be
+     * either packed or unpacked, and either sorted or unsorted.  Entries in
+     * the lower triangular part may be present if A is symmetric, but these
+     * are ignored. */
+
+    Ap = A->p ;
+    Ai = A->i ;
+    Anz = A->nz ;
+
+    if (stype != 0)
+    {
+	/* F not accessed */
+	Fp = NULL ;
+	Fj = NULL ;
+	Fnz = NULL ;
+	packed = TRUE ;
+    }
+    else
+    {
+	/* F = A(:,f) or A(p,f) in packed row form, either sorted or unsorted */
+	Fp = F->p ;
+	Fj = F->i ;
+	Fnz = F->nz ;
+	packed = F->packed ;
+    }
+
+    ColCount = L->ColCount ;
+
+    nrelax0 = Common->nrelax [0] ;
+    nrelax1 = Common->nrelax [1] ;
+    nrelax2 = Common->nrelax [2] ;
+
+    zrelax0 = Common->zrelax [0] ;
+    zrelax1 = Common->zrelax [1] ;
+    zrelax2 = Common->zrelax [2] ;
+
+    zrelax0 = IS_NAN (zrelax0) ? 0 : zrelax0 ;
+    zrelax1 = IS_NAN (zrelax1) ? 0 : zrelax1 ;
+    zrelax2 = IS_NAN (zrelax2) ? 0 : zrelax2 ;
+
+    ASSERT (CHOLMOD(dump_parent) (Parent, n, "Parent", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* Sparent, Snz, and Merged could be allocated later, of size nfsuper */
+
+    Iwork = Common->Iwork ;
+    Wi      = Iwork ;	    /* size n (i/l/l).  Lpi2 is i/l/l */
+    Wj      = Iwork + n ;   /* size n (i/l/l).  Zeros is i/l/l */
+    Sparent = Iwork + 2*((size_t) n) ; /* size nfsuper <= n [ */
+    Snz     = Iwork + 3*((size_t) n) ; /* size nfsuper <= n [ */
+    Merged  = Iwork + 4*((size_t) n) ; /* size nfsuper <= n [ */
+
+    Flag = Common->Flag ;   /* size n */
+    Head = Common->Head ;   /* size n+1 */
+
+    /* ---------------------------------------------------------------------- */
+    /* find the fundamental supernodes */
+    /* ---------------------------------------------------------------------- */
+
+    /* count the number of children of each node, using Wi [ */
+    for (j = 0 ; j < n ; j++)
+    {
+	Wi [j] = 0 ;
+    }
+    for (j = 0 ; j < n ; j++)
+    {
+	parent = Parent [j] ;
+	if (parent != EMPTY)
+	{
+	    Wi [parent]++ ;
+	}
+    }
+
+    Super = Head ;  /* use Head [0..nfsuper] as workspace for Super list ( */
+
+    /* column 0 always starts a new supernode */
+    nfsuper = (n == 0) ? 0 : 1 ;	/* number of fundamental supernodes */
+    Super [0] = 0 ;
+
+    for (j = 1 ; j < n ; j++)
+    {
+	/* check if j starts new supernode, or in the same supernode as j-1 */
+	if (Parent [j-1] != j	    /* parent of j-1 is not j */
+	    || (ColCount [j-1] != ColCount [j] + 1) /* j-1 not subset of j*/
+	    || Wi [j] > 1)	    /* j has more than one child */
+	{
+	    /* j is the leading node of a supernode */
+	    Super [nfsuper++] = j ;
+	}
+    }
+    Super [nfsuper] = n ;
+
+    /* contents of Wi no longer needed for child count ] */
+
+    Nscol = Wi ; /* use Wi as size-nfsuper workspace for Nscol [ */
+
+    /* ---------------------------------------------------------------------- */
+    /* find the mapping of fundamental nodes to supernodes */
+    /* ---------------------------------------------------------------------- */
+
+    SuperMap = Wj ;	/* use Wj as workspace for SuperMap [ */
+
+    /* SuperMap [k] = s if column k is contained in supernode s */
+    for (s = 0 ; s < nfsuper ; s++)
+    {
+	for (k = Super [s] ; k < Super [s+1] ; k++)
+	{
+	    SuperMap [k] = s ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the fundamental supernodal etree */
+    /* ---------------------------------------------------------------------- */
+
+    for (s = 0 ; s < nfsuper ; s++)
+    {
+	j = Super [s+1] - 1 ;	/* last node in supernode s */
+	parent = Parent [j] ;	/* parent of last node */
+	Sparent [s] = (parent == EMPTY) ? EMPTY : SuperMap [parent] ;
+	PRINT1 (("Sparent ["ID"] = "ID"\n", s, Sparent [s])) ;
+    }
+
+    /* contents of Wj no longer needed as workspace for SuperMap ]
+     * SuperMap will be recomputed below, for the relaxed supernodes. */
+
+    Zeros = Wj ;   /* use Wj for Zeros, workspace of size nfsuper [ */
+
+    /* ---------------------------------------------------------------------- */
+    /* relaxed amalgamation */
+    /* ---------------------------------------------------------------------- */
+
+    for (s = 0 ; s < nfsuper ; s++)
+    {
+	Merged [s] = EMPTY ;			/* s not merged into another */
+	Nscol [s] = Super [s+1] - Super [s] ;	/* # of columns in s */
+	Zeros [s] = 0 ;				/* # of zero entries in s */
+	ASSERT (s <= Super [s]) ;
+	Snz [s] = ColCount [Super [s]] ;  /* # of entries in leading col of s */
+	PRINT2 (("lnz ["ID"] "ID"\n", s, Snz [s])) ;
+    }
+
+    for (s = nfsuper-2 ; s >= 0 ; s--)
+    {
+	/* should supernodes s and s+1 merge into a new node s? */
+	PRINT1 (("\n========= Check relax of s "ID" and s+1 "ID"\n", s, s+1)) ;
+
+	ss = Sparent [s] ;
+	if (ss == EMPTY)
+	{
+	    PRINT1 (("s "ID" is a root, no merge with s+1 = "ID"\n", s, s+1)) ;
+	    continue ;
+	}
+
+	/* find the current parent of s (perform path compression as needed) */
+	for (ss = Sparent [s] ; Merged [ss] != EMPTY ; ss = Merged [ss]) ;
+	sparent = ss ;
+	PRINT2 (("Current sparent of s "ID" is "ID"\n", s, sparent)) ;
+
+	/* ss is the current parent of s */
+	for (ss = Sparent [s] ; Merged [ss] != EMPTY ; ss = snext)
+	{
+	    snext = Merged [ss] ;
+	    PRINT2 (("ss "ID" is dead, merged into snext "ID"\n", ss, snext)) ;
+	    Merged [ss] = sparent ;
+	}
+
+	/* if s+1 is not the current parent of s, do not merge */
+	if (sparent != s+1)
+	{
+	    continue ;
+	}
+
+	nscol0 = Nscol [s] ;	/* # of columns in s */
+	nscol1 = Nscol [s+1] ;	/* # of columns in s+1 */
+	ns = nscol0 + nscol1 ;
+	PRINT2 (("ns "ID" nscol0 "ID" nscol1 "ID"\n", ns, nscol0, nscol1)) ;
+
+	totzeros = Zeros [s+1] ;	/* current # of zeros in s+1 */
+
+	/* determine if supernodes s and s+1 should merge */
+	if (ns <= nrelax0)
+	{
+	    PRINT2 (("ns is tiny ("ID"), so go ahead and merge\n", ns)) ;
+	    merge = TRUE ;
+	}
+	else
+	{
+	    /* use double to avoid integer overflow */
+	    double lnz0 = Snz [s] ;	/* # entries in leading column of s */
+	    double lnz1 = Snz [s+1] ;	/* # entries in leading column of s+1 */
+	    double xnewzeros = nscol0 * (lnz1 + nscol0 - lnz0) ;
+
+	    /* use Int for the final update of Zeros [s] below */
+	    newzeros = nscol0 * (Snz [s+1] + nscol0 - Snz [s]) ;
+	    ASSERT (newzeros == xnewzeros) ;
+
+	    PRINT2 (("lnz0 %g lnz1 %g xnewzeros %g\n", lnz0, lnz1, xnewzeros)) ;
+	    if (xnewzeros == 0)
+	    {
+		/* no new zeros, so go ahead and merge */
+		PRINT2 (("no new fillin, so go ahead and merge\n")) ;
+		merge = TRUE ;
+	    }
+	    else
+	    {
+		/* # of zeros if merged */
+		double xtotzeros = ((double) totzeros) + xnewzeros ;
+
+		/* xtotsize: total size of merged supernode, if merged: */
+		double xns = (double) ns ;
+		double xtotsize  = (xns * (xns+1) / 2) + xns * (lnz1 - nscol1) ;
+		double z = xtotzeros / xtotsize ;
+
+		Int totsize ;
+		totsize  = (ns * (ns+1) / 2) + ns * (Snz [s+1] - nscol1) ;
+
+		PRINT2 (("oldzeros "ID" newzeros "ID" xtotsize %g z %g\n",
+			    Zeros [s+1], newzeros, xtotsize, z)) ;
+
+		/* use Int for the final update of Zeros [s] below */
+		totzeros += newzeros ;
+
+		/* do not merge if supernode would become too big
+		 * (Int overflow).  Continue computing; not (yet) an error. */
+		/* fl.pt. compare, but no NaN's can occur here */
+		merge = ((ns <= nrelax1 && z < zrelax0) ||
+			 (ns <= nrelax2 && z < zrelax1) ||
+					  (z < zrelax2)) &&
+			(xtotsize < Int_max / sizeof (double)) ;
+
+	    }
+	}
+
+	if (merge)
+	{
+	    PRINT1 (("Merge node s ("ID") and s+1 ("ID")\n", s, s+1)) ;
+	    Zeros [s] = totzeros ;
+	    Merged [s+1] = s ;
+	    Snz [s] = nscol0 + Snz [s+1] ;
+	    Nscol [s] += Nscol [s+1] ;
+	}
+    }
+
+    /* contents of Wj no longer needed for Zeros ] */
+    /* contents of Wi no longer needed for Nscol ] */
+    /* contents of Sparent no longer needed (recomputed below) */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the relaxed supernode list */
+    /* ---------------------------------------------------------------------- */
+
+    nsuper = 0 ;
+    for (s = 0 ; s < nfsuper ; s++)
+    {
+	if (Merged [s] == EMPTY)
+	{
+	    PRINT1 (("live supernode: "ID" snz "ID"\n", s, Snz [s])) ;
+	    Super [nsuper] = Super [s] ;
+	    Snz [nsuper] = Snz [s] ;
+	    nsuper++ ;
+	}
+    }
+    Super [nsuper] = n ;
+    PRINT1 (("Fundamental supernodes: "ID"  relaxed "ID"\n", nfsuper, nsuper)) ;
+
+    /* Merged no longer needed ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* find the mapping of relaxed nodes to supernodes */
+    /* ---------------------------------------------------------------------- */
+
+    /* use Wj as workspace for SuperMap { */
+
+    /* SuperMap [k] = s if column k is contained in supernode s */
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	for (k = Super [s] ; k < Super [s+1] ; k++)
+	{
+	    SuperMap [k] = s ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the relaxed supernodal etree */
+    /* ---------------------------------------------------------------------- */
+
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	j = Super [s+1] - 1 ;	/* last node in supernode s */
+	parent = Parent [j] ;	/* parent of last node */
+	Sparent [s] = (parent == EMPTY) ? EMPTY : SuperMap [parent] ;
+	PRINT1 (("new Sparent ["ID"] = "ID"\n", s, Sparent [s])) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the size of L->s and L->x */
+    /* ---------------------------------------------------------------------- */
+
+    ssize = 0 ;
+    xsize = 0 ;
+    xxsize = 0 ;
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	nscol = Super [s+1] - Super [s] ;
+	nsrow = Snz [s] ;
+	ASSERT (nscol > 0) ;
+	ssize += nsrow ;
+	xsize += nscol * nsrow ;
+	/* also compute xsize in double to guard against Int overflow */
+	xxsize += ((double) nscol) * ((double) nsrow) ;
+	if (xxsize > Int_max)
+	{
+	    /* Int overflow, clear workspace and return */
+	    ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	    FREE_WORKSPACE ;
+	    return (FALSE) ;
+	}
+	ASSERT (ssize > 0 && xsize > 0) ;
+    }
+    xsize = MAX (1, xsize) ;
+    ssize = MAX (1, ssize) ;
+    PRINT1 (("ix sizes: "ID" "ID" nsuper "ID"\n", ssize, xsize, nsuper)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate L (all except real part L->x) */
+    /* ---------------------------------------------------------------------- */
+
+    L->ssize = ssize ;
+    L->xsize = xsize ;
+    L->nsuper = nsuper ;
+
+    CHOLMOD(change_factor) (CHOLMOD_PATTERN, TRUE, TRUE, TRUE, TRUE, L, Common);
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory; L is still a valid simplicial symbolic factor */
+	FREE_WORKSPACE ;
+	return (FALSE) ;
+    }
+
+    DEBUG (CHOLMOD(dump_factor) (L, "L to symbolic super", Common)) ;
+    ASSERT (L->is_ll && L->xtype == CHOLMOD_PATTERN && L->is_super) ;
+
+    Lpi = L->pi ;
+    Lpx = L->px ;
+    Ls = L->s ;
+    Ls [0] = 0 ;    /* flag for cholmod_check_factor; supernodes are defined */
+    Lsuper = L->super ;
+
+    /* copy the list of relaxed supernodes into the final list in L */
+    for (s = 0 ; s <= nsuper ; s++)
+    {
+	Lsuper [s] = Super [s] ;
+    }
+
+    /* Head no longer needed as workspace for fundamental Super list ) */
+
+    Super = Lsuper ;	    /* Super is now the list of relaxed supernodes */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct column pointers of relaxed supernodal pattern (L->pi) */
+    /* ---------------------------------------------------------------------- */
+
+    p = 0 ;
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	Lpi [s] = p ;
+	p += Snz [s] ;
+	PRINT1 (("Snz ["ID"] = "ID", Super ["ID"] = "ID"\n",
+		    s, Snz [s], s, Super[s])) ;
+    }
+    Lpi [nsuper] = p ;
+    ASSERT ((Int) (L->ssize) == MAX (1,p)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* construct pointers for supernodal values (L->px) */
+    /* ---------------------------------------------------------------------- */
+
+    p = 0 ;
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	nscol = Super [s+1] - Super [s] ;   /* number of columns in s */
+	nsrow = Snz [s] ;		    /* # of rows, incl triangular part*/
+	Lpx [s] = p ;			    /* pointer to numerical part of s */
+	p += nscol * nsrow ;
+    }
+    Lpx [s] = p ;
+    ASSERT ((Int) (L->xsize) == MAX (1,p)) ;
+
+    /* Snz no longer needed ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* symbolic analysis to construct the relaxed supernodal pattern (L->s) */
+    /* ---------------------------------------------------------------------- */
+
+    Lpi2 = Wi ;	    /* copy Lpi into Lpi2, using Wi as workspace for Lpi2 [ */
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	Lpi2 [s] = Lpi [s] ;
+    }
+
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	/* sth supernode is in columns k1 to k2-1.
+	 * compute nonzero pattern of L (k1:k2-1,:). */
+
+	/* place rows k1 to k2-1 in leading column of supernode s */
+	k1 = Super [s] ;
+	k2 = Super [s+1] ;
+	PRINT1 (("=========>>> Supernode "ID" k1 "ID" k2-1 "ID"\n",
+		    s, k1, k2-1)) ;
+	for (k = k1 ; k < k2 ; k++)
+	{
+	    Ls [Lpi2 [s]++] = k ;
+	}
+
+	/* compute nonzero pattern each row k1 to k2-1 */
+	for (k = k1 ; k < k2 ; k++)
+	{
+	    /* compute row k of L.  In the symmetric case, the pattern of L(k,:)
+	     * is the set of nodes reachable in the supernodal etree from any
+	     * row i in the nonzero pattern of A(0:k,k).  In the unsymmetric
+	     * case, the pattern of the kth column of A*A' is the set union
+	     * of all columns A(0:k,j) for each nonzero F(j,k). */
+
+	    /* clear the Flag array and mark the current supernode */
+	    mark = CHOLMOD(clear_flag) (Common) ;
+	    Flag [s] = mark ;
+	    ASSERT (s == SuperMap [k]) ;
+
+	    /* traverse the row subtree for each nonzero in A or AA' */
+	    if (stype != 0)
+	    {
+		subtree (k, k, Ap, Ai, Anz, SuperMap, Sparent, mark,
+			Flag, Ls, Lpi2) ;
+	    }
+	    else
+	    {
+		/* for each nonzero in F (k,:) do */
+		p = Fp [k] ;
+		pend = (packed) ? (Fp [k+1]) : (p + Fnz [k]) ;
+		for ( ; p < pend ; p++)
+		{
+		    subtree (Fj [p], k, Ap, Ai, Anz, SuperMap, Sparent, mark,
+			    Flag, Ls, Lpi2) ;
+		}
+	    }
+	}
+    }
+
+#ifndef NDEBUG
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	PRINT1 (("Lpi2[s] "ID" Lpi[s+1] "ID"\n", Lpi2 [s], Lpi [s+1])) ;
+	ASSERT (Lpi2 [s] == Lpi [s+1]) ;
+	CHOLMOD(dump_super) (s, Super, Lpi, Ls, NULL, NULL, 0, Common) ;
+    }
+#endif
+
+    /* contents of Wi no longer needed for Lpi2 ] */
+    /* Sparent no longer needed ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the largest update matrix (L->maxcsize) */
+    /* ---------------------------------------------------------------------- */
+
+    /* maxcsize could be determined before L->s is allocated and defined, which
+     * would mean that all memory requirements for both the symbolic and numeric
+     * factorizations could be computed using O(nnz(A)+O(n)) space.  However, it
+     * would require a lot of extra work.  The analysis phase, above, would need
+     * to be duplicated, but with Ls not kept; instead, the algorithm would keep
+     * track of the current s and slast for each supernode d, and update them
+     * when a new row index appears in supernode d.  An alternative would be to
+     * do this computation only if the allocation of L->s failed, in which case
+     * the following code would be skipped.
+     *
+     * The csize for a supernode is the size of its largest contribution to
+     * a subsequent ancestor supernode.  For example, suppose the rows of #'s
+     * in the figure below correspond to the columns of a subsequent supernode,
+     * and the dots are the entries in that ancestore.
+     *
+     *	    c
+     *	    c c
+     *	    c c c
+     *	    x x x
+     *	    x x x
+     *	    # # #   .
+     *	    # # #   . .
+     *	    * * *   . .
+     *	    * * *   . .
+     *	    * * *   . .
+     *	            . .
+     *
+     * Then for this update, the csize is 3-by-2, or 6, because there are 3
+     * rows of *'s which is the number of rows in the update, and there are
+     * 2 rows of #'s, which is the number columns in the update.  The csize
+     * of a supernode is the largest such contribution for any ancestor
+     * supernode.  maxcsize, for the whole matrix, has a rough upper bound of
+     * the maximum size of any supernode.  This bound is loose, because the
+     * the contribution must be less than the size of the ancestor supernodal
+     * that it's updating.  maxcsize of a completely dense matrix, with one
+     * supernode, is zero.
+     *
+     * maxesize is the column dimension for the workspace E needed for the
+     * solve.  E is of size nrhs-by-maxesize, where the nrhs is the number of
+     * columns in the right-hand-side.  The maxesize is the largest esize of
+     * any supernode.  The esize of a supernode is the number of row indices
+     * it contains, excluding the column indices of the supernode itself.
+     * For the following example, esize is 4:
+     *
+     *	    c
+     *	    c c
+     *	    c c c
+     *	    x x x
+     *	    x x x
+     *	    x x x
+     *	    x x x
+     *
+     * maxesize can be no bigger than n.
+     */
+
+    maxcsize = 1 ;
+    maxesize = 1 ;
+
+    /* do not need to guard csize against Int overflow if xsize is OK */
+
+    for (d = 0 ; d < nsuper ; d++)
+    {
+	nscol = Super [d+1] - Super [d] ;
+	p = Lpi [d] + nscol ;
+	plast = p ;
+	pend = Lpi [d+1] ;
+	esize = pend - p ;
+	maxesize = MAX (maxesize, esize) ;
+	slast = (p == pend) ? (EMPTY) : (SuperMap [Ls [p]]) ;
+	for ( ; p <= pend ; p++)
+	{
+	    s = (p == pend) ? (EMPTY) : (SuperMap [Ls [p]]) ;
+	    if (s != slast)
+	    {
+		/* row i is the start of a new supernode */
+		ndrow1 = p - plast ;
+		ndrow2 = pend - plast ;
+		csize = ndrow2 * ndrow1 ;
+		PRINT1 (("Supernode "ID" ancestor "ID" C: "ID"-by-"ID"  csize "
+			""ID"\n", d, slast, ndrow1, ndrow2, csize)) ;
+		maxcsize = MAX (maxcsize, csize) ;
+		plast = p ;
+		slast = s ;
+	    }
+	}
+    }
+    PRINT1 (("max csize "ID"\n", maxcsize)) ;
+
+    /* Wj no longer needed for SuperMap } */
+
+    L->maxcsize = maxcsize ;
+    L->maxesize = maxesize ;
+    L->is_super = TRUE ;
+    ASSERT (L->xtype == CHOLMOD_PATTERN && L->is_ll) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* supernodal symbolic factorization is complete */
+    /* ---------------------------------------------------------------------- */
+
+    FREE_WORKSPACE ;
+    return (TRUE) ;
+}
+#endif
diff --git a/src/C/SuiteSparse/CHOLMOD/Supernodal/gpl.txt b/src/C/SuiteSparse/CHOLMOD/Supernodal/gpl.txt
new file mode 100644
index 0000000..3912109
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Supernodal/gpl.txt
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+

+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+

+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+

+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+

+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/src/C/SuiteSparse/CHOLMOD/Supernodal/t_cholmod_super_numeric.c b/src/C/SuiteSparse/CHOLMOD/Supernodal/t_cholmod_super_numeric.c
new file mode 100644
index 0000000..4757721
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Supernodal/t_cholmod_super_numeric.c
@@ -0,0 +1,741 @@
+/* ========================================================================== */
+/* === Supernodal/t_cholmod_super_numeric =================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Supernodal Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Supernodal Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Template routine for cholmod_super_numeric.  All xtypes supported, except
+ * that a zomplex A and F result in a complex L (there is no supernodal
+ * zomplex L).
+ */
+
+/* ========================================================================== */
+/* === complex arithmetic =================================================== */
+/* ========================================================================== */
+
+#include "cholmod_template.h"
+
+#undef L_ENTRY
+#undef L_CLEAR
+#undef L_ASSIGN
+#undef L_MULTADD
+#undef L_ASSEMBLE
+#undef L_ASSEMBLESUB
+
+#ifdef REAL
+
+/* -------------------------------------------------------------------------- */
+/* A, F, and L are all real */
+/* -------------------------------------------------------------------------- */
+
+#define L_ENTRY 1
+#define L_CLEAR(Lx,p)		    Lx [p] = 0
+#define L_ASSIGN(Lx,q, Ax,Az,p)	    Lx [q] = Ax [p]
+#define L_MULTADD(Lx,q, Ax,Az,p, f) Lx [q] += Ax [p] * f [0]
+#define L_ASSEMBLE(Lx,q,b)	    Lx [q] += b [0]
+#define L_ASSEMBLESUB(Lx,q,C,p)	    Lx [q] -= C [p]
+
+#else
+
+/* -------------------------------------------------------------------------- */
+/* A and F are complex or zomplex, L and C are complex */
+/* -------------------------------------------------------------------------- */
+
+#define L_ENTRY 2
+#define L_CLEAR(Lx,p)		    Lx [2*(p)] = 0 ; Lx [2*(p)+1] = 0
+#define L_ASSEMBLE(Lx,q,b)	    Lx [2*(q)] += b [0] ;
+#define L_ASSEMBLESUB(Lx,q,C,p)	\
+    Lx [2*(q)  ] -= C [2*(p)  ] ; \
+    Lx [2*(q)+1] -= C [2*(p)+1] ;
+
+#ifdef COMPLEX
+
+/* -------------------------------------------------------------------------- */
+/* A, F, L, and C are all complex */
+/* -------------------------------------------------------------------------- */
+
+#define L_ASSIGN(Lx,q, Ax,Az,p) \
+    Lx [2*(q)  ] = Ax [2*(p)  ] ; \
+    Lx [2*(q)+1] = Ax [2*(p)+1]
+
+#define L_MULTADD(Lx,q, Ax,Az,p, f) \
+    Lx [2*(q)  ] += Ax [2*(p)  ] * f [0] - Ax [2*(p)+1] * f [1] ; \
+    Lx [2*(q)+1] += Ax [2*(p)+1] * f [0] + Ax [2*(p)  ] * f [1]
+
+#else
+
+/* -------------------------------------------------------------------------- */
+/* A and F are zomplex, L and C is complex */
+/* -------------------------------------------------------------------------- */
+
+#define L_ASSIGN(Lx,q, Ax,Az,p)	\
+    Lx [2*(q)  ] = Ax [p] ; \
+    Lx [2*(q)+1] = Az [p] ;
+
+#define L_MULTADD(Lx,q, Ax,Az,p, f) \
+    Lx [2*(q)  ] += Ax [p] * f [0] - Az [p] * f [1] ; \
+    Lx [2*(q)+1] += Az [p] * f [0] + Ax [p] * f [1]
+
+#endif
+#endif
+
+
+/* ========================================================================== */
+/* === t_cholmod_super_numeric ============================================== */
+/* ========================================================================== */
+
+/* This function returns FALSE only if integer overflow occurs in the BLAS.
+ * It returns TRUE otherwise whether or not the matrix is positive definite. */
+
+static int TEMPLATE (cholmod_super_numeric)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    cholmod_sparse *F,	/* F = A' or A(:,f)' */
+    double beta [2],	/* beta*I is added to diagonal of matrix to factorize */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factorization */
+    /* -- workspace -- */
+    cholmod_dense *Cwork,	/* size (L->maxcsize)-by-1 */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double one [2], zero [2], fjk [2] ;
+    double *Lx, *Ax, *Fx, *Az, *Fz, *C ;
+    Int *Super, *Head, *Ls, *Lpi, *Lpx, *Map, *SuperMap, *RelativeMap, *Next,
+	*Lpos, *Fp, *Fi, *Fnz, *Ap, *Ai, *Anz, *Iwork, *Next_save, *Lpos_save ;
+    Int nsuper, n, j, i, k, s, p, pend, k1, k2, nscol, psi, psx, psend, nsrow,
+	pj, d, kd1, kd2, info, ndcol, ndrow, pdi, pdx, pdend, pdi1, pdi2, pdx1,
+	ndrow1, ndrow2, px, dancestor, sparent, dnext, nsrow2, ndrow3, pk, pf,
+	pfend, stype, Apacked, Fpacked, q, imap, repeat_supernode, nscol2, ss,
+	nscol_new = 0 ;
+
+    /* If integer overflow occurs in the BLAS, Common->status is set to
+     * CHOLMOD_TOO_LARGE, and the contents of Lx are undefined. */
+    int blas_ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nsuper = L->nsuper ;
+    n = L->n ;
+
+    C = Cwork->x ;	/* workspace of size L->maxcsize */
+
+    one [0] = 1.0 ;	/* ALPHA for *syrk, *herk, *gemm, and *trsm */
+    one [1] = 0. ;
+
+    zero [0] = 0. ;	/* BETA for *syrk, *herk, and *gemm */
+    zero [1] = 0. ;
+
+    Iwork = Common->Iwork ;
+    SuperMap    = Iwork ;		    /* size n (i/i/l) */
+    RelativeMap = Iwork + n ;		    /* size n (i/i/l) */
+    Next        = Iwork + 2*((size_t) n) ;			/* size nsuper*/
+    Lpos        = Iwork + 2*((size_t) n) + nsuper ;		/* size nsuper*/
+    Next_save   = Iwork + 2*((size_t) n) + 2*((size_t) nsuper) ;/* size nsuper*/
+    Lpos_save   = Iwork + 2*((size_t) n) + 3*((size_t) nsuper) ;/* size nsuper*/
+
+    Map  = Common->Flag ;   /* size n, use Flag as workspace for Map array */
+    Head = Common->Head ;   /* size n+1, only Head [0..nsuper-1] used */
+
+    Ls = L->s ;
+    Lpi = L->pi ;
+    Lpx = L->px ;
+
+    Super = L->super ;
+
+    Lx = L->x ;
+
+    stype = A->stype ;
+
+    if (stype != 0)
+    {
+	/* F not accessed */
+	Fp = NULL ;
+	Fi = NULL ;
+	Fx = NULL ;
+	Fz = NULL ;
+	Fnz = NULL ;
+	Fpacked = TRUE ;
+    }
+    else
+    {
+	Fp = F->p ;
+	Fi = F->i ;
+	Fx = F->x ;
+	Fz = F->z ;
+	Fnz = F->nz ;
+	Fpacked = F->packed ;
+    }
+
+    Ap = A->p ;
+    Ai = A->i ;
+    Ax = A->x ;
+    Az = A->z ;
+    Anz = A->nz ;
+    Apacked = A->packed ;
+
+    /* clear the Map so that changes in the pattern of A can be detected */
+    for (i = 0 ; i < n ; i++)
+    {
+	Map [i] = EMPTY ;
+    }
+
+    /* If the matrix is not positive definite, the supernode s containing the
+     * first zero or negative diagonal entry of L is repeated (but factorized
+     * only up to just before the problematic diagonal entry). The purpose is
+     * to provide MATLAB with [R,p]=chol(A); columns 1 to p-1 of L=R' are
+     * required, where L(p,p) is the problematic diagonal entry.  The 
+     * repeat_supernode flag tells us whether this is the repeated supernode.
+     * Once supernode s is repeated, the factorization is terminated. */
+    repeat_supernode = FALSE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* supernodal numerical factorization */
+    /* ---------------------------------------------------------------------- */
+
+    for (s = 0 ; s < nsuper ; s++)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* get the size of supernode s */
+	/* ------------------------------------------------------------------ */
+
+	k1 = Super [s] ;	    /* s contains columns k1 to k2-1 of L */
+	k2 = Super [s+1] ;
+	nscol = k2 - k1 ;	    /* # of columns in all of s */
+	psi = Lpi [s] ;		    /* pointer to first row of s in Ls */
+	psx = Lpx [s] ;		    /* pointer to first row of s in Lx */
+	psend = Lpi [s+1] ;	    /* pointer just past last row of s in Ls */
+	nsrow = psend - psi ;	    /* # of rows in all of s */
+
+	PRINT1 (("====================================================\n"
+		"S "ID" k1 "ID" k2 "ID" nsrow "ID" nscol "ID" psi "ID" psend "
+		""ID" psx "ID"\n", s, k1, k2, nsrow, nscol, psi, psend, psx)) ;
+
+	/* ------------------------------------------------------------------ */
+	/* zero the supernode s */
+	/* ------------------------------------------------------------------ */
+
+	ASSERT ((size_t) (psx + nsrow*nscol) <= L->xsize) ;
+
+	pend = psx + nsrow * nscol ;	    /* s is nsrow-by-nscol */
+	for (p = psx ; p < pend ; p++)
+	{
+	    /* Lx [p] = 0 ; */
+	    L_CLEAR (Lx,p) ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* construct the scattered Map for supernode s */
+	/* ------------------------------------------------------------------ */
+
+	/* If row i is the kth row in s, then Map [i] = k.  Similarly, if
+	 * column j is the kth column in s, then  Map [j] = k. */
+
+	for (k = 0 ; k < nsrow ; k++)
+	{
+	    PRINT1 (("  "ID" map "ID"\n", Ls [psi+k], k)) ;
+	    Map [Ls [psi + k]] = k ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* copy matrix into supernode s (lower triangular part only) */
+	/* ------------------------------------------------------------------ */
+
+	pk = psx ;
+	for (k = k1 ; k < k2 ; k++)
+	{
+	    if (stype != 0)
+	    {
+		/* copy the kth column of A into the supernode */
+		p = Ap [k] ;
+		pend = (Apacked) ? (Ap [k+1]) : (p + Anz [k]) ;
+		for ( ; p < pend ; p++)
+		{
+		    /* row i of L is located in row Map [i] of s */
+		    i = Ai [p] ;
+		    if (i >= k)
+		    {
+			/* This test is here simply to avoid a segfault.  If
+			 * the test is false, the numeric factorization of A
+			 * is undefined.  It does not detect all invalid
+			 * entries, only some of them (when debugging is
+			 * enabled, and Map is cleared after each step, then
+			 * all entries not in the pattern of L are detected). */
+			imap = Map [i] ;
+			if (imap >= 0 && imap < nsrow)
+			{
+			    /* Lx [Map [i] + pk] = Ax [p] ; */
+			    L_ASSIGN (Lx,(imap+pk), Ax,Az,p) ;
+			}
+		    }
+		}
+	    }
+	    else
+	    {
+		/* copy the kth column of A*F into the supernode */
+		pf = Fp [k] ;
+		pfend = (Fpacked) ? (Fp [k+1]) : (p + Fnz [k]) ;
+		for ( ; pf < pfend ; pf++)
+		{
+		    j = Fi [pf] ;
+
+		    /* fjk = Fx [pf] ; */
+		    L_ASSIGN (fjk,0, Fx,Fz,pf) ;
+
+		    p = Ap [j] ;
+		    pend = (Apacked) ? (Ap [j+1]) : (p + Anz [j]) ;
+		    for ( ; p < pend ; p++)
+		    {
+			i = Ai [p] ;
+			if (i >= k)
+			{
+			    /* See the discussion of imap above. */
+			    imap = Map [i] ;
+			    if (imap >= 0 && imap < nsrow)
+			    {
+				/* Lx [Map [i] + pk] += Ax [p] * fjk ; */
+				L_MULTADD (Lx,(imap+pk), Ax,Az,p, fjk) ;
+			    }
+			}
+		    }
+		}
+	    }
+	    pk += nsrow ;  /* advance to the next column of the supernode */
+	}
+
+	/* add beta to the diagonal of the supernode, if nonzero */
+	if (beta [0] != 0.0)
+	{
+	    /* note that only the real part of beta is used */
+	    pk = psx ;
+	    for (k = k1 ; k < k2 ; k++)
+	    {
+		/* Lx [pk] += beta [0] ; */
+		L_ASSEMBLE (Lx,pk, beta) ;
+		pk += nsrow + 1 ;	/* advance to the next diagonal entry */
+	    }
+	}
+
+	PRINT1 (("Supernode with just A: repeat: "ID"\n", repeat_supernode)) ;
+	DEBUG (CHOLMOD(dump_super) (s, Super, Lpi, Ls, Lpx, Lx, L_ENTRY,
+		    Common)) ;
+	PRINT1 (("\n\n")) ;
+
+	/* ------------------------------------------------------------------ */
+	/* save/restore the list of supernodes */
+	/* ------------------------------------------------------------------ */
+
+	if (!repeat_supernode)
+	{
+	    /* Save the list of pending descendants in case s is not positive
+	     * definite.  Also save Lpos for each descendant d, so that we can
+	     * find which part of d is used to update s. */
+	    for (d = Head [s] ; d != EMPTY ; d = Next [d])
+	    {
+		Lpos_save [d] = Lpos [d] ;
+		Next_save [d] = Next [d] ;
+	    }
+	}
+	else
+	{
+	    /* s is not positive definite, and is being repeated.  Restore
+	     * the list of supernodes.  This can be done with pointer assignment
+	     * because all 4 arrays are held within Common->Iwork. */
+	    Lpos = Lpos_save ;
+	    Next = Next_save ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* update supernode s with each pending descendant d */
+	/* ------------------------------------------------------------------ */
+
+#ifndef NDEBUG
+	for (d = Head [s] ; d != EMPTY ; d = Next [d])
+	{
+	    PRINT1 (("\nWill update "ID" with Child: "ID"\n", s, d)) ;
+	    DEBUG (CHOLMOD(dump_super) (d, Super, Lpi, Ls, Lpx, Lx, L_ENTRY,
+			Common)) ;
+	}
+	PRINT1 (("\nNow factorizing supernode "ID":\n", s)) ;
+#endif
+
+	for (d = Head [s] ; d != EMPTY ; d = dnext)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* get the size of supernode d */
+	    /* -------------------------------------------------------------- */
+
+	    kd1 = Super [d] ;	    /* d contains cols kd1 to kd2-1 of L */
+	    kd2 = Super [d+1] ;
+	    ndcol = kd2 - kd1 ;	    /* # of columns in all of d */
+	    pdi = Lpi [d] ;	    /* pointer to first row of d in Ls */
+	    pdx = Lpx [d] ;	    /* pointer to first row of d in Lx */
+	    pdend = Lpi [d+1] ;	    /* pointer just past last row of d in Ls */
+	    ndrow = pdend - pdi ;   /* # rows in all of d */
+
+	    PRINT1 (("Child: ")) ;
+	    DEBUG (CHOLMOD(dump_super) (d, Super, Lpi, Ls, Lpx, Lx, L_ENTRY,
+			Common)) ;
+
+	    /* -------------------------------------------------------------- */
+	    /* find the range of rows of d that affect rows k1 to k2-1 of s */
+	    /* -------------------------------------------------------------- */
+
+	    p = Lpos [d] ;	    /* offset of 1st row of d affecting s */
+	    pdi1 = pdi + p ;	    /* ptr to 1st row of d affecting s in Ls */
+	    pdx1 = pdx + p ;	    /* ptr to 1st row of d affecting s in Lx */
+
+	    /* there must be at least one row remaining in d to update s */
+	    ASSERT (pdi1 < pdend) ;
+	    PRINT1 (("Lpos[d] "ID" pdi1 "ID" Ls[pdi1] "ID"\n",
+			Lpos[d], pdi1, Ls [pdi1])) ;
+	    ASSERT (Ls [pdi1] >= k1 && Ls [pdi1] < k2) ;
+
+	    for (pdi2 = pdi1 ; pdi2 < pdend && Ls [pdi2] < k2 ; pdi2++) ;
+	    ndrow1 = pdi2 - pdi1 ;	    /* # rows in first part of d */
+	    ndrow2 = pdend - pdi1 ;	    /* # rows in remaining d */
+
+	    /* rows Ls [pdi1 ... pdi2-1] are in the range k1 to k2-1.  Since d
+	     * affects s, this set cannot be empty. */
+	    ASSERT (pdi1 < pdi2 && pdi2 <= pdend) ;
+	    PRINT1 (("ndrow1 "ID" ndrow2 "ID"\n", ndrow1, ndrow2)) ;
+	    DEBUG (for (p = pdi1 ; p < pdi2 ; p++)
+		    PRINT1 (("Ls["ID"] "ID"\n", p, Ls[p]))) ;
+
+	    /* -------------------------------------------------------------- */
+	    /* construct the update matrix C for this supernode d */
+	    /* -------------------------------------------------------------- */
+
+	    /* C = L (k1:n-1, kd1:kd2-1) * L (k1:k2-1, kd1:kd2-1)', except
+	     * that k1:n-1 refers to all of the rows in L, but many of the
+	     * rows are all zero.  Supernode d holds columns kd1 to kd2-1 of L.
+	     * Nonzero rows in the range k1:k2-1 are in the list
+	     * Ls [pdi1 ... pdi2-1], of size ndrow1.  Nonzero rows in the range
+	     * k2:n-1 are in the list Ls [pdi2 ... pdend], of size ndrow2.  Let
+	     * L1 = L (Ls [pdi1 ... pdi2-1], kd1:kd2-1), and let
+	     * L2 = L (Ls [pdi2 ... pdend],  kd1:kd2-1).  C is ndrow2-by-ndcol.
+	     * Let C1 be the first ndrow1 rows of C and let C2 be the last
+	     * ndrow2-ndrow1 rows of C.  Only the lower triangular part of C1
+	     * needs to be computed since C1 is symmetric.
+	     */
+
+	    /* maxcsize is the largest size of C for all pairs (d,s) */
+	    ASSERT (ndrow2 * ndrow1 <= ((Int) L->maxcsize)) ;
+
+	    /* compute leading ndrow1-by-ndrow1 lower triangular block of C,
+	     * C1 = L1*L1' */
+
+#ifdef REAL
+	    BLAS_dsyrk ("L", "N",
+		ndrow1, ndcol,			/* N, K: L1 is ndrow1-by-ndcol*/
+		one,				/* ALPHA:  1 */
+		Lx + L_ENTRY*pdx1, ndrow,	/* A, LDA: L1, ndrow */
+		zero,				/* BETA:   0 */
+		C, ndrow2) ;			/* C, LDC: C1 */
+#else
+	    BLAS_zherk ("L", "N",
+		ndrow1, ndcol,			/* N, K: L1 is ndrow1-by-ndcol*/
+		one,				/* ALPHA:  1 */
+		Lx + L_ENTRY*pdx1, ndrow,	/* A, LDA: L1, ndrow */
+		zero,				/* BETA:   0 */
+		C, ndrow2) ;			/* C, LDC: C1 */
+#endif
+
+	    /* compute remaining (ndrow3-ndrow1)-by-ndrow1 block of C,
+	     * C2 = L2*L1' */
+	    ndrow3 = ndrow2 - ndrow1 ;
+	    if (ndrow3 > 0)
+	    {
+
+#ifdef REAL
+		BLAS_dgemm ("N", "C",
+		    ndrow3, ndrow1, ndcol,	/* M, N, K */
+		    one,			/* ALPHA:  1 */
+		    Lx + L_ENTRY*(pdx1 + ndrow1),/* A, LDA: L2, ndrow */
+		    ndrow,	
+		    Lx + L_ENTRY*pdx1,		/* B, LDB: L1, ndrow */
+		    ndrow,
+		    zero,			/* BETA:   0 */
+		    C + L_ENTRY*ndrow1,		/* C, LDC: C2 */
+		    ndrow2) ;
+#else
+		BLAS_zgemm ("N", "C",
+		    ndrow3, ndrow1, ndcol,	/* M, N, K */
+		    one,			/* ALPHA:  1 */
+		    Lx + L_ENTRY*(pdx1 + ndrow1),/* A, LDA: L2, ndrow */
+		    ndrow,	
+		    Lx + L_ENTRY*pdx1,		/* B, LDB: L1, ndrow */
+		    ndrow,
+		    zero,			/* BETA:   0 */
+		    C + L_ENTRY*ndrow1,		/* C, LDC: C2 */
+		    ndrow2) ;
+#endif
+
+	    }
+
+	    DEBUG (CHOLMOD(dump_real) ("C", C, ndrow2, ndrow1, TRUE, L_ENTRY,
+			Common)) ;
+
+	    /* -------------------------------------------------------------- */
+	    /* construct relative map to assemble d into s */
+	    /* -------------------------------------------------------------- */
+
+	    for (i = 0 ; i < ndrow2 ; i++)
+	    {
+		RelativeMap [i] = Map [Ls [pdi1 + i]] ;
+		ASSERT (RelativeMap [i] >= 0 && RelativeMap [i] < nsrow) ;
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* assemble C into supernode s using the relative map */
+	    /* -------------------------------------------------------------- */
+
+	    pj = 0 ;
+	    for (j = 0 ; j < ndrow1 ; j++)		/* cols k1:k2-1 */
+	    {
+		ASSERT (RelativeMap [j] == Map [Ls [pdi1 + j]]) ;
+		ASSERT (RelativeMap [j] >= 0 && RelativeMap [j] < nscol) ;
+		px = psx + RelativeMap [j] * nsrow ;
+		for (i = j ; i < ndrow2 ; i++)		/* rows k1:n-1 */
+		{
+		    ASSERT (RelativeMap [i] == Map [Ls [pdi1 + i]]) ;
+		    ASSERT (RelativeMap [i] >= j && RelativeMap [i] < nsrow) ;
+		    /* Lx [px + RelativeMap [i]] -= C [i + pj] ; */
+		    q = px + RelativeMap [i] ;
+		    L_ASSEMBLESUB (Lx,q, C, i+pj) ;
+		}
+		pj += ndrow2 ;
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* prepare this supernode d for its next ancestor */
+	    /* -------------------------------------------------------------- */
+
+	    dnext = Next [d] ;
+
+	    if (!repeat_supernode)
+	    {
+		/* If node s is being repeated, Head [dancestor] has already
+		 * been cleared (set to EMPTY).  It must remain EMPTY.  The
+		 * dancestor will not be factorized since the factorization
+		 * terminates at node s. */
+		Lpos [d] = pdi2 - pdi ;
+		if (Lpos [d] < ndrow)
+		{
+		    dancestor = SuperMap [Ls [pdi2]] ;
+		    ASSERT (dancestor > s && dancestor < nsuper) ;
+		    /* place d in the link list of its next ancestor */
+		    Next [d] = Head [dancestor] ;
+		    Head [dancestor] = d ;
+		}
+	    }
+	}
+
+	PRINT1 (("\nSupernode with contributions A: repeat: "ID"\n",
+		    repeat_supernode)) ;
+	DEBUG (CHOLMOD(dump_super) (s, Super, Lpi, Ls, Lpx, Lx, L_ENTRY,
+		    Common)) ;
+	PRINT1 (("\n\n")) ;
+
+	/* ------------------------------------------------------------------ */
+	/* factorize diagonal block of supernode s in LL' */
+	/* ------------------------------------------------------------------ */
+
+	/* The current supernode s is ready to factorize.  It has been updated
+	 * by all descendant supernodes.  Let S = the current supernode, which
+	 * holds rows k1:n-1 and columns k1:k2-1 of the updated matrix.   It
+	 * splits into two parts:  the square diagonal block S1, and the
+	 * rectangular part S2.  Here, S1 is factorized into L1*L1' and
+	 * overwritten by S1.
+	 *
+	 * If supernode s is being repeated, only factorize it up to but not
+	 * including the column containing the problematic entry.
+	 */
+
+	nscol2 = (repeat_supernode) ? (nscol_new) : (nscol) ;
+
+#ifdef REAL
+	LAPACK_dpotrf ("L",
+	    nscol2,			    /* N: nscol2 */
+	    Lx + L_ENTRY*psx, nsrow,	    /* A, LDA: S1, nsrow */
+	    info) ;			    /* INFO */
+#else
+	LAPACK_zpotrf ("L",
+	    nscol2,			    /* N: nscol2 */
+	    Lx + L_ENTRY*psx, nsrow,	    /* A, LDA: S1, nsrow */
+	    info) ;			    /* INFO */
+#endif
+
+	/* ------------------------------------------------------------------ */
+	/* check if the matrix is not positive definite */
+	/* ------------------------------------------------------------------ */
+
+	if (repeat_supernode)
+	{
+	    /* the leading part has been refactorized; it must have succeeded */
+	    info = 0 ;
+
+	    /* zero out the rest of this supernode */
+	    p = psx + nsrow * nscol_new ;
+	    pend = psx + nsrow * nscol ;	    /* s is nsrow-by-nscol */
+	    for ( ; p < pend ; p++)
+	    {
+		/* Lx [p] = 0 ; */
+		L_CLEAR (Lx,p) ;
+	    }
+	}
+
+	/* info is set to one in LAPACK_*potrf if blas_ok is FALSE.  It is
+	 * set to zero in dpotrf/zpotrf if the factorization was successful. */
+	if (CHECK_BLAS_INT && !blas_ok)
+	{
+	    ERROR (CHOLMOD_TOO_LARGE, "problem too large for the BLAS") ;
+	}
+
+	if (info != 0)
+	{
+	    /* Matrix is not positive definite.  dpotrf/zpotrf do NOT report an
+	     * error if the diagonal of L has NaN's, only if it has a zero. */
+	    if (Common->status == CHOLMOD_OK)
+	    {
+		ERROR (CHOLMOD_NOT_POSDEF, "matrix not positive definite") ;
+	    }
+
+	    /* L->minor is the column of L that contains a zero or negative
+	     * diagonal term. */
+	    L->minor = k1 + info - 1 ;
+
+	    /* clear the link lists of all subsequent supernodes */
+	    for (ss = s+1 ; ss < nsuper ; ss++)
+	    {
+		Head [ss] = EMPTY ;
+	    }
+
+	    /* zero this supernode, and all remaining supernodes */
+	    pend = L->xsize ;
+	    for (p = psx ; p < pend ; p++)
+	    {
+		/* Lx [p] = 0. ; */
+		L_CLEAR (Lx,p) ;
+	    }
+
+	    /* If L is indefinite, it still contains useful information.
+	     * Supernodes 0 to s-1 are valid, similar to MATLAB [R,p]=chol(A),
+	     * where the 1-based p is identical to the 0-based L->minor.  Since
+	     * L->minor is in the current supernode s, it and any columns to the
+	     * left of it in supernode s are also all zero.  This differs from
+	     * [R,p]=chol(A), which contains nonzero rows 1 to p-1.  Fix this
+	     * by setting repeat_supernode to TRUE, and repeating supernode s.
+	     *
+	     * If Common->quick_return_if_not_posdef is true, then the entire
+	     * supernode s is not factorized; it is left as all zero.
+	     */
+
+	    if (info == 1 || Common->quick_return_if_not_posdef)
+	    {
+		/* If the first column of supernode s contains a zero or
+		 * negative diagonal entry, then it is already properly set to
+		 * zero.  Also, info will be 1 if integer overflow occured in
+		 * the BLAS. */
+		Head [s] = EMPTY ;
+		return (Common->status >= CHOLMOD_OK) ;
+	    }
+	    else
+	    {
+		/* Repeat supernode s, but only factorize it up to but not
+		 * including the column containing the problematic diagonal
+		 * entry. */
+		repeat_supernode = TRUE ;
+		s-- ;
+		nscol_new = info - 1 ;
+		continue ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* compute the subdiagonal block and prepare supernode for its parent */
+	/* ------------------------------------------------------------------ */
+
+	nsrow2 = nsrow - nscol2 ;
+	if (nsrow2 > 0)
+	{
+	    /* The current supernode is columns k1 to k2-1 of L.  Let L1 be the
+	     * diagonal block (factorized by dpotrf/zpotrf above; rows/cols
+	     * k1:k2-1), and L2 be rows k2:n-1 and columns k1:k2-1 of L.  The
+	     * triangular system to solve is L2*L1' = S2, where S2 is
+	     * overwritten with L2.  More precisely, L2 = S2 / L1' in MATLAB
+	     * notation.
+	     */
+
+#ifdef REAL
+	    BLAS_dtrsm ("R", "L", "C", "N",
+		nsrow2, nscol2,			/* M, N */
+		one,				/* ALPHA: 1 */
+		Lx + L_ENTRY*psx, nsrow,	/* A, LDA: L1, nsrow */
+		Lx + L_ENTRY*(psx + nscol2),	/* B, LDB, L2, nsrow */
+		nsrow) ;
+#else
+	    BLAS_ztrsm ("R", "L", "C", "N",
+		nsrow2, nscol2,			/* M, N */
+		one,				/* ALPHA: 1 */
+		Lx + L_ENTRY*psx, nsrow,	/* A, LDA: L1, nsrow */
+		Lx + L_ENTRY*(psx + nscol2),	/* B, LDB, L2, nsrow */
+		nsrow) ;
+#endif
+
+	    if (CHECK_BLAS_INT && !blas_ok)
+	    {
+		ERROR (CHOLMOD_TOO_LARGE, "problem too large for the BLAS") ;
+	    }
+
+	    if (!repeat_supernode)
+	    {
+		/* Lpos [s] is offset of first row of s affecting its parent */
+		Lpos [s] = nscol ;
+		sparent = SuperMap [Ls [psi + nscol]] ;
+		ASSERT (sparent != EMPTY) ;
+		ASSERT (Ls [psi + nscol] >= Super [sparent]) ;
+		ASSERT (Ls [psi + nscol] <  Super [sparent+1]) ;
+		ASSERT (SuperMap [Ls [psi + nscol]] == sparent) ;
+		ASSERT (sparent > s && sparent < nsuper) ;
+		/* place s in link list of its parent */
+		Next [s] = Head [sparent] ;
+		Head [sparent] = s ;
+	    }
+	}
+
+	Head [s] = EMPTY ;	/* link list for supernode s no longer needed */
+
+	/* clear the Map (debugging only, to detect changes in pattern of A) */
+	DEBUG (for (k = 0 ; k < nsrow ; k++) Map [Ls [psi + k]] = EMPTY) ;
+	DEBUG (CHOLMOD(dump_super) (s, Super, Lpi, Ls, Lpx, Lx, L_ENTRY,
+		    Common)) ;
+
+	if (repeat_supernode)
+	{
+	    /* matrix is not positive definite; finished clean-up for supernode
+	     * containing negative diagonal */
+	    return (Common->status >= CHOLMOD_OK) ;
+	}
+    }
+
+    /* success; matrix is positive definite */
+    L->minor = n ;
+    return (Common->status >= CHOLMOD_OK) ;
+}
+#undef PATTERN
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
diff --git a/src/C/SuiteSparse/CHOLMOD/Supernodal/t_cholmod_super_solve.c b/src/C/SuiteSparse/CHOLMOD/Supernodal/t_cholmod_super_solve.c
new file mode 100644
index 0000000..2f5e792
--- /dev/null
+++ b/src/C/SuiteSparse/CHOLMOD/Supernodal/t_cholmod_super_solve.c
@@ -0,0 +1,430 @@
+/* ========================================================================== */
+/* === Supernodal/t_cholmod_super_solve ===================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Supernodal Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Supernodal Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Template routine for cholmod_super_solve.  Supports real or complex L. */
+
+#include "cholmod_template.h"
+
+static int TEMPLATE (cholmod_super_lsolve)
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to use for the forward solve */
+    /* ---- output ---- */
+    cholmod_dense *X,	/* b on input, solution to Lx=b on output */
+    /* ---- workspace ---- */
+    cholmod_dense *E,	/* workspace of size nrhs*(L->maxesize) */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Lx, *Xx, *Ex ;
+    double minus_one [2], one [2] ;
+    Int *Lpi, *Lpx, *Ls, *Super ;
+    Int nsuper, k1, k2, psi, psend, psx, nsrow, nscol, ii, s,
+	nsrow2, n, ps2, j, i, d, nrhs ;
+
+    /* If integer overflow occurs in the BLAS, Common->status is set to
+     * CHOLMOD_TOO_LARGE in the caller, and the contents of X are undefined. */
+    int blas_ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nrhs = X->ncol ;
+    Ex = E->x ;
+    Xx = X->x ;
+    n = L->n ;
+    d = X->d ;
+
+    nsuper = L->nsuper ;
+    Lpi = L->pi ;
+    Lpx = L->px ;
+    Ls = L->s ;
+    Super = L->super ;
+    Lx = L->x ;
+    minus_one [0] = -1.0 ;
+    minus_one [1] = 0 ;
+    one [0] = 1.0 ;
+    one [1] = 0 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* solve Lx=b */
+    /* ---------------------------------------------------------------------- */
+
+    if (nrhs == 1)
+    {
+
+	for (s = 0 ; s < nsuper ; s++)
+	{
+	    k1 = Super [s] ;
+	    k2 = Super [s+1] ;
+	    psi = Lpi [s] ;
+	    psend = Lpi [s+1] ;
+	    psx = Lpx [s] ;
+	    nsrow = psend - psi ;
+	    nscol = k2 - k1 ;
+	    nsrow2 = nsrow - nscol ;
+	    ps2 = psi + nscol ;
+	    ASSERT ((size_t) nsrow2 <= L->maxesize) ;
+
+	    /* L1 is nscol-by-nscol, lower triangular with non-unit diagonal.
+	     * L2 is nsrow2-by-nscol.  L1 and L2 have leading dimension of
+	     * nsrow.  x1 is nscol-by-nsrow, with leading dimension n.
+	     * E is nsrow2-by-1, with leading dimension nsrow2.
+	     */
+
+	    /* gather X into E */
+	    for (ii = 0 ; ii < nsrow2 ; ii++)
+	    {
+		/* Ex [ii] = Xx [Ls [ps2 + ii]] ; */
+		ASSIGN (Ex,-,ii, Xx,-,Ls [ps2 + ii]) ;
+	    }
+
+#ifdef REAL
+
+	    /* solve L1*x1 (that is, x1 = L1\x1) */
+	    BLAS_dtrsv ("L", "N", "N",
+		nscol,			    /* N:       L1 is nscol-by-nscol */
+		Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA:  L1 */
+		Xx + ENTRY_SIZE*k1, 1) ;    /* X, INCX: x1 */
+
+	    /* E = E - L2*x1 */
+	    BLAS_dgemv ("N",
+		nsrow2, nscol,		    /* M, N:    L2 is nsrow2-by-nscol */
+		minus_one,		    /* ALPHA:   -1 */
+		Lx + ENTRY_SIZE*(psx + nscol),   /* A, LDA:  L2 */
+		nsrow,
+		Xx + ENTRY_SIZE*k1, 1,	    /* X, INCX: x1 */
+		one,			    /* BETA:    1 */
+		Ex, 1) ;		    /* Y, INCY: E */
+
+#else
+
+	    /* solve L1*x1 (that is, x1 = L1\x1) */
+	    BLAS_ztrsv ("L", "N", "N",
+		nscol,			    /* N:       L1 is nscol-by-nscol */
+		Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA:  L1 */
+		Xx + ENTRY_SIZE*k1, 1) ;    /* X, INCX: x1 */
+
+	    /* E = E - L2*x1 */
+	    BLAS_zgemv ("N",
+		nsrow2, nscol,		    /* M, N:    L2 is nsrow2-by-nscol */
+		minus_one,		    /* ALPHA:   -1 */
+		Lx + ENTRY_SIZE*(psx + nscol),   /* A, LDA:  L2 */
+		nsrow,
+		Xx + ENTRY_SIZE*k1, 1,	    /* X, INCX: x1 */
+		one,			    /* BETA:    1 */
+		Ex, 1) ;		    /* Y, INCY: E */
+
+#endif
+
+	    /* scatter E back into X */
+	    for (ii = 0 ; ii < nsrow2 ; ii++)
+	    {
+		/* Xx [Ls [ps2 + ii]] = Ex [ii] ; */
+		ASSIGN (Xx,-,Ls [ps2 + ii], Ex,-,ii) ;
+	    }
+	}
+    }
+    else
+    {
+
+	for (s = 0 ; s < nsuper ; s++)
+	{
+	    k1 = Super [s] ;
+	    k2 = Super [s+1] ;
+	    psi = Lpi [s] ;
+	    psend = Lpi [s+1] ;
+	    psx = Lpx [s] ;
+	    nsrow = psend - psi ;
+	    nscol = k2 - k1 ;
+	    nsrow2 = nsrow - nscol ;
+	    ps2 = psi + nscol ;
+	    ASSERT ((size_t) nsrow2 <= L->maxesize) ;
+
+	    /* E is nsrow2-by-nrhs, with leading dimension nsrow2. */
+
+	    /* gather X into E */
+	    for (ii = 0 ; ii < nsrow2 ; ii++)
+	    {
+		i = Ls [ps2 + ii] ;
+		for (j = 0 ; j < nrhs ; j++)
+		{
+		    /* Ex [ii + j*nsrow2] = Xx [i + j*d] ; */
+		    ASSIGN (Ex,-,ii+j*nsrow2, Xx,-,i+j*d) ;
+		}
+	    }
+
+#ifdef REAL
+
+	    /* solve L1*x1 */
+	    BLAS_dtrsm ("L", "L", "N", "N",
+		nscol, nrhs,			/* M, N: x1 is nscol-by-nrhs */
+		one,				/* ALPHA:  1 */
+		Lx + ENTRY_SIZE*psx, nsrow,	/* A, LDA: L1 */
+		Xx + ENTRY_SIZE*k1, d) ;	/* B, LDB: x1 */
+
+	    /* E = E - L2*x1 */
+	    if (nsrow2 > 0)
+	    {
+		BLAS_dgemm ("N", "N",
+		    nsrow2, nrhs, nscol,	    /* M, N, K */
+		    minus_one,			    /* ALPHA:  -1 */
+		    Lx + ENTRY_SIZE*(psx + nscol),  /* A, LDA: L2 */
+		    nsrow,
+		    Xx + ENTRY_SIZE*k1, d,	    /* B, LDB: X1 */
+		    one,			    /* BETA:   1 */
+		    Ex, nsrow2) ;		    /* C, LDC: E */
+	    }
+
+#else
+
+	    /* solve L1*x1 */
+	    BLAS_ztrsm ("L", "L", "N", "N",
+		nscol, nrhs,			/* M, N: x1 is nscol-by-nrhs */
+		one,				/* ALPHA:  1 */
+		Lx + ENTRY_SIZE*psx, nsrow,	/* A, LDA: L1 */
+		Xx + ENTRY_SIZE*k1, d) ;	/* B, LDB: x1 */
+
+	    /* E = E - L2*x1 */
+	    if (nsrow2 > 0)
+	    {
+		BLAS_zgemm ("N", "N",
+		    nsrow2, nrhs, nscol,	    /* M, N, K */
+		    minus_one,			    /* ALPHA:  -1 */
+		    Lx + ENTRY_SIZE*(psx + nscol),  /* A, LDA: L2 */
+		    nsrow,
+		    Xx + ENTRY_SIZE*k1, d,	    /* B, LDB: X1 */
+		    one,			    /* BETA:   1 */
+		    Ex, nsrow2) ;		    /* C, LDC: E */
+	    }
+
+#endif
+
+	    /* scatter E back into X */
+	    for (ii = 0 ; ii < nsrow2 ; ii++)
+	    {
+		i = Ls [ps2 + ii] ;
+		for (j = 0 ; j < nrhs ; j++)
+		{
+		    /* Xx [i + j*d] = Ex [ii + j*nsrow2] ; */
+		    ASSIGN (Xx,-,i+j*d, Ex,-,ii+j*nsrow2) ;
+		}
+	    }
+	}
+    }
+
+    Common->status = CHOLMOD_OK ;
+    return (blas_ok) ;
+}
+
+
+static int TEMPLATE (cholmod_super_ltsolve)
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to use for the forward solve */
+    /* ---- output ---- */
+    cholmod_dense *X,	/* b on input, solution to Lx=b on output */
+    /* ---- workspace ---- */
+    cholmod_dense *E,	/* workspace of size nrhs*(L->maxesize) */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Lx, *Xx, *Ex ;
+    double minus_one [2], one [2] ;
+    Int *Lpi, *Lpx, *Ls, *Super ;
+    Int nsuper, k1, k2, psi, psend, psx, nsrow, nscol, ii, s,
+	nsrow2, n, ps2, j, i, d, nrhs ;
+    int blas_ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nrhs = X->ncol ;
+    Ex = E->x ;
+    Xx = X->x ;
+    n = L->n ;
+    d = X->d ;
+
+    nsuper = L->nsuper ;
+    Lpi = L->pi ;
+    Lpx = L->px ;
+    Ls = L->s ;
+    Super = L->super ;
+    Lx = L->x ;
+    minus_one [0] = -1.0 ;
+    minus_one [1] = 0 ;
+    one [0] = 1.0 ;
+    one [1] = 0 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* solve L'x=b */
+    /* ---------------------------------------------------------------------- */
+
+    if (nrhs == 1)
+    {
+
+	for (s = nsuper-1 ; s >= 0 ; s--)
+	{
+	    k1 = Super [s] ;
+	    k2 = Super [s+1] ;
+	    psi = Lpi [s] ;
+	    psend = Lpi [s+1] ;
+	    psx = Lpx [s] ;
+	    nsrow = psend - psi ;
+	    nscol = k2 - k1 ;
+	    nsrow2 = nsrow - nscol ;
+	    ps2 = psi + nscol ;
+	    ASSERT ((size_t) nsrow2 <= L->maxesize) ;
+
+	    /* L1 is nscol-by-nscol, lower triangular with non-unit diagonal.
+	     * L2 is nsrow2-by-nscol.  L1 and L2 have leading dimension of
+	     * nsrow.  x1 is nscol-by-nsrow, with leading dimension n.
+	     * E is nsrow2-by-1, with leading dimension nsrow2.
+	     */
+
+	    /* gather X into E */
+	    for (ii = 0 ; ii < nsrow2 ; ii++)
+	    {
+		/* Ex [ii] = Xx [Ls [ps2 + ii]] ; */
+		ASSIGN (Ex,-,ii, Xx,-,Ls [ps2 + ii]) ;
+	    }
+
+#ifdef REAL
+
+	    /* x1 = x1 - L2'*E */
+	    BLAS_dgemv ("C",
+		nsrow2, nscol,		    /* M, N: L2 is nsrow2-by-nscol */
+		minus_one,		    /* ALPHA:   -1 */
+		Lx + ENTRY_SIZE*(psx + nscol),   /* A, LDA:  L2 */
+		nsrow,
+		Ex, 1,			    /* X, INCX: Ex */
+		one,			    /* BETA:    1 */
+		Xx + ENTRY_SIZE*k1, 1) ;    /* Y, INCY: x1 */
+
+	    /* solve L1'*x1 */
+	    BLAS_dtrsv ("L", "C", "N",
+		nscol,			    /* N:	L1 is nscol-by-nscol */
+		Lx + ENTRY_SIZE*psx, nsrow,	    /* A, LDA:  L1 */
+		Xx + ENTRY_SIZE*k1, 1) ;	    /* X, INCX: x1 */
+
+#else
+
+	    /* x1 = x1 - L2'*E */
+	    BLAS_zgemv ("C",
+		nsrow2, nscol,		    /* M, N: L2 is nsrow2-by-nscol */
+		minus_one,		    /* ALPHA:   -1 */
+		Lx + ENTRY_SIZE*(psx + nscol),   /* A, LDA:  L2 */
+		nsrow,
+		Ex, 1,			    /* X, INCX: Ex */
+		one,			    /* BETA:    1 */
+		Xx + ENTRY_SIZE*k1, 1) ;    /* Y, INCY: x1 */
+
+	    /* solve L1'*x1 */
+	    BLAS_ztrsv ("L", "C", "N",
+		nscol,			    /* N:	L1 is nscol-by-nscol */
+		Lx + ENTRY_SIZE*psx, nsrow,	    /* A, LDA:  L1 */
+		Xx + ENTRY_SIZE*k1, 1) ;	    /* X, INCX: x1 */
+
+#endif
+
+	}
+    }
+    else
+    {
+
+	for (s = nsuper-1 ; s >= 0 ; s--)
+	{
+	    k1 = Super [s] ;
+	    k2 = Super [s+1] ;
+	    psi = Lpi [s] ;
+	    psend = Lpi [s+1] ;
+	    psx = Lpx [s] ;
+	    nsrow = psend - psi ;
+	    nscol = k2 - k1 ;
+	    nsrow2 = nsrow - nscol ;
+	    ps2 = psi + nscol ;
+	    ASSERT ((size_t) nsrow2 <= L->maxesize) ;
+
+	    /* E is nsrow2-by-nrhs, with leading dimension nsrow2. */
+
+	    /* gather X into E */
+	    for (ii = 0 ; ii < nsrow2 ; ii++)
+	    {
+		i = Ls [ps2 + ii] ;
+		for (j = 0 ; j < nrhs ; j++)
+		{
+		    /* Ex [ii + j*nsrow2] = Xx [i + j*d] ; */
+		    ASSIGN (Ex,-,ii+j*nsrow2, Xx,-,i+j*d) ;
+		}
+	    }
+
+#ifdef REAL
+
+	    /* x1 = x1 - L2'*E */
+	    if (nsrow2 > 0)
+	    {
+		BLAS_dgemm ("C", "N",
+		    nscol, nrhs, nsrow2,	/* M, N, K */
+		    minus_one,			/* ALPHA:  -1 */
+		    Lx + ENTRY_SIZE*(psx + nscol),  /* A, LDA: L2 */
+		    nsrow,
+		    Ex, nsrow2,			/* B, LDB: E */
+		    one,			/* BETA:   1 */
+		    Xx + ENTRY_SIZE*k1, d) ;	/* C, LDC: x1 */
+	    }
+
+	    /* solve L1'*x1 */
+	    BLAS_dtrsm ("L", "L", "C", "N",
+		nscol,	nrhs,			/* M, N: x1 is nscol-by-nrhs */
+		one,				/* ALPHA:  1 */
+		Lx + ENTRY_SIZE*psx, nsrow,	/* A, LDA: L1 */
+		Xx + ENTRY_SIZE*k1, d) ;	/* B, LDB: x1 */
+
+#else
+
+	    /* x1 = x1 - L2'*E */
+	    if (nsrow2 > 0)
+	    {
+		BLAS_zgemm ("C", "N",
+		    nscol, nrhs, nsrow2,	/* M, N, K */
+		    minus_one,			/* ALPHA:  -1 */
+		    Lx + ENTRY_SIZE*(psx + nscol),  /* A, LDA: L2 */
+		    nsrow,
+		    Ex, nsrow2,			/* B, LDB: E */
+		    one,			/* BETA:   1 */
+		    Xx + ENTRY_SIZE*k1, d) ;	/* C, LDC: x1 */
+	    }
+
+	    /* solve L1'*x1 */
+	    BLAS_ztrsm ("L", "L", "C", "N",
+		nscol,	nrhs,			/* M, N: x1 is nscol-by-nrhs */
+		one,				/* ALPHA:  1 */
+		Lx + ENTRY_SIZE*psx, nsrow,	/* A, LDA: L1 */
+		Xx + ENTRY_SIZE*k1, d) ;	/* B, LDB: x1 */
+
+#endif
+
+	}
+    }
+
+    Common->status = CHOLMOD_OK ;
+    return (blas_ok) ;
+}
+
+#undef PATTERN
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
diff --git a/src/C/SuiteSparse/COLAMD/ChangeLog b/src/C/SuiteSparse/COLAMD/ChangeLog
new file mode 100644
index 0000000..e16e946
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/ChangeLog
@@ -0,0 +1,123 @@
+Dec 12, 2006, version 2.5.2
+
+	* minor MATLAB cleanup.  MATLAB functions renamed colamd2 and symamd2,
+	    so that they do not conflict with the built-in versions.  Note that
+	    the MATLAB built-in functions colamd and symamd are identical to
+	    the colamd and symamd functions here.
+
+Aug 31, 2006: Version 2.5.1
+
+	* minor change to colamd.m and symamd.m, to use etree instead
+	    of sparsfun.
+
+Apr. 30, 2006: Version 2.5
+
+	* colamd_recommended modified, to do more careful integer overflow
+	    checking.  It now returns size_t, not int.  colamd_l_recommended
+	    also returns size_t.  A zero is returned if an error occurs.  A
+	    postive return value denotes success.  In v2.4 and earlier,
+	    -1 was returned on error (an int or long).
+
+	* long replaced with UF_long integer, which is long except on WIN64.
+
+Nov 15, 2005:
+
+	* minor editting of comments; version number (2.4) unchanged.
+
+Changes from Version 2.3 to 2.4 (Aug 30, 2005)
+
+	* Makefile now relies on ../UFconfig/UFconfig.mk
+
+	* changed the dense row/col detection.  The meaning of the knobs
+	    has thus changed.
+
+	* added an option to turn off aggressive absorption.  It was
+	    always on in versions 2.3 and earlier.
+
+	* added a #define'd version number
+
+	* added a function pointer (colamd_printf) for COLAMD's printing.
+
+	* added a -DNPRINT option, to turn off printing at compile-time.
+
+	* added a check for integer overflow in colamd_recommended
+
+	* minor changes to allow for more simpler 100% test coverage
+
+	* bug fix.  If symamd v2.3 fails to allocate its copy of the input
+	    matrix, then it erroneously frees a calloc'd workspace twice.
+	    This bug has no effect on the MATLAB symamd mexFunction, since
+	    mxCalloc terminates the mexFunction if it fails to allocate
+	    memory.  Similarly, UMFPACK is not affected because it does not
+	    use symamd.  The bug has no effect on the colamd ordering
+	    routine in v2.3.
+
+Changes from Version 2.2 to 2.3 (Sept. 8, 2003)
+
+	* removed the call to the MATLAB spparms ('spumoni') function.
+	    This can take a lot of time if you are ordering many small
+	    matrices.  Only affects the MATLAB interface (colamdmex.c,
+	    symamdmex.c, colamdtestmex.c, and symamdtestmex.c).  The
+	    usage of the optional 2nd argument to the colamd and symamd
+	    mexFunctions was changed accordingly.
+
+Changes from Version 2.1 to 2.2 (Sept. 23, 2002)
+
+	* extensive testing routines added (colamd_test.m, colamdtestmex.c,
+	    and symamdtestmex.c), and the Makefile modified accordingly.
+
+	* a few typos in the comments corrected 
+
+	* use of the MATLAB "flops" command removed from colamd_demo, and an
+	    m-file routine luflops.m added.
+
+	* an explicit typecast from unsigned to int added, for COLAMD_C and
+	    COLAMD_R in colamd.h.
+
+	* #include <stdio.h> added to colamd_example.c
+
+
+Changes from Version 2.0 to 2.1 (May 4, 2001)
+
+	* TRUE and FALSE are predefined on some systems, so they are defined
+		here only if not already defined.
+	
+	* web site changed
+
+	* UNIX Makefile modified, to handle the case if "." is not in your path.
+
+
+Changes from Version 1.0 to 2.0 (January 31, 2000)
+
+	No bugs were found in version 1.1.  These changes merely add new
+	functionality.
+
+	* added the COLAMD_RECOMMENDED (nnz, n_row, n_col) macro.
+
+	* moved the output statistics, from A, to a separate output argument.
+		The arguments changed for the C-callable routines.
+
+	* added colamd_report and symamd_report.
+
+	* added a C-callable symamd routine.  Formerly, symamd was only
+		available as a mexFunction from MATLAB.
+
+	* added error-checking to symamd.  Formerly, it assumed its input
+		was error-free.
+
+	* added the optional stats and knobs arguments to the symamd mexFunction
+
+	* deleted colamd_help.  A help message is still available from
+		"help colamd" and "help symamd" in MATLAB.
+
+	* deleted colamdtree.m and symamdtree.m.  Now, colamd.m and symamd.m
+		also do the elimination tree post-ordering.  The Version 1.1
+		colamd and symamd mexFunctions, which do not do the post-
+		ordering, are now visible as colamdmex and symamdmex from
+		MATLAB.  Essentialy, the post-ordering is now the default
+		behavior of colamd.m and symamd.m, to match the behavior of
+		colmmd and symmmd.  The post-ordering is only available in the
+		MATLAB interface, not the C-callable interface.
+
+	* made a slight change to the dense row/column detection in symamd,
+		to match the stated specifications.
diff --git a/src/C/SuiteSparse/COLAMD/Contents.m b/src/C/SuiteSparse/COLAMD/Contents.m
new file mode 100644
index 0000000..5639549
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/Contents.m
@@ -0,0 +1,18 @@
+% COLAMD, column approximate minimum degree ordering
+%
+% Primary:
+%   colamd2     - Column approximate minimum degree permutation.
+%   symamd2     - SYMAMD Symmetric approximate minimum degree permutation.
+%
+% helper and test functions:
+%   colamd_demo - demo for colamd, column approx minimum degree ordering algorithm
+%   colamd_make - compiles COLAMD2 and SYMAMD2 for MATLAB
+%   colamd_test - test colamd2 and symamd2
+%   luflops     - compute the flop count for sparse LU factorization
+%
+% Example:
+%   p = colamd2 (A)
+%
+
+% Copyright 2006, Timothy A. Davis
+
diff --git a/src/C/SuiteSparse/COLAMD/Makefile b/src/C/SuiteSparse/COLAMD/Makefile
new file mode 100644
index 0000000..07a2518
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/Makefile
@@ -0,0 +1,51 @@
+
+default: libcolamd.a colamd_example colamd_l_example
+
+include ../UFconfig/UFconfig.mk
+
+I = -I../UFconfig
+
+colamd_example: colamd_example.c libcolamd.a
+	$(CC) $(CFLAGS) $(I) -o colamd_example colamd_example.c libcolamd.a -lm
+	- ./colamd_example > my_colamd_example.out
+	- diff colamd_example.out my_colamd_example.out
+
+colamd_l_example: colamd_l_example.c libcolamd.a
+	$(CC) $(CFLAGS) $(I) -o colamd_l_example colamd_l_example.c libcolamd.a -lm
+	- ./colamd_l_example > my_colamd_l_example.out
+	- diff colamd_example.out my_colamd_example.out
+
+purge: distclean
+
+distclean: clean2
+	- $(RM) libcolamd.a
+
+clean2: clean
+	- $(RM) *.o *.dll colamd_example colamd_l_example
+	- $(RM) colamd2mex.mex* symamd2mex.mex*
+	- $(RM) colamdtestmex.mex* symamdtestmex.mex*
+	- $(RM) my_colamd_example.out my_colamd_l_example.out
+
+# Compiles the MATLAB-callable routines
+mex: colamdmex.c symamdmex.c libcolamd.a
+	$(MEX) -output colamd2mex $(I) colamdmex.c libcolamd.a
+	$(MEX) -output symamd2mex $(I) symamdmex.c libcolamd.a
+
+# Compiles the extensive test code
+test: mex colamdtestmex.c symamdtestmex.c libcolamd.a
+	$(MEX) $(I) colamdtestmex.c libcolamd.a
+	$(MEX) $(I) symamdtestmex.c libcolamd.a
+
+# creates libcolamd.a, a C-callable COLAMD library
+libcolamd.a:  colamd.c colamd_global.c colamd.h
+	$(CC) $(CFLAGS) $(I) -c colamd_global.c
+	$(CC) $(CFLAGS) $(I) -c colamd.c
+	$(CC) $(CFLAGS) $(I) -c colamd.c -DDLONG -o colamd_l.o
+	$(AR) libcolamd.a colamd.o colamd_l.o colamd_global.o
+
+ccode: libcolamd.a
+
+library: libcolamd.a
+
+clean:
+	- $(RM) $(CLEAN)
diff --git a/src/C/SuiteSparse/COLAMD/README.txt b/src/C/SuiteSparse/COLAMD/README.txt
new file mode 100644
index 0000000..5561ec3
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/README.txt
@@ -0,0 +1,108 @@
+The COLAMD ordering method - Version 2.6
+-------------------------------------------------------------------------------
+
+The COLAMD column approximate minimum degree ordering algorithm computes
+a permutation vector P such that the LU factorization of A (:,P)
+tends to be sparser than that of A.  The Cholesky factorization of
+(A (:,P))'*(A (:,P)) will also tend to be sparser than that of A'*A.
+SYMAMD is a symmetric minimum degree ordering method based on COLAMD,
+available as a MATLAB-callable function.  It constructs a matrix M such
+that M'*M has the same pattern as A, and then uses COLAMD to compute a column
+ordering of M.  Colamd and symamd tend to be faster and generate better
+orderings than their MATLAB counterparts, colmmd and symmmd.
+
+To compile and test the colamd m-files and mexFunctions, just unpack the
+COLAMD/ directory from the COLAMD.tar.gz file, and run MATLAB from
+within that directory.  Next, type colamd_test to compile and test colamd
+and symamd.  This will work on any computer with MATLAB (Unix, PC, or Mac).
+Alternatively, type "make" (in Unix) to compile and run a simple example C
+code, without using MATLAB.
+
+Colamd is a built-in routine in MATLAB, available from The 
+Mathworks, Inc.  Under most cases, the compiled COLAMD from Versions 2.0
+through 2.6 do not differ.  Colamd Versions 2.2 and 2.3 differ only in their
+mexFunction interaces to MATLAB.  v2.4 fixes a bug in the symamd routine in
+v2.3.  The bug (in v2.3 and earlier) has no effect on the MATLAB symamd
+mexFunction.  v2.5 adds additional checks for integer overflow, so that
+the "int" version can be safely used with 64-bit pointers.  Refer to the
+ChangeLog for more details.
+
+    NOTE: DO NOT ATTEMPT TO USE THIS CODE IN 64-BIT MATLAB (v7.3).
+    It is not yet ported to that version of MATLAB.
+
+To use colamd and symamd within an application written in C, all you need are
+colamd.c, colamd_global.c, and colamd.h, which are the C-callable
+colamd/symamd codes.  See colamd.c for more information on how to call
+colamd from a C program.
+
+Requires UFconfig, in the ../UFconfig directory relative to this directory.
+
+	Copyright (c) 1998-2006, Timothy A. Davis, All Rights Reserved.
+
+	See http://www.cise.ufl.edu/research/sparse/colamd (the colamd.c
+	file) for the License.
+
+
+Related papers:
+
+	T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column
+	minimum degree ordering algorithm, ACM Transactions on Mathematical
+	Software, vol. 30, no. 3., pp. 353-376, 2004.
+
+	T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD,
+	an approximate column minimum degree ordering algorithm, ACM
+	Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
+	2004.
+
+	"An approximate minimum degree column ordering algorithm",
+	S. I. Larimore, MS Thesis, Dept. of Computer and Information
+	Science and Engineering, University of Florida, Gainesville, FL,
+	1998.  CISE Tech Report TR-98-016.  Available at 
+	ftp://ftp.cise.ufl.edu/cis/tech-reports/tr98/tr98-016.ps
+	via anonymous ftp.
+
+	Approximate Deficiency for Ordering the Columns of a Matrix,
+	J. L. Kern, Senior Thesis, Dept. of Computer and Information
+	Science and Engineering, University of Florida, Gainesville, FL,
+	1999.  Available at http://www.cise.ufl.edu/~davis/Kern/kern.ps 
+
+
+Authors:  Stefan I. Larimore and Timothy A. Davis, University of Florida,
+in collaboration with John Gilbert, Xerox PARC (now at UC Santa Barbara),
+and Esmong Ng, Lawrence Berkeley National Laboratory (much of this work
+he did while at Oak Ridge National Laboratory). 
+
+COLAMD files
+
+	colamd.c: the primary colamd computational kernel.
+
+	colamd.h: include file for colamd/symamd library.
+
+	colamd.m: the MATLAB interface to colamd.
+
+	colamd_demo.m: MATLAB demo file for colamd and symamd
+		(also compiles the colamdmex and symamdmex mexFunctions).
+
+	colamdmex.c: colamd mexFunction for use in MATLAB.
+
+	colamd_example.c: example C main program that calls colamd and symamd.
+
+	colamd_example.out: output of colamd_example.c.
+
+	Makefile: Makefile for colamd_example.c
+
+	symamd.m: the MATLAB interface to symamd.
+
+	symamdmex.c: symamd mexFunction for use in MATLAB.
+
+	README:  this file
+
+	ChangeLog: a log of changes since Version 1.0.
+
+	colamd_test.m:	test code
+
+	colamdtestmex.c:  test code
+
+	luflops.m:  test code
+
+	symamdtestmex.c:  test code
diff --git a/src/C/SuiteSparse/COLAMD/colamd.c b/src/C/SuiteSparse/COLAMD/colamd.c
new file mode 100644
index 0000000..abf67e7
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/colamd.c
@@ -0,0 +1,3611 @@
+/* ========================================================================== */
+/* === colamd/symamd - a sparse matrix column ordering algorithm ============ */
+/* ========================================================================== */
+
+/* COLAMD / SYMAMD
+
+    colamd:  an approximate minimum degree column ordering algorithm,
+    	for LU factorization of symmetric or unsymmetric matrices,
+	QR factorization, least squares, interior point methods for
+	linear programming problems, and other related problems.
+
+    symamd:  an approximate minimum degree ordering algorithm for Cholesky
+    	factorization of symmetric matrices.
+
+    Purpose:
+
+	Colamd computes a permutation Q such that the Cholesky factorization of
+	(AQ)'(AQ) has less fill-in and requires fewer floating point operations
+	than A'A.  This also provides a good ordering for sparse partial
+	pivoting methods, P(AQ) = LU, where Q is computed prior to numerical
+	factorization, and P is computed during numerical factorization via
+	conventional partial pivoting with row interchanges.  Colamd is the
+	column ordering method used in SuperLU, part of the ScaLAPACK library.
+	It is also available as built-in function in MATLAB Version 6,
+	available from MathWorks, Inc. (http://www.mathworks.com).  This
+	routine can be used in place of colmmd in MATLAB.
+
+    	Symamd computes a permutation P of a symmetric matrix A such that the
+	Cholesky factorization of PAP' has less fill-in and requires fewer
+	floating point operations than A.  Symamd constructs a matrix M such
+	that M'M has the same nonzero pattern of A, and then orders the columns
+	of M using colmmd.  The column ordering of M is then returned as the
+	row and column ordering P of A. 
+
+    Authors:
+
+	The authors of the code itself are Stefan I. Larimore and Timothy A.
+	Davis (davis at cise.ufl.edu), University of Florida.  The algorithm was
+	developed in collaboration with John Gilbert, Xerox PARC, and Esmond
+	Ng, Oak Ridge National Laboratory.
+
+    Acknowledgements:
+
+	This work was supported by the National Science Foundation, under
+	grants DMS-9504974 and DMS-9803599.
+
+    Copyright and License:
+
+	Copyright (c) 1998-2006, Timothy A. Davis, All Rights Reserved.
+	COLAMD is also available under alternate licenses, contact T. Davis
+	for details.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+	USA
+
+	Permission is hereby granted to use or copy this program under the
+	terms of the GNU LGPL, provided that the Copyright, this License,
+	and the Availability of the original version is retained on all copies.
+	User documentation of any code that uses this code or any modified
+	version of this code must cite the Copyright, this License, the
+	Availability note, and "Used by permission." Permission to modify
+	the code and to distribute modified code is granted, provided the
+	Copyright, this License, and the Availability note are retained,
+	and a notice that the code was modified is included.
+
+    Availability:
+
+	The colamd/symamd library is available at
+
+	    http://www.cise.ufl.edu/research/sparse/colamd/
+
+	This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.c
+	file.  It requires the colamd.h file.  It is required by the colamdmex.c
+	and symamdmex.c files, for the MATLAB interface to colamd and symamd.
+	Appears as ACM Algorithm 836.
+
+    See the ChangeLog file for changes since Version 1.0.
+
+    References:
+
+	T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column
+	minimum degree ordering algorithm, ACM Transactions on Mathematical
+	Software, vol. 30, no. 3., pp. 353-376, 2004.
+
+	T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD,
+	an approximate column minimum degree ordering algorithm, ACM
+	Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
+	2004.
+
+*/
+
+/* ========================================================================== */
+/* === Description of user-callable routines ================================ */
+/* ========================================================================== */
+
+/* COLAMD includes both int and UF_long versions of all its routines.  The
+ * description below is for the int version.  For UF_long, all int arguments
+ * become UF_long.  UF_long is normally defined as long, except for WIN64.
+
+    ----------------------------------------------------------------------------
+    colamd_recommended:
+    ----------------------------------------------------------------------------
+
+	C syntax:
+
+	    #include "colamd.h"
+	    size_t colamd_recommended (int nnz, int n_row, int n_col) ;
+	    size_t colamd_l_recommended (UF_long nnz, UF_long n_row,
+		UF_long n_col) ;
+
+	Purpose:
+
+	    Returns recommended value of Alen for use by colamd.  Returns 0
+	    if any input argument is negative.  The use of this routine
+	    is optional.  Not needed for symamd, which dynamically allocates
+	    its own memory.
+
+	    Note that in v2.4 and earlier, these routines returned int or long.
+	    They now return a value of type size_t.
+
+	Arguments (all input arguments):
+
+	    int nnz ;		Number of nonzeros in the matrix A.  This must
+				be the same value as p [n_col] in the call to
+				colamd - otherwise you will get a wrong value
+				of the recommended memory to use.
+
+	    int n_row ;		Number of rows in the matrix A.
+
+	    int n_col ;		Number of columns in the matrix A.
+
+    ----------------------------------------------------------------------------
+    colamd_set_defaults:
+    ----------------------------------------------------------------------------
+
+	C syntax:
+
+	    #include "colamd.h"
+	    colamd_set_defaults (double knobs [COLAMD_KNOBS]) ;
+	    colamd_l_set_defaults (double knobs [COLAMD_KNOBS]) ;
+
+	Purpose:
+
+	    Sets the default parameters.  The use of this routine is optional.
+
+	Arguments:
+
+	    double knobs [COLAMD_KNOBS] ;	Output only.
+
+		NOTE: the meaning of the dense row/col knobs has changed in v2.4
+
+		knobs [0] and knobs [1] control dense row and col detection:
+
+		Colamd: rows with more than
+		max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n_col))
+		entries are removed prior to ordering.  Columns with more than
+		max (16, knobs [COLAMD_DENSE_COL] * sqrt (MIN (n_row,n_col)))
+		entries are removed prior to
+		ordering, and placed last in the output column ordering. 
+
+		Symamd: uses only knobs [COLAMD_DENSE_ROW], which is knobs [0].
+		Rows and columns with more than
+		max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n))
+		entries are removed prior to ordering, and placed last in the
+		output ordering.
+
+		COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1,
+		respectively, in colamd.h.  Default values of these two knobs
+		are both 10.  Currently, only knobs [0] and knobs [1] are
+		used, but future versions may use more knobs.  If so, they will
+		be properly set to their defaults by the future version of
+		colamd_set_defaults, so that the code that calls colamd will
+		not need to change, assuming that you either use
+		colamd_set_defaults, or pass a (double *) NULL pointer as the
+		knobs array to colamd or symamd.
+
+	    knobs [2]: aggressive absorption
+
+	        knobs [COLAMD_AGGRESSIVE] controls whether or not to do
+	        aggressive absorption during the ordering.  Default is TRUE.
+
+
+    ----------------------------------------------------------------------------
+    colamd:
+    ----------------------------------------------------------------------------
+
+	C syntax:
+
+	    #include "colamd.h"
+	    int colamd (int n_row, int n_col, int Alen, int *A, int *p,
+	    	double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS]) ;
+	    UF_long colamd_l (UF_long n_row, UF_long n_col, UF_long Alen,
+		UF_long *A, UF_long *p, double knobs [COLAMD_KNOBS],
+		UF_long stats [COLAMD_STATS]) ;
+
+	Purpose:
+
+	    Computes a column ordering (Q) of A such that P(AQ)=LU or
+	    (AQ)'AQ=LL' have less fill-in and require fewer floating point
+	    operations than factorizing the unpermuted matrix A or A'A,
+	    respectively.
+	    
+	Returns:
+
+	    TRUE (1) if successful, FALSE (0) otherwise.
+
+	Arguments:
+
+	    int n_row ;		Input argument.
+
+		Number of rows in the matrix A.
+		Restriction:  n_row >= 0.
+		Colamd returns FALSE if n_row is negative.
+
+	    int n_col ;		Input argument.
+
+		Number of columns in the matrix A.
+		Restriction:  n_col >= 0.
+		Colamd returns FALSE if n_col is negative.
+
+	    int Alen ;		Input argument.
+
+		Restriction (see note):
+		Alen >= 2*nnz + 6*(n_col+1) + 4*(n_row+1) + n_col
+		Colamd returns FALSE if these conditions are not met.
+
+		Note:  this restriction makes an modest assumption regarding
+		the size of the two typedef's structures in colamd.h.
+		We do, however, guarantee that
+
+			Alen >= colamd_recommended (nnz, n_row, n_col)
+
+		will be sufficient.  Note: the macro version does not check
+		for integer overflow, and thus is not recommended.  Use
+		the colamd_recommended routine instead.
+
+	    int A [Alen] ;	Input argument, undefined on output.
+
+		A is an integer array of size Alen.  Alen must be at least as
+		large as the bare minimum value given above, but this is very
+		low, and can result in excessive run time.  For best
+		performance, we recommend that Alen be greater than or equal to
+		colamd_recommended (nnz, n_row, n_col), which adds
+		nnz/5 to the bare minimum value given above.
+
+		On input, the row indices of the entries in column c of the
+		matrix are held in A [(p [c]) ... (p [c+1]-1)].  The row indices
+		in a given column c need not be in ascending order, and
+		duplicate row indices may be be present.  However, colamd will
+		work a little faster if both of these conditions are met
+		(Colamd puts the matrix into this format, if it finds that the
+		the conditions are not met).
+
+		The matrix is 0-based.  That is, rows are in the range 0 to
+		n_row-1, and columns are in the range 0 to n_col-1.  Colamd
+		returns FALSE if any row index is out of range.
+
+		The contents of A are modified during ordering, and are
+		undefined on output.
+
+	    int p [n_col+1] ;	Both input and output argument.
+
+		p is an integer array of size n_col+1.  On input, it holds the
+		"pointers" for the column form of the matrix A.  Column c of
+		the matrix A is held in A [(p [c]) ... (p [c+1]-1)].  The first
+		entry, p [0], must be zero, and p [c] <= p [c+1] must hold
+		for all c in the range 0 to n_col-1.  The value p [n_col] is
+		thus the total number of entries in the pattern of the matrix A.
+		Colamd returns FALSE if these conditions are not met.
+
+		On output, if colamd returns TRUE, the array p holds the column
+		permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is
+		the first column index in the new ordering, and p [n_col-1] is
+		the last.  That is, p [k] = j means that column j of A is the
+		kth pivot column, in AQ, where k is in the range 0 to n_col-1
+		(p [0] = j means that column j of A is the first column in AQ).
+
+		If colamd returns FALSE, then no permutation is returned, and
+		p is undefined on output.
+
+	    double knobs [COLAMD_KNOBS] ;	Input argument.
+
+		See colamd_set_defaults for a description.
+
+	    int stats [COLAMD_STATS] ;		Output argument.
+
+		Statistics on the ordering, and error status.
+		See colamd.h for related definitions.
+		Colamd returns FALSE if stats is not present.
+
+		stats [0]:  number of dense or empty rows ignored.
+
+		stats [1]:  number of dense or empty columns ignored (and
+				ordered last in the output permutation p)
+				Note that a row can become "empty" if it
+				contains only "dense" and/or "empty" columns,
+				and similarly a column can become "empty" if it
+				only contains "dense" and/or "empty" rows.
+
+		stats [2]:  number of garbage collections performed.
+				This can be excessively high if Alen is close
+				to the minimum required value.
+
+		stats [3]:  status code.  < 0 is an error code.
+			    > 1 is a warning or notice.
+
+			0	OK.  Each column of the input matrix contained
+				row indices in increasing order, with no
+				duplicates.
+
+			1	OK, but columns of input matrix were jumbled
+				(unsorted columns or duplicate entries).  Colamd
+				had to do some extra work to sort the matrix
+				first and remove duplicate entries, but it
+				still was able to return a valid permutation
+				(return value of colamd was TRUE).
+
+					stats [4]: highest numbered column that
+						is unsorted or has duplicate
+						entries.
+					stats [5]: last seen duplicate or
+						unsorted row index.
+					stats [6]: number of duplicate or
+						unsorted row indices.
+
+			-1	A is a null pointer
+
+			-2	p is a null pointer
+
+			-3 	n_row is negative
+
+					stats [4]: n_row
+
+			-4	n_col is negative
+
+					stats [4]: n_col
+
+			-5	number of nonzeros in matrix is negative
+
+					stats [4]: number of nonzeros, p [n_col]
+
+			-6	p [0] is nonzero
+
+					stats [4]: p [0]
+
+			-7	A is too small
+
+					stats [4]: required size
+					stats [5]: actual size (Alen)
+
+			-8	a column has a negative number of entries
+
+					stats [4]: column with < 0 entries
+					stats [5]: number of entries in col
+
+			-9	a row index is out of bounds
+
+					stats [4]: column with bad row index
+					stats [5]: bad row index
+					stats [6]: n_row, # of rows of matrx
+
+			-10	(unused; see symamd.c)
+
+			-999	(unused; see symamd.c)
+
+		Future versions may return more statistics in the stats array.
+
+	Example:
+	
+	    See http://www.cise.ufl.edu/research/sparse/colamd/example.c
+	    for a complete example.
+
+	    To order the columns of a 5-by-4 matrix with 11 nonzero entries in
+	    the following nonzero pattern
+
+	    	x 0 x 0
+		x 0 x x
+		0 x x 0
+		0 0 x x
+		x x 0 0
+
+	    with default knobs and no output statistics, do the following:
+
+		#include "colamd.h"
+		#define ALEN 100
+		int A [ALEN] = {0, 1, 4, 2, 4, 0, 1, 2, 3, 1, 3} ;
+		int p [ ] = {0, 3, 5, 9, 11} ;
+		int stats [COLAMD_STATS] ;
+		colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ;
+
+	    The permutation is returned in the array p, and A is destroyed.
+
+    ----------------------------------------------------------------------------
+    symamd:
+    ----------------------------------------------------------------------------
+
+	C syntax:
+
+	    #include "colamd.h"
+	    int symamd (int n, int *A, int *p, int *perm,
+	    	double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS],
+		void (*allocate) (size_t, size_t), void (*release) (void *)) ;
+	    UF_long symamd_l (UF_long n, UF_long *A, UF_long *p, UF_long *perm,
+	    	double knobs [COLAMD_KNOBS], UF_long stats [COLAMD_STATS],
+		void (*allocate) (size_t, size_t), void (*release) (void *)) ;
+
+	Purpose:
+
+    	    The symamd routine computes an ordering P of a symmetric sparse
+	    matrix A such that the Cholesky factorization PAP' = LL' remains
+	    sparse.  It is based on a column ordering of a matrix M constructed
+	    so that the nonzero pattern of M'M is the same as A.  The matrix A
+	    is assumed to be symmetric; only the strictly lower triangular part
+	    is accessed.  You must pass your selected memory allocator (usually
+	    calloc/free or mxCalloc/mxFree) to symamd, for it to allocate
+	    memory for the temporary matrix M.
+
+	Returns:
+
+	    TRUE (1) if successful, FALSE (0) otherwise.
+
+	Arguments:
+
+	    int n ;		Input argument.
+
+	    	Number of rows and columns in the symmetrix matrix A.
+		Restriction:  n >= 0.
+		Symamd returns FALSE if n is negative.
+
+	    int A [nnz] ;	Input argument.
+
+	    	A is an integer array of size nnz, where nnz = p [n].
+		
+		The row indices of the entries in column c of the matrix are
+		held in A [(p [c]) ... (p [c+1]-1)].  The row indices in a
+		given column c need not be in ascending order, and duplicate
+		row indices may be present.  However, symamd will run faster
+		if the columns are in sorted order with no duplicate entries. 
+
+		The matrix is 0-based.  That is, rows are in the range 0 to
+		n-1, and columns are in the range 0 to n-1.  Symamd
+		returns FALSE if any row index is out of range.
+
+		The contents of A are not modified.
+
+	    int p [n+1] ;   	Input argument.
+
+		p is an integer array of size n+1.  On input, it holds the
+		"pointers" for the column form of the matrix A.  Column c of
+		the matrix A is held in A [(p [c]) ... (p [c+1]-1)].  The first
+		entry, p [0], must be zero, and p [c] <= p [c+1] must hold
+		for all c in the range 0 to n-1.  The value p [n] is
+		thus the total number of entries in the pattern of the matrix A.
+		Symamd returns FALSE if these conditions are not met.
+
+		The contents of p are not modified.
+
+	    int perm [n+1] ;   	Output argument.
+
+		On output, if symamd returns TRUE, the array perm holds the
+		permutation P, where perm [0] is the first index in the new
+		ordering, and perm [n-1] is the last.  That is, perm [k] = j
+		means that row and column j of A is the kth column in PAP',
+		where k is in the range 0 to n-1 (perm [0] = j means
+		that row and column j of A are the first row and column in
+		PAP').  The array is used as a workspace during the ordering,
+		which is why it must be of length n+1, not just n.
+
+	    double knobs [COLAMD_KNOBS] ;	Input argument.
+
+		See colamd_set_defaults for a description.
+
+	    int stats [COLAMD_STATS] ;		Output argument.
+
+		Statistics on the ordering, and error status.
+		See colamd.h for related definitions.
+		Symamd returns FALSE if stats is not present.
+
+		stats [0]:  number of dense or empty row and columns ignored
+				(and ordered last in the output permutation 
+				perm).  Note that a row/column can become
+				"empty" if it contains only "dense" and/or
+				"empty" columns/rows.
+
+		stats [1]:  (same as stats [0])
+
+		stats [2]:  number of garbage collections performed.
+
+		stats [3]:  status code.  < 0 is an error code.
+			    > 1 is a warning or notice.
+
+			0	OK.  Each column of the input matrix contained
+				row indices in increasing order, with no
+				duplicates.
+
+			1	OK, but columns of input matrix were jumbled
+				(unsorted columns or duplicate entries).  Symamd
+				had to do some extra work to sort the matrix
+				first and remove duplicate entries, but it
+				still was able to return a valid permutation
+				(return value of symamd was TRUE).
+
+					stats [4]: highest numbered column that
+						is unsorted or has duplicate
+						entries.
+					stats [5]: last seen duplicate or
+						unsorted row index.
+					stats [6]: number of duplicate or
+						unsorted row indices.
+
+			-1	A is a null pointer
+
+			-2	p is a null pointer
+
+			-3	(unused, see colamd.c)
+
+			-4 	n is negative
+
+					stats [4]: n
+
+			-5	number of nonzeros in matrix is negative
+
+					stats [4]: # of nonzeros (p [n]).
+
+			-6	p [0] is nonzero
+
+					stats [4]: p [0]
+
+			-7	(unused)
+
+			-8	a column has a negative number of entries
+
+					stats [4]: column with < 0 entries
+					stats [5]: number of entries in col
+
+			-9	a row index is out of bounds
+
+					stats [4]: column with bad row index
+					stats [5]: bad row index
+					stats [6]: n_row, # of rows of matrx
+
+			-10	out of memory (unable to allocate temporary
+				workspace for M or count arrays using the
+				"allocate" routine passed into symamd).
+
+		Future versions may return more statistics in the stats array.
+
+	    void * (*allocate) (size_t, size_t)
+
+	    	A pointer to a function providing memory allocation.  The
+		allocated memory must be returned initialized to zero.  For a
+		C application, this argument should normally be a pointer to
+		calloc.  For a MATLAB mexFunction, the routine mxCalloc is
+		passed instead.
+
+	    void (*release) (size_t, size_t)
+
+	    	A pointer to a function that frees memory allocated by the
+		memory allocation routine above.  For a C application, this
+		argument should normally be a pointer to free.  For a MATLAB
+		mexFunction, the routine mxFree is passed instead.
+
+
+    ----------------------------------------------------------------------------
+    colamd_report:
+    ----------------------------------------------------------------------------
+
+	C syntax:
+
+	    #include "colamd.h"
+	    colamd_report (int stats [COLAMD_STATS]) ;
+	    colamd_l_report (UF_long stats [COLAMD_STATS]) ;
+
+	Purpose:
+
+	    Prints the error status and statistics recorded in the stats
+	    array on the standard error output (for a standard C routine)
+	    or on the MATLAB output (for a mexFunction).
+
+	Arguments:
+
+	    int stats [COLAMD_STATS] ;	Input only.  Statistics from colamd.
+
+
+    ----------------------------------------------------------------------------
+    symamd_report:
+    ----------------------------------------------------------------------------
+
+	C syntax:
+
+	    #include "colamd.h"
+	    symamd_report (int stats [COLAMD_STATS]) ;
+	    symamd_l_report (UF_long stats [COLAMD_STATS]) ;
+
+	Purpose:
+
+	    Prints the error status and statistics recorded in the stats
+	    array on the standard error output (for a standard C routine)
+	    or on the MATLAB output (for a mexFunction).
+
+	Arguments:
+
+	    int stats [COLAMD_STATS] ;	Input only.  Statistics from symamd.
+
+
+*/
+
+/* ========================================================================== */
+/* === Scaffolding code definitions  ======================================== */
+/* ========================================================================== */
+
+/* Ensure that debugging is turned off: */
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+
+/* turn on debugging by uncommenting the following line
+ #undef NDEBUG
+*/
+
+/*
+   Our "scaffolding code" philosophy:  In our opinion, well-written library
+   code should keep its "debugging" code, and just normally have it turned off
+   by the compiler so as not to interfere with performance.  This serves
+   several purposes:
+
+   (1) assertions act as comments to the reader, telling you what the code
+	expects at that point.  All assertions will always be true (unless
+	there really is a bug, of course).
+
+   (2) leaving in the scaffolding code assists anyone who would like to modify
+	the code, or understand the algorithm (by reading the debugging output,
+	one can get a glimpse into what the code is doing).
+
+   (3) (gasp!) for actually finding bugs.  This code has been heavily tested
+	and "should" be fully functional and bug-free ... but you never know...
+
+    The code will become outrageously slow when debugging is
+    enabled.  To control the level of debugging output, set an environment
+    variable D to 0 (little), 1 (some), 2, 3, or 4 (lots).  When debugging,
+    you should see the following message on the standard output:
+
+    	colamd: debug version, D = 1 (THIS WILL BE SLOW!)
+
+    or a similar message for symamd.  If you don't, then debugging has not
+    been enabled.
+
+*/
+
+/* ========================================================================== */
+/* === Include files ======================================================== */
+/* ========================================================================== */
+
+#include "colamd.h"
+#include <limits.h>
+#include <math.h>
+
+#ifdef MATLAB_MEX_FILE
+#include "mex.h"
+#include "matrix.h"
+#endif /* MATLAB_MEX_FILE */
+
+#if !defined (NPRINT) || !defined (NDEBUG)
+#include <stdio.h>
+#endif
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+/* ========================================================================== */
+/* === int or UF_long ======================================================= */
+/* ========================================================================== */
+
+/* define UF_long */
+#include "UFconfig.h"
+
+#ifdef DLONG
+
+#define Int UF_long
+#define ID  UF_long_id
+#define Int_MAX UF_long_max
+
+#define COLAMD_recommended colamd_l_recommended
+#define COLAMD_set_defaults colamd_l_set_defaults
+#define COLAMD_MAIN colamd_l
+#define SYMAMD_MAIN symamd_l
+#define COLAMD_report colamd_l_report
+#define SYMAMD_report symamd_l_report
+
+#else
+
+#define Int int
+#define ID "%d"
+#define Int_MAX INT_MAX
+
+#define COLAMD_recommended colamd_recommended
+#define COLAMD_set_defaults colamd_set_defaults
+#define COLAMD_MAIN colamd
+#define SYMAMD_MAIN symamd
+#define COLAMD_report colamd_report
+#define SYMAMD_report symamd_report
+
+#endif
+
+/* ========================================================================== */
+/* === Row and Column structures ============================================ */
+/* ========================================================================== */
+
+/* User code that makes use of the colamd/symamd routines need not directly */
+/* reference these structures.  They are used only for colamd_recommended. */
+
+typedef struct Colamd_Col_struct
+{
+    Int start ;		/* index for A of first row in this column, or DEAD */
+			/* if column is dead */
+    Int length ;	/* number of rows in this column */
+    union
+    {
+	Int thickness ;	/* number of original columns represented by this */
+			/* col, if the column is alive */
+	Int parent ;	/* parent in parent tree super-column structure, if */
+			/* the column is dead */
+    } shared1 ;
+    union
+    {
+	Int score ;	/* the score used to maintain heap, if col is alive */
+	Int order ;	/* pivot ordering of this column, if col is dead */
+    } shared2 ;
+    union
+    {
+	Int headhash ;	/* head of a hash bucket, if col is at the head of */
+			/* a degree list */
+	Int hash ;	/* hash value, if col is not in a degree list */
+	Int prev ;	/* previous column in degree list, if col is in a */
+			/* degree list (but not at the head of a degree list) */
+    } shared3 ;
+    union
+    {
+	Int degree_next ;	/* next column, if col is in a degree list */
+	Int hash_next ;		/* next column, if col is in a hash list */
+    } shared4 ;
+
+} Colamd_Col ;
+
+typedef struct Colamd_Row_struct
+{
+    Int start ;		/* index for A of first col in this row */
+    Int length ;	/* number of principal columns in this row */
+    union
+    {
+	Int degree ;	/* number of principal & non-principal columns in row */
+	Int p ;		/* used as a row pointer in init_rows_cols () */
+    } shared1 ;
+    union
+    {
+	Int mark ;	/* for computing set differences and marking dead rows*/
+	Int first_column ;/* first column in row (used in garbage collection) */
+    } shared2 ;
+
+} Colamd_Row ;
+
+/* ========================================================================== */
+/* === Definitions ========================================================== */
+/* ========================================================================== */
+
+/* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */
+#define PUBLIC
+#define PRIVATE static
+
+#define DENSE_DEGREE(alpha,n) \
+    ((Int) MAX (16.0, (alpha) * sqrt ((double) (n))))
+
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+#define ONES_COMPLEMENT(r) (-(r)-1)
+
+/* -------------------------------------------------------------------------- */
+/* Change for version 2.1:  define TRUE and FALSE only if not yet defined */  
+/* -------------------------------------------------------------------------- */
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+#define EMPTY	(-1)
+
+/* Row and column status */
+#define ALIVE	(0)
+#define DEAD	(-1)
+
+/* Column status */
+#define DEAD_PRINCIPAL		(-1)
+#define DEAD_NON_PRINCIPAL	(-2)
+
+/* Macros for row and column status update and checking. */
+#define ROW_IS_DEAD(r)			ROW_IS_MARKED_DEAD (Row[r].shared2.mark)
+#define ROW_IS_MARKED_DEAD(row_mark)	(row_mark < ALIVE)
+#define ROW_IS_ALIVE(r)			(Row [r].shared2.mark >= ALIVE)
+#define COL_IS_DEAD(c)			(Col [c].start < ALIVE)
+#define COL_IS_ALIVE(c)			(Col [c].start >= ALIVE)
+#define COL_IS_DEAD_PRINCIPAL(c)	(Col [c].start == DEAD_PRINCIPAL)
+#define KILL_ROW(r)			{ Row [r].shared2.mark = DEAD ; }
+#define KILL_PRINCIPAL_COL(c)		{ Col [c].start = DEAD_PRINCIPAL ; }
+#define KILL_NON_PRINCIPAL_COL(c)	{ Col [c].start = DEAD_NON_PRINCIPAL ; }
+
+/* ========================================================================== */
+/* === Colamd reporting mechanism =========================================== */
+/* ========================================================================== */
+
+#if defined (MATLAB_MEX_FILE) || defined (MATHWORKS)
+/* In MATLAB, matrices are 1-based to the user, but 0-based internally */
+#define INDEX(i) ((i)+1)
+#else
+/* In C, matrices are 0-based and indices are reported as such in *_report */
+#define INDEX(i) (i)
+#endif
+
+/* All output goes through the PRINTF macro.  */
+#define PRINTF(params) { if (colamd_printf != NULL) (void) colamd_printf params ; }
+
+/* ========================================================================== */
+/* === Prototypes of PRIVATE routines ======================================= */
+/* ========================================================================== */
+
+PRIVATE Int init_rows_cols
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int p [],
+    Int stats [COLAMD_STATS]
+) ;
+
+PRIVATE void init_scoring
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int head [],
+    double knobs [COLAMD_KNOBS],
+    Int *p_n_row2,
+    Int *p_n_col2,
+    Int *p_max_deg
+) ;
+
+PRIVATE Int find_ordering
+(
+    Int n_row,
+    Int n_col,
+    Int Alen,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int head [],
+    Int n_col2,
+    Int max_deg,
+    Int pfree,
+    Int aggressive
+) ;
+
+PRIVATE void order_children
+(
+    Int n_col,
+    Colamd_Col Col [],
+    Int p []
+) ;
+
+PRIVATE void detect_super_cols
+(
+
+#ifndef NDEBUG
+    Int n_col,
+    Colamd_Row Row [],
+#endif /* NDEBUG */
+
+    Colamd_Col Col [],
+    Int A [],
+    Int head [],
+    Int row_start,
+    Int row_length
+) ;
+
+PRIVATE Int garbage_collection
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int *pfree
+) ;
+
+PRIVATE Int clear_mark
+(
+    Int tag_mark,
+    Int max_mark,
+    Int n_row,
+    Colamd_Row Row []
+) ;
+
+PRIVATE void print_report
+(
+    char *method,
+    Int stats [COLAMD_STATS]
+) ;
+
+/* ========================================================================== */
+/* === Debugging prototypes and definitions ================================= */
+/* ========================================================================== */
+
+#ifndef NDEBUG
+
+#include <assert.h>
+
+/* colamd_debug is the *ONLY* global variable, and is only */
+/* present when debugging */
+
+PRIVATE Int colamd_debug = 0 ;	/* debug print level */
+
+#define DEBUG0(params) { PRINTF (params) ; }
+#define DEBUG1(params) { if (colamd_debug >= 1) PRINTF (params) ; }
+#define DEBUG2(params) { if (colamd_debug >= 2) PRINTF (params) ; }
+#define DEBUG3(params) { if (colamd_debug >= 3) PRINTF (params) ; }
+#define DEBUG4(params) { if (colamd_debug >= 4) PRINTF (params) ; }
+
+#ifdef MATLAB_MEX_FILE
+#define ASSERT(expression) (mxAssert ((expression), ""))
+#else
+#define ASSERT(expression) (assert (expression))
+#endif /* MATLAB_MEX_FILE */
+
+PRIVATE void colamd_get_debug	/* gets the debug print level from getenv */
+(
+    char *method
+) ;
+
+PRIVATE void debug_deg_lists
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int head [],
+    Int min_score,
+    Int should,
+    Int max_deg
+) ;
+
+PRIVATE void debug_mark
+(
+    Int n_row,
+    Colamd_Row Row [],
+    Int tag_mark,
+    Int max_mark
+) ;
+
+PRIVATE void debug_matrix
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A []
+) ;
+
+PRIVATE void debug_structures
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int n_col2
+) ;
+
+#else /* NDEBUG */
+
+/* === No debugging ========================================================= */
+
+#define DEBUG0(params) ;
+#define DEBUG1(params) ;
+#define DEBUG2(params) ;
+#define DEBUG3(params) ;
+#define DEBUG4(params) ;
+
+#define ASSERT(expression)
+
+#endif /* NDEBUG */
+
+/* ========================================================================== */
+/* === USER-CALLABLE ROUTINES: ============================================== */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* === colamd_recommended =================================================== */
+/* ========================================================================== */
+
+/*
+    The colamd_recommended routine returns the suggested size for Alen.  This
+    value has been determined to provide good balance between the number of
+    garbage collections and the memory requirements for colamd.  If any
+    argument is negative, or if integer overflow occurs, a 0 is returned as an
+    error condition.  2*nnz space is required for the row and column
+    indices of the matrix. COLAMD_C (n_col) + COLAMD_R (n_row) space is
+    required for the Col and Row arrays, respectively, which are internal to
+    colamd (roughly 6*n_col + 4*n_row).  An additional n_col space is the
+    minimal amount of "elbow room", and nnz/5 more space is recommended for
+    run time efficiency.
+
+    Alen is approximately 2.2*nnz + 7*n_col + 4*n_row + 10.
+
+    This function is not needed when using symamd.
+*/
+
+/* add two values of type size_t, and check for integer overflow */
+static size_t t_add (size_t a, size_t b, int *ok)
+{
+    (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ;
+    return ((*ok) ? (a + b) : 0) ;
+}
+
+/* compute a*k where k is a small integer, and check for integer overflow */
+static size_t t_mult (size_t a, size_t k, int *ok)
+{
+    size_t i, s = 0 ;
+    for (i = 0 ; i < k ; i++)
+    {
+	s = t_add (s, a, ok) ;
+    }
+    return (s) ;
+}
+
+/* size of the Col and Row structures */
+#define COLAMD_C(n_col,ok) \
+    ((t_mult (t_add (n_col, 1, ok), sizeof (Colamd_Col), ok) / sizeof (Int)))
+
+#define COLAMD_R(n_row,ok) \
+    ((t_mult (t_add (n_row, 1, ok), sizeof (Colamd_Row), ok) / sizeof (Int)))
+
+
+PUBLIC size_t COLAMD_recommended	/* returns recommended value of Alen. */
+(
+    /* === Parameters ======================================================= */
+
+    Int nnz,			/* number of nonzeros in A */
+    Int n_row,			/* number of rows in A */
+    Int n_col			/* number of columns in A */
+)
+{
+    size_t s, c, r ;
+    int ok = TRUE ;
+    if (nnz < 0 || n_row < 0 || n_col < 0)
+    {
+	return (0) ;
+    }
+    s = t_mult (nnz, 2, &ok) ;	    /* 2*nnz */
+    c = COLAMD_C (n_col, &ok) ;	    /* size of column structures */
+    r = COLAMD_R (n_row, &ok) ;	    /* size of row structures */
+    s = t_add (s, c, &ok) ;
+    s = t_add (s, r, &ok) ;
+    s = t_add (s, n_col, &ok) ;	    /* elbow room */
+    s = t_add (s, nnz/5, &ok) ;	    /* elbow room */
+    ok = ok && (s < Int_MAX) ;
+    return (ok ? s : 0) ;
+}
+
+
+/* ========================================================================== */
+/* === colamd_set_defaults ================================================== */
+/* ========================================================================== */
+
+/*
+    The colamd_set_defaults routine sets the default values of the user-
+    controllable parameters for colamd and symamd:
+
+	Colamd: rows with more than max (16, knobs [0] * sqrt (n_col))
+	entries are removed prior to ordering.  Columns with more than
+	max (16, knobs [1] * sqrt (MIN (n_row,n_col))) entries are removed
+	prior to ordering, and placed last in the output column ordering. 
+
+	Symamd: Rows and columns with more than max (16, knobs [0] * sqrt (n))
+	entries are removed prior to ordering, and placed last in the
+	output ordering.
+
+	knobs [0]	dense row control
+
+	knobs [1]	dense column control
+
+	knobs [2]	if nonzero, do aggresive absorption
+
+	knobs [3..19]	unused, but future versions might use this
+
+*/
+
+PUBLIC void COLAMD_set_defaults
+(
+    /* === Parameters ======================================================= */
+
+    double knobs [COLAMD_KNOBS]		/* knob array */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;
+
+    if (!knobs)
+    {
+	return ;			/* no knobs to initialize */
+    }
+    for (i = 0 ; i < COLAMD_KNOBS ; i++)
+    {
+	knobs [i] = 0 ;
+    }
+    knobs [COLAMD_DENSE_ROW] = 10 ;
+    knobs [COLAMD_DENSE_COL] = 10 ;
+    knobs [COLAMD_AGGRESSIVE] = TRUE ;	/* default: do aggressive absorption*/
+}
+
+
+/* ========================================================================== */
+/* === symamd =============================================================== */
+/* ========================================================================== */
+
+PUBLIC Int SYMAMD_MAIN			/* return TRUE if OK, FALSE otherwise */
+(
+    /* === Parameters ======================================================= */
+
+    Int n,				/* number of rows and columns of A */
+    Int A [],				/* row indices of A */
+    Int p [],				/* column pointers of A */
+    Int perm [],			/* output permutation, size n+1 */
+    double knobs [COLAMD_KNOBS],	/* parameters (uses defaults if NULL) */
+    Int stats [COLAMD_STATS],		/* output statistics and error codes */
+    void * (*allocate) (size_t, size_t),
+    					/* pointer to calloc (ANSI C) or */
+					/* mxCalloc (for MATLAB mexFunction) */
+    void (*release) (void *)
+    					/* pointer to free (ANSI C) or */
+    					/* mxFree (for MATLAB mexFunction) */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int *count ;		/* length of each column of M, and col pointer*/
+    Int *mark ;			/* mark array for finding duplicate entries */
+    Int *M ;			/* row indices of matrix M */
+    size_t Mlen ;		/* length of M */
+    Int n_row ;			/* number of rows in M */
+    Int nnz ;			/* number of entries in A */
+    Int i ;			/* row index of A */
+    Int j ;			/* column index of A */
+    Int k ;			/* row index of M */ 
+    Int mnz ;			/* number of nonzeros in M */
+    Int pp ;			/* index into a column of A */
+    Int last_row ;		/* last row seen in the current column */
+    Int length ;		/* number of nonzeros in a column */
+
+    double cknobs [COLAMD_KNOBS] ;		/* knobs for colamd */
+    double default_knobs [COLAMD_KNOBS] ;	/* default knobs for colamd */
+
+#ifndef NDEBUG
+    colamd_get_debug ("symamd") ;
+#endif /* NDEBUG */
+
+    /* === Check the input arguments ======================================== */
+
+    if (!stats)
+    {
+	DEBUG0 (("symamd: stats not present\n")) ;
+	return (FALSE) ;
+    }
+    for (i = 0 ; i < COLAMD_STATS ; i++)
+    {
+	stats [i] = 0 ;
+    }
+    stats [COLAMD_STATUS] = COLAMD_OK ;
+    stats [COLAMD_INFO1] = -1 ;
+    stats [COLAMD_INFO2] = -1 ;
+
+    if (!A)
+    {
+    	stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
+	DEBUG0 (("symamd: A not present\n")) ;
+	return (FALSE) ;
+    }
+
+    if (!p)		/* p is not present */
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
+	DEBUG0 (("symamd: p not present\n")) ;
+    	return (FALSE) ;
+    }
+
+    if (n < 0)		/* n must be >= 0 */
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
+	stats [COLAMD_INFO1] = n ;
+	DEBUG0 (("symamd: n negative %d\n", n)) ;
+    	return (FALSE) ;
+    }
+
+    nnz = p [n] ;
+    if (nnz < 0)	/* nnz must be >= 0 */
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
+	stats [COLAMD_INFO1] = nnz ;
+	DEBUG0 (("symamd: number of entries negative %d\n", nnz)) ;
+	return (FALSE) ;
+    }
+
+    if (p [0] != 0)
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
+	stats [COLAMD_INFO1] = p [0] ;
+	DEBUG0 (("symamd: p[0] not zero %d\n", p [0])) ;
+	return (FALSE) ;
+    }
+
+    /* === If no knobs, set default knobs =================================== */
+
+    if (!knobs)
+    {
+	COLAMD_set_defaults (default_knobs) ;
+	knobs = default_knobs ;
+    }
+
+    /* === Allocate count and mark ========================================== */
+
+    count = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
+    if (!count)
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
+	DEBUG0 (("symamd: allocate count (size %d) failed\n", n+1)) ;
+	return (FALSE) ;
+    }
+
+    mark = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
+    if (!mark)
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
+	(*release) ((void *) count) ;
+	DEBUG0 (("symamd: allocate mark (size %d) failed\n", n+1)) ;
+	return (FALSE) ;
+    }
+
+    /* === Compute column counts of M, check if A is valid ================== */
+
+    stats [COLAMD_INFO3] = 0 ;  /* number of duplicate or unsorted row indices*/
+
+    for (i = 0 ; i < n ; i++)
+    {
+    	mark [i] = -1 ;
+    }
+
+    for (j = 0 ; j < n ; j++)
+    {
+	last_row = -1 ;
+
+	length = p [j+1] - p [j] ;
+	if (length < 0)
+	{
+	    /* column pointers must be non-decreasing */
+	    stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
+	    stats [COLAMD_INFO1] = j ;
+	    stats [COLAMD_INFO2] = length ;
+	    (*release) ((void *) count) ;
+	    (*release) ((void *) mark) ;
+	    DEBUG0 (("symamd: col %d negative length %d\n", j, length)) ;
+	    return (FALSE) ;
+	}
+
+	for (pp = p [j] ; pp < p [j+1] ; pp++)
+	{
+	    i = A [pp] ;
+	    if (i < 0 || i >= n)
+	    {
+		/* row index i, in column j, is out of bounds */
+		stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
+		stats [COLAMD_INFO1] = j ;
+		stats [COLAMD_INFO2] = i ;
+		stats [COLAMD_INFO3] = n ;
+		(*release) ((void *) count) ;
+		(*release) ((void *) mark) ;
+		DEBUG0 (("symamd: row %d col %d out of bounds\n", i, j)) ;
+		return (FALSE) ;
+	    }
+
+	    if (i <= last_row || mark [i] == j)
+	    {
+		/* row index is unsorted or repeated (or both), thus col */
+		/* is jumbled.  This is a notice, not an error condition. */
+		stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
+		stats [COLAMD_INFO1] = j ;
+		stats [COLAMD_INFO2] = i ;
+		(stats [COLAMD_INFO3]) ++ ;
+		DEBUG1 (("symamd: row %d col %d unsorted/duplicate\n", i, j)) ;
+	    }
+
+	    if (i > j && mark [i] != j)
+	    {
+		/* row k of M will contain column indices i and j */
+		count [i]++ ;
+		count [j]++ ;
+	    }
+
+	    /* mark the row as having been seen in this column */
+	    mark [i] = j ;
+
+	    last_row = i ;
+	}
+    }
+
+    /* v2.4: removed free(mark) */
+
+    /* === Compute column pointers of M ===================================== */
+
+    /* use output permutation, perm, for column pointers of M */
+    perm [0] = 0 ;
+    for (j = 1 ; j <= n ; j++)
+    {
+	perm [j] = perm [j-1] + count [j-1] ;
+    }
+    for (j = 0 ; j < n ; j++)
+    {
+	count [j] = perm [j] ;
+    }
+
+    /* === Construct M ====================================================== */
+
+    mnz = perm [n] ;
+    n_row = mnz / 2 ;
+    Mlen = COLAMD_recommended (mnz, n_row, n) ;
+    M = (Int *) ((*allocate) (Mlen, sizeof (Int))) ;
+    DEBUG0 (("symamd: M is %d-by-%d with %d entries, Mlen = %g\n",
+    	n_row, n, mnz, (double) Mlen)) ;
+
+    if (!M)
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
+	(*release) ((void *) count) ;
+	(*release) ((void *) mark) ;
+	DEBUG0 (("symamd: allocate M (size %g) failed\n", (double) Mlen)) ;
+	return (FALSE) ;
+    }
+
+    k = 0 ;
+
+    if (stats [COLAMD_STATUS] == COLAMD_OK)
+    {
+	/* Matrix is OK */
+	for (j = 0 ; j < n ; j++)
+	{
+	    ASSERT (p [j+1] - p [j] >= 0) ;
+	    for (pp = p [j] ; pp < p [j+1] ; pp++)
+	    {
+		i = A [pp] ;
+		ASSERT (i >= 0 && i < n) ;
+		if (i > j)
+		{
+		    /* row k of M contains column indices i and j */
+		    M [count [i]++] = k ;
+		    M [count [j]++] = k ;
+		    k++ ;
+		}
+	    }
+	}
+    }
+    else
+    {
+	/* Matrix is jumbled.  Do not add duplicates to M.  Unsorted cols OK. */
+	DEBUG0 (("symamd: Duplicates in A.\n")) ;
+	for (i = 0 ; i < n ; i++)
+	{
+	    mark [i] = -1 ;
+	}
+	for (j = 0 ; j < n ; j++)
+	{
+	    ASSERT (p [j+1] - p [j] >= 0) ;
+	    for (pp = p [j] ; pp < p [j+1] ; pp++)
+	    {
+		i = A [pp] ;
+		ASSERT (i >= 0 && i < n) ;
+		if (i > j && mark [i] != j)
+		{
+		    /* row k of M contains column indices i and j */
+		    M [count [i]++] = k ;
+		    M [count [j]++] = k ;
+		    k++ ;
+		    mark [i] = j ;
+		}
+	    }
+	}
+	/* v2.4: free(mark) moved below */
+    }
+
+    /* count and mark no longer needed */
+    (*release) ((void *) count) ;
+    (*release) ((void *) mark) ;	/* v2.4: free (mark) moved here */
+    ASSERT (k == n_row) ;
+
+    /* === Adjust the knobs for M =========================================== */
+
+    for (i = 0 ; i < COLAMD_KNOBS ; i++)
+    {
+	cknobs [i] = knobs [i] ;
+    }
+
+    /* there are no dense rows in M */
+    cknobs [COLAMD_DENSE_ROW] = -1 ;
+    cknobs [COLAMD_DENSE_COL] = knobs [COLAMD_DENSE_ROW] ;
+
+    /* === Order the columns of M =========================================== */
+
+    /* v2.4: colamd cannot fail here, so the error check is removed */
+    (void) COLAMD_MAIN (n_row, n, (Int) Mlen, M, perm, cknobs, stats) ;
+
+    /* Note that the output permutation is now in perm */
+
+    /* === get the statistics for symamd from colamd ======================== */
+
+    /* a dense column in colamd means a dense row and col in symamd */
+    stats [COLAMD_DENSE_ROW] = stats [COLAMD_DENSE_COL] ;
+
+    /* === Free M =========================================================== */
+
+    (*release) ((void *) M) ;
+    DEBUG0 (("symamd: done.\n")) ;
+    return (TRUE) ;
+
+}
+
+/* ========================================================================== */
+/* === colamd =============================================================== */
+/* ========================================================================== */
+
+/*
+    The colamd routine computes a column ordering Q of a sparse matrix
+    A such that the LU factorization P(AQ) = LU remains sparse, where P is
+    selected via partial pivoting.   The routine can also be viewed as
+    providing a permutation Q such that the Cholesky factorization
+    (AQ)'(AQ) = LL' remains sparse.
+*/
+
+PUBLIC Int COLAMD_MAIN		/* returns TRUE if successful, FALSE otherwise*/
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,			/* number of rows in A */
+    Int n_col,			/* number of columns in A */
+    Int Alen,			/* length of A */
+    Int A [],			/* row indices of A */
+    Int p [],			/* pointers to columns in A */
+    double knobs [COLAMD_KNOBS],/* parameters (uses defaults if NULL) */
+    Int stats [COLAMD_STATS]	/* output statistics and error codes */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;			/* loop index */
+    Int nnz ;			/* nonzeros in A */
+    size_t Row_size ;		/* size of Row [], in integers */
+    size_t Col_size ;		/* size of Col [], in integers */
+    size_t need ;		/* minimum required length of A */
+    Colamd_Row *Row ;		/* pointer into A of Row [0..n_row] array */
+    Colamd_Col *Col ;		/* pointer into A of Col [0..n_col] array */
+    Int n_col2 ;		/* number of non-dense, non-empty columns */
+    Int n_row2 ;		/* number of non-dense, non-empty rows */
+    Int ngarbage ;		/* number of garbage collections performed */
+    Int max_deg ;		/* maximum row degree */
+    double default_knobs [COLAMD_KNOBS] ;	/* default knobs array */
+    Int aggressive ;		/* do aggressive absorption */
+    int ok ;
+
+#ifndef NDEBUG
+    colamd_get_debug ("colamd") ;
+#endif /* NDEBUG */
+
+    /* === Check the input arguments ======================================== */
+
+    if (!stats)
+    {
+	DEBUG0 (("colamd: stats not present\n")) ;
+	return (FALSE) ;
+    }
+    for (i = 0 ; i < COLAMD_STATS ; i++)
+    {
+	stats [i] = 0 ;
+    }
+    stats [COLAMD_STATUS] = COLAMD_OK ;
+    stats [COLAMD_INFO1] = -1 ;
+    stats [COLAMD_INFO2] = -1 ;
+
+    if (!A)		/* A is not present */
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
+	DEBUG0 (("colamd: A not present\n")) ;
+	return (FALSE) ;
+    }
+
+    if (!p)		/* p is not present */
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
+	DEBUG0 (("colamd: p not present\n")) ;
+    	return (FALSE) ;
+    }
+
+    if (n_row < 0)	/* n_row must be >= 0 */
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ;
+	stats [COLAMD_INFO1] = n_row ;
+	DEBUG0 (("colamd: nrow negative %d\n", n_row)) ;
+    	return (FALSE) ;
+    }
+
+    if (n_col < 0)	/* n_col must be >= 0 */
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
+	stats [COLAMD_INFO1] = n_col ;
+	DEBUG0 (("colamd: ncol negative %d\n", n_col)) ;
+    	return (FALSE) ;
+    }
+
+    nnz = p [n_col] ;
+    if (nnz < 0)	/* nnz must be >= 0 */
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
+	stats [COLAMD_INFO1] = nnz ;
+	DEBUG0 (("colamd: number of entries negative %d\n", nnz)) ;
+	return (FALSE) ;
+    }
+
+    if (p [0] != 0)
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero	;
+	stats [COLAMD_INFO1] = p [0] ;
+	DEBUG0 (("colamd: p[0] not zero %d\n", p [0])) ;
+	return (FALSE) ;
+    }
+
+    /* === If no knobs, set default knobs =================================== */
+
+    if (!knobs)
+    {
+	COLAMD_set_defaults (default_knobs) ;
+	knobs = default_knobs ;
+    }
+
+    aggressive = (knobs [COLAMD_AGGRESSIVE] != FALSE) ;
+
+    /* === Allocate the Row and Col arrays from array A ===================== */
+
+    ok = TRUE ;
+    Col_size = COLAMD_C (n_col, &ok) ;	    /* size of Col array of structs */
+    Row_size = COLAMD_R (n_row, &ok) ;	    /* size of Row array of structs */
+
+    /* need = 2*nnz + n_col + Col_size + Row_size ; */
+    need = t_mult (nnz, 2, &ok) ;
+    need = t_add (need, n_col, &ok) ;
+    need = t_add (need, Col_size, &ok) ;
+    need = t_add (need, Row_size, &ok) ;
+
+    if (!ok || need > (size_t) Alen || need > Int_MAX)
+    {
+	/* not enough space in array A to perform the ordering */
+	stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ;
+	stats [COLAMD_INFO1] = need ;
+	stats [COLAMD_INFO2] = Alen ;
+	DEBUG0 (("colamd: Need Alen >= %d, given only Alen = %d\n", need,Alen));
+	return (FALSE) ;
+    }
+
+    Alen -= Col_size + Row_size ;
+    Col = (Colamd_Col *) &A [Alen] ;
+    Row = (Colamd_Row *) &A [Alen + Col_size] ;
+
+    /* === Construct the row and column data structures ===================== */
+
+    if (!init_rows_cols (n_row, n_col, Row, Col, A, p, stats))
+    {
+	/* input matrix is invalid */
+	DEBUG0 (("colamd: Matrix invalid\n")) ;
+	return (FALSE) ;
+    }
+
+    /* === Initialize scores, kill dense rows/columns ======================= */
+
+    init_scoring (n_row, n_col, Row, Col, A, p, knobs,
+	&n_row2, &n_col2, &max_deg) ;
+
+    /* === Order the supercolumns =========================================== */
+
+    ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p,
+	n_col2, max_deg, 2*nnz, aggressive) ;
+
+    /* === Order the non-principal columns ================================== */
+
+    order_children (n_col, Col, p) ;
+
+    /* === Return statistics in stats ======================================= */
+
+    stats [COLAMD_DENSE_ROW] = n_row - n_row2 ;
+    stats [COLAMD_DENSE_COL] = n_col - n_col2 ;
+    stats [COLAMD_DEFRAG_COUNT] = ngarbage ;
+    DEBUG0 (("colamd: done.\n")) ; 
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === colamd_report ======================================================== */
+/* ========================================================================== */
+
+PUBLIC void COLAMD_report
+(
+    Int stats [COLAMD_STATS]
+)
+{
+    print_report ("colamd", stats) ;
+}
+
+
+/* ========================================================================== */
+/* === symamd_report ======================================================== */
+/* ========================================================================== */
+
+PUBLIC void SYMAMD_report
+(
+    Int stats [COLAMD_STATS]
+)
+{
+    print_report ("symamd", stats) ;
+}
+
+
+
+/* ========================================================================== */
+/* === NON-USER-CALLABLE ROUTINES: ========================================== */
+/* ========================================================================== */
+
+/* There are no user-callable routines beyond this point in the file */
+
+
+/* ========================================================================== */
+/* === init_rows_cols ======================================================= */
+/* ========================================================================== */
+
+/*
+    Takes the column form of the matrix in A and creates the row form of the
+    matrix.  Also, row and column attributes are stored in the Col and Row
+    structs.  If the columns are un-sorted or contain duplicate row indices,
+    this routine will also sort and remove duplicate row indices from the
+    column form of the matrix.  Returns FALSE if the matrix is invalid,
+    TRUE otherwise.  Not user-callable.
+*/
+
+PRIVATE Int init_rows_cols	/* returns TRUE if OK, or FALSE otherwise */
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,			/* number of rows of A */
+    Int n_col,			/* number of columns of A */
+    Colamd_Row Row [],		/* of size n_row+1 */
+    Colamd_Col Col [],		/* of size n_col+1 */
+    Int A [],			/* row indices of A, of size Alen */
+    Int p [],			/* pointers to columns in A, of size n_col+1 */
+    Int stats [COLAMD_STATS]	/* colamd statistics */ 
+)
+{
+    /* === Local variables ================================================== */
+
+    Int col ;			/* a column index */
+    Int row ;			/* a row index */
+    Int *cp ;			/* a column pointer */
+    Int *cp_end ;		/* a pointer to the end of a column */
+    Int *rp ;			/* a row pointer */
+    Int *rp_end ;		/* a pointer to the end of a row */
+    Int last_row ;		/* previous row */
+
+    /* === Initialize columns, and check column pointers ==================== */
+
+    for (col = 0 ; col < n_col ; col++)
+    {
+	Col [col].start = p [col] ;
+	Col [col].length = p [col+1] - p [col] ;
+
+	if (Col [col].length < 0)
+	{
+	    /* column pointers must be non-decreasing */
+	    stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
+	    stats [COLAMD_INFO1] = col ;
+	    stats [COLAMD_INFO2] = Col [col].length ;
+	    DEBUG0 (("colamd: col %d length %d < 0\n", col, Col [col].length)) ;
+	    return (FALSE) ;
+	}
+
+	Col [col].shared1.thickness = 1 ;
+	Col [col].shared2.score = 0 ;
+	Col [col].shared3.prev = EMPTY ;
+	Col [col].shared4.degree_next = EMPTY ;
+    }
+
+    /* p [0..n_col] no longer needed, used as "head" in subsequent routines */
+
+    /* === Scan columns, compute row degrees, and check row indices ========= */
+
+    stats [COLAMD_INFO3] = 0 ;	/* number of duplicate or unsorted row indices*/
+
+    for (row = 0 ; row < n_row ; row++)
+    {
+	Row [row].length = 0 ;
+	Row [row].shared2.mark = -1 ;
+    }
+
+    for (col = 0 ; col < n_col ; col++)
+    {
+	last_row = -1 ;
+
+	cp = &A [p [col]] ;
+	cp_end = &A [p [col+1]] ;
+
+	while (cp < cp_end)
+	{
+	    row = *cp++ ;
+
+	    /* make sure row indices within range */
+	    if (row < 0 || row >= n_row)
+	    {
+		stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
+		stats [COLAMD_INFO1] = col ;
+		stats [COLAMD_INFO2] = row ;
+		stats [COLAMD_INFO3] = n_row ;
+		DEBUG0 (("colamd: row %d col %d out of bounds\n", row, col)) ;
+		return (FALSE) ;
+	    }
+
+	    if (row <= last_row || Row [row].shared2.mark == col)
+	    {
+		/* row index are unsorted or repeated (or both), thus col */
+		/* is jumbled.  This is a notice, not an error condition. */
+		stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
+		stats [COLAMD_INFO1] = col ;
+		stats [COLAMD_INFO2] = row ;
+		(stats [COLAMD_INFO3]) ++ ;
+		DEBUG1 (("colamd: row %d col %d unsorted/duplicate\n",row,col));
+	    }
+
+	    if (Row [row].shared2.mark != col)
+	    {
+		Row [row].length++ ;
+	    }
+	    else
+	    {
+		/* this is a repeated entry in the column, */
+		/* it will be removed */
+		Col [col].length-- ;
+	    }
+
+	    /* mark the row as having been seen in this column */
+	    Row [row].shared2.mark = col ;
+
+	    last_row = row ;
+	}
+    }
+
+    /* === Compute row pointers ============================================= */
+
+    /* row form of the matrix starts directly after the column */
+    /* form of matrix in A */
+    Row [0].start = p [n_col] ;
+    Row [0].shared1.p = Row [0].start ;
+    Row [0].shared2.mark = -1 ;
+    for (row = 1 ; row < n_row ; row++)
+    {
+	Row [row].start = Row [row-1].start + Row [row-1].length ;
+	Row [row].shared1.p = Row [row].start ;
+	Row [row].shared2.mark = -1 ;
+    }
+
+    /* === Create row form ================================================== */
+
+    if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
+    {
+	/* if cols jumbled, watch for repeated row indices */
+	for (col = 0 ; col < n_col ; col++)
+	{
+	    cp = &A [p [col]] ;
+	    cp_end = &A [p [col+1]] ;
+	    while (cp < cp_end)
+	    {
+		row = *cp++ ;
+		if (Row [row].shared2.mark != col)
+		{
+		    A [(Row [row].shared1.p)++] = col ;
+		    Row [row].shared2.mark = col ;
+		}
+	    }
+	}
+    }
+    else
+    {
+	/* if cols not jumbled, we don't need the mark (this is faster) */
+	for (col = 0 ; col < n_col ; col++)
+	{
+	    cp = &A [p [col]] ;
+	    cp_end = &A [p [col+1]] ;
+	    while (cp < cp_end)
+	    {
+		A [(Row [*cp++].shared1.p)++] = col ;
+	    }
+	}
+    }
+
+    /* === Clear the row marks and set row degrees ========================== */
+
+    for (row = 0 ; row < n_row ; row++)
+    {
+	Row [row].shared2.mark = 0 ;
+	Row [row].shared1.degree = Row [row].length ;
+    }
+
+    /* === See if we need to re-create columns ============================== */
+
+    if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
+    {
+    	DEBUG0 (("colamd: reconstructing column form, matrix jumbled\n")) ;
+
+#ifndef NDEBUG
+	/* make sure column lengths are correct */
+	for (col = 0 ; col < n_col ; col++)
+	{
+	    p [col] = Col [col].length ;
+	}
+	for (row = 0 ; row < n_row ; row++)
+	{
+	    rp = &A [Row [row].start] ;
+	    rp_end = rp + Row [row].length ;
+	    while (rp < rp_end)
+	    {
+		p [*rp++]-- ;
+	    }
+	}
+	for (col = 0 ; col < n_col ; col++)
+	{
+	    ASSERT (p [col] == 0) ;
+	}
+	/* now p is all zero (different than when debugging is turned off) */
+#endif /* NDEBUG */
+
+	/* === Compute col pointers ========================================= */
+
+	/* col form of the matrix starts at A [0]. */
+	/* Note, we may have a gap between the col form and the row */
+	/* form if there were duplicate entries, if so, it will be */
+	/* removed upon the first garbage collection */
+	Col [0].start = 0 ;
+	p [0] = Col [0].start ;
+	for (col = 1 ; col < n_col ; col++)
+	{
+	    /* note that the lengths here are for pruned columns, i.e. */
+	    /* no duplicate row indices will exist for these columns */
+	    Col [col].start = Col [col-1].start + Col [col-1].length ;
+	    p [col] = Col [col].start ;
+	}
+
+	/* === Re-create col form =========================================== */
+
+	for (row = 0 ; row < n_row ; row++)
+	{
+	    rp = &A [Row [row].start] ;
+	    rp_end = rp + Row [row].length ;
+	    while (rp < rp_end)
+	    {
+		A [(p [*rp++])++] = row ;
+	    }
+	}
+    }
+
+    /* === Done.  Matrix is not (or no longer) jumbled ====================== */
+
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === init_scoring ========================================================= */
+/* ========================================================================== */
+
+/*
+    Kills dense or empty columns and rows, calculates an initial score for
+    each column, and places all columns in the degree lists.  Not user-callable.
+*/
+
+PRIVATE void init_scoring
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,			/* number of rows of A */
+    Int n_col,			/* number of columns of A */
+    Colamd_Row Row [],		/* of size n_row+1 */
+    Colamd_Col Col [],		/* of size n_col+1 */
+    Int A [],			/* column form and row form of A */
+    Int head [],		/* of size n_col+1 */
+    double knobs [COLAMD_KNOBS],/* parameters */
+    Int *p_n_row2,		/* number of non-dense, non-empty rows */
+    Int *p_n_col2,		/* number of non-dense, non-empty columns */
+    Int *p_max_deg		/* maximum row degree */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int c ;			/* a column index */
+    Int r, row ;		/* a row index */
+    Int *cp ;			/* a column pointer */
+    Int deg ;			/* degree of a row or column */
+    Int *cp_end ;		/* a pointer to the end of a column */
+    Int *new_cp ;		/* new column pointer */
+    Int col_length ;		/* length of pruned column */
+    Int score ;			/* current column score */
+    Int n_col2 ;		/* number of non-dense, non-empty columns */
+    Int n_row2 ;		/* number of non-dense, non-empty rows */
+    Int dense_row_count ;	/* remove rows with more entries than this */
+    Int dense_col_count ;	/* remove cols with more entries than this */
+    Int min_score ;		/* smallest column score */
+    Int max_deg ;		/* maximum row degree */
+    Int next_col ;		/* Used to add to degree list.*/
+
+#ifndef NDEBUG
+    Int debug_count ;		/* debug only. */
+#endif /* NDEBUG */
+
+    /* === Extract knobs ==================================================== */
+
+    /* Note: if knobs contains a NaN, this is undefined: */
+    if (knobs [COLAMD_DENSE_ROW] < 0)
+    {
+	/* only remove completely dense rows */
+	dense_row_count = n_col-1 ;
+    }
+    else
+    {
+	dense_row_count = DENSE_DEGREE (knobs [COLAMD_DENSE_ROW], n_col) ;
+    }
+    if (knobs [COLAMD_DENSE_COL] < 0)
+    {
+	/* only remove completely dense columns */
+	dense_col_count = n_row-1 ;
+    }
+    else
+    {
+	dense_col_count =
+	    DENSE_DEGREE (knobs [COLAMD_DENSE_COL], MIN (n_row, n_col)) ;
+    }
+
+    DEBUG1 (("colamd: densecount: %d %d\n", dense_row_count, dense_col_count)) ;
+    max_deg = 0 ;
+    n_col2 = n_col ;
+    n_row2 = n_row ;
+
+    /* === Kill empty columns =============================================== */
+
+    /* Put the empty columns at the end in their natural order, so that LU */
+    /* factorization can proceed as far as possible. */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+	deg = Col [c].length ;
+	if (deg == 0)
+	{
+	    /* this is a empty column, kill and order it last */
+	    Col [c].shared2.order = --n_col2 ;
+	    KILL_PRINCIPAL_COL (c) ;
+	}
+    }
+    DEBUG1 (("colamd: null columns killed: %d\n", n_col - n_col2)) ;
+
+    /* === Kill dense columns =============================================== */
+
+    /* Put the dense columns at the end, in their natural order */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+	/* skip any dead columns */
+	if (COL_IS_DEAD (c))
+	{
+	    continue ;
+	}
+	deg = Col [c].length ;
+	if (deg > dense_col_count)
+	{
+	    /* this is a dense column, kill and order it last */
+	    Col [c].shared2.order = --n_col2 ;
+	    /* decrement the row degrees */
+	    cp = &A [Col [c].start] ;
+	    cp_end = cp + Col [c].length ;
+	    while (cp < cp_end)
+	    {
+		Row [*cp++].shared1.degree-- ;
+	    }
+	    KILL_PRINCIPAL_COL (c) ;
+	}
+    }
+    DEBUG1 (("colamd: Dense and null columns killed: %d\n", n_col - n_col2)) ;
+
+    /* === Kill dense and empty rows ======================================== */
+
+    for (r = 0 ; r < n_row ; r++)
+    {
+	deg = Row [r].shared1.degree ;
+	ASSERT (deg >= 0 && deg <= n_col) ;
+	if (deg > dense_row_count || deg == 0)
+	{
+	    /* kill a dense or empty row */
+	    KILL_ROW (r) ;
+	    --n_row2 ;
+	}
+	else
+	{
+	    /* keep track of max degree of remaining rows */
+	    max_deg = MAX (max_deg, deg) ;
+	}
+    }
+    DEBUG1 (("colamd: Dense and null rows killed: %d\n", n_row - n_row2)) ;
+
+    /* === Compute initial column scores ==================================== */
+
+    /* At this point the row degrees are accurate.  They reflect the number */
+    /* of "live" (non-dense) columns in each row.  No empty rows exist. */
+    /* Some "live" columns may contain only dead rows, however.  These are */
+    /* pruned in the code below. */
+
+    /* now find the initial matlab score for each column */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+	/* skip dead column */
+	if (COL_IS_DEAD (c))
+	{
+	    continue ;
+	}
+	score = 0 ;
+	cp = &A [Col [c].start] ;
+	new_cp = cp ;
+	cp_end = cp + Col [c].length ;
+	while (cp < cp_end)
+	{
+	    /* get a row */
+	    row = *cp++ ;
+	    /* skip if dead */
+	    if (ROW_IS_DEAD (row))
+	    {
+		continue ;
+	    }
+	    /* compact the column */
+	    *new_cp++ = row ;
+	    /* add row's external degree */
+	    score += Row [row].shared1.degree - 1 ;
+	    /* guard against integer overflow */
+	    score = MIN (score, n_col) ;
+	}
+	/* determine pruned column length */
+	col_length = (Int) (new_cp - &A [Col [c].start]) ;
+	if (col_length == 0)
+	{
+	    /* a newly-made null column (all rows in this col are "dense" */
+	    /* and have already been killed) */
+	    DEBUG2 (("Newly null killed: %d\n", c)) ;
+	    Col [c].shared2.order = --n_col2 ;
+	    KILL_PRINCIPAL_COL (c) ;
+	}
+	else
+	{
+	    /* set column length and set score */
+	    ASSERT (score >= 0) ;
+	    ASSERT (score <= n_col) ;
+	    Col [c].length = col_length ;
+	    Col [c].shared2.score = score ;
+	}
+    }
+    DEBUG1 (("colamd: Dense, null, and newly-null columns killed: %d\n",
+    	n_col-n_col2)) ;
+
+    /* At this point, all empty rows and columns are dead.  All live columns */
+    /* are "clean" (containing no dead rows) and simplicial (no supercolumns */
+    /* yet).  Rows may contain dead columns, but all live rows contain at */
+    /* least one live column. */
+
+#ifndef NDEBUG
+    debug_structures (n_row, n_col, Row, Col, A, n_col2) ;
+#endif /* NDEBUG */
+
+    /* === Initialize degree lists ========================================== */
+
+#ifndef NDEBUG
+    debug_count = 0 ;
+#endif /* NDEBUG */
+
+    /* clear the hash buckets */
+    for (c = 0 ; c <= n_col ; c++)
+    {
+	head [c] = EMPTY ;
+    }
+    min_score = n_col ;
+    /* place in reverse order, so low column indices are at the front */
+    /* of the lists.  This is to encourage natural tie-breaking */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+	/* only add principal columns to degree lists */
+	if (COL_IS_ALIVE (c))
+	{
+	    DEBUG4 (("place %d score %d minscore %d ncol %d\n",
+		c, Col [c].shared2.score, min_score, n_col)) ;
+
+	    /* === Add columns score to DList =============================== */
+
+	    score = Col [c].shared2.score ;
+
+	    ASSERT (min_score >= 0) ;
+	    ASSERT (min_score <= n_col) ;
+	    ASSERT (score >= 0) ;
+	    ASSERT (score <= n_col) ;
+	    ASSERT (head [score] >= EMPTY) ;
+
+	    /* now add this column to dList at proper score location */
+	    next_col = head [score] ;
+	    Col [c].shared3.prev = EMPTY ;
+	    Col [c].shared4.degree_next = next_col ;
+
+	    /* if there already was a column with the same score, set its */
+	    /* previous pointer to this new column */
+	    if (next_col != EMPTY)
+	    {
+		Col [next_col].shared3.prev = c ;
+	    }
+	    head [score] = c ;
+
+	    /* see if this score is less than current min */
+	    min_score = MIN (min_score, score) ;
+
+#ifndef NDEBUG
+	    debug_count++ ;
+#endif /* NDEBUG */
+
+	}
+    }
+
+#ifndef NDEBUG
+    DEBUG1 (("colamd: Live cols %d out of %d, non-princ: %d\n",
+	debug_count, n_col, n_col-debug_count)) ;
+    ASSERT (debug_count == n_col2) ;
+    debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ;
+#endif /* NDEBUG */
+
+    /* === Return number of remaining columns, and max row degree =========== */
+
+    *p_n_col2 = n_col2 ;
+    *p_n_row2 = n_row2 ;
+    *p_max_deg = max_deg ;
+}
+
+
+/* ========================================================================== */
+/* === find_ordering ======================================================== */
+/* ========================================================================== */
+
+/*
+    Order the principal columns of the supercolumn form of the matrix
+    (no supercolumns on input).  Uses a minimum approximate column minimum
+    degree ordering method.  Not user-callable.
+*/
+
+PRIVATE Int find_ordering	/* return the number of garbage collections */
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,			/* number of rows of A */
+    Int n_col,			/* number of columns of A */
+    Int Alen,			/* size of A, 2*nnz + n_col or larger */
+    Colamd_Row Row [],		/* of size n_row+1 */
+    Colamd_Col Col [],		/* of size n_col+1 */
+    Int A [],			/* column form and row form of A */
+    Int head [],		/* of size n_col+1 */
+    Int n_col2,			/* Remaining columns to order */
+    Int max_deg,		/* Maximum row degree */
+    Int pfree,			/* index of first free slot (2*nnz on entry) */
+    Int aggressive
+)
+{
+    /* === Local variables ================================================== */
+
+    Int k ;			/* current pivot ordering step */
+    Int pivot_col ;		/* current pivot column */
+    Int *cp ;			/* a column pointer */
+    Int *rp ;			/* a row pointer */
+    Int pivot_row ;		/* current pivot row */
+    Int *new_cp ;		/* modified column pointer */
+    Int *new_rp ;		/* modified row pointer */
+    Int pivot_row_start ;	/* pointer to start of pivot row */
+    Int pivot_row_degree ;	/* number of columns in pivot row */
+    Int pivot_row_length ;	/* number of supercolumns in pivot row */
+    Int pivot_col_score ;	/* score of pivot column */
+    Int needed_memory ;		/* free space needed for pivot row */
+    Int *cp_end ;		/* pointer to the end of a column */
+    Int *rp_end ;		/* pointer to the end of a row */
+    Int row ;			/* a row index */
+    Int col ;			/* a column index */
+    Int max_score ;		/* maximum possible score */
+    Int cur_score ;		/* score of current column */
+    unsigned Int hash ;		/* hash value for supernode detection */
+    Int head_column ;		/* head of hash bucket */
+    Int first_col ;		/* first column in hash bucket */
+    Int tag_mark ;		/* marker value for mark array */
+    Int row_mark ;		/* Row [row].shared2.mark */
+    Int set_difference ;	/* set difference size of row with pivot row */
+    Int min_score ;		/* smallest column score */
+    Int col_thickness ;		/* "thickness" (no. of columns in a supercol) */
+    Int max_mark ;		/* maximum value of tag_mark */
+    Int pivot_col_thickness ;	/* number of columns represented by pivot col */
+    Int prev_col ;		/* Used by Dlist operations. */
+    Int next_col ;		/* Used by Dlist operations. */
+    Int ngarbage ;		/* number of garbage collections performed */
+
+#ifndef NDEBUG
+    Int debug_d ;		/* debug loop counter */
+    Int debug_step = 0 ;	/* debug loop counter */
+#endif /* NDEBUG */
+
+    /* === Initialization and clear mark ==================================== */
+
+    max_mark = INT_MAX - n_col ;	/* INT_MAX defined in <limits.h> */
+    tag_mark = clear_mark (0, max_mark, n_row, Row) ;
+    min_score = 0 ;
+    ngarbage = 0 ;
+    DEBUG1 (("colamd: Ordering, n_col2=%d\n", n_col2)) ;
+
+    /* === Order the columns ================================================ */
+
+    for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */)
+    {
+
+#ifndef NDEBUG
+	if (debug_step % 100 == 0)
+	{
+	    DEBUG2 (("\n...       Step k: %d out of n_col2: %d\n", k, n_col2)) ;
+	}
+	else
+	{
+	    DEBUG3 (("\n----------Step k: %d out of n_col2: %d\n", k, n_col2)) ;
+	}
+	debug_step++ ;
+	debug_deg_lists (n_row, n_col, Row, Col, head,
+		min_score, n_col2-k, max_deg) ;
+	debug_matrix (n_row, n_col, Row, Col, A) ;
+#endif /* NDEBUG */
+
+	/* === Select pivot column, and order it ============================ */
+
+	/* make sure degree list isn't empty */
+	ASSERT (min_score >= 0) ;
+	ASSERT (min_score <= n_col) ;
+	ASSERT (head [min_score] >= EMPTY) ;
+
+#ifndef NDEBUG
+	for (debug_d = 0 ; debug_d < min_score ; debug_d++)
+	{
+	    ASSERT (head [debug_d] == EMPTY) ;
+	}
+#endif /* NDEBUG */
+
+	/* get pivot column from head of minimum degree list */
+	while (head [min_score] == EMPTY && min_score < n_col)
+	{
+	    min_score++ ;
+	}
+	pivot_col = head [min_score] ;
+	ASSERT (pivot_col >= 0 && pivot_col <= n_col) ;
+	next_col = Col [pivot_col].shared4.degree_next ;
+	head [min_score] = next_col ;
+	if (next_col != EMPTY)
+	{
+	    Col [next_col].shared3.prev = EMPTY ;
+	}
+
+	ASSERT (COL_IS_ALIVE (pivot_col)) ;
+
+	/* remember score for defrag check */
+	pivot_col_score = Col [pivot_col].shared2.score ;
+
+	/* the pivot column is the kth column in the pivot order */
+	Col [pivot_col].shared2.order = k ;
+
+	/* increment order count by column thickness */
+	pivot_col_thickness = Col [pivot_col].shared1.thickness ;
+	k += pivot_col_thickness ;
+	ASSERT (pivot_col_thickness > 0) ;
+	DEBUG3 (("Pivot col: %d thick %d\n", pivot_col, pivot_col_thickness)) ;
+
+	/* === Garbage_collection, if necessary ============================= */
+
+	needed_memory = MIN (pivot_col_score, n_col - k) ;
+	if (pfree + needed_memory >= Alen)
+	{
+	    pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ;
+	    ngarbage++ ;
+	    /* after garbage collection we will have enough */
+	    ASSERT (pfree + needed_memory < Alen) ;
+	    /* garbage collection has wiped out the Row[].shared2.mark array */
+	    tag_mark = clear_mark (0, max_mark, n_row, Row) ;
+
+#ifndef NDEBUG
+	    debug_matrix (n_row, n_col, Row, Col, A) ;
+#endif /* NDEBUG */
+	}
+
+	/* === Compute pivot row pattern ==================================== */
+
+	/* get starting location for this new merged row */
+	pivot_row_start = pfree ;
+
+	/* initialize new row counts to zero */
+	pivot_row_degree = 0 ;
+
+	/* tag pivot column as having been visited so it isn't included */
+	/* in merged pivot row */
+	Col [pivot_col].shared1.thickness = -pivot_col_thickness ;
+
+	/* pivot row is the union of all rows in the pivot column pattern */
+	cp = &A [Col [pivot_col].start] ;
+	cp_end = cp + Col [pivot_col].length ;
+	while (cp < cp_end)
+	{
+	    /* get a row */
+	    row = *cp++ ;
+	    DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ;
+	    /* skip if row is dead */
+	    if (ROW_IS_ALIVE (row))
+	    {
+		rp = &A [Row [row].start] ;
+		rp_end = rp + Row [row].length ;
+		while (rp < rp_end)
+		{
+		    /* get a column */
+		    col = *rp++ ;
+		    /* add the column, if alive and untagged */
+		    col_thickness = Col [col].shared1.thickness ;
+		    if (col_thickness > 0 && COL_IS_ALIVE (col))
+		    {
+			/* tag column in pivot row */
+			Col [col].shared1.thickness = -col_thickness ;
+			ASSERT (pfree < Alen) ;
+			/* place column in pivot row */
+			A [pfree++] = col ;
+			pivot_row_degree += col_thickness ;
+		    }
+		}
+	    }
+	}
+
+	/* clear tag on pivot column */
+	Col [pivot_col].shared1.thickness = pivot_col_thickness ;
+	max_deg = MAX (max_deg, pivot_row_degree) ;
+
+#ifndef NDEBUG
+	DEBUG3 (("check2\n")) ;
+	debug_mark (n_row, Row, tag_mark, max_mark) ;
+#endif /* NDEBUG */
+
+	/* === Kill all rows used to construct pivot row ==================== */
+
+	/* also kill pivot row, temporarily */
+	cp = &A [Col [pivot_col].start] ;
+	cp_end = cp + Col [pivot_col].length ;
+	while (cp < cp_end)
+	{
+	    /* may be killing an already dead row */
+	    row = *cp++ ;
+	    DEBUG3 (("Kill row in pivot col: %d\n", row)) ;
+	    KILL_ROW (row) ;
+	}
+
+	/* === Select a row index to use as the new pivot row =============== */
+
+	pivot_row_length = pfree - pivot_row_start ;
+	if (pivot_row_length > 0)
+	{
+	    /* pick the "pivot" row arbitrarily (first row in col) */
+	    pivot_row = A [Col [pivot_col].start] ;
+	    DEBUG3 (("Pivotal row is %d\n", pivot_row)) ;
+	}
+	else
+	{
+	    /* there is no pivot row, since it is of zero length */
+	    pivot_row = EMPTY ;
+	    ASSERT (pivot_row_length == 0) ;
+	}
+	ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ;
+
+	/* === Approximate degree computation =============================== */
+
+	/* Here begins the computation of the approximate degree.  The column */
+	/* score is the sum of the pivot row "length", plus the size of the */
+	/* set differences of each row in the column minus the pattern of the */
+	/* pivot row itself.  The column ("thickness") itself is also */
+	/* excluded from the column score (we thus use an approximate */
+	/* external degree). */
+
+	/* The time taken by the following code (compute set differences, and */
+	/* add them up) is proportional to the size of the data structure */
+	/* being scanned - that is, the sum of the sizes of each column in */
+	/* the pivot row.  Thus, the amortized time to compute a column score */
+	/* is proportional to the size of that column (where size, in this */
+	/* context, is the column "length", or the number of row indices */
+	/* in that column).  The number of row indices in a column is */
+	/* monotonically non-decreasing, from the length of the original */
+	/* column on input to colamd. */
+
+	/* === Compute set differences ====================================== */
+
+	DEBUG3 (("** Computing set differences phase. **\n")) ;
+
+	/* pivot row is currently dead - it will be revived later. */
+
+	DEBUG3 (("Pivot row: ")) ;
+	/* for each column in pivot row */
+	rp = &A [pivot_row_start] ;
+	rp_end = rp + pivot_row_length ;
+	while (rp < rp_end)
+	{
+	    col = *rp++ ;
+	    ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
+	    DEBUG3 (("Col: %d\n", col)) ;
+
+	    /* clear tags used to construct pivot row pattern */
+	    col_thickness = -Col [col].shared1.thickness ;
+	    ASSERT (col_thickness > 0) ;
+	    Col [col].shared1.thickness = col_thickness ;
+
+	    /* === Remove column from degree list =========================== */
+
+	    cur_score = Col [col].shared2.score ;
+	    prev_col = Col [col].shared3.prev ;
+	    next_col = Col [col].shared4.degree_next ;
+	    ASSERT (cur_score >= 0) ;
+	    ASSERT (cur_score <= n_col) ;
+	    ASSERT (cur_score >= EMPTY) ;
+	    if (prev_col == EMPTY)
+	    {
+		head [cur_score] = next_col ;
+	    }
+	    else
+	    {
+		Col [prev_col].shared4.degree_next = next_col ;
+	    }
+	    if (next_col != EMPTY)
+	    {
+		Col [next_col].shared3.prev = prev_col ;
+	    }
+
+	    /* === Scan the column ========================================== */
+
+	    cp = &A [Col [col].start] ;
+	    cp_end = cp + Col [col].length ;
+	    while (cp < cp_end)
+	    {
+		/* get a row */
+		row = *cp++ ;
+		row_mark = Row [row].shared2.mark ;
+		/* skip if dead */
+		if (ROW_IS_MARKED_DEAD (row_mark))
+		{
+		    continue ;
+		}
+		ASSERT (row != pivot_row) ;
+		set_difference = row_mark - tag_mark ;
+		/* check if the row has been seen yet */
+		if (set_difference < 0)
+		{
+		    ASSERT (Row [row].shared1.degree <= max_deg) ;
+		    set_difference = Row [row].shared1.degree ;
+		}
+		/* subtract column thickness from this row's set difference */
+		set_difference -= col_thickness ;
+		ASSERT (set_difference >= 0) ;
+		/* absorb this row if the set difference becomes zero */
+		if (set_difference == 0 && aggressive)
+		{
+		    DEBUG3 (("aggressive absorption. Row: %d\n", row)) ;
+		    KILL_ROW (row) ;
+		}
+		else
+		{
+		    /* save the new mark */
+		    Row [row].shared2.mark = set_difference + tag_mark ;
+		}
+	    }
+	}
+
+#ifndef NDEBUG
+	debug_deg_lists (n_row, n_col, Row, Col, head,
+		min_score, n_col2-k-pivot_row_degree, max_deg) ;
+#endif /* NDEBUG */
+
+	/* === Add up set differences for each column ======================= */
+
+	DEBUG3 (("** Adding set differences phase. **\n")) ;
+
+	/* for each column in pivot row */
+	rp = &A [pivot_row_start] ;
+	rp_end = rp + pivot_row_length ;
+	while (rp < rp_end)
+	{
+	    /* get a column */
+	    col = *rp++ ;
+	    ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
+	    hash = 0 ;
+	    cur_score = 0 ;
+	    cp = &A [Col [col].start] ;
+	    /* compact the column */
+	    new_cp = cp ;
+	    cp_end = cp + Col [col].length ;
+
+	    DEBUG4 (("Adding set diffs for Col: %d.\n", col)) ;
+
+	    while (cp < cp_end)
+	    {
+		/* get a row */
+		row = *cp++ ;
+		ASSERT(row >= 0 && row < n_row) ;
+		row_mark = Row [row].shared2.mark ;
+		/* skip if dead */
+		if (ROW_IS_MARKED_DEAD (row_mark))
+		{
+		    DEBUG4 ((" Row %d, dead\n", row)) ;
+		    continue ;
+		}
+		DEBUG4 ((" Row %d, set diff %d\n", row, row_mark-tag_mark));
+		ASSERT (row_mark >= tag_mark) ;
+		/* compact the column */
+		*new_cp++ = row ;
+		/* compute hash function */
+		hash += row ;
+		/* add set difference */
+		cur_score += row_mark - tag_mark ;
+		/* integer overflow... */
+		cur_score = MIN (cur_score, n_col) ;
+	    }
+
+	    /* recompute the column's length */
+	    Col [col].length = (Int) (new_cp - &A [Col [col].start]) ;
+
+	    /* === Further mass elimination ================================= */
+
+	    if (Col [col].length == 0)
+	    {
+		DEBUG4 (("further mass elimination. Col: %d\n", col)) ;
+		/* nothing left but the pivot row in this column */
+		KILL_PRINCIPAL_COL (col) ;
+		pivot_row_degree -= Col [col].shared1.thickness ;
+		ASSERT (pivot_row_degree >= 0) ;
+		/* order it */
+		Col [col].shared2.order = k ;
+		/* increment order count by column thickness */
+		k += Col [col].shared1.thickness ;
+	    }
+	    else
+	    {
+		/* === Prepare for supercolumn detection ==================== */
+
+		DEBUG4 (("Preparing supercol detection for Col: %d.\n", col)) ;
+
+		/* save score so far */
+		Col [col].shared2.score = cur_score ;
+
+		/* add column to hash table, for supercolumn detection */
+		hash %= n_col + 1 ;
+
+		DEBUG4 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ;
+		ASSERT (((Int) hash) <= n_col) ;
+
+		head_column = head [hash] ;
+		if (head_column > EMPTY)
+		{
+		    /* degree list "hash" is non-empty, use prev (shared3) of */
+		    /* first column in degree list as head of hash bucket */
+		    first_col = Col [head_column].shared3.headhash ;
+		    Col [head_column].shared3.headhash = col ;
+		}
+		else
+		{
+		    /* degree list "hash" is empty, use head as hash bucket */
+		    first_col = - (head_column + 2) ;
+		    head [hash] = - (col + 2) ;
+		}
+		Col [col].shared4.hash_next = first_col ;
+
+		/* save hash function in Col [col].shared3.hash */
+		Col [col].shared3.hash = (Int) hash ;
+		ASSERT (COL_IS_ALIVE (col)) ;
+	    }
+	}
+
+	/* The approximate external column degree is now computed.  */
+
+	/* === Supercolumn detection ======================================== */
+
+	DEBUG3 (("** Supercolumn detection phase. **\n")) ;
+
+	detect_super_cols (
+
+#ifndef NDEBUG
+		n_col, Row,
+#endif /* NDEBUG */
+
+		Col, A, head, pivot_row_start, pivot_row_length) ;
+
+	/* === Kill the pivotal column ====================================== */
+
+	KILL_PRINCIPAL_COL (pivot_col) ;
+
+	/* === Clear mark =================================================== */
+
+	tag_mark = clear_mark (tag_mark+max_deg+1, max_mark, n_row, Row) ;
+
+#ifndef NDEBUG
+	DEBUG3 (("check3\n")) ;
+	debug_mark (n_row, Row, tag_mark, max_mark) ;
+#endif /* NDEBUG */
+
+	/* === Finalize the new pivot row, and column scores ================ */
+
+	DEBUG3 (("** Finalize scores phase. **\n")) ;
+
+	/* for each column in pivot row */
+	rp = &A [pivot_row_start] ;
+	/* compact the pivot row */
+	new_rp = rp ;
+	rp_end = rp + pivot_row_length ;
+	while (rp < rp_end)
+	{
+	    col = *rp++ ;
+	    /* skip dead columns */
+	    if (COL_IS_DEAD (col))
+	    {
+		continue ;
+	    }
+	    *new_rp++ = col ;
+	    /* add new pivot row to column */
+	    A [Col [col].start + (Col [col].length++)] = pivot_row ;
+
+	    /* retrieve score so far and add on pivot row's degree. */
+	    /* (we wait until here for this in case the pivot */
+	    /* row's degree was reduced due to mass elimination). */
+	    cur_score = Col [col].shared2.score + pivot_row_degree ;
+
+	    /* calculate the max possible score as the number of */
+	    /* external columns minus the 'k' value minus the */
+	    /* columns thickness */
+	    max_score = n_col - k - Col [col].shared1.thickness ;
+
+	    /* make the score the external degree of the union-of-rows */
+	    cur_score -= Col [col].shared1.thickness ;
+
+	    /* make sure score is less or equal than the max score */
+	    cur_score = MIN (cur_score, max_score) ;
+	    ASSERT (cur_score >= 0) ;
+
+	    /* store updated score */
+	    Col [col].shared2.score = cur_score ;
+
+	    /* === Place column back in degree list ========================= */
+
+	    ASSERT (min_score >= 0) ;
+	    ASSERT (min_score <= n_col) ;
+	    ASSERT (cur_score >= 0) ;
+	    ASSERT (cur_score <= n_col) ;
+	    ASSERT (head [cur_score] >= EMPTY) ;
+	    next_col = head [cur_score] ;
+	    Col [col].shared4.degree_next = next_col ;
+	    Col [col].shared3.prev = EMPTY ;
+	    if (next_col != EMPTY)
+	    {
+		Col [next_col].shared3.prev = col ;
+	    }
+	    head [cur_score] = col ;
+
+	    /* see if this score is less than current min */
+	    min_score = MIN (min_score, cur_score) ;
+
+	}
+
+#ifndef NDEBUG
+	debug_deg_lists (n_row, n_col, Row, Col, head,
+		min_score, n_col2-k, max_deg) ;
+#endif /* NDEBUG */
+
+	/* === Resurrect the new pivot row ================================== */
+
+	if (pivot_row_degree > 0)
+	{
+	    /* update pivot row length to reflect any cols that were killed */
+	    /* during super-col detection and mass elimination */
+	    Row [pivot_row].start  = pivot_row_start ;
+	    Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ;
+	    ASSERT (Row [pivot_row].length > 0) ;
+	    Row [pivot_row].shared1.degree = pivot_row_degree ;
+	    Row [pivot_row].shared2.mark = 0 ;
+	    /* pivot row is no longer dead */
+
+	    DEBUG1 (("Resurrect Pivot_row %d deg: %d\n",
+			pivot_row, pivot_row_degree)) ;
+	}
+    }
+
+    /* === All principal columns have now been ordered ====================== */
+
+    return (ngarbage) ;
+}
+
+
+/* ========================================================================== */
+/* === order_children ======================================================= */
+/* ========================================================================== */
+
+/*
+    The find_ordering routine has ordered all of the principal columns (the
+    representatives of the supercolumns).  The non-principal columns have not
+    yet been ordered.  This routine orders those columns by walking up the
+    parent tree (a column is a child of the column which absorbed it).  The
+    final permutation vector is then placed in p [0 ... n_col-1], with p [0]
+    being the first column, and p [n_col-1] being the last.  It doesn't look
+    like it at first glance, but be assured that this routine takes time linear
+    in the number of columns.  Although not immediately obvious, the time
+    taken by this routine is O (n_col), that is, linear in the number of
+    columns.  Not user-callable.
+*/
+
+PRIVATE void order_children
+(
+    /* === Parameters ======================================================= */
+
+    Int n_col,			/* number of columns of A */
+    Colamd_Col Col [],		/* of size n_col+1 */
+    Int p []			/* p [0 ... n_col-1] is the column permutation*/
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;			/* loop counter for all columns */
+    Int c ;			/* column index */
+    Int parent ;		/* index of column's parent */
+    Int order ;			/* column's order */
+
+    /* === Order each non-principal column ================================== */
+
+    for (i = 0 ; i < n_col ; i++)
+    {
+	/* find an un-ordered non-principal column */
+	ASSERT (COL_IS_DEAD (i)) ;
+	if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == EMPTY)
+	{
+	    parent = i ;
+	    /* once found, find its principal parent */
+	    do
+	    {
+		parent = Col [parent].shared1.parent ;
+	    } while (!COL_IS_DEAD_PRINCIPAL (parent)) ;
+
+	    /* now, order all un-ordered non-principal columns along path */
+	    /* to this parent.  collapse tree at the same time */
+	    c = i ;
+	    /* get order of parent */
+	    order = Col [parent].shared2.order ;
+
+	    do
+	    {
+		ASSERT (Col [c].shared2.order == EMPTY) ;
+
+		/* order this column */
+		Col [c].shared2.order = order++ ;
+		/* collaps tree */
+		Col [c].shared1.parent = parent ;
+
+		/* get immediate parent of this column */
+		c = Col [c].shared1.parent ;
+
+		/* continue until we hit an ordered column.  There are */
+		/* guarranteed not to be anymore unordered columns */
+		/* above an ordered column */
+	    } while (Col [c].shared2.order == EMPTY) ;
+
+	    /* re-order the super_col parent to largest order for this group */
+	    Col [parent].shared2.order = order ;
+	}
+    }
+
+    /* === Generate the permutation ========================================= */
+
+    for (c = 0 ; c < n_col ; c++)
+    {
+	p [Col [c].shared2.order] = c ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === detect_super_cols ==================================================== */
+/* ========================================================================== */
+
+/*
+    Detects supercolumns by finding matches between columns in the hash buckets.
+    Check amongst columns in the set A [row_start ... row_start + row_length-1].
+    The columns under consideration are currently *not* in the degree lists,
+    and have already been placed in the hash buckets.
+
+    The hash bucket for columns whose hash function is equal to h is stored
+    as follows:
+
+	if head [h] is >= 0, then head [h] contains a degree list, so:
+
+		head [h] is the first column in degree bucket h.
+		Col [head [h]].headhash gives the first column in hash bucket h.
+
+	otherwise, the degree list is empty, and:
+
+		-(head [h] + 2) is the first column in hash bucket h.
+
+    For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous
+    column" pointer.  Col [c].shared3.hash is used instead as the hash number
+    for that column.  The value of Col [c].shared4.hash_next is the next column
+    in the same hash bucket.
+
+    Assuming no, or "few" hash collisions, the time taken by this routine is
+    linear in the sum of the sizes (lengths) of each column whose score has
+    just been computed in the approximate degree computation.
+    Not user-callable.
+*/
+
+PRIVATE void detect_super_cols
+(
+    /* === Parameters ======================================================= */
+
+#ifndef NDEBUG
+    /* these two parameters are only needed when debugging is enabled: */
+    Int n_col,			/* number of columns of A */
+    Colamd_Row Row [],		/* of size n_row+1 */
+#endif /* NDEBUG */
+
+    Colamd_Col Col [],		/* of size n_col+1 */
+    Int A [],			/* row indices of A */
+    Int head [],		/* head of degree lists and hash buckets */
+    Int row_start,		/* pointer to set of columns to check */
+    Int row_length		/* number of columns to check */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int hash ;			/* hash value for a column */
+    Int *rp ;			/* pointer to a row */
+    Int c ;			/* a column index */
+    Int super_c ;		/* column index of the column to absorb into */
+    Int *cp1 ;			/* column pointer for column super_c */
+    Int *cp2 ;			/* column pointer for column c */
+    Int length ;		/* length of column super_c */
+    Int prev_c ;		/* column preceding c in hash bucket */
+    Int i ;			/* loop counter */
+    Int *rp_end ;		/* pointer to the end of the row */
+    Int col ;			/* a column index in the row to check */
+    Int head_column ;		/* first column in hash bucket or degree list */
+    Int first_col ;		/* first column in hash bucket */
+
+    /* === Consider each column in the row ================================== */
+
+    rp = &A [row_start] ;
+    rp_end = rp + row_length ;
+    while (rp < rp_end)
+    {
+	col = *rp++ ;
+	if (COL_IS_DEAD (col))
+	{
+	    continue ;
+	}
+
+	/* get hash number for this column */
+	hash = Col [col].shared3.hash ;
+	ASSERT (hash <= n_col) ;
+
+	/* === Get the first column in this hash bucket ===================== */
+
+	head_column = head [hash] ;
+	if (head_column > EMPTY)
+	{
+	    first_col = Col [head_column].shared3.headhash ;
+	}
+	else
+	{
+	    first_col = - (head_column + 2) ;
+	}
+
+	/* === Consider each column in the hash bucket ====================== */
+
+	for (super_c = first_col ; super_c != EMPTY ;
+	    super_c = Col [super_c].shared4.hash_next)
+	{
+	    ASSERT (COL_IS_ALIVE (super_c)) ;
+	    ASSERT (Col [super_c].shared3.hash == hash) ;
+	    length = Col [super_c].length ;
+
+	    /* prev_c is the column preceding column c in the hash bucket */
+	    prev_c = super_c ;
+
+	    /* === Compare super_c with all columns after it ================ */
+
+	    for (c = Col [super_c].shared4.hash_next ;
+		 c != EMPTY ; c = Col [c].shared4.hash_next)
+	    {
+		ASSERT (c != super_c) ;
+		ASSERT (COL_IS_ALIVE (c)) ;
+		ASSERT (Col [c].shared3.hash == hash) ;
+
+		/* not identical if lengths or scores are different */
+		if (Col [c].length != length ||
+		    Col [c].shared2.score != Col [super_c].shared2.score)
+		{
+		    prev_c = c ;
+		    continue ;
+		}
+
+		/* compare the two columns */
+		cp1 = &A [Col [super_c].start] ;
+		cp2 = &A [Col [c].start] ;
+
+		for (i = 0 ; i < length ; i++)
+		{
+		    /* the columns are "clean" (no dead rows) */
+		    ASSERT (ROW_IS_ALIVE (*cp1))  ;
+		    ASSERT (ROW_IS_ALIVE (*cp2))  ;
+		    /* row indices will same order for both supercols, */
+		    /* no gather scatter nessasary */
+		    if (*cp1++ != *cp2++)
+		    {
+			break ;
+		    }
+		}
+
+		/* the two columns are different if the for-loop "broke" */
+		if (i != length)
+		{
+		    prev_c = c ;
+		    continue ;
+		}
+
+		/* === Got it!  two columns are identical =================== */
+
+		ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ;
+
+		Col [super_c].shared1.thickness += Col [c].shared1.thickness ;
+		Col [c].shared1.parent = super_c ;
+		KILL_NON_PRINCIPAL_COL (c) ;
+		/* order c later, in order_children() */
+		Col [c].shared2.order = EMPTY ;
+		/* remove c from hash bucket */
+		Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ;
+	    }
+	}
+
+	/* === Empty this hash bucket ======================================= */
+
+	if (head_column > EMPTY)
+	{
+	    /* corresponding degree list "hash" is not empty */
+	    Col [head_column].shared3.headhash = EMPTY ;
+	}
+	else
+	{
+	    /* corresponding degree list "hash" is empty */
+	    head [hash] = EMPTY ;
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === garbage_collection =================================================== */
+/* ========================================================================== */
+
+/*
+    Defragments and compacts columns and rows in the workspace A.  Used when
+    all avaliable memory has been used while performing row merging.  Returns
+    the index of the first free position in A, after garbage collection.  The
+    time taken by this routine is linear is the size of the array A, which is
+    itself linear in the number of nonzeros in the input matrix.
+    Not user-callable.
+*/
+
+PRIVATE Int garbage_collection  /* returns the new value of pfree */
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,			/* number of rows */
+    Int n_col,			/* number of columns */
+    Colamd_Row Row [],		/* row info */
+    Colamd_Col Col [],		/* column info */
+    Int A [],			/* A [0 ... Alen-1] holds the matrix */
+    Int *pfree			/* &A [0] ... pfree is in use */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int *psrc ;			/* source pointer */
+    Int *pdest ;		/* destination pointer */
+    Int j ;			/* counter */
+    Int r ;			/* a row index */
+    Int c ;			/* a column index */
+    Int length ;		/* length of a row or column */
+
+#ifndef NDEBUG
+    Int debug_rows ;
+    DEBUG2 (("Defrag..\n")) ;
+    for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ;
+    debug_rows = 0 ;
+#endif /* NDEBUG */
+
+    /* === Defragment the columns =========================================== */
+
+    pdest = &A[0] ;
+    for (c = 0 ; c < n_col ; c++)
+    {
+	if (COL_IS_ALIVE (c))
+	{
+	    psrc = &A [Col [c].start] ;
+
+	    /* move and compact the column */
+	    ASSERT (pdest <= psrc) ;
+	    Col [c].start = (Int) (pdest - &A [0]) ;
+	    length = Col [c].length ;
+	    for (j = 0 ; j < length ; j++)
+	    {
+		r = *psrc++ ;
+		if (ROW_IS_ALIVE (r))
+		{
+		    *pdest++ = r ;
+		}
+	    }
+	    Col [c].length = (Int) (pdest - &A [Col [c].start]) ;
+	}
+    }
+
+    /* === Prepare to defragment the rows =================================== */
+
+    for (r = 0 ; r < n_row ; r++)
+    {
+	if (ROW_IS_DEAD (r) || (Row [r].length == 0))
+	{
+	    /* This row is already dead, or is of zero length.  Cannot compact
+	     * a row of zero length, so kill it.  NOTE: in the current version,
+	     * there are no zero-length live rows.  Kill the row (for the first
+	     * time, or again) just to be safe. */
+	    KILL_ROW (r) ;
+	}
+	else
+	{
+	    /* save first column index in Row [r].shared2.first_column */
+	    psrc = &A [Row [r].start] ;
+	    Row [r].shared2.first_column = *psrc ;
+	    ASSERT (ROW_IS_ALIVE (r)) ;
+	    /* flag the start of the row with the one's complement of row */
+	    *psrc = ONES_COMPLEMENT (r) ;
+#ifndef NDEBUG
+	    debug_rows++ ;
+#endif /* NDEBUG */
+	}
+    }
+
+    /* === Defragment the rows ============================================== */
+
+    psrc = pdest ;
+    while (psrc < pfree)
+    {
+	/* find a negative number ... the start of a row */
+	if (*psrc++ < 0)
+	{
+	    psrc-- ;
+	    /* get the row index */
+	    r = ONES_COMPLEMENT (*psrc) ;
+	    ASSERT (r >= 0 && r < n_row) ;
+	    /* restore first column index */
+	    *psrc = Row [r].shared2.first_column ;
+	    ASSERT (ROW_IS_ALIVE (r)) ;
+	    ASSERT (Row [r].length > 0) ;
+	    /* move and compact the row */
+	    ASSERT (pdest <= psrc) ;
+	    Row [r].start = (Int) (pdest - &A [0]) ;
+	    length = Row [r].length ;
+	    for (j = 0 ; j < length ; j++)
+	    {
+		c = *psrc++ ;
+		if (COL_IS_ALIVE (c))
+		{
+		    *pdest++ = c ;
+		}
+	    }
+	    Row [r].length = (Int) (pdest - &A [Row [r].start]) ;
+	    ASSERT (Row [r].length > 0) ;
+#ifndef NDEBUG
+	    debug_rows-- ;
+#endif /* NDEBUG */
+	}
+    }
+    /* ensure we found all the rows */
+    ASSERT (debug_rows == 0) ;
+
+    /* === Return the new value of pfree ==================================== */
+
+    return ((Int) (pdest - &A [0])) ;
+}
+
+
+/* ========================================================================== */
+/* === clear_mark =========================================================== */
+/* ========================================================================== */
+
+/*
+    Clears the Row [].shared2.mark array, and returns the new tag_mark.
+    Return value is the new tag_mark.  Not user-callable.
+*/
+
+PRIVATE Int clear_mark	/* return the new value for tag_mark */
+(
+    /* === Parameters ======================================================= */
+
+    Int tag_mark,	/* new value of tag_mark */
+    Int max_mark,	/* max allowed value of tag_mark */
+
+    Int n_row,		/* number of rows in A */
+    Colamd_Row Row []	/* Row [0 ... n_row-1].shared2.mark is set to zero */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int r ;
+
+    if (tag_mark <= 0 || tag_mark >= max_mark)
+    {
+	for (r = 0 ; r < n_row ; r++)
+	{
+	    if (ROW_IS_ALIVE (r))
+	    {
+		Row [r].shared2.mark = 0 ;
+	    }
+	}
+	tag_mark = 1 ;
+    }
+
+    return (tag_mark) ;
+}
+
+
+/* ========================================================================== */
+/* === print_report ========================================================= */
+/* ========================================================================== */
+
+PRIVATE void print_report
+(
+    char *method,
+    Int stats [COLAMD_STATS]
+)
+{
+
+    Int i1, i2, i3 ;
+
+    PRINTF (("\n%s version %d.%d, %s: ", method,
+	    COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE)) ;
+
+    if (!stats)
+    {
+    	PRINTF (("No statistics available.\n")) ;
+	return ;
+    }
+
+    i1 = stats [COLAMD_INFO1] ;
+    i2 = stats [COLAMD_INFO2] ;
+    i3 = stats [COLAMD_INFO3] ;
+
+    if (stats [COLAMD_STATUS] >= 0)
+    {
+    	PRINTF (("OK.  ")) ;
+    }
+    else
+    {
+    	PRINTF (("ERROR.  ")) ;
+    }
+
+    switch (stats [COLAMD_STATUS])
+    {
+
+	case COLAMD_OK_BUT_JUMBLED:
+
+	    PRINTF(("Matrix has unsorted or duplicate row indices.\n")) ;
+
+	    PRINTF(("%s: number of duplicate or out-of-order row indices: %d\n",
+	    method, i3)) ;
+
+	    PRINTF(("%s: last seen duplicate or out-of-order row index:   %d\n",
+	    method, INDEX (i2))) ;
+
+	    PRINTF(("%s: last seen in column:                             %d",
+	    method, INDEX (i1))) ;
+
+	    /* no break - fall through to next case instead */
+
+	case COLAMD_OK:
+
+	    PRINTF(("\n")) ;
+
+ 	    PRINTF(("%s: number of dense or empty rows ignored:           %d\n",
+	    method, stats [COLAMD_DENSE_ROW])) ;
+
+	    PRINTF(("%s: number of dense or empty columns ignored:        %d\n",
+	    method, stats [COLAMD_DENSE_COL])) ;
+
+	    PRINTF(("%s: number of garbage collections performed:         %d\n",
+	    method, stats [COLAMD_DEFRAG_COUNT])) ;
+	    break ;
+
+	case COLAMD_ERROR_A_not_present:
+
+	    PRINTF(("Array A (row indices of matrix) not present.\n")) ;
+	    break ;
+
+	case COLAMD_ERROR_p_not_present:
+
+	    PRINTF(("Array p (column pointers for matrix) not present.\n")) ;
+	    break ;
+
+	case COLAMD_ERROR_nrow_negative:
+
+	    PRINTF(("Invalid number of rows (%d).\n", i1)) ;
+	    break ;
+
+	case COLAMD_ERROR_ncol_negative:
+
+	    PRINTF(("Invalid number of columns (%d).\n", i1)) ;
+	    break ;
+
+	case COLAMD_ERROR_nnz_negative:
+
+	    PRINTF(("Invalid number of nonzero entries (%d).\n", i1)) ;
+	    break ;
+
+	case COLAMD_ERROR_p0_nonzero:
+
+	    PRINTF(("Invalid column pointer, p [0] = %d, must be zero.\n", i1));
+	    break ;
+
+	case COLAMD_ERROR_A_too_small:
+
+	    PRINTF(("Array A too small.\n")) ;
+	    PRINTF(("        Need Alen >= %d, but given only Alen = %d.\n",
+	    i1, i2)) ;
+	    break ;
+
+	case COLAMD_ERROR_col_length_negative:
+
+	    PRINTF
+	    (("Column %d has a negative number of nonzero entries (%d).\n",
+	    INDEX (i1), i2)) ;
+	    break ;
+
+	case COLAMD_ERROR_row_index_out_of_bounds:
+
+	    PRINTF
+	    (("Row index (row %d) out of bounds (%d to %d) in column %d.\n",
+	    INDEX (i2), INDEX (0), INDEX (i3-1), INDEX (i1))) ;
+	    break ;
+
+	case COLAMD_ERROR_out_of_memory:
+
+	    PRINTF(("Out of memory.\n")) ;
+	    break ;
+
+	/* v2.4: internal-error case deleted */
+    }
+}
+
+
+
+
+/* ========================================================================== */
+/* === colamd debugging routines ============================================ */
+/* ========================================================================== */
+
+/* When debugging is disabled, the remainder of this file is ignored. */
+
+#ifndef NDEBUG
+
+
+/* ========================================================================== */
+/* === debug_structures ===================================================== */
+/* ========================================================================== */
+
+/*
+    At this point, all empty rows and columns are dead.  All live columns
+    are "clean" (containing no dead rows) and simplicial (no supercolumns
+    yet).  Rows may contain dead columns, but all live rows contain at
+    least one live column.
+*/
+
+PRIVATE void debug_structures
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int n_col2
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;
+    Int c ;
+    Int *cp ;
+    Int *cp_end ;
+    Int len ;
+    Int score ;
+    Int r ;
+    Int *rp ;
+    Int *rp_end ;
+    Int deg ;
+
+    /* === Check A, Row, and Col ============================================ */
+
+    for (c = 0 ; c < n_col ; c++)
+    {
+	if (COL_IS_ALIVE (c))
+	{
+	    len = Col [c].length ;
+	    score = Col [c].shared2.score ;
+	    DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ;
+	    ASSERT (len > 0) ;
+	    ASSERT (score >= 0) ;
+	    ASSERT (Col [c].shared1.thickness == 1) ;
+	    cp = &A [Col [c].start] ;
+	    cp_end = cp + len ;
+	    while (cp < cp_end)
+	    {
+		r = *cp++ ;
+		ASSERT (ROW_IS_ALIVE (r)) ;
+	    }
+	}
+	else
+	{
+	    i = Col [c].shared2.order ;
+	    ASSERT (i >= n_col2 && i < n_col) ;
+	}
+    }
+
+    for (r = 0 ; r < n_row ; r++)
+    {
+	if (ROW_IS_ALIVE (r))
+	{
+	    i = 0 ;
+	    len = Row [r].length ;
+	    deg = Row [r].shared1.degree ;
+	    ASSERT (len > 0) ;
+	    ASSERT (deg > 0) ;
+	    rp = &A [Row [r].start] ;
+	    rp_end = rp + len ;
+	    while (rp < rp_end)
+	    {
+		c = *rp++ ;
+		if (COL_IS_ALIVE (c))
+		{
+		    i++ ;
+		}
+	    }
+	    ASSERT (i > 0) ;
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === debug_deg_lists ====================================================== */
+/* ========================================================================== */
+
+/*
+    Prints the contents of the degree lists.  Counts the number of columns
+    in the degree list and compares it to the total it should have.  Also
+    checks the row degrees.
+*/
+
+PRIVATE void debug_deg_lists
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int head [],
+    Int min_score,
+    Int should,
+    Int max_deg
+)
+{
+    /* === Local variables ================================================== */
+
+    Int deg ;
+    Int col ;
+    Int have ;
+    Int row ;
+
+    /* === Check the degree lists =========================================== */
+
+    if (n_col > 10000 && colamd_debug <= 0)
+    {
+	return ;
+    }
+    have = 0 ;
+    DEBUG4 (("Degree lists: %d\n", min_score)) ;
+    for (deg = 0 ; deg <= n_col ; deg++)
+    {
+	col = head [deg] ;
+	if (col == EMPTY)
+	{
+	    continue ;
+	}
+	DEBUG4 (("%d:", deg)) ;
+	while (col != EMPTY)
+	{
+	    DEBUG4 ((" %d", col)) ;
+	    have += Col [col].shared1.thickness ;
+	    ASSERT (COL_IS_ALIVE (col)) ;
+	    col = Col [col].shared4.degree_next ;
+	}
+	DEBUG4 (("\n")) ;
+    }
+    DEBUG4 (("should %d have %d\n", should, have)) ;
+    ASSERT (should == have) ;
+
+    /* === Check the row degrees ============================================ */
+
+    if (n_row > 10000 && colamd_debug <= 0)
+    {
+	return ;
+    }
+    for (row = 0 ; row < n_row ; row++)
+    {
+	if (ROW_IS_ALIVE (row))
+	{
+	    ASSERT (Row [row].shared1.degree <= max_deg) ;
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === debug_mark =========================================================== */
+/* ========================================================================== */
+
+/*
+    Ensures that the tag_mark is less that the maximum and also ensures that
+    each entry in the mark array is less than the tag mark.
+*/
+
+PRIVATE void debug_mark
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Colamd_Row Row [],
+    Int tag_mark,
+    Int max_mark
+)
+{
+    /* === Local variables ================================================== */
+
+    Int r ;
+
+    /* === Check the Row marks ============================================== */
+
+    ASSERT (tag_mark > 0 && tag_mark <= max_mark) ;
+    if (n_row > 10000 && colamd_debug <= 0)
+    {
+	return ;
+    }
+    for (r = 0 ; r < n_row ; r++)
+    {
+	ASSERT (Row [r].shared2.mark < tag_mark) ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === debug_matrix ========================================================= */
+/* ========================================================================== */
+
+/*
+    Prints out the contents of the columns and the rows.
+*/
+
+PRIVATE void debug_matrix
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A []
+)
+{
+    /* === Local variables ================================================== */
+
+    Int r ;
+    Int c ;
+    Int *rp ;
+    Int *rp_end ;
+    Int *cp ;
+    Int *cp_end ;
+
+    /* === Dump the rows and columns of the matrix ========================== */
+
+    if (colamd_debug < 3)
+    {
+	return ;
+    }
+    DEBUG3 (("DUMP MATRIX:\n")) ;
+    for (r = 0 ; r < n_row ; r++)
+    {
+	DEBUG3 (("Row %d alive? %d\n", r, ROW_IS_ALIVE (r))) ;
+	if (ROW_IS_DEAD (r))
+	{
+	    continue ;
+	}
+	DEBUG3 (("start %d length %d degree %d\n",
+		Row [r].start, Row [r].length, Row [r].shared1.degree)) ;
+	rp = &A [Row [r].start] ;
+	rp_end = rp + Row [r].length ;
+	while (rp < rp_end)
+	{
+	    c = *rp++ ;
+	    DEBUG4 (("	%d col %d\n", COL_IS_ALIVE (c), c)) ;
+	}
+    }
+
+    for (c = 0 ; c < n_col ; c++)
+    {
+	DEBUG3 (("Col %d alive? %d\n", c, COL_IS_ALIVE (c))) ;
+	if (COL_IS_DEAD (c))
+	{
+	    continue ;
+	}
+	DEBUG3 (("start %d length %d shared1 %d shared2 %d\n",
+		Col [c].start, Col [c].length,
+		Col [c].shared1.thickness, Col [c].shared2.score)) ;
+	cp = &A [Col [c].start] ;
+	cp_end = cp + Col [c].length ;
+	while (cp < cp_end)
+	{
+	    r = *cp++ ;
+	    DEBUG4 (("	%d row %d\n", ROW_IS_ALIVE (r), r)) ;
+	}
+    }
+}
+
+PRIVATE void colamd_get_debug
+(
+    char *method
+)
+{
+    FILE *f ;
+    colamd_debug = 0 ;		/* no debug printing */
+    f = fopen ("debug", "r") ;
+    if (f == (FILE *) NULL)
+    {
+	colamd_debug = 0 ;
+    }
+    else
+    {
+	fscanf (f, "%d", &colamd_debug) ;
+	fclose (f) ;
+    }
+    DEBUG0 (("%s: debug version, D = %d (THIS WILL BE SLOW!)\n",
+    	method, colamd_debug)) ;
+}
+
+#endif /* NDEBUG */
diff --git a/src/C/SuiteSparse/COLAMD/colamd.h b/src/C/SuiteSparse/COLAMD/colamd.h
new file mode 100644
index 0000000..7af4213
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/colamd.h
@@ -0,0 +1,254 @@
+/* ========================================================================== */
+/* === colamd/symamd prototypes and definitions ============================= */
+/* ========================================================================== */
+
+/* COLAMD / SYMAMD include file
+
+    You must include this file (colamd.h) in any routine that uses colamd,
+    symamd, or the related macros and definitions.
+
+    Authors:
+
+	The authors of the code itself are Stefan I. Larimore and Timothy A.
+	Davis (davis at cise.ufl.edu), University of Florida.  The algorithm was
+	developed in collaboration with John Gilbert, Xerox PARC, and Esmond
+	Ng, Oak Ridge National Laboratory.
+
+    Acknowledgements:
+
+	This work was supported by the National Science Foundation, under
+	grants DMS-9504974 and DMS-9803599.
+
+    Notice:
+
+	Copyright (c) 1998-2006, Timothy A. Davis, All Rights Reserved.
+
+	THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+	EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+
+	Permission is hereby granted to use, copy, modify, and/or distribute
+	this program, provided that the Copyright, this License, and the
+	Availability of the original version is retained on all copies and made
+	accessible to the end-user of any code or package that includes COLAMD
+	or any modified version of COLAMD. 
+
+    Availability:
+
+	The colamd/symamd library is available at
+
+	    http://www.cise.ufl.edu/research/sparse/colamd/
+
+	This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.h
+	file.  It is required by the colamd.c, colamdmex.c, and symamdmex.c
+	files, and by any C code that calls the routines whose prototypes are
+	listed below, or that uses the colamd/symamd definitions listed below.
+
+*/
+
+#ifndef COLAMD_H
+#define COLAMD_H
+
+/* make it easy for C++ programs to include COLAMD */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ========================================================================== */
+/* === Include files ======================================================== */
+/* ========================================================================== */
+
+#include <stdlib.h>
+
+/* ========================================================================== */
+/* === COLAMD version ======================================================= */
+/* ========================================================================== */
+
+/* COLAMD Version 2.4 and later will include the following definitions.
+ * As an example, to test if the version you are using is 2.4 or later:
+ *
+ * #ifdef COLAMD_VERSION
+ *	if (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4)) ...
+ * #endif
+ *
+ * This also works during compile-time:
+ *
+ *  #if defined(COLAMD_VERSION) && (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4))
+ *    printf ("This is version 2.4 or later\n") ;
+ *  #else
+ *    printf ("This is an early version\n") ;
+ *  #endif
+ *
+ * Versions 2.3 and earlier of COLAMD do not include a #define'd version number.
+ */
+
+#define COLAMD_DATE "Dec 12, 2006"
+#define COLAMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub))
+#define COLAMD_MAIN_VERSION 2
+#define COLAMD_SUB_VERSION 6
+#define COLAMD_VERSION \
+	COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION,COLAMD_SUB_VERSION)
+
+/* ========================================================================== */
+/* === Knob and statistics definitions ====================================== */
+/* ========================================================================== */
+
+/* size of the knobs [ ] array.  Only knobs [0..1] are currently used. */
+#define COLAMD_KNOBS 20
+
+/* number of output statistics.  Only stats [0..6] are currently used. */
+#define COLAMD_STATS 20
+
+/* knobs [0] and stats [0]: dense row knob and output statistic. */
+#define COLAMD_DENSE_ROW 0
+
+/* knobs [1] and stats [1]: dense column knob and output statistic. */
+#define COLAMD_DENSE_COL 1
+
+/* knobs [2]: aggressive absorption */
+#define COLAMD_AGGRESSIVE 2
+
+/* stats [2]: memory defragmentation count output statistic */
+#define COLAMD_DEFRAG_COUNT 2
+
+/* stats [3]: colamd status:  zero OK, > 0 warning or notice, < 0 error */
+#define COLAMD_STATUS 3
+
+/* stats [4..6]: error info, or info on jumbled columns */ 
+#define COLAMD_INFO1 4
+#define COLAMD_INFO2 5
+#define COLAMD_INFO3 6
+
+/* error codes returned in stats [3]: */
+#define COLAMD_OK				(0)
+#define COLAMD_OK_BUT_JUMBLED			(1)
+#define COLAMD_ERROR_A_not_present		(-1)
+#define COLAMD_ERROR_p_not_present		(-2)
+#define COLAMD_ERROR_nrow_negative		(-3)
+#define COLAMD_ERROR_ncol_negative		(-4)
+#define COLAMD_ERROR_nnz_negative		(-5)
+#define COLAMD_ERROR_p0_nonzero			(-6)
+#define COLAMD_ERROR_A_too_small		(-7)
+#define COLAMD_ERROR_col_length_negative	(-8)
+#define COLAMD_ERROR_row_index_out_of_bounds	(-9)
+#define COLAMD_ERROR_out_of_memory		(-10)
+#define COLAMD_ERROR_internal_error		(-999)
+
+
+/* ========================================================================== */
+/* === Prototypes of user-callable routines ================================= */
+/* ========================================================================== */
+
+/* define UF_long */
+#include "UFconfig.h"
+
+size_t colamd_recommended	/* returns recommended value of Alen, */
+				/* or 0 if input arguments are erroneous */
+(
+    int nnz,			/* nonzeros in A */
+    int n_row,			/* number of rows in A */
+    int n_col			/* number of columns in A */
+) ;
+
+size_t colamd_l_recommended	/* returns recommended value of Alen, */
+				/* or 0 if input arguments are erroneous */
+(
+    UF_long nnz,		/* nonzeros in A */
+    UF_long n_row,		/* number of rows in A */
+    UF_long n_col		/* number of columns in A */
+) ;
+
+void colamd_set_defaults	/* sets default parameters */
+(				/* knobs argument is modified on output */
+    double knobs [COLAMD_KNOBS]	/* parameter settings for colamd */
+) ;
+
+void colamd_l_set_defaults	/* sets default parameters */
+(				/* knobs argument is modified on output */
+    double knobs [COLAMD_KNOBS]	/* parameter settings for colamd */
+) ;
+
+int colamd			/* returns (1) if successful, (0) otherwise*/
+(				/* A and p arguments are modified on output */
+    int n_row,			/* number of rows in A */
+    int n_col,			/* number of columns in A */
+    int Alen,			/* size of the array A */
+    int A [],			/* row indices of A, of size Alen */
+    int p [],			/* column pointers of A, of size n_col+1 */
+    double knobs [COLAMD_KNOBS],/* parameter settings for colamd */
+    int stats [COLAMD_STATS]	/* colamd output statistics and error codes */
+) ;
+
+UF_long colamd_l		/* returns (1) if successful, (0) otherwise*/
+(				/* A and p arguments are modified on output */
+    UF_long n_row,		/* number of rows in A */
+    UF_long n_col,		/* number of columns in A */
+    UF_long Alen,		/* size of the array A */
+    UF_long A [],		/* row indices of A, of size Alen */
+    UF_long p [],		/* column pointers of A, of size n_col+1 */
+    double knobs [COLAMD_KNOBS],/* parameter settings for colamd */
+    UF_long stats [COLAMD_STATS]/* colamd output statistics and error codes */
+) ;
+
+int symamd				/* return (1) if OK, (0) otherwise */
+(
+    int n,				/* number of rows and columns of A */
+    int A [],				/* row indices of A */
+    int p [],				/* column pointers of A */
+    int perm [],			/* output permutation, size n_col+1 */
+    double knobs [COLAMD_KNOBS],	/* parameters (uses defaults if NULL) */
+    int stats [COLAMD_STATS],		/* output statistics and error codes */
+    void * (*allocate) (size_t, size_t),
+    					/* pointer to calloc (ANSI C) or */
+					/* mxCalloc (for MATLAB mexFunction) */
+    void (*release) (void *)
+    					/* pointer to free (ANSI C) or */
+    					/* mxFree (for MATLAB mexFunction) */
+) ;
+
+UF_long symamd_l			/* return (1) if OK, (0) otherwise */
+(
+    UF_long n,				/* number of rows and columns of A */
+    UF_long A [],			/* row indices of A */
+    UF_long p [],			/* column pointers of A */
+    UF_long perm [],			/* output permutation, size n_col+1 */
+    double knobs [COLAMD_KNOBS],	/* parameters (uses defaults if NULL) */
+    UF_long stats [COLAMD_STATS],	/* output statistics and error codes */
+    void * (*allocate) (size_t, size_t),
+    					/* pointer to calloc (ANSI C) or */
+					/* mxCalloc (for MATLAB mexFunction) */
+    void (*release) (void *)
+    					/* pointer to free (ANSI C) or */
+    					/* mxFree (for MATLAB mexFunction) */
+) ;
+
+void colamd_report
+(
+    int stats [COLAMD_STATS]
+) ;
+
+void colamd_l_report
+(
+    UF_long stats [COLAMD_STATS]
+) ;
+
+void symamd_report
+(
+    int stats [COLAMD_STATS]
+) ;
+
+void symamd_l_report
+(
+    UF_long stats [COLAMD_STATS]
+) ;
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+EXTERN int (*colamd_printf) (const char *, ...) ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* COLAMD_H */
diff --git a/src/C/SuiteSparse/COLAMD/colamd2.m b/src/C/SuiteSparse/COLAMD/colamd2.m
new file mode 100644
index 0000000..69348c3
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/colamd2.m
@@ -0,0 +1,103 @@
+function [p,stats] = colamd2 (S, knobs)
+%COLAMD2 Column approximate minimum degree permutation.
+%    P = COLAMD2(S) returns the column approximate minimum degree permutation
+%    vector for the sparse matrix S.  For a non-symmetric matrix S, S(:,P)
+%    tends to have sparser LU factors than S.  The Cholesky factorization of
+%    S(:,P)'*S(:,P) also tends to be sparser than that of S'*S.  The ordering
+%    is followed by a column elimination tree post-ordering.
+%
+%    Note that this function is the source code for the built-in MATLAB colamd
+%    function.  It has been renamed here to colamd2 to avoid a filename clash.
+%    colamd and colamd2 are identical.
+%
+%    See also COLAMD, AMD, SYMAMD, SYMAMD2.
+%
+%    Example:
+%            P = colamd2 (S)
+%            [P, stats] = colamd2 (S, knobs)
+%
+%    knobs is an optional one- to three-element input vector.  If S is m-by-n,
+%    then rows with more than max(16,knobs(1)*sqrt(n)) entries are ignored.
+%    Columns with more than max(16,knobs(2)*sqrt(min(m,n))) entries are
+%    removed prior to ordering, and ordered last in the output permutation P.
+%    Only completely dense rows or columns are removed if knobs(1) and knobs(2)
+%    are < 0, respectively.  If knobs(3) is nonzero, stats and knobs are
+%    printed.  The default is knobs = [10 10 0].  Note that knobs differs from
+%    earlier versions of colamd.
+%
+%    Type the command "type colamd2" for a description of the optional stats
+%    output and for the copyright information.
+%
+%    Authors: S. Larimore and T. Davis, University of Florida.  Developed in
+%       collaboration with J. Gilbert and E. Ng.
+%
+%    Acknowledgements: This work was supported by the National Science
+%       Foundation, under grants DMS-9504974 and DMS-9803599.
+
+%    Notice:
+%
+%	Copyright 1998-2006, Timothy A. Davis, All Rights Reserved.
+%
+%       See http://www.cise.ufl.edu/research/sparse/colamd (the colamd.c
+%       file) for the License.
+%
+%    Availability:
+%
+%       colamd, symamd, amd, ccolamd, and csymamd are available at
+%       http://www.cise.ufl.edu/research/sparse
+
+%-------------------------------------------------------------------------------
+% Perform the colamd ordering:
+%-------------------------------------------------------------------------------
+
+if (nargout <= 1 && nargin == 1)
+    p = colamd2mex (S) ;
+elseif (nargout <= 1 && nargin == 2)
+    p = colamd2mex (S, knobs) ;
+elseif (nargout == 2 && nargin == 1)
+    [p, stats] = colamd2mex (S) ;
+elseif (nargout == 2 && nargin == 2)
+    [p, stats] = colamd2mex (S, knobs) ;
+else
+    error ('MATLAB:colamd:WrongInputOrOutputNumber',...
+           'colamd:  incorrect number of input and/or output arguments') ;
+end
+
+%-------------------------------------------------------------------------------
+% column elimination tree post-ordering:
+%-------------------------------------------------------------------------------
+
+[ignore, q] = etree (S (:,p), 'col') ;
+p = p (q) ;
+
+%    stats is an optional 20-element output vector that provides data about the
+%    ordering and the validity of the input matrix S.  Ordering statistics are
+%    in stats (1:3).  stats (1) and stats (2) are the number of dense or empty
+%    rows and columns ignored by COLAMD and stats (3) is the number of
+%    garbage collections performed on the internal data structure used by
+%    COLAMD (roughly of size 2.2*nnz(S) + 4*m + 7*n integers).
+%
+%    MATLAB built-in functions are intended to generate valid sparse matrices,
+%    with no duplicate entries, with ascending row indices of the nonzeros
+%    in each column, with a non-negative number of entries in each column (!)
+%    and so on.  If a matrix is invalid, then COLAMD may or may not be able
+%    to continue.  If there are duplicate entries (a row index appears two or
+%    more times in the same column) or if the row indices in a column are out
+%    of order, then COLAMD can correct these errors by ignoring the duplicate
+%    entries and sorting each column of its internal copy of the matrix S (the
+%    input matrix S is not repaired, however).  If a matrix is invalid in other
+%    ways then COLAMD cannot continue, an error message is printed, and no
+%    output arguments (P or stats) are returned.  COLAMD is thus a simple way
+%    to check a sparse matrix to see if it's valid.
+%
+%    stats (4:7) provide information if COLAMD was able to continue.  The
+%    matrix is OK if stats (4) is zero, or 1 if invalid.  stats (5) is the
+%    rightmost column index that is unsorted or contains duplicate entries,
+%    or zero if no such column exists.  stats (6) is the last seen duplicate
+%    or out-of-order row index in the column index given by stats (5), or zero
+%    if no such row index exists.  stats (7) is the number of duplicate or
+%    out-of-order row indices.
+%
+%    stats (8:20) is always zero in the current version of COLAMD (reserved
+%    for future use).
+
diff --git a/src/C/SuiteSparse/COLAMD/colamd_demo.m b/src/C/SuiteSparse/COLAMD/colamd_demo.m
new file mode 100644
index 0000000..265daf4
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/colamd_demo.m
@@ -0,0 +1,178 @@
+%COLAMD_DEMO demo for colamd, column approx minimum degree ordering algorithm
+%
+% Example:
+%   colamd_demo
+% 
+% The following m-files and mexFunctions provide alternative sparse matrix
+% ordering methods for MATLAB.  They are typically faster (sometimes much
+% faster) and typically provide better orderings than their MATLAB counterparts:
+% 
+%	colamd		a replacement for colmmd.
+%
+%			Typical usage:  p = colamd (A) ;
+%
+%	symamd		a replacement for symmmd.  Based on colamd.
+%
+%			Typical usage:  p = symamd (A) ;
+%
+% For a description of the methods used, see the colamd.c file.
+%
+% http://www.cise.ufl.edu/research/sparse/colamd/
+%
+% See also colamd, symamd
+
+% Minor changes:  in MATLAB 7, symmmd and colmmd are flagged as "obsolete".
+% This demo checks if they exist, so it should still work when they are removed.
+
+% Copyright 2006, Timothy A. Davis, University of Florida
+
+%-------------------------------------------------------------------------------
+% Print the introduction, the help info, and compile the mexFunctions
+%-------------------------------------------------------------------------------
+
+fprintf (1, '\n-----------------------------------------------------------\n') ;
+fprintf (1, 'Colamd2/symamd2 demo.') ;
+fprintf (1, '\n-----------------------------------------------------------\n') ;
+help colamd_demo ;
+
+fprintf (1, '\n-----------------------------------------------------------\n') ;
+fprintf (1, 'Colamd help information:') ;
+fprintf (1, '\n-----------------------------------------------------------\n') ;
+help colamd2 ;
+
+fprintf (1, '\n-----------------------------------------------------------\n') ;
+fprintf (1, 'Symamd help information:') ;
+fprintf (1, '\n-----------------------------------------------------------\n') ;
+help symamd2 ;
+
+%-------------------------------------------------------------------------------
+% Solving Ax=b
+%-------------------------------------------------------------------------------
+
+n = 100 ;
+fprintf (1, '\n-----------------------------------------------------------\n') ;
+fprintf (1, 'Solving Ax=b for a small %d-by-%d random matrix:', n, n) ;
+fprintf (1, '\n-----------------------------------------------------------\n') ;
+fprintf (1, '\nNote: Random sparse matrices are AWFUL test cases.\n') ;
+fprintf (1, 'They''re just easy to generate in a demo.\n') ;
+
+% set up the system
+
+rand ('state', 0) ;
+randn ('state', 0) ;
+spparms ('default') ;
+A = sprandn (n, n, 5/n) + speye (n) ;
+b = (1:n)' ;
+
+fprintf (1, '\n\nSolving via lu (PAQ = LU), where Q is from colamd2:\n') ;
+q = colamd2 (A) ;
+I = speye (n) ;
+Q = I (:, q) ;
+[L,U,P] = lu (A*Q) ;
+fl = luflops (L, U) ;
+x = Q * (U \ (L \ (P * b))) ;
+fprintf (1, '\nFlop count for [L,U,P] = lu (A*Q):          %d\n', fl) ;
+fprintf (1, 'residual:                                     %e\n', norm (A*x-b));
+
+try
+    fprintf (1, '\n\nSolving via lu (PAQ = LU), where Q is from colmmd:\n') ;
+    q = colmmd (A) ;
+    I = speye (n) ;
+    Q = I (:, q) ;
+    [L,U,P] = lu (A*Q) ;
+    fl = luflops (L, U) ;
+    x = Q * (U \ (L \ (P * b))) ;
+    fprintf (1, '\nFlop count for [L,U,P] = lu (A*Q):          %d\n', fl) ;
+    fprintf (1, 'residual:                                     %e\n', ...
+	norm (A*x-b)) ;
+catch
+    fprintf (1, 'colmmd is obsolete\n') ;
+end
+
+fprintf (1, '\n\nSolving via lu (PA = LU), without regard for sparsity:\n') ;
+[L,U,P] = lu (A) ;
+fl = luflops (L, U) ;
+x = U \ (L \ (P * b)) ;
+fprintf (1, '\nFlop count for [L,U,P] = lu (A*Q):          %d\n', fl) ;
+fprintf (1, 'residual:                                     %e\n', norm (A*x-b));
+
+%-------------------------------------------------------------------------------
+% Large demo for colamd2
+%-------------------------------------------------------------------------------
+
+fprintf (1, '\n-----------------------------------------------------------\n') ;
+fprintf (1, 'Large demo for colamd2 (symbolic analysis only):') ;
+fprintf (1, '\n-----------------------------------------------------------\n') ;
+
+rand ('state', 0) ;
+randn ('state', 0) ;
+spparms ('default') ;
+n = 1000 ;
+fprintf (1, 'Generating a random %d-by-%d sparse matrix.\n', n, n) ;
+A = sprandn (n, n, 5/n) + speye (n) ;
+
+fprintf (1, '\n\nUnordered matrix:\n') ;
+lnz = symbfact (A, 'col') ;
+fprintf (1, 'nz in Cholesky factors of A''A:            %d\n', sum (lnz)) ;
+fprintf (1, 'flop count for Cholesky of A''A:           %d\n', sum (lnz.^2)) ;
+
+tic ;
+p = colamd2 (A) ;
+t = toc ;
+lnz = symbfact (A (:,p), 'col') ;
+fprintf (1, '\n\nColamd run time:                          %f\n', t) ;
+fprintf (1, 'colamd2 ordering quality: \n') ;
+fprintf (1, 'nz in Cholesky factors of A(:,p)''A(:,p):  %d\n', sum (lnz)) ;
+fprintf (1, 'flop count for Cholesky of A(:,p)''A(:,p): %d\n', sum (lnz.^2)) ;
+
+try
+    tic ;
+    p = colmmd (A) ;
+    t = toc ;
+    lnz = symbfact (A (:,p), 'col') ;
+    fprintf (1, '\n\nColmmd run time:                          %f\n', t) ;
+    fprintf (1, 'colmmd ordering quality: \n') ;
+    fprintf (1, 'nz in Cholesky factors of A(:,p)''A(:,p):  %d\n', sum (lnz)) ;
+    fprintf (1, 'flop count for Cholesky of A(:,p)''A(:,p): %d\n', ...
+	sum (lnz.^2)) ;
+catch
+    fprintf (1, 'colmmd is obsolete\n') ;
+end
+
+%-------------------------------------------------------------------------------
+% Large demo for symamd2
+%-------------------------------------------------------------------------------
+
+fprintf (1, '\n-----------------------------------------------------------\n') ;
+fprintf (1, 'Large demo for symamd2 (symbolic analysis only):') ;
+fprintf (1, '\n-----------------------------------------------------------\n') ;
+
+fprintf (1, 'Generating a random symmetric %d-by-%d sparse matrix.\n', n, n) ;
+A = A+A' ;
+
+fprintf (1, '\n\nUnordered matrix:\n') ;
+lnz = symbfact (A, 'sym') ;
+fprintf (1, 'nz in Cholesky factors of A:       %d\n', sum (lnz)) ;
+fprintf (1, 'flop count for Cholesky of A:      %d\n', sum (lnz.^2)) ;
+
+tic ;
+p = symamd2 (A) ;
+t = toc ;
+lnz = symbfact (A (p,p), 'sym') ;
+fprintf (1, '\n\nSymamd run time:                   %f\n', t) ;
+fprintf (1, 'symamd2 ordering quality: \n') ;
+fprintf (1, 'nz in Cholesky factors of A(p,p):  %d\n', sum (lnz)) ;
+fprintf (1, 'flop count for Cholesky of A(p,p): %d\n', sum (lnz.^2)) ;
+
+try
+    tic ;
+    p = symmmd (A) ;
+    t = toc ;
+    lnz = symbfact (A (p,p), 'sym') ;
+    fprintf (1, '\n\nSymmmd run time:                   %f\n', t) ;
+    fprintf (1, 'symmmd ordering quality: \n') ;
+    fprintf (1, 'nz in Cholesky factors of A(p,p):  %d\n', sum (lnz)) ;
+    fprintf (1, 'flop count for Cholesky of A(p,p): %d\n', sum (lnz.^2)) ;
+catch
+    fprintf (1, 'symmmd is obsolete\n') ;
+end
diff --git a/src/C/SuiteSparse/COLAMD/colamd_example.c b/src/C/SuiteSparse/COLAMD/colamd_example.c
new file mode 100644
index 0000000..fe824d8
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/colamd_example.c
@@ -0,0 +1,181 @@
+/* ========================================================================== */
+/* === colamd and symamd example ============================================ */
+/* ========================================================================== */
+
+/* COLAMD / SYMAMD example
+
+    colamd example of use, to order the columns of a 5-by-4 matrix with
+    11 nonzero entries in the following nonzero pattern, with default knobs.
+
+       x 0 x 0
+       x 0 x x
+       0 x x 0
+       0 0 x x
+       x x 0 0
+
+    symamd example of use, to order the rows and columns of a 5-by-5
+    matrix with 13 nonzero entries in the following nonzero pattern,
+    with default knobs.
+
+       x x 0 0 0
+       x x x x 0
+       0 x x 0 0
+       0 x 0 x x
+       0 0 0 x x
+
+    (where x denotes a nonzero value).
+
+    See http://www.cise.ufl.edu/research/sparse/colamd/ (the colamd.c file)
+    for the routines this program calls, and for the License.
+*/
+
+/* ========================================================================== */
+
+#include <stdio.h>
+#include "colamd.h"
+
+#define A_NNZ 11
+#define A_NROW 5
+#define A_NCOL 4
+#define ALEN 150
+
+#define B_NNZ 4
+#define B_N 5
+
+int main (void)
+{
+
+    /* ====================================================================== */
+    /* input matrix A definition */
+    /* ====================================================================== */
+
+    int A [ALEN] = {
+
+    	0, 1, 4,		/* row indices of nonzeros in column 0 */
+	2, 4,			/* row indices of nonzeros in column 1 */
+	0, 1, 2, 3,		/* row indices of nonzeros in column 2 */
+	1, 3} ;			/* row indices of nonzeros in column 3 */
+
+    int p [ ] = {
+
+    	0,			/* column 0 is in A [0..2] */
+	3,			/* column 1 is in A [3..4] */ 
+	5,			/* column 2 is in A [5..8] */
+	9,			/* column 3 is in A [9..10] */
+	A_NNZ} ;		/* number of nonzeros in A */
+
+    /* ====================================================================== */
+    /* input matrix B definition */
+    /* ====================================================================== */
+
+    int B [ ] = {		/* Note: only strictly lower triangular part */
+    				/* is included, since symamd ignores the */
+				/* diagonal and upper triangular part of B. */
+
+    	1,			/* row indices of nonzeros in column 0 */
+    	2, 3,			/* row indices of nonzeros in column 1 */
+    				/* row indices of nonzeros in column 2 (none) */
+    	4			/* row indices of nonzeros in column 3 */
+    	} ;			/* row indices of nonzeros in column 4 (none) */
+
+    int q [ ] = {
+
+    	0,			/* column 0 is in B [0] */
+	1,			/* column 1 is in B [1..2] */ 
+	3,			/* column 2 is empty */
+	3,			/* column 3 is in B [3] */
+	4,			/* column 4 is empty */
+	B_NNZ} ;		/* number of nonzeros in strictly lower B */
+
+    /* ====================================================================== */
+    /* other variable definitions */
+    /* ====================================================================== */
+
+    int perm [B_N+1] ;		/* note the size is N+1 */
+    int stats [COLAMD_STATS] ;	/* for colamd and symamd output statistics */
+
+    int row, col, pp, length, ok ;
+
+    /* ====================================================================== */
+    /* dump the input matrix A */
+    /* ====================================================================== */
+
+    printf ("colamd %d-by-%d input matrix:\n", A_NROW, A_NCOL) ;
+    for (col = 0 ; col < A_NCOL ; col++)
+    {
+	length = p [col+1] - p [col] ;
+    	printf ("Column %d, with %d entries:\n", col, length) ;
+	for (pp = p [col] ; pp < p [col+1] ; pp++)
+	{
+	    row = A [pp] ;
+	    printf ("    row %d\n", row) ;
+	}
+    }
+
+    /* ====================================================================== */
+    /* order the matrix.  Note that this destroys A and overwrites p */
+    /* ====================================================================== */
+
+    ok = colamd (A_NROW, A_NCOL, ALEN, A, p, (double *) NULL, stats) ;
+    colamd_report (stats) ;
+
+    if (!ok)
+    {
+	printf ("colamd error!\n") ;
+	exit (1) ;
+    }
+
+    /* ====================================================================== */
+    /* print the column ordering */
+    /* ====================================================================== */
+
+    printf ("colamd column ordering:\n") ;
+    printf ("1st column: %d\n", p [0]) ;
+    printf ("2nd column: %d\n", p [1]) ;
+    printf ("3rd column: %d\n", p [2]) ;
+    printf ("4th column: %d\n", p [3]) ;
+
+    /* ====================================================================== */
+    /* dump the strictly lower triangular part of symmetric input matrix B */
+    /* ====================================================================== */
+
+    printf ("\n\nsymamd %d-by-%d input matrix:\n", B_N, B_N) ;
+    printf ("Entries in strictly lower triangular part:\n") ;
+    for (col = 0 ; col < B_N ; col++)
+    {
+	length = q [col+1] - q [col] ;
+    	printf ("Column %d, with %d entries:\n", col, length) ;
+	for (pp = q [col] ; pp < q [col+1] ; pp++)
+	{
+	    row = B [pp] ;
+	    printf ("    row %d\n", row) ;
+	}
+    }
+
+    /* ====================================================================== */
+    /* order the matrix B.  Note that this does not modify B or q. */
+    /* ====================================================================== */
+
+    ok = symamd (B_N, B, q, perm, (double *) NULL, stats, &calloc, &free) ;
+    symamd_report (stats) ;
+
+    if (!ok)
+    {
+	printf ("symamd error!\n") ;
+	exit (1) ;
+    }
+
+    /* ====================================================================== */
+    /* print the symmetric ordering */
+    /* ====================================================================== */
+
+    printf ("symamd column ordering:\n") ;
+    printf ("1st row/column: %d\n", perm [0]) ;
+    printf ("2nd row/column: %d\n", perm [1]) ;
+    printf ("3rd row/column: %d\n", perm [2]) ;
+    printf ("4th row/column: %d\n", perm [3]) ;
+    printf ("5th row/column: %d\n", perm [4]) ;
+
+    exit (0) ;
+}
+
diff --git a/src/C/SuiteSparse/COLAMD/colamd_example.out b/src/C/SuiteSparse/COLAMD/colamd_example.out
new file mode 100644
index 0000000..45377ca
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/colamd_example.out
@@ -0,0 +1,50 @@
+colamd 5-by-4 input matrix:
+Column 0, with 3 entries:
+    row 0
+    row 1
+    row 4
+Column 1, with 2 entries:
+    row 2
+    row 4
+Column 2, with 4 entries:
+    row 0
+    row 1
+    row 2
+    row 3
+Column 3, with 2 entries:
+    row 1
+    row 3
+
+colamd version 2.6, Dec 12, 2006: OK.  
+colamd: number of dense or empty rows ignored:           0
+colamd: number of dense or empty columns ignored:        0
+colamd: number of garbage collections performed:         0
+colamd column ordering:
+1st column: 1
+2nd column: 0
+3rd column: 2
+4th column: 3
+
+
+symamd 5-by-5 input matrix:
+Entries in strictly lower triangular part:
+Column 0, with 1 entries:
+    row 1
+Column 1, with 2 entries:
+    row 2
+    row 3
+Column 2, with 0 entries:
+Column 3, with 1 entries:
+    row 4
+Column 4, with 0 entries:
+
+symamd version 2.6, Dec 12, 2006: OK.  
+symamd: number of dense or empty rows ignored:           0
+symamd: number of dense or empty columns ignored:        0
+symamd: number of garbage collections performed:         0
+symamd column ordering:
+1st row/column: 0
+2nd row/column: 2
+3rd row/column: 1
+4th row/column: 3
+5th row/column: 4
diff --git a/src/C/SuiteSparse/COLAMD/colamd_global.c b/src/C/SuiteSparse/COLAMD/colamd_global.c
new file mode 100644
index 0000000..6c9dfde
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/colamd_global.c
@@ -0,0 +1,24 @@
+/* ========================================================================== */
+/* === colamd_global.c ====================================================== */
+/* ========================================================================== */
+
+/* ----------------------------------------------------------------------------
+ * COLAMD, Copyright (C) 2006, Timothy A. Davis.
+ * See License.txt for the Version 2.1 of the GNU Lesser General Public License
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Global variables for COLAMD */
+
+#ifndef NPRINT
+#ifdef MATLAB_MEX_FILE
+#include "mex.h"
+int (*colamd_printf) (const char *, ...) = mexPrintf ;
+#else
+#include <stdio.h>
+int (*colamd_printf) (const char *, ...) = printf ;
+#endif
+#else
+int (*colamd_printf) (const char *, ...) = ((void *) 0) ;
+#endif
+
diff --git a/src/C/SuiteSparse/COLAMD/colamd_l_example.c b/src/C/SuiteSparse/COLAMD/colamd_l_example.c
new file mode 100644
index 0000000..9ff9aeb
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/colamd_l_example.c
@@ -0,0 +1,185 @@
+/* ========================================================================== */
+/* === colamd and symamd example ============================================ */
+/* ========================================================================== */
+
+/* COLAMD / SYMAMD example
+
+    colamd example of use, to order the columns of a 5-by-4 matrix with
+    11 nonzero entries in the following nonzero pattern, with default knobs.
+
+       x 0 x 0
+       x 0 x x
+       0 x x 0
+       0 0 x x
+       x x 0 0
+
+    symamd example of use, to order the rows and columns of a 5-by-5
+    matrix with 13 nonzero entries in the following nonzero pattern,
+    with default knobs.
+
+       x x 0 0 0
+       x x x x 0
+       0 x x 0 0
+       0 x 0 x x
+       0 0 0 x x
+
+    (where x denotes a nonzero value).
+
+
+    See http://www.cise.ufl.edu/research/sparse/colamd/ (the colamd.c file)
+    for the routines this program calls, and for the License.
+*/
+
+/* ========================================================================== */
+
+#include <stdio.h>
+#include "colamd.h"
+
+#define A_NNZ 11
+#define A_NROW 5
+#define A_NCOL 4
+#define ALEN 150
+
+#define B_NNZ 4
+#define B_N 5
+
+/* define UF_long */
+#include "UFconfig.h"
+
+int main (void)
+{
+
+    /* ====================================================================== */
+    /* input matrix A definition */
+    /* ====================================================================== */
+
+    UF_long A [ALEN] = {
+
+    	0, 1, 4,		/* row indices of nonzeros in column 0 */
+	2, 4,			/* row indices of nonzeros in column 1 */
+	0, 1, 2, 3,		/* row indices of nonzeros in column 2 */
+	1, 3} ;			/* row indices of nonzeros in column 3 */
+
+    UF_long p [ ] = {
+
+    	0,			/* column 0 is in A [0..2] */
+	3,			/* column 1 is in A [3..4] */ 
+	5,			/* column 2 is in A [5..8] */
+	9,			/* column 3 is in A [9..10] */
+	A_NNZ} ;		/* number of nonzeros in A */
+
+    /* ====================================================================== */
+    /* input matrix B definition */
+    /* ====================================================================== */
+
+    UF_long B [ ] = {		/* Note: only strictly lower triangular part */
+    				/* is included, since symamd ignores the */
+				/* diagonal and upper triangular part of B. */
+
+    	1,			/* row indices of nonzeros in column 0 */
+    	2, 3,			/* row indices of nonzeros in column 1 */
+    				/* row indices of nonzeros in column 2 (none) */
+    	4			/* row indices of nonzeros in column 3 */
+    	} ;			/* row indices of nonzeros in column 4 (none) */
+
+    UF_long q [ ] = {
+
+    	0,			/* column 0 is in B [0] */
+	1,			/* column 1 is in B [1..2] */ 
+	3,			/* column 2 is empty */
+	3,			/* column 3 is in B [3] */
+	4,			/* column 4 is empty */
+	B_NNZ} ;		/* number of nonzeros in strictly lower B */
+
+    /* ====================================================================== */
+    /* other variable definitions */
+    /* ====================================================================== */
+
+    UF_long perm [B_N+1] ;	/* note the size is N+1 */
+    UF_long stats [COLAMD_STATS] ;/* for colamd and symamd output statistics */
+
+    UF_long row, col, pp, length, ok ;
+
+    /* ====================================================================== */
+    /* dump the input matrix A */
+    /* ====================================================================== */
+
+    printf ("colamd %d-by-%d input matrix:\n", A_NROW, A_NCOL) ;
+    for (col = 0 ; col < A_NCOL ; col++)
+    {
+	length = p [col+1] - p [col] ;
+    	printf ("Column %ld, with %ld entries:\n", col, length) ;
+	for (pp = p [col] ; pp < p [col+1] ; pp++)
+	{
+	    row = A [pp] ;
+	    printf ("    row %ld\n", row) ;
+	}
+    }
+
+    /* ====================================================================== */
+    /* order the matrix.  Note that this destroys A and overwrites p */
+    /* ====================================================================== */
+
+    ok = colamd_l (A_NROW, A_NCOL, ALEN, A, p, (double *) NULL, stats) ;
+    colamd_l_report (stats) ;
+
+    if (!ok)
+    {
+	printf ("colamd error!\n") ;
+	exit (1) ;
+    }
+
+    /* ====================================================================== */
+    /* print the column ordering */
+    /* ====================================================================== */
+
+    printf ("colamd_l column ordering:\n") ;
+    printf ("1st column: %ld\n", p [0]) ;
+    printf ("2nd column: %ld\n", p [1]) ;
+    printf ("3rd column: %ld\n", p [2]) ;
+    printf ("4th column: %ld\n", p [3]) ;
+
+    /* ====================================================================== */
+    /* dump the strictly lower triangular part of symmetric input matrix B */
+    /* ====================================================================== */
+
+    printf ("\n\nsymamd_l %d-by-%d input matrix:\n", B_N, B_N) ;
+    printf ("Entries in strictly lower triangular part:\n") ;
+    for (col = 0 ; col < B_N ; col++)
+    {
+	length = q [col+1] - q [col] ;
+    	printf ("Column %ld, with %ld entries:\n", col, length) ;
+	for (pp = q [col] ; pp < q [col+1] ; pp++)
+	{
+	    row = B [pp] ;
+	    printf ("    row %ld\n", row) ;
+	}
+    }
+
+    /* ====================================================================== */
+    /* order the matrix B.  Note that this does not modify B or q. */
+    /* ====================================================================== */
+
+    ok = symamd_l (B_N, B, q, perm, (double *) NULL, stats, &calloc, &free) ;
+    symamd_l_report (stats) ;
+
+    if (!ok)
+    {
+	printf ("symamd error!\n") ;
+	exit (1) ;
+    }
+
+    /* ====================================================================== */
+    /* print the symmetric ordering */
+    /* ====================================================================== */
+
+    printf ("symamd_l column ordering:\n") ;
+    printf ("1st row/column: %ld\n", perm [0]) ;
+    printf ("2nd row/column: %ld\n", perm [1]) ;
+    printf ("3rd row/column: %ld\n", perm [2]) ;
+    printf ("4th row/column: %ld\n", perm [3]) ;
+    printf ("5th row/column: %ld\n", perm [4]) ;
+
+    exit (0) ;
+}
+
diff --git a/src/C/SuiteSparse/COLAMD/colamd_l_example.out b/src/C/SuiteSparse/COLAMD/colamd_l_example.out
new file mode 100644
index 0000000..f088b27
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/colamd_l_example.out
@@ -0,0 +1,50 @@
+colamd 5-by-4 input matrix:
+Column 0, with 3 entries:
+    row 0
+    row 1
+    row 4
+Column 1, with 2 entries:
+    row 2
+    row 4
+Column 2, with 4 entries:
+    row 0
+    row 1
+    row 2
+    row 3
+Column 3, with 2 entries:
+    row 1
+    row 3
+
+colamd version 2.6, Dec 12, 2006: OK.  
+colamd: number of dense or empty rows ignored:           0
+colamd: number of dense or empty columns ignored:        0
+colamd: number of garbage collections performed:         0
+colamd_l column ordering:
+1st column: 1
+2nd column: 0
+3rd column: 2
+4th column: 3
+
+
+symamd_l 5-by-5 input matrix:
+Entries in strictly lower triangular part:
+Column 0, with 1 entries:
+    row 1
+Column 1, with 2 entries:
+    row 2
+    row 3
+Column 2, with 0 entries:
+Column 3, with 1 entries:
+    row 4
+Column 4, with 0 entries:
+
+symamd version 2.6, Dec 12, 2006: OK.  
+symamd: number of dense or empty rows ignored:           0
+symamd: number of dense or empty columns ignored:        0
+symamd: number of garbage collections performed:         0
+symamd_l column ordering:
+1st row/column: 0
+2nd row/column: 2
+3rd row/column: 1
+4th row/column: 3
+5th row/column: 4
diff --git a/src/C/SuiteSparse/COLAMD/colamd_make.m b/src/C/SuiteSparse/COLAMD/colamd_make.m
new file mode 100644
index 0000000..48d8b98
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/colamd_make.m
@@ -0,0 +1,18 @@
+function colamd_make
+%COLAMD_MAKE compiles COLAMD2 and SYMAMD2 for MATLAB
+%
+% Example:
+%   colamd_make
+%
+% See also colamd, symamd
+
+% Copyright 2006, Timothy A. Davis, University of Florida
+
+
+if (~isempty (strfind (computer, '64')))
+    error ('64-bit version not yet supported') ;
+end
+
+mex -output colamd2mex -O -I../UFconfig colamdmex.c colamd.c colamd_global.c
+mex -output symamd2mex -O -I../UFconfig symamdmex.c colamd.c colamd_global.c
+fprintf ('COLAMD2 and SYMAMD2 successfully compiled.\n') ;
diff --git a/src/C/SuiteSparse/COLAMD/colamd_test.m b/src/C/SuiteSparse/COLAMD/colamd_test.m
new file mode 100644
index 0000000..cd909b6
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/colamd_test.m
@@ -0,0 +1,507 @@
+function colamd_test
+%COLAMD_TEST test colamd2 and symamd2
+% Example:
+%   colamd_test
+%
+% COLAMD and SYMAMD testing function.  Here we try to give colamd2 and symamd2
+% every possible type of matrix and erroneous input that they may encounter. 
+% We want either a valid permutation returned or we want them to fail
+% gracefully.
+%
+% You are prompted as to whether or not the colamd2 and symand routines and
+% the test mexFunctions are to be compiled.
+%
+% See also colamd2, symamd2
+%
+% Tim Davis
+% http://www.cise.ufl.edu/research/sparse/colamd/
+
+% Copyright 2006, Timothy A. Davis, University of Florida
+
+
+help colamd_test
+
+s = input (...
+'Compile colamd2, symand, and the test codes? (y/n, default is yes): ', 's') ;
+
+do_compile = 1 ;
+if (~isempty (s))
+    if (s (1) == 'n' || s (1) == 'N')
+	do_compile = 0 ;
+    end
+end
+
+if (do_compile)
+    fprintf ('Compiling colamd2, symamd2, and test mexFunctions.\n') ;
+    colamd_make ;
+    cmd = 'mex -O -I../UFconfig colamdtestmex.c colamd.c colamd_global.c' ;
+    fprintf ('%s\n', cmd) ;
+    eval (cmd) ;
+    cmd = 'mex -O -I../UFconfig symamdtestmex.c colamd.c colamd_global.c' ;
+    fprintf ('%s\n', cmd) ;
+    eval (cmd) ;
+    fprintf ('Done compiling.\n') ; 
+end
+
+fprintf ('\nThe following codes will be tested:\n') ;
+which colamd2 
+which symamd2
+which colamdmex
+which symamdmex
+
+fprintf ('\nStarting the tests.  Please be patient.\n') ;
+
+rand ('state', 0) ;
+randn ('state', 0) ;
+
+A = sprandn (500,500,0.4) ;
+
+p = colamd2 (A, [10 10 1]) ; check_perm (p, A) ;
+p = colamd2 (A, [2  7  1]) ; check_perm (p, A) ;
+p = symamd2 (A, [10 1]) ; check_perm (p, A) ;
+p = symamd2 (A, [7  1]) ; check_perm (p, A) ;
+p = symamd2 (A, [4  1]) ; check_perm (p, A) ;
+
+
+fprintf ('Null matrices') ;
+A = zeros (0,0) ;
+A = sparse (A) ;
+
+[p, stats] = colamd2 (A, [10 10 0]) ;					    %#ok
+check_perm (p, A) ;
+
+[p, stats] = symamd2 (A, [10 0]) ;					    %#ok
+check_perm (p, A) ;
+
+A = zeros (0, 100) ;
+A = sparse (A) ;
+[p, stats] = colamd2 (A, [10 10 0]) ;					    %#ok
+check_perm (p, A) ;
+
+A = zeros (100, 0) ;
+A = sparse (A) ;
+[p, stats] = colamd2 (A, [10 10 0]) ;
+check_perm (p, A) ;
+fprintf (' OK\n') ;
+
+
+fprintf ('Matrices with a few dense row/cols\n') ;
+
+for trial = 1:20
+
+    % random square unsymmetric matrix
+    A = rand_matrix (1000, 1000, 1, 10, 20) ;
+
+    for tol = [0:.1:2 3:20 1e6]
+
+	[p, stats] = colamd2 (A, [tol tol 0]) ;				    %#ok
+	check_perm (p, A) ;
+
+	B = A + A' ;
+	[p, stats] = symamd2 (B, [tol 0]) ;				    %#ok
+	check_perm (p, A) ;
+
+	[p, stats] = colamd2 (A, [tol 1 0]) ;				    %#ok
+	check_perm (p, A) ;
+
+	[p, stats] = colamd2 (A, [1 tol 0]) ;				    %#ok
+	check_perm (p, A) ;
+
+	fprintf ('.') ;
+
+    end
+end
+fprintf (' OK\n') ;
+
+fprintf ('General matrices\n') ;
+for trial = 1:400
+
+    % matrix of random mtype
+    mtype = irand (3) ;
+    A = rand_matrix (2000, 2000, mtype, 0, 0) ;
+    p = colamd2 (A) ;
+    check_perm (p, A) ;
+    if (mtype == 3)
+	p = symamd2 (A) ;
+	check_perm (p, A) ;
+    end
+
+    fprintf ('.') ;
+end
+fprintf (' OK\n') ;
+
+fprintf ('Test error handling with invalid inputs\n') ;
+
+% Check different erroneous input.
+for trial = 1:30
+
+    A = rand_matrix (1000, 1000, 2, 0, 0) ;
+    [m n] = size (A) ;
+
+    for err = 1:13
+
+        p = Tcolamd (A, [n n 0 0 err]) ;
+        if (p ~= -1)							    %#ok
+	    check_perm (p, A) ;
+	end
+
+	if (err == 1)
+	    % check different (valid) input args to colamd2
+	    p = Acolamd (A) ;
+
+	    p2 = Acolamd (A, [10 10 0 0 0]) ;
+	    if (any (p ~= p2))
+		error ('colamd2: mismatch 1!') ;
+	    end
+	    [p2 stats] = Acolamd (A) ;					    %#ok
+	    if (any (p ~= p2))
+		error ('colamd2: mismatch 2!') ;
+	    end
+	    [p2 stats] = Acolamd (A, [10 10 0 0 0]) ;
+	    if (any (p ~= p2))
+		error ('colamd2: mismatch 3!') ;
+	    end
+	end
+
+	B = A'*A ;
+        p = Tsymamd (B, [n 0 err]) ;
+        if (p ~= -1)							    %#ok
+	    check_perm (p, A) ;
+	end
+
+	if (err == 1)
+
+	    % check different (valid) input args to symamd2
+	    p = Asymamd (B) ;
+	    check_perm (p, A) ;
+	    p2 = Asymamd (B, [10 0 0]) ;
+	    if (any (p ~= p2))
+		error ('symamd2: mismatch 1!') ;
+	    end
+	    [p2 stats] = Asymamd (B) ;					    %#ok
+	    if (any (p ~= p2))
+		error ('symamd2: mismatch 2!') ;
+	    end
+	    [p2 stats] = Asymamd (B, [10 0 0]) ;			    %#ok
+	    if (any (p ~= p2))
+		error ('symamd2: mismatch 3!') ;
+	    end
+	end
+
+	fprintf ('.') ;
+    end
+
+end
+fprintf (' OK\n') ;
+
+fprintf ('Matrices with a few empty columns\n') ;
+
+for trial = 1:400
+
+    % some are square, some are rectangular
+    n = 0 ;
+    while (n < 5)
+	A = rand_matrix (1000, 1000, irand (2), 0, 0) ;
+	[m n] = size (A) ;
+    end
+
+    % Add 5 null columns at random locations.
+    null_col = randperm (n) ;
+    null_col = sort (null_col (1:5)) ;
+    A (:, null_col) = 0 ;
+
+    % Order the matrix and make sure that the null columns are ordered last.
+    [p, stats] = colamd2 (A, [1e6 1e6 0]) ;
+    check_perm (p, A) ;
+
+%    if (stats (2) ~= 5)
+%	stats (2)
+%	error ('colamd2: wrong number of null columns') ;
+%    end
+
+    % find all null columns in A
+    null_col = find (sum (spones (A), 1) == 0) ;
+    nnull = length (null_col) ;						    %#ok
+    if (any (null_col ~= p ((n-4):n)))
+	error ('colamd2: Null cols are not ordered last in natural order') ;
+    end
+
+    fprintf ('.') ;
+
+end
+fprintf (' OK\n') ;
+
+fprintf ('Matrices with a few empty rows and columns\n') ;
+
+for trial = 1:400
+
+    % symmetric matrices
+    n = 0 ;
+    while (n < 5)
+	A = rand_matrix (1000, 1000, 3, 0, 0) ;
+	[m n] = size (A) ;
+    end
+
+    % Add 5 null columns and rows at random locations.
+    null_col = randperm (n) ;
+    null_col = sort (null_col (1:5)) ;
+    A (:, null_col) = 0 ;
+    A (null_col, :) = 0 ;
+
+    % Order the matrix and make sure that the null rows/cols are ordered last.
+    [p,stats] = symamd2 (A, [10 0]) ;
+    check_perm (p, A) ;
+
+    % find actual number of null rows and columns
+    Alo = tril (A, -1) ;
+    nnull = length (find (sum (Alo') == 0 & sum (Alo) == 0)) ;		    %#ok
+
+    if (stats (2) ~= nnull || nnull < 5)
+	error ('symamd2: wrong number of null columns') ;
+    end
+    if (any (null_col ~= p ((n-4):n)))
+	error ('symamd2: Null cols are not ordered last in natural order') ;
+    end
+
+    fprintf ('.') ;
+
+end
+fprintf (' OK\n') ;
+
+fprintf ('Matrices with a few empty rows\n') ;
+
+% Test matrices with null rows inserted.
+
+for trial = 1:400
+
+    m = 0 ;
+    while (m < 5)
+	A = rand_matrix (1000, 1000, 2, 0, 0) ;
+	[m n] = size (A) ;						    %#ok
+    end
+
+    % Add 5 null rows at random locations.
+    null_row = randperm (m) ;
+    null_row = sort (null_row (1:5)) ;
+    A (null_row, :) = 0 ;
+
+    p = colamd2 (A, [10 10 0]) ;
+    check_perm (p, A) ;
+    if (stats (1) ~= 5)
+	error ('colamd2: wrong number of null rows') ;
+    end
+    fprintf ('.') ;
+end
+fprintf (' OK\n') ;
+
+
+fprintf ('\ncolamd and symamd2:  all tests passed\n\n') ;
+
+%-------------------------------------------------------------------------------
+
+function [p,stats] = Acolamd (S, knobs)
+% Acolamd:  compare colamd2 and Tcolamd results
+
+if (nargin < 3)
+    if (nargout == 1)
+	[p] = colamd2 (S) ;
+	[p1] = Tcolamd (S, [10 10 0 0 0]) ;
+    else
+	[p, stats] = colamd2 (S) ;
+	[p1, stats1] = Tcolamd (S, [10 10 0 0 0]) ;			    %#ok
+    end
+else
+    if (nargout == 1)
+	[p] = colamd2 (S, knobs (1:3)) ;
+	[p1] = Tcolamd (S, knobs) ;
+    else
+	[p, stats] = colamd2 (S, knobs (1:3)) ;
+	[p1, stats1] = Tcolamd (S, knobs) ;			    %#ok
+    end
+end
+
+check_perm (p, S) ;
+check_perm (p1, S) ;
+
+if (any (p1 ~= p))
+    error ('Acolamd mismatch!') ;
+end
+
+
+%-------------------------------------------------------------------------------
+
+function [p,stats] = Asymamd (S, knobs)
+% Asymamd:  compare symamd2 and Tsymamd results
+
+if (nargin < 3)
+    if (nargout == 1)
+	[p] = symamd2 (S) ;
+	[p1] = Tsymamd (S, [10 0 0]) ;
+    else
+	[p, stats] = symamd2 (S) ;
+	[p1, stats1] = Tsymamd (S, [10 0 0]) ;				%#ok
+    end
+else
+    if (nargout == 1)
+	[p] = symamd2 (S, knobs (1:2)) ;
+	[p1] = Tsymamd (S, knobs) ;
+    else
+	[p, stats] = symamd2 (S, knobs (1:2)) ;
+	[p1, stats1] = Tsymamd (S, knobs) ;			    %#ok
+    end
+end
+
+if (any (p1 ~= p))
+    error ('Asymamd mismatch!') ;
+end
+
+
+%-------------------------------------------------------------------------------
+
+function check_perm (p, A)
+% check_perm:  check for a valid permutation vector
+
+if (isempty (A) && isempty (p))						    %#ok
+    % empty permutation vectors of empty matrices are OK
+    return
+end
+
+if (isempty (p))
+    error ('bad permutation: cannot be empty') ;
+end
+
+[m n] = size (A) ;
+[pm pn] = size (p) ;
+if (pn == 1)
+    % force p to be a row vector
+    p = p' ;
+    [pm pn] = size (p) ;
+end
+
+if (n ~= pn)
+    error ('bad permutation: wrong size') ;
+end
+
+if (pm ~= 1) ;
+    % p must be a vector
+    error ('bad permutation: not a vector') ;
+else
+    if (any (sort (p) - (1:pn)))
+	error ('bad permutation') ;
+    end
+end
+
+%-------------------------------------------------------------------------------
+
+function i = irand (n)
+% irand: return a random integer between 1 and n
+i = min (n, 1 + floor (rand * n)) ;
+
+%-------------------------------------------------------------------------------
+
+function A = rand_matrix (nmax, mmax, mtype, drows, dcols)
+% rand_matrix:  return a random sparse matrix
+%
+% A = rand_matrix (nmax, mmax, mtype, drows, dcols)
+%
+% A binary matrix of random size, at most nmax-by-mmax, with drows dense rows
+% and dcols dense columns.
+%
+% mtype 1: square unsymmetric (mmax is ignored)
+% mtype 2: rectangular
+% mtype 3: symmetric (mmax is ignored)
+
+n = irand (nmax) ;
+if (mtype ~= 2)
+    % square
+    m = n ;
+else
+    m = irand (mmax) ;
+end
+
+A = sprand (m, n, 10 / max (m,n)) ;
+
+if (drows > 0)
+    % add dense rows
+    for k = 1:drows
+	i = irand (m) ;
+	nz = irand (n) ;
+	p = randperm (n) ;
+	p = p (1:nz) ;
+	A (i,p) = 1 ;
+    end
+end
+
+if (dcols > 0)
+    % add dense cols
+    for k = 1:dcols
+	j = irand (n) ;
+	nz = irand (m) ;
+	p = randperm (m) ;
+	p = p (1:nz) ;
+	A (p,j) = 1 ;
+    end
+end
+
+A = spones (A) ;
+
+% ensure that there are no empty columns
+d = find (full (sum (A)) == 0) ;					    %#ok
+A (m,d) = 1 ;								    %#ok
+
+% ensure that there are no empty rows
+d = find (full (sum (A,2)) == 0) ;					    %#ok
+A (d,n) = 1 ;								    %#ok
+
+if (mtype == 3)
+    % symmetric
+    A = A + A' + speye (n) ;
+end
+
+A = spones (A) ;
+
+%-------------------------------------------------------------------------------
+
+function [p,stats] = Tcolamd (S, knobs)
+% Tcolamd:  run colamd2 in a testing mode
+
+if (nargout <= 1 && nargin == 1)
+    p = colamdtestmex (S) ;
+elseif (nargout <= 1 && nargin == 2)
+    p = colamdtestmex (S, knobs) ;
+elseif (nargout == 2 && nargin == 1)
+    [p, stats] = colamdtestmex (S) ;
+elseif (nargout == 2 && nargin == 2)
+    [p, stats] = colamdtestmex (S, knobs) ;
+else
+    error ('colamd2:  incorrect number of input and/or output arguments') ;
+end
+
+if (p (1) ~= -1)
+    [ignore, q] = etree (S (:,p), 'col') ;
+    p = p (q) ;
+    check_perm (p, S) ;
+end
+
+%-------------------------------------------------------------------------------
+
+function [p, stats] = Tsymamd (S, knobs)
+% Tsymamd: run symamd2 in a testing mode
+
+if (nargout <= 1 && nargin == 1)
+    p = symamdtestmex (S) ;
+elseif (nargout <= 1 && nargin == 2)
+    p = symamdtestmex (S, knobs) ;
+elseif (nargout == 2 && nargin == 1)
+    [p, stats] = symamdtestmex (S) ;
+elseif (nargout == 2 && nargin == 2)
+    [p, stats] = symamdtestmex (S, knobs) ;
+else
+    error ('symamd2:  incorrect number of input and/or output arguments') ;
+end
+
+if (p (1) ~= -1)
+    [ignore, q] = etree (S (p,p)) ;
+    p = p (q) ;
+    check_perm (p, S) ;
+end
diff --git a/src/C/SuiteSparse/COLAMD/colamdmex.c b/src/C/SuiteSparse/COLAMD/colamdmex.c
new file mode 100644
index 0000000..d5ae3fd
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/colamdmex.c
@@ -0,0 +1,219 @@
+/* ========================================================================== */
+/* === colamd mexFunction =================================================== */
+/* ========================================================================== */
+
+/* Usage:
+
+	P = colamd2 (A) ;
+	[ P, stats ] = colamd2 (A, knobs) ;
+
+    see colamd.m for a description.
+
+    Authors:
+
+	The authors of the code itself are Stefan I. Larimore and Timothy A.
+	Davis (davis at cise.ufl.edu), University of Florida.  The algorithm was
+	developed in collaboration with John Gilbert, Xerox PARC, and Esmond
+	Ng, Oak Ridge National Laboratory.
+
+    Acknowledgements:
+
+	This work was supported by the National Science Foundation, under
+	grants DMS-9504974 and DMS-9803599.
+
+    Notice:
+
+	Copyright (c) 1998-2006, Timothy A. Davis, All Rights Reserved.
+
+	See http://www.cise.ufl.edu/research/sparse/colamd (the colamd.c
+	file) for the License.
+
+    Availability:
+
+	The colamd/symamd library is available at
+
+	    http://www.cise.ufl.edu/research/sparse/colamd/
+
+	This is the http://www.cise.ufl.edu/research/sparse/colamd/colamdmex.c
+	file.  It requires the colamd.c and colamd.h files.
+
+*/
+
+/* ========================================================================== */
+/* === Include files ======================================================== */
+/* ========================================================================== */
+
+#include "colamd.h"
+#include "mex.h"
+#include "matrix.h"
+#include <stdlib.h>
+#include <string.h>
+
+/* ========================================================================== */
+/* === colamd mexFunction =================================================== */
+/* ========================================================================== */
+
+void mexFunction
+(
+    /* === Parameters ======================================================= */
+
+    int nlhs,			/* number of left-hand sides */
+    mxArray *plhs [],		/* left-hand side matrices */
+    int nrhs,			/* number of right--hand sides */
+    const mxArray *prhs []	/* right-hand side matrices */
+)
+{
+    /* === Local variables ================================================== */
+
+    int *A ;			/* colamd's copy of the matrix, and workspace */
+    int *p ;			/* colamd's copy of the column pointers */
+    int Alen ;			/* size of A */
+    int n_col ;			/* number of columns of A */
+    int n_row ;			/* number of rows of A */
+    int nnz ;			/* number of entries in A */
+    int full ;			/* TRUE if input matrix full, FALSE if sparse */
+    double knobs [COLAMD_KNOBS] ; /* colamd user-controllable parameters */
+    double *out_perm ;		/* output permutation vector */
+    double *out_stats ;		/* output stats vector */
+    double *in_knobs ;		/* input knobs vector */
+    int i ;			/* loop counter */
+    mxArray *Ainput ;		/* input matrix handle */
+    int spumoni ;		/* verbosity variable */
+    int stats [COLAMD_STATS] ;	/* stats for colamd */
+
+    colamd_printf = mexPrintf ;	/* COLAMD printf routine */
+
+    /* === Check inputs ===================================================== */
+
+    if (nrhs < 1 || nrhs > 2 || nlhs < 0 || nlhs > 2)
+    {
+	mexErrMsgTxt (
+	"colamd: incorrect number of input and/or output arguments") ;
+    }
+
+    /* === Get knobs ======================================================== */
+
+    colamd_set_defaults (knobs) ;
+    spumoni = 0 ;
+
+    /* check for user-passed knobs */
+    if (nrhs == 2)
+    {
+	in_knobs = mxGetPr (prhs [1]) ;
+	i = mxGetNumberOfElements (prhs [1]) ;
+	if (i > 0) knobs [COLAMD_DENSE_ROW] = in_knobs [0] ;
+	if (i > 1) knobs [COLAMD_DENSE_COL] = in_knobs [1] ;
+	if (i > 2) spumoni = (int) (in_knobs [2] != 0) ;
+    }
+
+    /* print knob settings if spumoni is set */
+    if (spumoni)
+    {
+	mexPrintf ("\ncolamd version %d.%d, %s:\n",
+	    COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE) ;
+	if (knobs [COLAMD_DENSE_ROW] >= 0)
+	{
+	    mexPrintf ("knobs(1): %g, rows with > max(16,%g*sqrt(size(A,2)))"
+		" entries removed\n", in_knobs [0], knobs [COLAMD_DENSE_ROW]) ;
+	}
+	else
+	{
+	    mexPrintf ("knobs(1): %g, only completely dense rows removed\n",
+		in_knobs [0]) ;
+	}
+	if (knobs [COLAMD_DENSE_COL] >= 0)
+	{
+	    mexPrintf ("knobs(2): %g, cols with > max(16,%g*sqrt(min(size(A)))"
+		" entries removed\n", in_knobs [1], knobs [COLAMD_DENSE_COL]) ;
+	}
+	else
+	{
+	    mexPrintf ("knobs(2): %g, only completely dense columns removed\n",
+		in_knobs [1]) ;
+	}
+	mexPrintf ("knobs(3): %g, statistics and knobs printed\n",
+	    in_knobs [2]) ;
+    }
+
+    /* === If A is full, convert to a sparse matrix ========================= */
+
+    Ainput = (mxArray *) prhs [0] ;
+    if (mxGetNumberOfDimensions (Ainput) != 2)
+    {
+	mexErrMsgTxt ("colamd: input matrix must be 2-dimensional") ;
+    }
+    full = !mxIsSparse (Ainput) ;
+    if (full)
+    {
+	mexCallMATLAB (1, &Ainput, 1, (mxArray **) prhs, "sparse") ;
+    }
+
+    /* === Allocate workspace for colamd ==================================== */
+
+    /* get size of matrix */
+    n_row = mxGetM (Ainput) ;
+    n_col = mxGetN (Ainput) ;
+
+    /* get column pointer vector so we can find nnz */
+    p = (int *) mxCalloc (n_col+1, sizeof (int)) ;
+    (void) memcpy (p, mxGetJc (Ainput), (n_col+1)*sizeof (int)) ;
+    nnz = p [n_col] ;
+    Alen = (int) colamd_recommended (nnz, n_row, n_col) ;
+    if (Alen == 0)
+    {
+    	mexErrMsgTxt ("colamd: problem too large") ;
+    }
+
+    /* === Copy input matrix into workspace ================================= */
+
+    A = (int *) mxCalloc (Alen, sizeof (int)) ;
+    (void) memcpy (A, mxGetIr (Ainput), nnz*sizeof (int)) ;
+
+    if (full)
+    {
+	mxDestroyArray (Ainput) ;
+    }
+
+    /* === Order the columns (destroys A) =================================== */
+
+    if (!colamd (n_row, n_col, Alen, A, p, knobs, stats))
+    {
+	colamd_report (stats) ;
+	mexErrMsgTxt ("colamd error!") ;
+    }
+    mxFree (A) ;
+
+    /* === Return the permutation vector ==================================== */
+
+    plhs [0] = mxCreateDoubleMatrix (1, n_col, mxREAL) ;
+    out_perm = mxGetPr (plhs [0]) ;
+    for (i = 0 ; i < n_col ; i++)
+    {
+	/* colamd is 0-based, but MATLAB expects this to be 1-based */
+	out_perm [i] = p [i] + 1 ;
+    }
+    mxFree (p) ;
+
+    /* === Return the stats vector ========================================== */
+
+    /* print stats if spumoni is set */
+    if (spumoni)
+    {
+	colamd_report (stats) ;
+    }
+
+    if (nlhs == 2)
+    {
+	plhs [1] = mxCreateDoubleMatrix (1, COLAMD_STATS, mxREAL) ;
+	out_stats = mxGetPr (plhs [1]) ;
+	for (i = 0 ; i < COLAMD_STATS ; i++)
+	{
+	    out_stats [i] = stats [i] ;
+	}
+
+	/* fix stats (5) and (6), for 1-based information on jumbled matrix. */
+	/* note that this correction doesn't occur if symamd returns FALSE */
+	out_stats [COLAMD_INFO1] ++ ; 
+	out_stats [COLAMD_INFO2] ++ ; 
+    }
+}
diff --git a/src/C/SuiteSparse/COLAMD/colamdtestmex.c b/src/C/SuiteSparse/COLAMD/colamdtestmex.c
new file mode 100644
index 0000000..fe3a4c4
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/colamdtestmex.c
@@ -0,0 +1,576 @@
+/* ========================================================================== */
+/* === colamdtest mexFunction =============================================== */
+/* ========================================================================== */
+
+/* COLAMD test function
+ 
+    This MATLAB mexFunction is for testing only.  It is not meant for
+    production use.  See colamdmex.c instead.
+
+    Usage:
+
+	[ P, stats ] = colamdtest (A, knobs) ;
+
+    See colamd.m for a description.  knobs is required.
+
+	knobs (1)	dense row control
+	knobs (2)	dense column control
+	knobs (3)	spumoni
+	knobs (4)	for testing only.  Controls the workspace used by
+			colamd.
+
+	knobs (5)	for testing only.  Controls how the input matrix is
+			jumbled prior to calling colamd, to test its error
+			handling capability.
+
+    Authors:
+
+	The authors of the code itself are Stefan I. Larimore and Timothy A.
+	Davis (davis at cise.ufl.edu), University of Florida.  The algorithm was
+	developed in collaboration with John Gilbert, Xerox PARC, and Esmond
+	Ng, Oak Ridge National Laboratory.
+
+    Acknowledgements:
+
+	This work was supported by the National Science Foundation, under
+	grants DMS-9504974 and DMS-9803599.
+
+    Notice:
+
+	Copyright (c) 1998-2006, Timothy A. Davis, All Rights Reserved.
+
+	See http://www.cise.ufl.edu/research/sparse/colamd (the colamd.c
+	file) for the License.
+
+    Availability:
+
+	The colamd/symamd library is available at
+
+	    http://www.cise.ufl.edu/research/sparse/colamd/
+
+	This is the
+	http://www.cise.ufl.edu/research/sparse/colamd/colamdtestmex.c
+       	file.  It requires the colamd.c and colamd.h files.
+
+*/
+
+/* ========================================================================== */
+/* === Include files ======================================================== */
+/* ========================================================================== */
+
+#include "colamd.h"
+#include "mex.h"
+#include "matrix.h"
+#include <stdlib.h>
+#include <string.h>
+
+static void dump_matrix
+(
+    int A [ ],
+    int p [ ],
+    int n_row,
+    int n_col,
+    int Alen,
+    int limit
+) ;
+
+/* ========================================================================== */
+/* === colamd mexFunction =================================================== */
+/* ========================================================================== */
+
+void mexFunction
+(
+    /* === Parameters ======================================================= */
+
+    int nlhs,			/* number of left-hand sides */
+    mxArray *plhs [],		/* left-hand side matrices */
+    int nrhs,			/* number of right--hand sides */
+    const mxArray *prhs []	/* right-hand side matrices */
+)
+{
+    /* === Local variables ================================================== */
+
+    int *A ;			/* colamd's copy of the matrix, and workspace */
+    int *p ;			/* colamd's copy of the column pointers */
+    int Alen ;			/* size of A */
+    int n_col ;			/* number of columns of A */
+    int n_row ;			/* number of rows of A */
+    int nnz ;			/* number of entries in A */
+    int full ;			/* TRUE if input matrix full, FALSE if sparse */
+    double knobs [COLAMD_KNOBS] ; /* colamd user-controllable parameters */
+    double *out_perm ;		/* output permutation vector */
+    double *out_stats ;		/* output stats vector */
+    double *in_knobs ;		/* input knobs vector */
+    int i ;			/* loop counter */
+    mxArray *Ainput ;		/* input matrix handle */
+    int spumoni ;		/* verbosity variable */
+    int stats2 [COLAMD_STATS] ;	/* stats for colamd */
+
+    int *cp, *cp_end, result, col, length ;
+    int *stats ;
+    stats = stats2 ;
+
+    colamd_printf = mexPrintf ;	/* COLAMD printf routine */
+
+    /* === Check inputs ===================================================== */
+
+    if (nrhs < 1 || nrhs > 2 || nlhs < 0 || nlhs > 2)
+    {
+	mexErrMsgTxt (
+	"colamd: incorrect number of input and/or output arguments") ;
+    }
+
+    if (nrhs != 2)
+    {
+	mexErrMsgTxt ("colamdtest: knobs are required") ;
+    }
+    /* for testing we require all 5 knobs */
+    if (mxGetNumberOfElements (prhs [1]) != 5)
+    {
+	mexErrMsgTxt ("colamd: must have all 5 knobs for testing") ;
+    }
+
+    /* === Get knobs ======================================================== */
+
+    colamd_set_defaults (knobs) ;
+    spumoni = 0 ;
+
+    /* check for user-passed knobs */
+    if (nrhs == 2)
+    {
+	in_knobs = mxGetPr (prhs [1]) ;
+	i = mxGetNumberOfElements (prhs [1]) ;
+	if (i > 0) knobs [COLAMD_DENSE_ROW] = in_knobs [0] ;
+	if (i > 1) knobs [COLAMD_DENSE_COL] = in_knobs [1] ;
+	if (i > 2) spumoni = (int) in_knobs [2] ;
+    }
+
+    /* print knob settings if spumoni is set */
+    if (spumoni)
+    {
+	mexPrintf ("\ncolamd version %d.%d, %s:\n",
+	    COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE) ;
+	if (knobs [COLAMD_DENSE_ROW] >= 0)
+	{
+	    mexPrintf ("knobs(1): %g, rows with > max(16,%g*sqrt(size(A,2)))"
+		" entries removed\n", in_knobs [0], knobs [COLAMD_DENSE_ROW]) ;
+	}
+	else
+	{
+	    mexPrintf ("knobs(1): %g, only completely dense rows removed\n",
+		in_knobs [0]) ;
+	}
+	if (knobs [COLAMD_DENSE_COL] >= 0)
+	{
+	    mexPrintf ("knobs(2): %g, cols with > max(16,%g*sqrt(min(size(A)))"
+		" entries removed\n", in_knobs [1], knobs [COLAMD_DENSE_COL]) ;
+	}
+	else
+	{
+	    mexPrintf ("knobs(2): %g, only completely dense columns removed\n",
+		in_knobs [1]) ;
+	}
+	mexPrintf ("knobs(3): %g, statistics and knobs printed\n",
+	    in_knobs [2]) ;
+    }
+
+    /* === If A is full, convert to a sparse matrix ========================= */
+
+    Ainput = (mxArray *) prhs [0] ;
+    if (mxGetNumberOfDimensions (Ainput) != 2)
+    {
+	mexErrMsgTxt ("colamd: input matrix must be 2-dimensional") ;
+    }
+    full = !mxIsSparse (Ainput) ;
+    if (full)
+    {
+	mexCallMATLAB (1, &Ainput, 1, (mxArray **) prhs, "sparse") ;
+    }
+
+    /* === Allocate workspace for colamd ==================================== */
+
+    /* get size of matrix */
+    n_row = mxGetM (Ainput) ;
+    n_col = mxGetN (Ainput) ;
+
+    /* get column pointer vector so we can find nnz */
+    p = (int *) mxCalloc (n_col+1, sizeof (int)) ;
+    (void) memcpy (p, mxGetJc (Ainput), (n_col+1)*sizeof (int)) ;
+    nnz = p [n_col] ;
+    Alen = (int) colamd_recommended (nnz, n_row, n_col) ;
+    if (Alen == 0)
+    {
+    	mexErrMsgTxt ("colamd: problem too large") ;
+    }
+
+
+/* === Modify size of Alen if testing ======================================= */
+
+/*
+	knobs [3]	amount of workspace given to colamd.
+			<  0 : TIGHT memory
+			>  0 : MIN + knob [3] - 1
+			== 0 : RECOMMENDED memory
+*/
+
+/* Here only for testing */
+/* size of the Col and Row structures */
+#define COLAMD_C(n_col) (((n_col) + 1) * 24 / sizeof (int))
+#define COLAMD_R(n_row) (((n_row) + 1) * 16 / sizeof (int))
+#ifdef MIN
+#undef MIN
+#endif
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define COLAMD_MIN_MEMORY(nnz,n_row,n_col) \
+    (2 * (nnz) + COLAMD_C (n_col) + COLAMD_R (n_row))
+
+    /* get knob [3], if negative */
+    if (in_knobs [3] < 0)
+    {
+	Alen = COLAMD_MIN_MEMORY (nnz, n_row, n_col) + n_col ;
+    }
+    else if (in_knobs [3] > 0)
+    {
+	Alen = COLAMD_MIN_MEMORY (nnz, n_row, n_col) + in_knobs [3] - 1 ;
+    }
+
+    /* otherwise, we use the recommended amount set above */
+
+    /* === Copy input matrix into workspace ================================= */
+
+    A = (int *) mxCalloc (Alen, sizeof (int)) ;
+    (void) memcpy (A, mxGetIr (Ainput), nnz*sizeof (int)) ;
+
+    if (full)
+    {
+	mxDestroyArray (Ainput) ;
+    }
+
+
+/* === Jumble matrix ======================================================== */
+
+/*
+	knobs [4]	FOR TESTING ONLY: Specifies how to jumble matrix
+			0 : No jumbling
+			1 : Make n_row less than zero
+			2 : Make first pointer non-zero
+			3 : Make column pointers not non-decreasing
+			4 : Make a column pointer greater or equal to Alen
+			5 : Make row indices not strictly increasing
+			6 : Make a row index greater or equal to n_row
+			7 : Set A = NULL
+			8 : Set p = NULL
+			9 : Repeat row index
+			10: make row indices not sorted
+			11: jumble columns massively (note this changes
+				the pattern of the matrix A.)
+			12: Set stats = NULL
+			13: Make n_col less than zero
+*/
+
+    /* jumble appropriately */
+    switch ((int) in_knobs [4])
+    {
+
+	case 0 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("colamdtest: no errors expected\n") ;
+	    }
+	    result = 1 ;		/* no errors */
+	    break ;
+
+	case 1 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("colamdtest: nrow out of range\n") ;
+	    }
+	    result = 0 ;		/* nrow out of range */
+	    n_row = -1 ;
+	    break ;
+
+	case 2 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("colamdtest: p [0] nonzero\n") ;
+	    }
+	    result = 0 ;		/* p [0] must be zero */
+	    p [0] = 1 ;
+	    break ;
+
+	case 3 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("colamdtest: negative length last column\n") ;
+	    }
+	    result = (n_col == 0) ;	/* p must be monotonically inc. */
+	    p [n_col] = p [0] ;
+	    break ;
+
+	case 4 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("colamdtest: Alen too small\n") ;
+	    }
+	    result = 0 ;		/* out of memory */
+	    p [n_col] = Alen ;
+	    break ;
+
+	case 5 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("colamdtest: row index out of range (-1)\n") ;
+	    }
+	    if (nnz > 0)		/* row index out of range */
+	    {
+		result = 0 ;
+		A [nnz-1] = -1 ;
+	    }
+	    else
+	    {
+	        if (spumoni > 0)
+		{
+		    mexPrintf ("Note: no row indices to put out of range\n") ;
+		}
+		result = 1 ;
+	    }
+	    break ;
+
+	case 6 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("colamdtest: row index out of range (n_row)\n") ;
+	    }
+	    if (nnz > 0)		/* row index out of range */
+	    {
+		if (spumoni > 0)
+		{
+		    mexPrintf ("Changing A[nnz-1] from %d to %d\n",
+			    A [nnz-1], n_row) ; 
+		}
+		result = 0 ;
+		A [nnz-1] = n_row ;
+	    }
+	    else
+	    {
+	        if (spumoni > 0)
+		{
+		    mexPrintf ("Note: no row indices to put out of range\n") ;
+		}
+		result = 1 ;
+	    }
+	    break ;
+
+	case 7 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("colamdtest: A not present\n") ;
+	    }
+	    result = 0 ;		/* A not present */
+	    A = (int *) NULL ;
+	    break ;
+
+	case 8 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("colamdtest: p not present\n") ;
+	    }
+	    result = 0 ;		/* p not present */
+	    p = (int *) NULL ;
+	    break ;
+
+	case 9 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("colamdtest: duplicate row index\n") ;
+	    }
+	    result = 1 ;		/* duplicate row index */
+
+	    for (col = 0 ; col < n_col ; col++)
+	    {
+		length = p [col+1] - p [col] ;
+	    	if (length > 1)
+		{
+		    A [p [col]] = A [p [col] + 1] ;
+		    if (spumoni > 0)
+		    {
+			mexPrintf ("Made duplicate row %d in col %d\n",
+		    	 A [p [col] + 1], col) ;
+		    }
+		    break ;
+		}
+	    }
+
+	    if (spumoni > 1)
+	    {
+		dump_matrix (A, p, n_row, n_col, Alen, col+2) ;
+	    }
+	    break ;
+
+	case 10 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("colamdtest: unsorted column\n") ;
+	    }
+	    result = 1 ;		/* jumbled columns */
+
+	    for (col = 0 ; col < n_col ; col++)
+	    {
+		length = p [col+1] - p [col] ;
+	    	if (length > 1)
+		{
+		    i = A[p [col]] ;
+		    A [p [col]] = A[p [col] + 1] ;
+		    A [p [col] + 1] = i ;
+		    if (spumoni > 0)
+		    {
+			mexPrintf ("Unsorted column %d \n", col) ;
+		    }
+		    break ;
+		}
+	    }
+
+	    if (spumoni > 1)
+	    {
+		dump_matrix (A, p, n_row, n_col, Alen, col+2) ;
+	    }
+	    break ;
+
+	case 11 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("colamdtest: massive jumbling\n") ;
+	    }
+	    result = 1 ;		/* massive jumbling, but no errors */
+	    srand (1) ;
+	    for (i = 0 ; i < n_col ; i++)
+	    {
+		cp = &A [p [i]] ;
+		cp_end = &A [p [i+1]] ;
+		while (cp < cp_end)
+		{
+		    *cp++ = rand() % n_row ;
+		}
+	    }
+	    if (spumoni > 1)
+	    {
+		dump_matrix (A, p, n_row, n_col, Alen, n_col) ;
+	    }
+	    break ;
+
+	case 12 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("colamdtest: stats not present\n") ;
+	    }
+	    result = 0 ;		/* stats not present */
+	    stats = (int *) NULL ;
+	    break ;
+
+	case 13 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("colamdtest: ncol out of range\n") ;
+	    }
+	    result = 0 ;		/* ncol out of range */
+	    n_col = -1 ;
+	    break ;
+
+    }
+
+
+    /* === Order the columns (destroys A) =================================== */
+
+    if (!colamd (n_row, n_col, Alen, A, p, knobs, stats))
+    {
+
+	/* return p = -1 if colamd failed */
+	plhs [0] = mxCreateDoubleMatrix (1, 1, mxREAL) ;
+	out_perm = mxGetPr (plhs [0]) ;
+	out_perm [0] = -1 ;
+	mxFree (p) ;
+	mxFree (A) ;
+
+	if (spumoni > 0 || result)
+	{
+	    colamd_report (stats) ;
+	}
+
+	if (result)
+	{
+	    mexErrMsgTxt ("colamd should have returned TRUE\n") ;
+	}
+
+	return ;
+	/* mexErrMsgTxt ("colamd error!") ; */
+    }
+
+    if (!result)
+    {
+	colamd_report (stats) ;
+	mexErrMsgTxt ("colamd should have returned FALSE\n") ;
+    }
+    mxFree (A) ;
+
+    /* === Return the permutation vector ==================================== */
+
+    plhs [0] = mxCreateDoubleMatrix (1, n_col, mxREAL) ;
+    out_perm = mxGetPr (plhs [0]) ;
+    for (i = 0 ; i < n_col ; i++)
+    {
+	/* colamd is 0-based, but MATLAB expects this to be 1-based */
+	out_perm [i] = p [i] + 1 ;
+    }
+    mxFree (p) ;
+
+    /* === Return the stats vector ========================================== */
+
+    /* print stats if spumoni > 0 */
+    if (spumoni > 0)
+    {
+	colamd_report (stats) ;
+    }
+
+    if (nlhs == 2)
+    {
+	plhs [1] = mxCreateDoubleMatrix (1, COLAMD_STATS, mxREAL) ;
+	out_stats = mxGetPr (plhs [1]) ;
+	for (i = 0 ; i < COLAMD_STATS ; i++)
+	{
+	    out_stats [i] = stats [i] ;
+	}
+
+	/* fix stats (5) and (6), for 1-based information on jumbled matrix. */
+	/* note that this correction doesn't occur if symamd returns FALSE */
+	out_stats [COLAMD_INFO1] ++ ; 
+	out_stats [COLAMD_INFO2] ++ ; 
+    }
+}
+
+
+static void dump_matrix
+(
+    int A [ ],
+    int p [ ],
+    int n_row,
+    int n_col,
+    int Alen,
+    int limit
+)
+{
+    int col, k, row ;
+
+    mexPrintf ("dump matrix: nrow %d ncol %d Alen %d\n", n_row, n_col, Alen) ;
+
+    for (col = 0 ; col < MIN (n_col, limit) ; col++)
+    {
+	mexPrintf ("column %d, p[col] %d, p [col+1] %d, length %d\n",
+		col, p [col], p [col+1], p [col+1] - p [col]) ;
+    	for (k = p [col] ; k < p [col+1] ; k++)
+	{
+	    row = A [k] ;
+	    mexPrintf (" %d", row) ;
+	}
+	mexPrintf ("\n") ;
+    }
+}
diff --git a/src/C/SuiteSparse/COLAMD/lesser.txt b/src/C/SuiteSparse/COLAMD/lesser.txt
new file mode 100644
index 0000000..8add30a
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/lesser.txt
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+

+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+

+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+

+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+

+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+

+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+

+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+

+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+

+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/C/SuiteSparse/COLAMD/luflops.m b/src/C/SuiteSparse/COLAMD/luflops.m
new file mode 100644
index 0000000..0f6f46d
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/luflops.m
@@ -0,0 +1,35 @@
+function fl = luflops (L, U)
+%LUFLOPS compute the flop count for sparse LU factorization
+%
+%  Example:
+%      fl = luflops (L,U)
+%
+%  Given a sparse LU factorization (L and U), return the flop count required
+%  by a conventional LU factorization algorithm to compute it.   L and U can
+%  be either sparse or full matrices.  L must be lower triangular and U must
+%  be upper triangular.  Do not attempt to use this on the permuted L from
+%  [L,U] = lu (A).  Instead, use [L,U,P] = lu (A) or [L,U,P,Q] = lu (A).
+%
+%  Note that there is a subtle undercount in this estimate.  Suppose A is
+%  completely dense, but during LU factorization exact cancellation occurs,
+%  causing some of the entries in L and U to become identically zero.  The
+%  flop count returned by this routine is an undercount.  There is a simple
+%  way to fix this (L = spones (L) + spones (tril (A))), but the fix is partial.
+%  It can also occur that some entry in L is a "symbolic" fill-in (zero in
+%  A, but a fill-in entry and thus must be computed), but numerically
+%  zero.  The only way to get a reliable LU factorization would be to do a
+%  purely symbolic factorization of A.  This cannot be done with
+%  symbfact (A, 'col').
+%
+%  See NA Digest, Vol 00, #50, Tuesday, Dec. 5, 2000
+%
+% See also symbfact
+%
+
+% Copyright 2006, Timothy A. Davis, University of Florida
+
+
+Lnz = full (sum (spones (L))) - 1 ;	% off diagonal nz in cols of L
+Unz = full (sum (spones (U')))' - 1 ;	% off diagonal nz in rows of U
+fl = 2*Lnz*Unz + sum (Lnz) ;
+
diff --git a/src/C/SuiteSparse/COLAMD/symamd2.m b/src/C/SuiteSparse/COLAMD/symamd2.m
new file mode 100644
index 0000000..2ec705c
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/symamd2.m
@@ -0,0 +1,103 @@
+function [p, stats] = symamd2 (S, knobs)
+%SYMAMD Symmetric approximate minimum degree permutation.
+%    P = SYMAMD2(S) for a symmetric positive definite matrix S, returns the
+%    permutation vector p such that S(p,p) tends to have a sparser Cholesky
+%    factor than S.  Sometimes SYMAMD works well for symmetric indefinite
+%    matrices too.  The matrix S is assumed to be symmetric; only the
+%    strictly lower triangular part is referenced.   S must be square.
+%    Note that p = amd(S) is much faster and generates comparable orderings.
+%    The ordering is followed by an elimination tree post-ordering.
+%
+%    Note that this function is source code for the built-in MATLAB symamd
+%    function.  It has been renamed here to symamd2 to avoid a filename clash.
+%    symamd and symamd2 are identical.
+%
+%    See also SYMAMD, AMD, COLAMD, COLAMD2.
+%
+%    Example:
+%            P = symamd2 (S)
+%            [P, stats] = symamd2 (S, knobs)
+%
+%    knobs is an optional one- to two-element input vector.  If S is n-by-n,
+%    then rows and columns with more than max(16,knobs(1)*sqrt(n)) entries are
+%    removed prior to ordering, and ordered last in the output permutation P.
+%    No rows/columns are removed if knobs(1)<0.  If knobs(2) is nonzero, stats
+%    and knobs are printed.  The default is knobs = [10 0].  Note that knobs
+%    differs from earlier versions of symamd.
+%
+%    Type the command "type symamd2" for a description of the optional stats
+%    output and for the copyright information.
+%
+%    Authors: S. Larimore and T. Davis, University of Florida.  Developed in
+%       collaboration with J. Gilbert and E. Ng.
+%
+%    Acknowledgements: This work was supported by the National Science
+%       Foundation, under grants DMS-9504974 and DMS-9803599.
+
+%    Notice:
+%
+%	Copyright 1998-2006, Timothy A. Davis, All Rights Reserved.
+%
+%       See http://www.cise.ufl.edu/research/sparse/colamd (the colamd.c
+%       file) for the License.
+%
+%    Availability:
+%
+%       colamd, symamd, amd, ccolamd, and csymamd are available at
+%       http://www.cise.ufl.edu/research/sparse
+
+%-------------------------------------------------------------------------------
+% perform the symamd ordering:
+%-------------------------------------------------------------------------------
+
+if (nargout <= 1 && nargin == 1)
+    p = symamd2mex (S) ;
+elseif (nargout <= 1 && nargin == 2)
+    p = symamd2mex (S, knobs) ;
+elseif (nargout == 2 && nargin == 1)
+    [p, stats] = symamd2mex (S) ;
+elseif (nargout == 2 && nargin == 2)
+    [p, stats] = symamd2mex (S, knobs) ;
+else
+    error('MATLAB:symamd:WrongInputOrOutputNumber',...
+           'symamd:  incorrect number of input and/or output arguments.') ;
+end
+
+%-------------------------------------------------------------------------------
+% symmetric elimination tree post-ordering:
+%-------------------------------------------------------------------------------
+
+[ignore, q] = etree (S (p,p)) ;
+p = p (q) ;
+
+
+%    stats is an optional 20-element output vector that provides data about the
+%    ordering and the validity of the input matrix S.  Ordering statistics are
+%    in stats (1:3).  stats (1) = stats (2) is the number of dense or empty
+%    rows and columns ignored by SYMAMD and stats (3) is the number of
+%    garbage collections performed on the internal data structure used by
+%    SYMAMD (roughly of size 8.4*nnz(tril(S,-1)) + 9*n integers).
+%
+%    MATLAB built-in functions are intended to generate valid sparse matrices,
+%    with no duplicate entries, with ascending row indices of the nonzeros
+%    in each column, with a non-negative number of entries in each column (!)
+%    and so on.  If a matrix is invalid, then SYMAMD may or may not be able
+%    to continue.  If there are duplicate entries (a row index appears two or
+%    more times in the same column) or if the row indices in a column are out
+%    of order, then SYMAMD can correct these errors by ignoring the duplicate
+%    entries and sorting each column of its internal copy of the matrix S (the
+%    input matrix S is not repaired, however).  If a matrix is invalid in other
+%    ways then SYMAMD cannot continue, an error message is printed, and no
+%    output arguments (P or stats) are returned.  SYMAMD is thus a simple way
+%    to check a sparse matrix to see if it's valid.
+%
+%    stats (4:7) provide information if SYMAMD was able to continue.  The
+%    matrix is OK if stats (4) is zero, or 1 if invalid.  stats (5) is the
+%    rightmost column index that is unsorted or contains duplicate entries,
+%    or zero if no such column exists.  stats (6) is the last seen duplicate
+%    or out-of-order row index in the column index given by stats (5), or zero
+%    if no such row index exists.  stats (7) is the number of duplicate or
+%    out-of-order row indices.
+%
+%    stats (8:20) is always zero in the current version of SYMAMD (reserved
+%    for future use).
diff --git a/src/C/SuiteSparse/COLAMD/symamdmex.c b/src/C/SuiteSparse/COLAMD/symamdmex.c
new file mode 100644
index 0000000..74ed936
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/symamdmex.c
@@ -0,0 +1,200 @@
+/* ========================================================================== */
+/* === symamd mexFunction =================================================== */
+/* ========================================================================== */
+
+/* SYMAMD mexFunction
+
+    Usage:
+
+	P = symamd2 (A) ;
+	[ P, stats ] = symamd2 (A, knobs) ;
+
+    See symamd.m for a description.
+
+    Authors:
+
+	The authors of the code itself are Stefan I. Larimore and Timothy A.
+	Davis (davis at cise.ufl.edu), University of Florida.  The algorithm was
+	developed in collaboration with John Gilbert, Xerox PARC, and Esmond
+	Ng, Oak Ridge National Laboratory.
+
+    Acknowledgements:
+
+	This work was supported by the National Science Foundation, under
+	grants DMS-9504974 and DMS-9803599.
+
+    Notice:
+
+	Copyright (c) 1998-2006, Timothy A. Davis.  All Rights Reserved.
+
+	See http://www.cise.ufl.edu/research/sparse/colamd (the colamd.c
+	file) for the License.
+
+    Availability:
+
+	The colamd/symamd library is available at
+
+	    http://www.cise.ufl.edu/research/sparse/colamd/
+
+	This is the http://www.cise.ufl.edu/research/sparse/colamd/symamdmex.c
+	file.  It requires the colamd.c and colamd.h files.
+
+*/
+
+/* ========================================================================== */
+/* === Include files ======================================================== */
+/* ========================================================================== */
+
+#include "colamd.h"
+#include "mex.h"
+#include "matrix.h"
+#include <stdlib.h>
+
+/* ========================================================================== */
+/* === symamd mexFunction =================================================== */
+/* ========================================================================== */
+
+void mexFunction
+(
+    /* === Parameters ======================================================= */
+
+    int nlhs,			/* number of left-hand sides */
+    mxArray *plhs [],		/* left-hand side matrices */
+    int nrhs,			/* number of right--hand sides */
+    const mxArray *prhs []	/* right-hand side matrices */
+)
+{
+    /* === Local variables ================================================== */
+
+    int *perm ;			/* column ordering of M and ordering of A */
+    int *A ;			/* row indices of input matrix A */
+    int *p ;			/* column pointers of input matrix A */
+    int n_col ;			/* number of columns of A */
+    int n_row ;			/* number of rows of A */
+    int full ;			/* TRUE if input matrix full, FALSE if sparse */
+    double knobs [COLAMD_KNOBS] ; /* colamd user-controllable parameters */
+    double *out_perm ;		/* output permutation vector */
+    double *out_stats ;		/* output stats vector */
+    double *in_knobs ;		/* input knobs vector */
+    int i ;			/* loop counter */
+    mxArray *Ainput ;		/* input matrix handle */
+    int spumoni ;		/* verbosity variable */
+    int stats [COLAMD_STATS] ;	/* stats for symamd */
+
+    colamd_printf = mexPrintf ;	/* COLAMD printf routine */
+
+    /* === Check inputs ===================================================== */
+
+    if (nrhs < 1 || nrhs > 2 || nlhs < 0 || nlhs > 2)
+    {
+	mexErrMsgTxt (
+	"symamd: incorrect number of input and/or output arguments.") ;
+    }
+
+    /* === Get knobs ======================================================== */
+
+    colamd_set_defaults (knobs) ;
+    spumoni = 0 ;
+
+    /* check for user-passed knobs */
+    if (nrhs == 2)
+    {
+	in_knobs = mxGetPr (prhs [1]) ;
+	i = mxGetNumberOfElements (prhs [1]) ;
+	if (i > 0) knobs [COLAMD_DENSE_ROW] = in_knobs [0] ;
+	if (i > 1) spumoni = (int) (in_knobs [1] != 0) ;
+    }
+
+    /* print knob settings if spumoni is set */
+    if (spumoni)
+    {
+	mexPrintf ("\nsymamd version %d.%d, %s:\n",
+	    COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE) ;
+	if (knobs [COLAMD_DENSE_ROW] >= 0)
+	{
+	    mexPrintf ("knobs(1): %g, rows/cols with > "
+		"max(16,%g*sqrt(size(A,2))) entries removed\n",
+		in_knobs [0], knobs [COLAMD_DENSE_ROW]) ;
+	}
+	else
+	{
+	    mexPrintf ("knobs(1): %g, no dense rows removed\n", in_knobs [0]) ;
+	}
+	mexPrintf ("knobs(2): %g, statistics and knobs printed\n",
+	    in_knobs [1]) ;
+    }
+
+    /* === If A is full, convert to a sparse matrix ========================= */
+
+    Ainput = (mxArray *) prhs [0] ;
+    if (mxGetNumberOfDimensions (Ainput) != 2)
+    {
+	mexErrMsgTxt ("symamd: input matrix must be 2-dimensional.") ;
+    }
+    full = !mxIsSparse (Ainput) ;
+    if (full)
+    {
+	mexCallMATLAB (1, &Ainput, 1, (mxArray **) prhs, "sparse") ;
+    }
+
+    /* === Allocate workspace for symamd ==================================== */
+
+    /* get size of matrix */
+    n_row = mxGetM (Ainput) ;
+    n_col = mxGetN (Ainput) ;
+    if (n_col != n_row)
+    {
+	mexErrMsgTxt ("symamd: matrix must be square.") ;
+    }
+
+    A = mxGetIr (Ainput) ;
+    p = mxGetJc (Ainput) ;
+    perm = (int *) mxCalloc (n_col+1, sizeof (int)) ;
+
+    /* === Order the rows and columns of A (does not destroy A) ============= */
+
+    if (!symamd (n_col, A, p, perm, knobs, stats, &mxCalloc, &mxFree))
+    {
+	symamd_report (stats) ;
+	mexErrMsgTxt ("symamd error!") ;
+    }
+
+    if (full)
+    {
+	mxDestroyArray (Ainput) ;
+    }
+
+    /* === Return the permutation vector ==================================== */
+
+    plhs [0] = mxCreateDoubleMatrix (1, n_col, mxREAL) ;
+    out_perm = mxGetPr (plhs [0]) ;
+    for (i = 0 ; i < n_col ; i++)
+    {
+	/* symamd is 0-based, but MATLAB expects this to be 1-based */
+	out_perm [i] = perm [i] + 1 ;
+    }
+    mxFree (perm) ;
+
+    /* === Return the stats vector ========================================== */
+
+    /* print stats if spumoni is set */
+    if (spumoni)
+    {
+	symamd_report (stats) ;
+    }
+
+    if (nlhs == 2)
+    {
+	plhs [1] = mxCreateDoubleMatrix (1, COLAMD_STATS, mxREAL) ;
+	out_stats = mxGetPr (plhs [1]) ;
+	for (i = 0 ; i < COLAMD_STATS ; i++)
+	{
+	    out_stats [i] = stats [i] ;
+	}
+
+	/* fix stats (5) and (6), for 1-based information on jumbled matrix. */
+	/* note that this correction doesn't occur if symamd returns FALSE */
+	out_stats [COLAMD_INFO1] ++ ; 
+	out_stats [COLAMD_INFO2] ++ ; 
+    }
+}
diff --git a/src/C/SuiteSparse/COLAMD/symamdtestmex.c b/src/C/SuiteSparse/COLAMD/symamdtestmex.c
new file mode 100644
index 0000000..75c946e
--- /dev/null
+++ b/src/C/SuiteSparse/COLAMD/symamdtestmex.c
@@ -0,0 +1,542 @@
+/* ========================================================================== */
+/* === symamdtest mexFunction =============================================== */
+/* ========================================================================== */
+
+/* SYMAMD test function
+
+    This MATLAB mexFunction is for testing only.  It is not meant for
+    production use.  See symamdmex.c instead.
+
+    Usage:
+
+	[ P, stats ] = symamdtest (A, knobs) ;
+
+    See symamd.m for a description.  knobs is required.
+
+	knobs (1)	dense row control
+	knobs (2)	spumoni
+	knobs (3)	for testing only.  Controls how the input matrix is
+			jumbled prior to calling symamd, to test its error
+			handling capability.
+
+    Authors:
+
+	The authors of the code itself are Stefan I. Larimore and Timothy A.
+	Davis (davis at cise.ufl.edu), University of Florida.  The algorithm was
+	developed in collaboration with John Gilbert, Xerox PARC, and Esmond
+	Ng, Oak Ridge National Laboratory.
+
+    Acknowledgements:
+
+	This work was supported by the National Science Foundation, under
+	grants DMS-9504974 and DMS-9803599.
+
+    Notice:
+
+	Copyright (c) 1998-2006, Timothy A. Davis.  All Rights Reserved.
+
+	See http://www.cise.ufl.edu/research/sparse/colamd (the colamd.c
+	file) for the License.
+
+    Availability:
+
+	The colamd/symamd library is available at
+
+	    http://www.cise.ufl.edu/research/sparse/colamd/
+
+	This is the
+	http://www.cise.ufl.edu/research/sparse/colamd/symamdtestmex.c
+       	file.  It requires the colamd.c and colamd.h files.
+
+*/
+
+/* ========================================================================== */
+/* === Include files ======================================================== */
+/* ========================================================================== */
+
+#include "colamd.h"
+#include "mex.h"
+#include "matrix.h"
+#include <stdlib.h>
+#include <string.h>
+
+static void dump_matrix
+(
+    int A [ ],
+    int p [ ],
+    int n_row,
+    int n_col,
+    int Alen,
+    int limit
+) ;
+
+/* ========================================================================== */
+/* === symamd mexFunction =================================================== */
+/* ========================================================================== */
+
+void mexFunction
+(
+    /* === Parameters ======================================================= */
+
+    int nlhs,			/* number of left-hand sides */
+    mxArray *plhs [],		/* left-hand side matrices */
+    int nrhs,			/* number of right--hand sides */
+    const mxArray *prhs []	/* right-hand side matrices */
+)
+{
+    /* === Local variables ================================================== */
+
+    int *perm ;			/* column ordering of M and ordering of A */
+    int *A ;			/* row indices of input matrix A */
+    int *p ;			/* column pointers of input matrix A */
+    int n_col ;			/* number of columns of A */
+    int n_row ;			/* number of rows of A */
+    int full ;			/* TRUE if input matrix full, FALSE if sparse */
+    double knobs [COLAMD_KNOBS] ; /* colamd user-controllable parameters */
+    double *out_perm ;		/* output permutation vector */
+    double *out_stats ;		/* output stats vector */
+    double *in_knobs ;		/* input knobs vector */
+    int i ;			/* loop counter */
+    mxArray *Ainput ;		/* input matrix handle */
+    int spumoni ;		/* verbosity variable */
+    int stats2 [COLAMD_STATS] ;	/* stats for symamd */
+
+    int *cp, *cp_end, result, nnz, col, length ;
+    int *stats ;
+    stats = stats2 ;
+
+    colamd_printf = mexPrintf ;	/* COLAMD printf routine */
+
+    /* === Check inputs ===================================================== */
+
+    if (nrhs < 1 || nrhs > 2 || nlhs < 0 || nlhs > 2)
+    {
+	mexErrMsgTxt (
+	"symamd: incorrect number of input and/or output arguments.") ;
+    }
+
+    if (nrhs != 2)
+    {
+	mexErrMsgTxt ("symamdtest: knobs are required") ;
+    }
+    /* for testing we require all 3 knobs */
+    if (mxGetNumberOfElements (prhs [1]) != 3)
+    {
+	mexErrMsgTxt ("symamdtest: must have all 3 knobs for testing") ;
+    }
+
+    /* === Get knobs ======================================================== */
+
+    colamd_set_defaults (knobs) ;
+    spumoni = 0 ;
+
+    /* check for user-passed knobs */
+    if (nrhs == 2)
+    {
+	in_knobs = mxGetPr (prhs [1]) ;
+	i = mxGetNumberOfElements (prhs [1]) ;
+	if (i > 0) knobs [COLAMD_DENSE_ROW] = in_knobs [0] ;
+	if (i > 1) spumoni = (int) in_knobs [1] ;
+    }
+
+    /* print knob settings if spumoni is set */
+    if (spumoni)
+    {
+	mexPrintf ("\nsymamd version %d.%d, %s:\n",
+	    COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE) ;
+	if (knobs [COLAMD_DENSE_ROW] >= 0)
+	{
+	    mexPrintf ("knobs(1): %g, rows/cols with > "
+		"max(16,%g*sqrt(size(A,2))) entries removed\n",
+		in_knobs [0], knobs [COLAMD_DENSE_ROW]) ;
+	}
+	else
+	{
+	    mexPrintf ("knobs(1): %g, no dense rows removed\n", in_knobs [0]) ;
+	}
+	mexPrintf ("knobs(2): %g, statistics and knobs printed\n",
+	    in_knobs [1]) ;
+	mexPrintf ("Testing %d\n", in_knobs [2]) ;
+    }
+
+    /* === If A is full, convert to a sparse matrix ========================= */
+
+    Ainput = (mxArray *) prhs [0] ;
+    if (mxGetNumberOfDimensions (Ainput) != 2)
+    {
+	mexErrMsgTxt ("symamd: input matrix must be 2-dimensional.") ;
+    }
+    full = !mxIsSparse (Ainput) ;
+    if (full)
+    {
+	mexCallMATLAB (1, &Ainput, 1, (mxArray **) prhs, "sparse") ;
+    }
+
+    /* === Allocate workspace for symamd ==================================== */
+
+    /* get size of matrix */
+    n_row = mxGetM (Ainput) ;
+    n_col = mxGetN (Ainput) ;
+    if (n_col != n_row)
+    {
+	mexErrMsgTxt ("symamd: matrix must be square.") ;
+    }
+
+    /* p = mxGetJc (Ainput) ; */
+    p = (int *) mxCalloc (n_col+1, sizeof (int)) ;
+    (void) memcpy (p, mxGetJc (Ainput), (n_col+1)*sizeof (int)) ;
+
+    nnz = p [n_col] ;
+    if (spumoni > 0)
+    {
+	mexPrintf ("symamdtest: nnz %d\n", nnz) ;
+    }
+
+    /* A = mxGetIr (Ainput) ; */
+    A = (int *) mxCalloc (nnz+1, sizeof (int)) ;
+    (void) memcpy (A, mxGetIr (Ainput), nnz*sizeof (int)) ;
+
+    perm = (int *) mxCalloc (n_col+1, sizeof (int)) ;
+
+/* === Jumble matrix ======================================================== */
+
+
+/*
+	knobs [2]	FOR TESTING ONLY: Specifies how to jumble matrix
+			0 : No jumbling
+			1 : (no errors)
+			2 : Make first pointer non-zero
+			3 : Make column pointers not non-decreasing
+			4 : (no errors)
+			5 : Make row indices not strictly increasing
+			6 : Make a row index greater or equal to n_row
+			7 : Set A = NULL
+			8 : Set p = NULL
+			9 : Repeat row index
+			10: make row indices not sorted
+			11: jumble columns massively (note this changes
+				the pattern of the matrix A.)
+			12: Set stats = NULL
+			13: Make n_col less than zero
+*/
+
+    /* jumble appropriately */
+    switch ((int) in_knobs [2])
+    {
+
+	case 0 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("symamdtest: no errors expected\n") ;
+	    }
+	    result = 1 ;		/* no errors */
+	    break ;
+
+	case 1 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("symamdtest: no errors expected (1)\n") ;
+	    }
+	    result = 1 ;
+	    break ;
+
+	case 2 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("symamdtest: p [0] nonzero\n") ;
+	    }
+	    result = 0 ;		/* p [0] must be zero */
+	    p [0] = 1 ;
+	    break ;
+
+	case 3 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("symamdtest: negative length last column\n") ;
+	    }
+	    result = (n_col == 0) ;	/* p must be monotonically inc. */
+	    p [n_col] = p [0] ;
+	    break ;
+
+	case 4 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("symamdtest: no errors expected (4)\n") ;
+	    }
+	    result = 1 ;
+	    break ;
+
+	case 5 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("symamdtest: row index out of range (-1)\n") ;
+	    }
+	    if (nnz > 0)		/* row index out of range */
+	    {
+		result = 0 ;
+		A [nnz-1] = -1 ;
+	    }
+	    else
+	    {
+	        if (spumoni > 0)
+		{
+		    mexPrintf ("Note: no row indices to put out of range\n") ;
+		}
+		result = 1 ;
+	    }
+	    break ;
+
+	case 6 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("symamdtest: row index out of range (ncol)\n") ;
+	    }
+	    if (nnz > 0)		/* row index out of range */
+	    {
+		result = 0 ;
+		A [nnz-1] = n_col ;
+	    }
+	    else
+	    {
+	        if (spumoni > 0)
+		{
+		    mexPrintf ("Note: no row indices to put out of range\n") ;
+		}
+		result = 1 ;
+	    }
+	    break ;
+
+	case 7 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("symamdtest: A not present\n") ;
+	    }
+	    result = 0 ;		/* A not present */
+	    A = (int *) NULL ;
+	    break ;
+
+	case 8 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("symamdtest: p not present\n") ;
+	    }
+	    result = 0 ;		/* p not present */
+	    p = (int *) NULL ;
+	    break ;
+
+	case 9 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("symamdtest: duplicate row index\n") ;
+	    }
+	    result = 1 ;		/* duplicate row index */
+
+	    for (col = 0 ; col < n_col ; col++)
+	    {
+		length = p [col+1] - p [col] ;
+	    	if (length > 1)
+		{
+		    A [p [col+1]-2] = A [p [col+1] - 1] ;
+		    if (spumoni > 0)
+		    {
+			mexPrintf ("Made duplicate row %d in col %d\n",
+		    	 A [p [col+1] - 1], col) ;
+		    }
+		    break ;
+		}
+	    }
+
+	    if (spumoni > 1)
+	    {
+		dump_matrix (A, p, n_row, n_col, nnz, col+2) ;
+	    }
+	    break ;
+
+	case 10 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("symamdtest: unsorted column\n") ;
+	    }
+	    result = 1 ;		/* jumbled columns */
+
+	    for (col = 0 ; col < n_col ; col++)
+	    {
+		length = p [col+1] - p [col] ;
+	    	if (length > 1)
+		{
+		    i = A[p [col]] ;
+		    A [p [col]] = A[p [col] + 1] ;
+		    A [p [col] + 1] = i ;
+		    if (spumoni > 0)
+		    {
+			mexPrintf ("Unsorted column %d \n", col) ;
+		    }
+		    break ;
+		}
+	    }
+
+	    if (spumoni > 1)
+	    {
+		dump_matrix (A, p, n_row, n_col, nnz, col+2) ;
+	    }
+	    break ;
+
+	case 11 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("symamdtest: massive jumbling\n") ;
+	    }
+	    result = 1 ;		/* massive jumbling, but no errors */
+	    srand (1) ;
+	    for (i = 0 ; i < n_col ; i++)
+	    {
+		cp = &A [p [i]] ;
+		cp_end = &A [p [i+1]] ;
+		while (cp < cp_end)
+		{
+		    *cp++ = rand() % n_row ;
+		}
+	    }
+	    if (spumoni > 1)
+	    {
+		dump_matrix (A, p, n_row, n_col, nnz, n_col) ;
+	    }
+	    break ;
+
+	case 12 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("symamdtest: stats not present\n") ;
+	    }
+	    result = 0 ;		/* stats not present */
+	    stats = (int *) NULL ;
+	    break ;
+
+	case 13 :
+	    if (spumoni > 0)
+	    {
+		mexPrintf ("symamdtest: ncol out of range\n") ;
+	    }
+	    result = 0 ;		/* ncol out of range */
+	    n_col = -1 ;
+	    break ;
+
+    }
+
+    /* === Order the rows and columns of A (does not destroy A) ============= */
+
+    if (!symamd (n_col, A, p, perm, knobs, stats, &mxCalloc, &mxFree))
+    {
+
+	/* return p = -1 if colamd failed */
+	plhs [0] = mxCreateDoubleMatrix (1, 1, mxREAL) ;
+	out_perm = mxGetPr (plhs [0]) ;
+	out_perm [0] = -1 ;
+	mxFree (p) ;
+	mxFree (A) ;
+
+	if (spumoni > 0 || result)
+	{
+	    symamd_report (stats) ;
+	}
+
+	if (result)
+	{
+	    mexErrMsgTxt ("symamd should have returned TRUE\n") ;
+	}
+
+	return ;
+	/* mexErrMsgTxt ("symamd error!") ; */
+    }
+
+    if (!result)
+    {
+	symamd_report (stats) ;
+	mexErrMsgTxt ("symamd should have returned FALSE\n") ;
+    }
+
+    if (full)
+    {
+	mxDestroyArray (Ainput) ;
+    }
+
+    /* === Return the permutation vector ==================================== */
+
+    plhs [0] = mxCreateDoubleMatrix (1, n_col, mxREAL) ;
+    out_perm = mxGetPr (plhs [0]) ;
+    for (i = 0 ; i < n_col ; i++)
+    {
+	/* symamd is 0-based, but MATLAB expects this to be 1-based */
+	out_perm [i] = perm [i] + 1 ;
+    }
+    mxFree (perm) ;
+
+    /* === Return the stats vector ========================================== */
+
+    /* print stats if spumoni > 0 */
+    if (spumoni > 0)
+    {
+	symamd_report (stats) ;
+    }
+
+    if (nlhs == 2)
+    {
+	plhs [1] = mxCreateDoubleMatrix (1, COLAMD_STATS, mxREAL) ;
+	out_stats = mxGetPr (plhs [1]) ;
+	for (i = 0 ; i < COLAMD_STATS ; i++)
+	{
+	    out_stats [i] = stats [i] ;
+	}
+
+	/* fix stats (5) and (6), for 1-based information on jumbled matrix. */
+	/* note that this correction doesn't occur if symamd returns FALSE */
+	out_stats [COLAMD_INFO1] ++ ; 
+	out_stats [COLAMD_INFO2] ++ ; 
+    }
+}
+
+
+#ifdef MIN
+#undef MIN
+#endif
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+
+static void dump_matrix
+(
+    int A [ ],
+    int p [ ],
+    int n_row,
+    int n_col,
+    int Alen,
+    int limit
+)
+{
+    int col, k, row ;
+
+    mexPrintf ("dump matrix: nrow %d ncol %d Alen %d\n", n_row, n_col, Alen) ;
+
+    if (!A)
+    {
+    	mexPrintf ("A not present\n") ;
+	return ;
+    }
+
+    if (!p)
+    {
+    	mexPrintf ("p not present\n") ;
+	return ;
+    }
+
+    for (col = 0 ; col < MIN (n_col, limit) ; col++)
+    {
+	mexPrintf ("column %d, p[col] %d, p [col+1] %d, length %d\n",
+		col, p [col], p [col+1], p [col+1] - p [col]) ;
+    	for (k = p [col] ; k < p [col+1] ; k++)
+	{
+	    row = A [k] ;
+	    mexPrintf (" %d", row) ;
+	}
+	mexPrintf ("\n") ;
+    }
+}
diff --git a/src/C/SuiteSparse/Contents.m b/src/C/SuiteSparse/Contents.m
new file mode 100644
index 0000000..b1c7cce
--- /dev/null
+++ b/src/C/SuiteSparse/Contents.m
@@ -0,0 +1,134 @@
+% Welcome to SuiteSparse : a Suite of Sparse matrix packages, containing a
+% collection of sparse matrix packages authored or co-authored by Tim Davis.
+% Only the primary MATLAB functions are listed below.
+%
+% Example:
+%   SuiteSparse_install - compiles and installs all of SuiteSparse, and runs
+%               several demos and tests.
+%
+%-------------------
+% Ordering methods:
+%-------------------
+%
+%   amd          - approximate minimum degree ordering.
+%   colamd       - column approximate minimum degree ordering.
+%   symamd       - symmetrix approximate min degree ordering based on colamd.
+%   camd         - constrained amd.
+%   ccolamd      - constrained colamd.
+%   csymamd      - constrained symamd.
+%
+%---------------------------------------------------------------
+% CHOLMOD: a sparse supernodal Cholesky update/downdate package:
+%---------------------------------------------------------------
+%
+%   cholmod      - computes x=A\b when A is symmetric and positive definite.
+%   chol2        - same as MATLAB chol(sparse(A)), just faster.
+%   lchol        - computes an LL' factorization.
+%   ldlchol      - computes an LDL' factorization.
+%   ldlupdate    - updates an LDL' factorization.
+%   resymbol     - recomputes symbolic LL or LDL' factorization.
+%   ldlsolve     - solves Ax=b using an LDL' factorization.
+%   ldlsplit     - splits LD into L and D.
+%   metis        - interface to METIS node-nested-dissection.
+%   nesdis       - interface to CHOLMOD's nested-dissection (based on METIS).
+%   septree      - prune a separator tree.
+%   bisect       - interface to METIS' node bisector.
+%   analyze      - order and analyze using CHOLMOD.
+%   etree2       - same as MATLAB "etree", just faster and more reliable.
+%   sparse2      - same as MATLAB "sparse", just faster.
+%   symbfact2    - same as MATLAB "symbfact", just faster and more reliable.
+%   sdmult       - same as MATLAB S*F or S'*F (S sparse, F full), just faster.
+%   ldl_normest  - compute error in LDL' factorization.
+%   lu_normest   - compute error in LU factorization.
+%   mread        - read a sparse matrix in Matrix Market format
+%   mwrite       - write a sparse matrix in Matrix Market format
+%   spsym        - determine the symmetry of a sparse matrix
+%
+%------------------------------------------
+% CSPARSE: a Concise Sparse matrix package:
+%------------------------------------------
+%
+%   Matrices used in CSparse must in general be either sparse and real,
+%   or dense vectors.  Ordering methods can accept any sparse matrix.
+%
+%   cs_add       - sparse matrix addition.
+%   cs_amd       - approximate minimum degree ordering.
+%   cs_chol      - sparse Cholesky factorization.
+%   cs_cholsol   - solve A*x=b using a sparse Cholesky factorization.
+%   cs_counts    - column counts for sparse Cholesky factor L.
+%   cs_dmperm    - maximum matching or Dulmage-Mendelsohn permutation.
+%   cs_dmsol     - x=A\b using the coarse Dulmage-Mendelsohn decomposition.
+%   cs_dmspy     - plot the Dulmage-Mendelsohn decomposition of a matrix.
+%   cs_droptol   - remove small entries from a sparse matrix.
+%   cs_esep      - find an edge separator of a symmetric matrix A
+%   cs_etree     - elimination tree of A or A'*A.
+%   cs_gaxpy     - sparse matrix times vector.
+%   cs_lsolve    - solve a sparse lower triangular system L*x=b.
+%   cs_ltsolve   - solve a sparse upper triangular system L'*x=b.
+%   cs_lu        - sparse LU factorization, with fill-reducing ordering.
+%   cs_lusol     - solve Ax=b using LU factorization.
+%   cs_make      - compiles CSparse for use in MATLAB.
+%   cs_multiply  - sparse matrix multiply.
+%   cs_nd        - generalized nested dissection ordering.
+%   cs_nsep      - find a node separator of a symmetric matrix A.
+%   cs_permute   - permute a sparse matrix.
+%   cs_print     - print the contents of a sparse matrix.
+%   cs_qr        - sparse QR factorization.
+%   cs_qleft     - apply Householder vectors on the left.
+%   cs_qright    - apply Householder vectors on the right.
+%   cs_qrsol     - solve a sparse least-squares problem.
+%   cs_randperm  - random permutation.
+%   cs_sep       - convert an edge separator into a node separator.
+%   cs_scc       - strongly-connected components of a square sparse matrix.
+%   cs_scc2      - cs_scc, or connected components of a bipartite graph.
+%   cs_sparse    - convert a triplet form into a sparse matrix.
+%   cs_sqr       - symbolic sparse QR factorization.
+%   cs_symperm   - symmetric permutation of a symmetric matrix.
+%   cs_transpose - transpose a real sparse matrix.
+%   cs_updown    - rank-1 update/downdate of a sparse Cholesky factorization.
+%   cs_usolve    - solve a sparse upper triangular system U*x=b.
+%   cs_utsolve   - solve a sparse lower triangular system U'*x=b.
+%   cspy         - plot a sparse matrix in color.
+%   ccspy	 - plot the connected components of a matrix.
+%
+%-------------------------------
+% LDL: Sparse LDL factorization:
+%-------------------------------
+% 
+%   ldlsparse   - LDL' factorization of a real, sparse, symmetric matrix.
+%   ldlrow      - an m-file description of the algorithm used by LDL.
+%
+%-----------------------------------------------
+% UMFPACK: the Unsymmetric MultiFrontal Package:
+%-----------------------------------------------
+%
+%   umfpack           - computes x=A\b, x=A/b, or lu (A) for a sparse matrix A
+%   umfpack_details   - details on all the options for using umfpack in MATLAB
+%   umfpack_report    - prints optional control settings and statistics
+%   umfpack_btf       - factorize A using a block triangular form
+%   umfpack_solve     - x = A\b or x = b/A
+%   lu_normest        - estimates norm (L*U-A,1) without forming L*U-A
+%                       (duplicate of CHOLMOD/lu_normest, for completeness)
+%   luflop            - given L and U, computes # of flops required
+%
+%------------------------------------------------------
+% RBio: read/write matrices in Rutherford/Boeing format
+%------------------------------------------------------
+%
+%   RBread    - read a sparse matrix from a Rutherford/Boeing file
+%   RBreade   - read a symmetric finite-element matrix from a R/B file
+%   RBtype    - determine the Rutherford/Boeing type of a sparse matrix
+%   RBwrite   - write a sparse matrix to a Rutherford/Boeing file
+%
+%-------------------------------------------------------------------------------
+%
+% For help on compiling SuiteSparse or the demos, testing functions, etc.,
+% please see the help for each individual package. 
+%
+% NOTE: None of the packages above have yet been ported to 64-bit MATLAB.
+% Do not attempt to use these in 64-bit MATLAB.
+%
+% Copyright 2006, Timothy A. Davis
+% http://www.cise.ufl.edu/research/sparse
+
+help SuiteSparse
diff --git a/src/C/SuiteSparse/Makefile b/src/C/SuiteSparse/Makefile
new file mode 100644
index 0000000..dafd591
--- /dev/null
+++ b/src/C/SuiteSparse/Makefile
@@ -0,0 +1,93 @@
+#-------------------------------------------------------------------------------
+# Makefile for all UF sparse matrix packages
+#-------------------------------------------------------------------------------
+
+include UFconfig/UFconfig.mk
+
+# Compile the default rules for each package
+default:
+	( cd UFconfig/xerbla ; $(MAKE) )
+	( cd metis-4.0 ; $(MAKE) )
+	( cd AMD ; $(MAKE) )
+	( cd CAMD ; $(MAKE) )
+	( cd COLAMD ; $(MAKE) )
+	( cd BTF ; $(MAKE) )
+	( cd KLU ; $(MAKE) )
+	( cd LDL ; $(MAKE) )
+	( cd CCOLAMD ; $(MAKE) )
+	( cd UMFPACK ; $(MAKE) )
+	( cd CHOLMOD ; $(MAKE) )
+	( cd CSparse ; $(MAKE) )
+	( cd CXSparse ; $(MAKE) )
+#	( cd LPDASA ; $(MAKE) )
+#	( cd PARAKLETE ; $(MAKE) )
+
+library: default
+
+# Compile the MATLAB mexFunctions
+mex:
+	( cd AMD ; $(MAKE) mex )
+	( cd CAMD ; $(MAKE) mex )
+	( cd COLAMD ; $(MAKE) mex )
+	( cd BTF ; $(MAKE) mex )
+	( cd KLU ; $(MAKE) mex )
+	( cd LDL ; $(MAKE) mex )
+	( cd CCOLAMD ; $(MAKE) mex )
+	( cd CHOLMOD ; $(MAKE) mex )
+	( cd UMFPACK ; $(MAKE) mex )
+	( cd CSparse ; $(MAKE) mex )
+	( cd RBio ; $(MAKE) )
+	( cd UFcollection ; $(MAKE) )
+
+# Remove all files not in the original distribution
+purge:
+	( cd UFconfig/xerbla ; $(MAKE) purge )
+	( cd metis-4.0 ; $(MAKE) realclean )
+	( cd AMD ; $(MAKE) purge )
+	( cd CAMD ; $(MAKE) purge )
+	( cd COLAMD ; $(MAKE) purge )
+	( cd BTF ; $(MAKE) purge )
+	( cd KLU ; $(MAKE) purge )
+	( cd LDL ; $(MAKE) purge )
+	( cd CCOLAMD ; $(MAKE) purge )
+	( cd UMFPACK ; $(MAKE) purge )
+	( cd CHOLMOD ; $(MAKE) purge )
+	( cd CSparse ; $(MAKE) purge )
+	( cd CXSparse ; $(MAKE) purge )
+	( cd RBio ; $(MAKE) purge )
+	( cd UFcollection ; $(MAKE) purge )
+#	( cd LPDASA ; $(MAKE) purge )
+#	( cd PARAKLETE ; $(MAKE) purge )
+
+# Remove all files not in the original distribution, but keep the libraries
+clean:
+	( cd UFconfig/xerbla ; $(MAKE) clean )
+	( cd metis-4.0 ; $(MAKE) clean )
+	( cd AMD ; $(MAKE) clean )
+	( cd CAMD ; $(MAKE) clean )
+	( cd COLAMD ; $(MAKE) clean )
+	( cd BTF ; $(MAKE) clean )
+	( cd KLU ; $(MAKE) clean )
+	( cd LDL ; $(MAKE) clean )
+	( cd CCOLAMD ; $(MAKE) clean )
+	( cd UMFPACK ; $(MAKE) clean )
+	( cd CHOLMOD ; $(MAKE) clean )
+	( cd CSparse ; $(MAKE) clean )
+	( cd CXSparse ; $(MAKE) clean )
+	( cd RBio ; $(MAKE) clean )
+	( cd UFcollection ; $(MAKE) clean )
+#	( cd LPDASA ; $(MAKE) clean )
+#	( cd PARAKLETE ; $(MAKE) clean )
+
+distclean: purge
+
+# Create CXSparse from CSparse.  Note that the CXSparse directory should
+# initially not exist.
+cx:
+	( cd CSparse ; $(MAKE) purge )
+	( cd CXSparse_newfiles ; tar cfv - * | gzip -9 > ../CXSparse_newfiles.tar.gz )
+	./CSparse_to_CXSparse CSparse CXSparse CXSparse_newfiles.tar.gz
+	( cd CXSparse/Demo ; $(MAKE) )
+	( cd CXSparse/Demo ; $(MAKE) > cs_demo.out )
+	( cd CXSparse ; $(MAKE) purge )
+
diff --git a/src/C/SuiteSparse/README.txt b/src/C/SuiteSparse/README.txt
new file mode 100644
index 0000000..a87e1ea
--- /dev/null
+++ b/src/C/SuiteSparse/README.txt
@@ -0,0 +1,120 @@
+SuiteSparse:  A Suite of Sparse matrix packages
+
+------------------
+SuiteSparse/README
+------------------
+
+================================================================================
+QUICK START FOR MATLAB USERS:  unzip the SuiteSparse.zip file, then in the
+MATLAB Command Window, cd to the SuiteSparse directory and type
+SuiteSparse_install.  All packages will be compiled, and several demos will be
+run.
+================================================================================
+
+All codes, below, are stable except KLU and BTF.  KLU and BTF are "beta", but
+robust enough for production use.  They merely are still in development, and
+are missing a few minor features to make them "1.0".  Thus the "beta".  They
+are bug-free as far as I know, and are in use in commercial circuit simulation
+packages.
+
+Nov, 2006.  SuiteSparse version 2.3.  Note that SuiteSparse is now given
+its own version number, rather than merely a date of release.
+
+UF suite of sparse matrix algorithms:
+
+    AMD		approximate minimum degree ordering
+
+    CAMD	constrained column approximate minimum degree ordering
+
+    COLAMD	column approximate minimum degree ordering
+
+    CCOLAMD	constrained column approximate minimum degree ordering
+
+    BTF		permutation to block triangular form (beta)
+
+    KLU		sparse LU factorization, primarily for circuit simulation.
+		Requires AMD, COLAMD, and BTF (beta).  Optionally
+		uses CHOLMOD, CCOLAMD, and METIS.
+
+    UMFPACK	sparse LU factorization.  Requires AMD and the BLAS.
+
+    CHOLMOD	sparse Cholesky factorization.  Requires AMD, COLAMD, CCOLAMD,
+		METIS, the BLAS, and LAPACK.
+
+    UFconfig	configuration file for all the above packages.  The
+		UFconfig/UFconfig.mk is included in the Makefile's of all
+		packages.  CSparse and CXSparse do not use UFconfig.
+
+    CSparse	a concise sparse matrix package, developed for my upcoming
+		book, "Direct Methods for Sparse Linear Systems", to be
+		published by SIAM.
+
+    CXSparse	CSparse Extended.  Includes support for complex matrices
+		and both int or long integers.
+
+    RBio	read/write sparse matrices in Rutherford/Boeing format
+
+    UFcollection    toolbox for managing the UF Sparse Matrix Collection
+
+    LPDASA	LP dual active set algorithm (to appear)
+
+
+See http://www.netlib.org/blas for the Fortran reference BLAS (slow, but they
+work).  See http://www.tacc.utexas.edu/~kgoto/ or
+http://www.cs.utexas.edu/users/flame/goto/ for an optimized BLAS.
+See http://www.netlib.org/lapack for LAPACK.  The UFconfig/UFconfig.mk
+file assumes the Goto BLAS; change -lgoto to -l(your BLAS library here),
+if you have another BLAS (-lblas, for example).
+
+CHOLMOD requires METIS 4.0.1 (http://www-users.cs.umn.edu/~karypis/metis)
+by default.  Place a copy of the metis-4.0 directory in the same directory
+(SuiteSparse) containing this README file.  cd to metis-4.0 and edit the
+Makefile.in file.  I recommend making these changes to metis-4.0/Makefile.in:
+
+CC = gcc
+OPTFLAGS = -O3
+COPTIONS = -fexceptions -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
+
+then type "make".  You can now compile CHOLMOD.  First,
+edit the UFconfig/UFconfig.mk file (see that file for instructions), if
+necessary.  Next, type "make" in this directory to compile all packages in
+this distribution.  CHOLMOD can be compiled without METIS (use -DNPARTITION).
+
+Refer to each package for license, copyright, and author information.  All
+codes are authored or co-authored by Timothy A. Davis, CISE Dept., Univ. of
+Florida.  email: my last name @ cise dot ufl dot edu.
+
+To compile each package, cd to the top-level directory (AMD, COLAMD, etc)
+and type "make".  Type "make clean" in the same directory to remove all but
+the compiled libraries.  Type "make distclean" to remove all files not in
+the original distribution.  Alternatively, just type "make" in this directory.
+
+If you intend on compiling the MATLAB mexFunction interfaces, UFconfig.mk
+should use
+
+    CFLAGS = -O3 -fexceptions
+
+(for Linux), to ensure that exceptions are properly caught.  See your
+default MATLAB mexopts.sh file for how to do this for other systems
+(type the command "mex -v").  Alternatively, you can use the various M-files
+in each package to compile them from within the MATLAB Command Window, or
+just type "SuiteSparse_install" in the MATLAB Command Window when MATLAB's
+working directory is this one.  That is the only way to compile these packages
+for Windows, unless you have Cygwin or wish to write your own MS Visual Studio
+scripts.
+
+--------------------------------------------------------------------------------
+
+To turn on debugging (for development only, not needed by the typical user):
+
+SuiteSparse/UFconfig/UFconfig.mk
+    change CFLAGS = -O to CFLAGS = -g
+
+To turn on debugging, add the line "#undef NDEBUG" in the following files.
+To turn off debugging, remove that line.
+
+    SuiteSparse/CHOLMOD/Include/cholmod_internal.h
+    SuiteSparse/AMD/Source/amd_internal.h
+    SuiteSparse/CAMD/Source/camd_internal.h
+    SuiteSparse/CCOLAMD/ccolmod.c
+    SuiteSparse/COLAMD/colamd.c
diff --git a/src/C/SuiteSparse/README_cvxopt b/src/C/SuiteSparse/README_cvxopt
new file mode 100644
index 0000000..83bc799
--- /dev/null
+++ b/src/C/SuiteSparse/README_cvxopt
@@ -0,0 +1,28 @@
+This is the January 30, 2007 (version 2.4.0) distribution of the  
+SuiteSparse package, with the following files and directories removed.
+
+AMD/Demo
+AMD/MATLAB
+BTF 
+CAMD
+CCOLAMD 
+CHOLMOD/Demo
+CHOLMOD/MATLAB
+CHOLMOD/MatrixOps
+CHOLMOD/Modify
+CHOLMOD/Partition
+CHOLMOD/Tcov
+CHOLMOD/Valgrind
+CSparse
+Csparse_to_CXsparse
+CXSparse
+CXSparse_newfiles
+CXSparse_newfiles.tar.gz
+KLU
+LDL
+RBio
+SuiteSparse_install.m
+UFcollection
+UMFPACK/Demo
+UMFPACK/MATLAB
+UMFPACK/Tcov
diff --git a/src/C/SuiteSparse/UFconfig/README.txt b/src/C/SuiteSparse/UFconfig/README.txt
new file mode 100644
index 0000000..b505181
--- /dev/null
+++ b/src/C/SuiteSparse/UFconfig/README.txt
@@ -0,0 +1,25 @@
+This file contains configuration settings for
+all many of the software packages that I develop or
+co-author:
+
+  Package Version	    Description
+  ------- -------	    -----------
+  AMD	   1.2 or later	    approximate minimum degree ordering
+  CAMD	   any
+  COLAMD   2.4 or later	    column approximate minimum degree ordering
+  CCOLAMD  any		    constrained approximate minimum degree ordering
+  UMFPACK  4.5 or later	    sparse LU factorization, with the BLAS
+  CXSparse any
+  CHOLMOD  any		    sparse Cholesky factorization, update/downdate
+  KLU	   1.0 or later	    sparse LU factorization, BLAS-free
+  BTF	   1.0 or later	    permutation to block triangular form
+  LDL	   any		    concise sparse LDL'
+  LPDASA   any		    LP Dual Active Set Algorithm
+
+In addition, the xerbla/ directory contains Fortan and C versions
+of the BLAS/LAPACK xerbla routine, which is called when an invalid
+input is passed to the BLAS or LAPACK.  The xerbla provided here
+does not print any message, so the entire Fortran I/O library does
+not need to be linked into a C application.  Most versions of the
+BLAS contain xerbla, but those from K. Goto do not.  Use this if
+you need too.
diff --git a/src/C/SuiteSparse/UFconfig/UFconfig.h b/src/C/SuiteSparse/UFconfig/UFconfig.h
new file mode 100644
index 0000000..051a40f
--- /dev/null
+++ b/src/C/SuiteSparse/UFconfig/UFconfig.h
@@ -0,0 +1,115 @@
+/* ========================================================================== */
+/* === UFconfig.h =========================================================== */
+/* ========================================================================== */
+
+/* Configuration file for SuiteSparse: a Suite of Sparse matrix packages
+ * (AMD, COLAMD, CCOLAMD, CAMD, CHOLMOD, UMFPACK, CXSparse, and others).
+ *
+ * UFconfig.h provides the definition of the long integer.  On most systems,
+ * a C program can be compiled in LP64 mode, in which long's and pointers are
+ * both 64-bits, and int's are 32-bits.  Windows 64, however, uses the LLP64
+ * model, in which int's and long's are 32-bits, and long long's and pointers
+ * are 64-bits.
+ *
+ * SuiteSparse packages that include long integer versions are
+ * intended for the LP64 mode.  However, as a workaround for Windows 64
+ * (and perhaps other systems), the long integer can be redefined.
+ *
+ * If _WIN64 is defined, then the __int64 type is used instead of long.
+ *
+ * The long integer can also be defined at compile time.  For example, this
+ * could be added to UFconfig.mk:
+ *
+ * CFLAGS = -O -D'UF_long=long long' -D'UF_long_max=9223372036854775801' \
+ *   -D'UF_long_id="%lld"'
+ *
+ * This file defines UF_long as either long (on all but _WIN64) or
+ * __int64 on Windows 64.  The intent is that a UF_long is always a 64-bit
+ * integer in a 64-bit code.  ptrdiff_t might be a better choice than long;
+ * it is always the same size as a pointer.
+ *
+ * This file also defines the SUITESPARSE_VERSION and related definitions.
+ *
+ * Copyright (c) 2006, University of Florida.  No licensing restrictions
+ * apply to this file or to the UFconfig directory.  Author: Timothy A. Davis.
+ */
+
+#ifndef _UFCONFIG_H
+#define _UFCONFIG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <limits.h>
+
+/* ========================================================================== */
+/* === UF_long ============================================================== */
+/* ========================================================================== */
+
+#ifndef UF_long
+
+#ifdef _WIN64
+
+#define UF_long __int64
+#define UF_long_max _I64_MAX
+#define UF_long_id "%I64d"
+
+#else
+
+#define UF_long long
+#define UF_long_max LONG_MAX
+#define UF_long_id "%ld"
+
+#endif
+#endif
+
+/* ========================================================================== */
+/* === SuiteSparse version ================================================== */
+/* ========================================================================== */
+
+/* SuiteSparse is not a package itself, but a collection of packages, some of
+ * which must be used together (UMFPACK requires AMD, CHOLMOD requires AMD,
+ * COLAMD, CAMD, and CCOLAMD, etc).  A version number is provided here for the
+ * collection itself.  The versions of packages within each version of
+ * SuiteSparse are meant to work together.  Combining one packge from one
+ * version of SuiteSparse, with another package from another version of
+ * SuiteSparse, may or may not work.
+ *
+ * SuiteSparse Version 2.4 contains the following packages:
+ *
+ *  AMD		    version 2.0.4
+ *  CAMD	    version 2.1.3
+ *  COLAMD	    version 2.6.0
+ *  CCOLAMD	    version 2.5.2
+ *  CHOLMOD	    version 1.4.0
+ *  CSparse	    version 2.0.7
+ *  CXSparse	    version 2.0.7
+ *  KLU		    version 0.11
+ *  BTF		    version 0.11
+ *  LDL		    version 1.3.4
+ *  UFconfig	    version number is the same as SuiteSparse
+ *  UMFPACK	    version 5.0.3
+ *  RBio	    version 1.0.0
+ *  UFcollection    version 1.0.1
+ *
+ * Other package dependencies:
+ *  BLAS	    required by CHOLMOD and UMFPACK
+ *  LAPACK	    required by CHOLMOD
+ *  METIS 4.0.1	    required by CHOLMOD (optional)
+ */
+
+#define SUITESPARSE_DATE "Dec 13, 2006"
+#define SUITESPARSE_VER_CODE(main,sub) ((main) * 1000 + (sub))
+#define SUITESPARSE_MAIN_VERSION 2
+#define SUITESPARSE_SUB_VERSION 4
+#define SUITESPARSE_SUBSUB_VERSION 0
+#define SUITESPARSE_VERSION \
+    SUITESPARSE_VER_CODE(SUITESPARSE_MAIN_VERSION,SUITESPARSE_SUB_VERSION)
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/src/C/SuiteSparse/UFconfig/UFconfig.mk b/src/C/SuiteSparse/UFconfig/UFconfig.mk
new file mode 100644
index 0000000..61dcbee
--- /dev/null
+++ b/src/C/SuiteSparse/UFconfig/UFconfig.mk
@@ -0,0 +1,298 @@
+#===============================================================================
+# UFconfig.mk:  common configuration file for the SuiteSparse
+#===============================================================================
+
+# This file contains all configuration settings for all packages authored or
+# co-authored by Tim Davis at the University of Florida:
+#
+# Package Version       Description
+# ------- -------       -----------
+# AMD	  1.2 or later  approximate minimum degree ordering
+# COLAMD  2.4 or later  column approximate minimum degree ordering
+# CCOLAMD 1.0 or later  constrained column approximate minimum degree ordering
+# CAMD    any		constrained approximate minimum degree ordering
+# UMFPACK 4.5 or later	sparse LU factorization, with the BLAS
+# CHOLMOD any		sparse Cholesky factorization, update/downdate
+# KLU	  0.8 or later  sparse LU factorization, BLAS-free
+# BTF	  0.8 or later  permutation to block triangular form
+# LDL	  1.2 or later	concise sparse LDL'
+# LPDASA  any		linear program solve (dual active set algorithm)
+#
+# The UFconfig directory and the above packages should all appear in a single
+# directory, in order for the Makefile's within each package to find this file.
+#
+# To enable an option of the form "# OPTION = ...", edit this file and
+# delete the "#" in the first column of the option you wish to use.
+
+#------------------------------------------------------------------------------
+# Generic configuration
+#------------------------------------------------------------------------------
+
+# C compiler and compiler flags:  These will normally not give you optimal
+# performance.  You should select the optimization parameters that are best
+# for your system.  On Linux, use "CFLAGS = -O3 -fexceptions" for example.
+CC = cc
+CFLAGS = -O
+
+# ranlib, and ar, for generating libraries
+RANLIB = ranlib
+AR = ar cr
+
+# delete and rename a file
+RM = rm -f
+MV = mv -f
+
+# Fortran compiler (not normally required)
+F77 = f77
+F77FLAGS = -O
+F77LIB =
+
+# C and Fortran libraries
+LIB = -lm
+
+# For compiling MATLAB mexFunctions
+MEX = mex -O
+
+# Which version of MAKE you are using (default is "make")
+# MAKE = make
+# MAKE = gmake
+
+#------------------------------------------------------------------------------
+# BLAS and LAPACK configuration:
+#------------------------------------------------------------------------------
+
+# UMFPACK and CHOLMOD both require the BLAS.  CHOLMOD also requires LAPACK.
+# See Kazushige Goto's BLAS at http://www.cs.utexas.edu/users/flame/goto/ or
+# http://www.tacc.utexas.edu/~kgoto/ for the best BLAS to use with CHOLMOD.
+# LAPACK is at http://www.netlib.org/lapack/ .  You can use the standard
+# Fortran LAPACK along with Goto's BLAS to obtain very good performance.
+# CHOLMOD gets a peak numeric factorization rate of 3.6 Gflops on a 3.2 GHz
+# Pentium 4 (512K cache, 4GB main memory) with the Goto BLAS, and 6 Gflops
+# on a 2.5Ghz dual-core AMD Opteron.
+
+# These settings will probably not work, since there is no fixed convention for
+# naming the BLAS and LAPACK library (*.a or *.so) files.  Assume the Goto
+# BLAS are available.
+BLAS = -lgoto -lgfortran -lgfortranbegin
+LAPACK = -llapack
+
+# The BLAS might not contain xerbla, an error-handling routine for LAPACK and
+# the BLAS.  Also, the standard xerbla requires the Fortran I/O library, and
+# stops the application program if an error occurs.  A C version of xerbla
+# distributed with this software (UFconfig/xerbla/libcerbla.a) includes a
+# Fortran-callable xerbla routine that prints nothing and does not stop the
+# application program.  This is optional.
+# XERBLA = ../../UFconfig/xerbla/libcerbla.a 
+
+# If you wish to use the XERBLA in LAPACK and/or the BLAS instead,
+# use this option:
+XERBLA = 
+
+# If you wish to use the Fortran UFconfig/xerbla/xerbla.f instead, use this:
+# XERBLA = ../../UFconfig/xerbla/libxerbla.a 
+
+#------------------------------------------------------------------------------
+# METIS, optionally used by CHOLMOD
+#------------------------------------------------------------------------------
+
+# If you do not have METIS, or do not wish to use it in CHOLMOD, you must
+# compile CHOLMOD with the -DNPARTITION flag.  You must also use the
+# "METIS =" option, below.
+
+# The path is relative to where it is used, in CHOLMOD/Lib, CHOLMOD/MATLAB, etc.
+# You may wish to use an absolute path.  METIS is optional.  Compile
+# CHOLMOD with -DNPARTITION if you do not wish to use METIS.
+METIS_PATH = ../../metis-4.0
+METIS = ../../metis-4.0/libmetis.a
+
+# If you use CHOLMOD_CONFIG = -DNPARTITION then you must use the following
+# options:
+# METIS_PATH =
+# METIS =
+
+#------------------------------------------------------------------------------
+# UMFPACK configuration:
+#------------------------------------------------------------------------------
+
+# Configuration flags for UMFPACK.  See UMFPACK/Source/umf_config.h for details.
+#
+# -DNBLAS	do not use the BLAS.  UMFPACK will be very slow.
+# -D'LONGBLAS=long' or -DLONGBLAS='long long' defines the integers used by
+#  		LAPACK and the BLAS (defaults to 'int')
+# -DNSUNPERF	do not use the Sun Perf. Library (default is use it on Solaris)
+# -DNPOSIX	do not use POSIX routines sysconf and times.
+# -DGETRUSAGE	use getrusage
+# -DNO_TIMER	do not use any timing routines
+# -DNRECIPROCAL	do not multiply by the reciprocal
+# -DNO_DIVIDE_BY_ZERO	do not divide by zero
+
+UMFPACK_CONFIG = 
+
+#------------------------------------------------------------------------------
+# CHOLMOD configuration
+#------------------------------------------------------------------------------
+
+# CHOLMOD Library Modules, which appear in libcholmod.a:
+# Core		requires: none
+# Check		requires: Core
+# Cholesky	requires: Core, AMD, COLAMD.  optional: Partition, Supernodal
+# MatrixOps	requires: Core
+# Modify	requires: Core
+# Partition	requires: Core, CCOLAMD, METIS.  optional: Cholesky
+# Supernodal	requires: Core, BLAS, LAPACK
+#
+# CHOLMOD test/demo Modules (all are GNU GPL, do not appear in libcholmod.a):
+# Tcov		requires: Core, Check, Cholesky, MatrixOps, Modify, Supernodal
+#		optional: Partition
+# Valgrind	same as Tcov
+# Demo		requires: Core, Check, Cholesky, MatrixOps, Supernodal
+#		optional: Partition
+#
+# Configuration flags:
+# -DNCHECK	    do not include the Check module.	   License GNU LGPL
+# -DNCHOLESKY	    do not include the Cholesky module.	   License GNU LGPL
+# -DNPARTITION	    do not include the Partition module.   License GNU LGPL
+#		    also do not include METIS.
+# -DNGPL	    do not include any GNU GPL Modules in the CHOLMOD library:
+# -DNMATRIXOPS	    do not include the MatrixOps module.   License GNU GPL
+# -DNMODIFY	    do not include the Modify module.      License GNU GPL
+# -DNSUPERNODAL     do not include the Supernodal module.  License GNU GPL
+#
+# -DNPRINT	    do not print anything.
+# -D'LONGBLAS=long' or -DLONGBLAS='long long' defines the integers used by
+#  		    	LAPACK and the BLAS (defaults to 'int')
+# -DNSUNPERF	    for Solaris only.  If defined, do not use the Sun
+#			Performance Library
+
+CHOLMOD_CONFIG =
+
+#------------------------------------------------------------------------------
+# Linux
+#------------------------------------------------------------------------------
+
+# Using default compilers:
+# CC = gcc
+# CFLAGS = -O3
+
+# alternatives:
+# CFLAGS = -g -fexceptions \
+   	-Wall -W -Wshadow -Wmissing-prototypes -Wstrict-prototypes \
+    	-Wredundant-decls -Wnested-externs -Wdisabled-optimization -ansi
+# CFLAGS = -O3 -fexceptions \
+   	-Wall -W -Werror -Wshadow -Wmissing-prototypes -Wstrict-prototypes \
+    	-Wredundant-decls -Wnested-externs -Wdisabled-optimization -ansi
+CFLAGS = -O3 -fexceptions -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
+# CFLAGS = -O3
+
+# consider:
+# -fforce-addr -fmove-all-movables -freduce-all-givs -ftsp-ordering
+# -frename-registers -ffast-math -funroll-loops
+
+# Using the Goto BLAS:
+# BLAS = -lgoto -lfrtbegin -lg2c $(XERBLA) -lpthread
+
+# Using Intel's icc and ifort compilers:
+#   (does not work for mexFunctions unless you add a mexopts.sh file)
+# F77 = ifort
+# CC = icc
+# CFLAGS = -O3 -xN -vec_report=0
+# CFLAGS = -g
+# old (broken): CFLAGS = -ansi -O3 -ip -tpp7 -xW -vec_report0
+
+# 64bit:
+# F77FLAGS = -O -m64
+# CFLAGS = -O3 -fexceptions -m64
+# BLAS = -lgoto64 -lfrtbegin -lg2c -lpthread $(XERBLA)
+# LAPACK = -llapack64
+
+
+# SUSE Linux 10.1, AMD Opteron
+# F77 = gfortran
+# BLAS = -lgoto_opteron64 -lgfortran
+
+# SUSE Linux 10.1, Intel Pentium
+# F77 = gfortran
+# BLAS = -lgoto -lgfortran
+
+#------------------------------------------------------------------------------
+# Solaris
+#------------------------------------------------------------------------------
+
+# 32-bit
+# CFLAGS = -KPIC -dalign -xc99=%none -Xc -xlibmieee -xO5 -xlibmil
+
+# 64-bit
+# CFLAGS = -KPIC -dalign -xc99=%none -Xc -xlibmieee -xO5 -xlibmil -xarch=v9
+
+# BLAS = -xlic_lib=sunperf
+# LAPACK =
+
+#------------------------------------------------------------------------------
+# Compaq Alpha
+#------------------------------------------------------------------------------
+
+# 64-bit mode only
+# CFLAGS = -O2 -std1
+# BLAS = -ldxml
+# LAPACK =
+
+#------------------------------------------------------------------------------
+# Macintosh
+#------------------------------------------------------------------------------
+
+# CC = gcc
+# CFLAGS = -O3 -fno-common -no-cpp-precomp -fexceptions
+# LIB = -lstdc++
+# BLAS = -framework Accelerate
+# LAPACK = -framework Accelerate
+
+#------------------------------------------------------------------------------
+# IBM RS 6000
+#------------------------------------------------------------------------------
+
+# BLAS = -lessl
+# LAPACK =
+
+# 32-bit mode:
+# CFLAGS   = -O4 -qipa -qmaxmem=16384 -qproto
+# F77FLAGS = -O4 -qipa -qmaxmem=16384
+
+# 64-bit mode:
+# CFLAGS   = -O4 -qipa -qmaxmem=16384 -q64 -qproto
+# F77FLAGS = -O4 -qipa -qmaxmem=16384 -q64
+# AR = ar -X64
+
+#------------------------------------------------------------------------------
+# SGI IRIX
+#------------------------------------------------------------------------------
+
+# BLAS = -lscsl
+# LAPACK =
+
+# 32-bit mode
+# CFLAGS = -O
+
+# 64-bit mode (32 bit int's and 64-bit long's):
+# CFLAGS = -64
+# F77FLAGS = -64
+
+# SGI doesn't have ranlib
+# RANLIB = echo
+
+#------------------------------------------------------------------------------
+# AMD Opteron (64 bit)
+#------------------------------------------------------------------------------
+
+# BLAS = -lgoto_opteron64 -lg2c
+# LAPACK = -llapack_opteron64
+
+# SUSE Linux 10.1, AMD Opteron
+# F77 = gfortran
+# BLAS = -lgoto_opteron64 -lgfortran
+# LAPACK = -llapack_opteron64
+
+#------------------------------------------------------------------------------
+# remove object files and profile output
+#------------------------------------------------------------------------------
+
+CLEAN = *.o *.obj *.ln *.bb *.bbg *.da *.tcov *.gcov gmon.out *.bak *.d
diff --git a/src/C/SuiteSparse/UFconfig/xerbla/Makefile b/src/C/SuiteSparse/UFconfig/xerbla/Makefile
new file mode 100644
index 0000000..7eb2d58
--- /dev/null
+++ b/src/C/SuiteSparse/UFconfig/xerbla/Makefile
@@ -0,0 +1,31 @@
+# Makefile for null-output xerbla
+
+default: ccode
+
+include ../UFconfig.mk
+
+ccode: libcerbla.a
+
+fortran: libxerbla.a 
+
+all: libxerbla.a libcerbla.a
+
+# Fortran version:
+libxerbla.a: xerbla.f
+	$(F77) $(F77FLAGS) -c xerbla.f
+	$(AR) libxerbla.a xerbla.o
+	- $(RM) xerbla.o
+
+# C version:
+libcerbla.a: xerbla.c xerbla.h
+	$(CC) $(CFLAGS) -c xerbla.c
+	$(AR) libcerbla.a xerbla.o
+	- $(RM) xerbla.o
+
+distclean: purge
+
+purge: clean
+	- $(RM) *.o *.a
+
+clean:
+	- $(RM) $(CLEAN)
diff --git a/src/C/SuiteSparse/UFconfig/xerbla/xerbla.c b/src/C/SuiteSparse/UFconfig/xerbla/xerbla.c
new file mode 100644
index 0000000..5107f03
--- /dev/null
+++ b/src/C/SuiteSparse/UFconfig/xerbla/xerbla.c
@@ -0,0 +1,12 @@
+
+void xerbla_ (char *srname, int *info)
+{
+    /* do nothing */ ;
+}
+
+
+void xerbla (char *srname, int *info)
+{
+    /* do nothing */ ;
+}
+
diff --git a/src/C/SuiteSparse/UFconfig/xerbla/xerbla.f b/src/C/SuiteSparse/UFconfig/xerbla/xerbla.f
new file mode 100644
index 0000000..4272004
--- /dev/null
+++ b/src/C/SuiteSparse/UFconfig/xerbla/xerbla.f
@@ -0,0 +1,46 @@
+      SUBROUTINE XERBLA( SRNAME, INFO )
+*
+*  -- LAPACK auxiliary routine (version 3.0) --
+*     Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
+*     Courant Institute, Argonne National Lab, and Rice University
+*     September 30, 1994
+*
+*     .. Scalar Arguments ..
+      CHARACTER*6        SRNAME
+      INTEGER            INFO
+*     ..
+*
+*  Purpose
+*  =======
+*
+*  XERBLA  is an error handler for the LAPACK routines.
+*  It is called by an LAPACK routine if an input parameter has an
+*  invalid value.  A message is printed and execution stops.
+*
+*  Installers may consider modifying the STOP statement in order to
+*  call system-specific exception-handling facilities.
+*
+*  Arguments
+*  =========
+*
+*  SRNAME  (input) CHARACTER*6
+*          The name of the routine which called XERBLA.
+*
+*  INFO    (input) INTEGER
+*          The position of the invalid parameter in the parameter list
+*          of the calling routine.
+*
+* =====================================================================
+*
+*     .. Executable Statements ..
+*
+*****      WRITE( *, FMT = 9999 )SRNAME, INFO
+*
+*****      STOP
+*
+***** 9999 FORMAT( ' ** On entry to ', A6, ' parameter number ', I2, ' had ',
+*****     $      'an illegal value' )
+*
+*     End of XERBLA
+*
+      END
diff --git a/src/C/SuiteSparse/UFconfig/xerbla/xerbla.h b/src/C/SuiteSparse/UFconfig/xerbla/xerbla.h
new file mode 100644
index 0000000..b332eb3
--- /dev/null
+++ b/src/C/SuiteSparse/UFconfig/xerbla/xerbla.h
@@ -0,0 +1,2 @@
+void xerbla_ (char *srname, int *info) ;
+void xerbla  (char *srname, int *info) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Doc/ChangeLog b/src/C/SuiteSparse/UMFPACK/Doc/ChangeLog
new file mode 100644
index 0000000..4ecbfd7
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Doc/ChangeLog
@@ -0,0 +1,452 @@
+Dec 12, 2006: version 5.0.3
+
+    * minor MATLAB cleanup.  Renamed umfpack mexFunction to umfpack2, to avoid
+	filename clash with the built-in version of umfpack.
+
+Dec 2, 2006, version 5.0.2
+
+    * minor change to umfpack_report_info: does not print timings less
+	than 0.001 seconds.
+
+    * bug fix for complex case when using a non-gcc compiler (simplified the
+	scaling of the pivot column).  Does not affect the use of UMFPACK in
+	MATLAB.
+
+Aug 31, 2006, version 5.0.1
+
+    * Minor correction to comments in umfpack_get_numeric.h.
+
+May 5, 2006, version 5.0
+
+    * Tcov subdirectory added.  This has existed since the first C version of
+	UMFPACK, but is only now included in the released version.  It provides
+	a near 100% test coverage for UMFPACK.  The code isn't pretty, but it
+	works.
+
+    * now uses CHOLMOD's method for interfacing to the BLAS, including the
+	BLAS_INT definition.  This way, the UF_long version of UMFPACK can
+	call the int BLAS.
+
+    * revised to use AMD v2.0
+
+Apr 7, 2006
+
+    * Minor correction to UMFPACK/Source/Makefile, for those who
+	do not have GNU make.  No change to version number, because
+	no code was modified.
+
+Oct 10, 2005, version 4.6
+
+    * umf_solve.c modified for the complex case.  A, X, and b can be
+	split complex or unsplit.  Prior version required the form of
+	A, X, and B to be identical (all split or all unsplit).
+	(Thanks to David Bateman).
+
+    * added Cygwin to architecture detection.
+
+    * added UMFPACK_SUBSUB_VERSION
+
+Aug. 30, 2005: v4.5 released
+
+    * License changed to GNU LGPL.
+
+    * The Make/ directory removed; configurations are now in ../UFconfig.
+
+    * requires AMD v1.2 or later
+
+    * added UMFPACK_MAIN_VERSION and UMFPACK_SUB_VERSION, defined as 4 and 5,
+	respectively, for version 4.5.  These macros will be updated for all
+	future versions.  See Include/umfpack.h for details.
+
+    * function pointers used for malloc, free, calloc, realloc, printf,
+	hypot, and complex divide.  Defined in AMD/Source/amd_global.c,
+	AMD/Source/amd_internal.h, UMFPACK/Source/umfpack_global.c,
+	and UMFPACK/Include/umfpack_global.h.
+	Compile-time dependence on The MathWorks "util.h", ut* routines
+	and ut* macros removed.
+
+Jan. 28, 2005: v4.4 released
+
+    * bug fix:  when Qinit is provided to umfpack_*_qsymbolic,
+	only the symmetric and unsymmetric strategies are now permitted.
+	The auto and 2-by-2 strategies are not allowed.  In v4.3 and
+	earlier, providing Qinit and requesting the symmetric strategy
+	did not always work (you got the unsymmetric strategy instead).
+	This does not affect umfpack_*_symbolic, which computes its own
+	ordering and can use all 4 strategies (auto, symmetric, unsymmetric,
+	and 2-by-2).
+
+    * umfpack_get_determinant added.  (Thanks to David Bateman).
+
+    * packed complex case added for all routines (previously only used in
+	umfpack_report_vector).  This allows arrays of ANSI C/C++ complex
+	type to be passed directly to UMFPACK.
+
+    * added umf_multicomple.c to assist in the compilation of UMFPACK
+	in Microsoft Visual Studio, which does not have the required
+	flexibility of the Unix "make" command.
+
+    * local variable declarations reordered to encourage double-word
+	alignment of double's and Entry's, for better performance.
+
+    * note that with the exception of the behavior when a user-provided
+	ordering is passed to umfpack_*_qsymbolic, versions 4.1 through 4.4
+	have comparable performance (ordering quality, memory usage,
+	and run time).  v4.1 is much better than v4.0 in performance.
+
+Jan. 11, 2005: v4.3.1 released
+
+    * bug fix in umf_solve.  This bug is only the 4th one found in the C
+	versions of UMFPACK to date (Version 3.0 to 4.3.1, from March 2001 to
+	Jan. 2005, excluding workarounds for quirky compilers).  No bugs have
+	been reported in the last Fortran version of UMFPACK (MA38, or UMFPACK
+	V2.2.1) since its release in Jan. 1998.
+
+	In Version 4.3, a bug in umf_solve caused iterative refinement
+	to be disabled when solving A'x=b or A.'x=b after factorizing A.
+	Modified the umfpack mexFunction to factorize A and then solve A'x=b
+	when performing the operation x=b/A (as "umfpack(b,'/',A).  Note that
+	this has no effect on the use of UMFPACK in MATLAB itself, since MATLAB
+	does not use the umfpack mexFunction for x=b/A.  When computing x=b/A,
+	MATLAB factorizes A' and computes x=(A'\b')' instead. The following
+	source code files changed:
+
+	    UMFPACK/MATLAB/umfpackmex.c	 (see above)
+	    UMFPACK/Source/umf_solve.c	 (see source code: 2 lines changed)
+	    UMFPACK/Include/umfpack.h    (version and date changed)
+	    UMFPACK/MATLAB/umfpack_test.m   (new file)
+
+Jan. 16, 2004: v4.3 released.
+
+    * user interface of v4.3 is upwardly-compatible with v4.2 and v4.1.
+	No bugs found in v4.1 (except for one workaround for an old compiler).
+	These changes add features only.
+
+    * Note that v4.0 has a bug in umf_scale_column.c.  The bug was patched
+	in that version on Jan. 12, 2004.  The bug does not appear in v4.1
+	and later.  The bug is thus present in MATLAB 6.5, but it occurs
+	very rarely, fortunately.  It can occur when dividing a nonzero entry
+	in the pivot column by the pivot value results in an underflow.
+
+    * <float.h> added to umfpackmex.c, for DBL_EPSILON.  Some non-standard
+	compilers (Microsoft Visual C++) require this.
+
+    * #pragma added to umf_analyze.c, as a workaround around a bug in an
+	old Intel compiler.
+
+    * mexFunction interface to MATLAB modified.  Call to mexCallMATLAB removed,
+	which can be slow.  In V4.1 it was used only to get MATLAB's
+	spparms ('spumoni') value.
+
+    * The AMD mexFunction was also modified in the same way (v1.1), with
+	the call to mexCallMATLAB removed.  Note that UMFPACK v4.1 through
+	v4.3 can use either AMD v1.0 or AMD v1.1.
+
+    * -DNO_DIVIDE_BY_ZERO option added.  If this non-default option is enabled
+	at compile time, and if the pivot value is zero, then no division
+	occurs (zeros on the diagonal of U are treated as if they were equal
+	to one).  By default, the division by zero does occur.
+
+    * -DNO_TIMER option added.  If this non-default option is enabled at
+	compile time, then no timers (times ( ), clock ( ), getrusage ( ))
+	are used.
+
+V4.2:  A special release for COMSOL, Inc., only (FEMLAB)
+
+    * drop tolerance added.  A few new parameters in the Control array are used,
+	and a few new Info entries.
+
+May 6, 2003:  V4.1 released.
+
+    * No bugs were found in the prior version, Version 4.0.  New features
+	added only.  Major changes throughout the code.  User interface
+	nearly unchanged, however.
+
+    * Version 4.1 is upward-compatible with Version 4.0.  The calling
+	sequence of some user-callable routines in Version 4.0 have changed
+	in this version.  The routines umfpack_*_symbolic, umfpack_*_qsymbolic,
+	umfpack_*_get_symbolic, and umfpack_*_get_numeric have new arguments
+	added to them.  The new arguments are optional.  If you want to use
+	a calling sequence similar to v4.0, simply pass NULL pointers in
+	place of the new arguments.  There are two new timing routines,
+	umfpack_tic and umfpack_toc.  A new user-callable routine, 
+	umfpack_*_scale, has been added.
+
+    *	"auto", "unsymmetric", "symmetric", and "2-by-2" strategies added.
+	The symmetric strategy uses AMD on A+A' as the column preordering,
+	followed by a postorder of the assembly tree of A+A'.  Column ordering
+	refinement is turned off, and diagonal entries are prefered as pivots.
+	V4.0 only had the unsymmetric strategy.  The 2-by-2 strategy does row
+	permutations and attempts to find a zero-free diagonal while at the
+	same time maintaining structural symmetry, and then uses the 
+	symmetric strategy on the permuted matrix.
+
+    * row-scaling added.  The default is to divide each row by the sum of
+	the absolute values of each row.  Other options are no scaling,
+	and to divide each row by the max abs value in each row.
+
+    * Matrices with upper bound memory usage greater than the maximum integer
+	(2GB for 32-bit int's) can now be factorized (assuming the actual
+	memory usage is still less than the maximum integer).  With this change,
+	the UMFPACK_ERROR_problem_too_large error code is no longer returned.
+
+    * The current frontal matrix (Work->Fx) is no longer allocated as a
+	static size, via malloc.  It can grow and shrink, and is allocated
+	from Numeric->Memory.
+
+    * The AMD (Version 1.0) package is now required.  It is available
+	separately.  To compile UMFPACK, it must appear as ../AMD if you are
+	in the main UMFPACK directory.
+
+    * The UMFPACK mexFunction now uses the internal utMalloc, utRealloc,
+	and utFree routines, by default (except on Windows).
+
+    * Three control parameters for modifying relaxed amalgamation removed.
+	These values are now fixed at compile-time.
+
+    * Many new statistics added to Info, and new control parameters added.
+
+    * The umfpack mexFunction now returns permutation matrices for P and Q,
+	not permutation vectors.  It also returns the scale factors as a
+	diagonal matrix.  The factorization is now L*U = P*(R\A)*Q.
+
+    * Option added for controlling the initial allocation of the workspace for
+	the current frontal matrix.
+
+    * pivot tolerance of zero treated differently.  symmetric pivot tolerance
+	added.
+
+    * Makefile and GNUmakefile changed.  umf_* routines with no double or
+	complex values are now compiled just twice (int and long versions)
+	rather than 4 times.
+
+    * New routines added to save and load the Numeric and Symbolic objects
+	to/from binary files.
+
+    * Simple Fortran interface added.
+
+Apr 11, 2002:
+
+    * Version 4.0 released.
+
+    * bug fix:  the Microsoft compiler doesn't handle NaN's properly.
+	utIsNaN, and other ut* routines, added for MathWorks version
+	to handle this properly.
+
+Apr 1, 2002:
+
+    * bug fix:  if a column was all NaN's, then UMFPACK would fail
+	to find a pivot row.  umf_row_search.c and umf_internal.h
+	modified to fix this problem.
+
+Mar 9, 2002:  V4.0beta released
+
+    * Map argument added to umfpack_*_triplet_to_col.  New files
+	(umf_triplet.[ch]) added.
+    * minor changes made so that UMFPACK can be compiled with g++ 
+    * additional error checking added to umfpack_*_numeric, for
+	detecting more changes in pattern (Ap, Ai) since last
+	call to umfpack_*_symbolic
+
+Feb 21, 2002:
+
+    * User Guide explains the Makefile vs. GNUmakefile
+
+    * umf_config.h modified, so that the complex SCSL C-BLAS uses
+	(void *) arguments instead of (scsl_zomplex *).  gcc generates
+	some spurious warnings (cc doesn't complain).  Affects the SGI
+	IRIX only.
+
+    * ported to Compaq Alpha
+
+Feb 20, 2002: V4.0 (alpha) released.
+
+    * V4.0 not yet ported to the Compaq Alpha (V3.2 was ported).
+
+Feb 6 to Feb 19, 2002:
+
+    * Relaxed restrictions on sizes of arrays for umfpack_*_transpose and
+	umfpack_*_triplet_to_col.  Size of "max(n,nz)" now just size nz.
+
+    * workspace for umfpack_*_wsolve increased in size.
+
+    * two user arrays for umfpack_*_get_symbolic increased in size,
+	by 1 (Chain_maxrows, Chain_maxcols).
+
+    * lu_normest.m added.
+
+Jan 18 to Feb 5, 2002:
+
+    * The matrix A can be complex, singular, and/or rectangular.
+	The solve step that uses the LU factors can only handle
+	matrices that are complex or real, singuluar or non-singular, 
+	and *** square ***, however.
+
+    * Estimate of the condition number computed:
+	(min (abs (diag (U))) / (max (abs (diag (U)))))
+
+    * Forward/backsolves can solve with A.' as well as A'.
+
+    * char * arguments removed from user-callable routines to make it
+	easier for Fortran to call UMFPACK.  No Fortran interface is (yet)
+	provided, however.
+
+	The solve codes for umfpack_*_*solve changed to #define'd
+	integers:
+
+	    UMFPACK_A       Ax=b
+	    UMFPACK_At      A'x=b
+	    UMFPACK_Aat     A.'x=b
+	    UMFPACK_Pt_L    P'Lx=b
+	    UMFPACK_L       Lx=b
+	    UMFPACK_Lt_P    L'Px=b
+	    UMFPACK_Lat_P   L.'Px=b
+	    UMFPACK_Lt      L'x=b
+	    UMFPACK_U_Qt    UQ'x=b
+	    UMFPACK_U       Ux=b
+	    UMFPACK_Q_Ut    QU'x=b
+	    UMFPACK_Q_Uat   QU.'x=b
+	    UMFPACK_Ut      U'x=b
+	    UMFPACK_Uat     U.'x=b
+
+	All arguments are now either int, long scalars (pass by value),
+	or int, long, double arrays (pass by reference), or void * pointers
+	(pass by value or reference).  A void * pointer is of size 32 or 64
+	bits on most machines.  There is no need for the caller (C or Fortran)
+	to dereference the void * pointers, so these can be treated as
+	integer*4 or integer*8 in Fortran.  A Fortran interface would have to
+	have all arguments passed by reference.
+
+    * All user-callable routine names changed.  The four sets are now:
+	umfpack_di_*	real (double precision), int's as integers
+	umfpack_dl_*	real (double precision), longs's as integers
+	umfpack_zi_*	real (double precision), int's as integers
+	umfpack_zl_*	real (double precision), longs's as integers
+
+    * Ptree (row preordering) and info on pivotal rows for each front
+	added to Symbolic object (extracted by umfpack_*_get_symbolic).
+	Ptree added as output argument to "umfpack (A, 'symbolic')"
+	mexFunction.
+
+    * umfpack_*_transpose can do A' or A.'
+
+    * umfpack_wsolve.c file removed (now generated from umfpack_solve.c).
+
+    * Can now extract just the diagonal of U with umfpack_*_get_numeric,
+	without having to extract the entire matrix U.
+
+    * UMFPACK_ERROR_singular_matrix (-2) removed.
+
+    * UMFPACK_WARNING_singular_matrix (1) added.
+
+    * Control [UMFPACK_PIVOT_OPTION] removed.  No longer any symmetric
+	pivot option (conflicts with the handling of singular and
+	rectangular matrices).
+
+    * Iterative refinement can do Ax=b, A'x=b, or A.'x=b.
+
+    * Most floating-point operations done in macros, to support the complex
+	versions.
+
+    * Info [UMFPACK_N] is now Info [UMFPACK_NROW]
+
+    * Info [UMFPACK_NCOL], Info [UMFPACK_UDIAG_NZ], Info [UMFPACK_UDIAG_NZ]
+	added.
+
+    * umfpack_* routines with "n" as input now use two arguments,
+	n_row and n_col.
+
+    * umfpack mexFunction now explicitly transposes A for b/A.  It computes
+	it using the array transpose as (A.'\b.').'
+
+January 1, 2002:  UMFPACK Version 3.2 released.  Submitted to ACM Trans.
+	on Mathematical Software.
+
+    * The umfpack mexFunction now returns the Info array when the matrix
+	is singular.  Returned an empty array prior to this change.
+
+    * Renamed variable that conflicted with system library routines
+    	(system and j1).
+
+    * Added a #ifdef MATHWORKS definition, so the built-in UMFPACK routine
+	(in a future release of MATLAB) can use the internal ut* memory
+	allocation routines, ut* assertion routine, and utPrintf.
+
+    * MAX and MIN are not defined if they are already defined.
+
+    * A bug fix in umf_kernel_init (a variable was not properly initialized).
+
+    * Removed unused variables.
+
+October 8, 2001:  UMFPACK Version 3.1 released.
+
+August-October, 2001:
+
+    * added umfpack_btf M-file.
+
+    * modified the BLAS update in the frontal matrix.  If there are only
+	a few pivots in remaining in the current front, then the BLAS3 update
+	is delayed to include pivots in the next front.
+
+    * Removed the special-case handling of dense columns from the numerical
+	factorization (kept it in the colamd preordering).  This improves the
+	performance of UMFPACK on dense matrices by a factor of 5 or so, and
+	simplifies the code.
+
+    * Added a symmetric-preference pivoting option.  The option slightly
+	(but uniformly) improves the ordering when factorizing matrices with
+	symmetric nonzero pattern.  That class of matrix is better handled by
+	the symmetric-pattern multifrontal method (MA41 in the Harwell
+	Subroutine Library), however.
+
+    * Fixed the detection of integer overflow.  The 32-bit version cannot
+	make use of more than 2GB of main memory (use the 64-bit version
+	in that case, instead).  The 32-bit version did not correctly detect
+	when it was trying to factorize too large of a matrix.
+
+May 4, 2001:
+
+    * SGI port extended.  It can now call the SCSL Scientific Library, with
+	64-bit BLAS.  Make.sgi and umf_config.h modified.
+
+April 30, 2001:  UMFPACK Version 3.0 released.  Changes since 3.0Beta release:
+
+    * long integer version added (umfpack_l_* user-callable routines).
+
+    * Peak memory usage in the numerical factorization reduced by a total of
+	12n integers (8n temporary workspace used during numerical factorization,
+	and 4n for the permanent LU factors which was allocated
+	at the beginning of factorization).
+
+    * Ported to the IBM RS 6000 and Compaq Alpha, with help from Anshul Gupta
+	and Friedrich Grund, respectively.
+
+    * 64-bit version added.  Uses dgemm_64, dgemv_64, and dger_64 in the Sun
+	Performance Library.  64-bit versions with the BLAS might not work on
+	any other platform, because they take int's as their integer input
+	arguments instead of long's.  Unfortunately, the proposed ANSI
+	definition of the C-BLAS also uses int's as input integer arguments.
+	It ought to use long's, or include a version that uses long's, just
+	like the Sun Performance Library BLAS.
+
+    * Additional statistics returned in Info:
+	Info [UMFPACK_SIZE_OF_INT]	sizeof (int)
+	Info [UMFPACK_SIZE_OF_LONG]	sizeof (long)
+	Info [UMFPACK_SIZE_OF_POINTER]	sizeof (void *)
+	Info [UMFPACK_SIZE_OF_ENTRY]	(was Info [UMFPACK_WORD])
+	Info [UMFPACK_MAX_FRONT_SIZE_ESTIMATE]	est. front matrix size
+	Info [UMFPACK_MAX_FRONT_SIZE]	actual max frontal matrix size.
+	Contents of Info rearranged.
+
+    * UMFPACK_ERROR_bad_configurution error code replaced with
+	UMFPACK_ERROR_problem_too_large error code.  The "bad configuration"
+	error occured when sizeof (int) < sizeof (size_t).  Now, the int
+	version of UMFPACK can use 32-bit int's and 64-bit pointers, and the
+	long version can use 64-bit long's and 64-bit pointers.  Both versions
+	check to see if the array sizes allocated are larger than what can be
+	accessed by an integer index variable (int or long, depending on the
+	version), and returns UMFPACK_ERROR_problem_too_large if they become
+	too large.
+
+March 15, 2001:  UMFPACK Version 3.0Beta released.
+
diff --git a/src/C/SuiteSparse/UMFPACK/Doc/License b/src/C/SuiteSparse/UMFPACK/Doc/License
new file mode 100644
index 0000000..3ee02fd
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Doc/License
@@ -0,0 +1,38 @@
+UMFPACK Version 5.0, Copyright 1995-2006 by Timothy A. Davis.
+All Rights Reserved.
+UMFPACK is available under alternate licenses, contact T. Davis for details.
+
+UMFPACK License:
+
+    Your use or distribution of UMFPACK or any modified version of
+    UMFPACK implies that you agree to this License.
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+    USA
+
+    Permission is hereby granted to use or copy this program under the
+    terms of the GNU LGPL, provided that the Copyright, this License,
+    and the Availability of the original version is retained on all copies.
+    User documentation of any code that uses this code or any modified
+    version of this code must cite the Copyright, this License, the
+    Availability note, and "Used by permission." Permission to modify
+    the code and to distribute modified code is granted, provided the
+    Copyright, this License, and the Availability note are retained,
+    and a notice that the code was modified is included.
+
+Availability:
+
+    http://www.cise.ufl.edu/research/sparse/umfpack
+
diff --git a/src/C/SuiteSparse/UMFPACK/Doc/Makefile b/src/C/SuiteSparse/UMFPACK/Doc/Makefile
new file mode 100644
index 0000000..41cf07e
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Doc/Makefile
@@ -0,0 +1,59 @@
+#-------------------------------------------------------------------------------
+# UMFPACK Makefile for compiling on Unix systems (for GNU or original make)
+#-------------------------------------------------------------------------------
+
+# UMFPACK Version 4.4, Copyright (c) 2005 by Timothy A. Davis.
+# All Rights Reserved.  See ../Doc/License for License.
+
+default: dist
+
+include ../../UFconfig/UFconfig.mk
+
+#-------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#-------------------------------------------------------------------------------
+
+# Note that UserGuide.tex is created from UserGuide.stex, the files in 
+# the ../Include directory, and the ../Demo/umfpack_simple.c file.
+purge: clean
+	- $(RM) *.aux *.bbl *.blg *.log *.toc
+	- $(RM) UserGuide.tex
+
+clean:
+	- $(RM) $(CLEAN)
+
+#-------------------------------------------------------------------------------
+# Create the User Guide and Quick Start Guide
+#-------------------------------------------------------------------------------
+
+UMFPACK = umfpack_col_to_triplet umfpack_defaults umfpack_free_numeric \
+	umfpack_free_symbolic umfpack_get_numeric umfpack_get_lunz \
+	umfpack_get_determinant \
+	umfpack_get_symbolic umfpack_numeric umfpack_qsymbolic \
+	umfpack_report_control umfpack_report_info umfpack_report_matrix \
+	umfpack_report_numeric umfpack_report_perm umfpack_report_status \
+	umfpack_report_symbolic umfpack_report_triplet \
+	umfpack_report_vector umfpack_solve umfpack_symbolic \
+	umfpack_transpose umfpack_triplet_to_col umfpack_scale
+
+UMFPACKW = umfpack_wsolve
+
+USER = $(UMFPACKW) $(UMFPACK)
+
+SRC = $(addprefix ../Include/, $(addsuffix .h,$(USER))) ../Demo/umfpack_simple.c
+
+UserGuide.pdf:  UserGuide.stex UserGuide.sed1 UserGuide.sed2 $(SRC) UserGuide.bib
+	sed -f UserGuide.sed1 < UserGuide.stex | sed -f UserGuide.sed2 \
+	    | expand -8 > UserGuide.tex
+	pdflatex UserGuide
+	bibtex UserGuide
+	pdflatex UserGuide
+	pdflatex UserGuide
+
+QuickStart.pdf: QuickStart.tex
+	pdflatex QuickStart
+	pdflatex QuickStart
+
+dist:  QuickStart.pdf UserGuide.pdf
+	- $(RM) *.aux *.bbl *.blg *.log *.toc
+	- $(RM) UserGuide.tex
diff --git a/src/C/SuiteSparse/UMFPACK/Doc/QuickStart.pdf b/src/C/SuiteSparse/UMFPACK/Doc/QuickStart.pdf
new file mode 100644
index 0000000..986f282
Binary files /dev/null and b/src/C/SuiteSparse/UMFPACK/Doc/QuickStart.pdf differ
diff --git a/src/C/SuiteSparse/UMFPACK/Doc/QuickStart.tex b/src/C/SuiteSparse/UMFPACK/Doc/QuickStart.tex
new file mode 100644
index 0000000..9958477
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Doc/QuickStart.tex
@@ -0,0 +1,1020 @@
+%-------------------------------------------------------------------------------
+% The QuickStart.tex file.
+%-------------------------------------------------------------------------------
+
+\documentclass[11pt]{article}
+
+\newcommand{\m}[1]{{\bf{#1}}}       % for matrices and vectors
+\newcommand{\tr}{^{\sf T}}          % transpose
+
+\topmargin 0in
+\textheight 9in
+\oddsidemargin 0pt
+\evensidemargin 0pt
+\textwidth 6.5in
+
+\begin{document}
+
+\author{Timothy A. Davis \\
+Dept. of Computer and Information Science and Engineering \\
+Univ. of Florida, Gainesville, FL}
+\title{UMFPACK Version 5.0 Quick Start Guide}
+\date{May 5, 2006}
+\maketitle
+
+%-------------------------------------------------------------------------------
+\begin{abstract}
+    UMFPACK is a set of routines for solving unsymmetric sparse linear
+    systems, $\m{Ax}=\m{b}$, using the Unsymmetric-pattern MultiFrontal method
+    and direct sparse LU factorization.  It is written in ANSI/ISO C, with a
+    MATLAB interface.  UMFPACK relies on the Level-3
+    Basic Linear Algebra Subprograms (dense matrix multiply) for its
+    performance.  This code works on Windows and many versions of Unix (Sun
+    Solaris, Red Hat Linux, IBM AIX, SGI IRIX, and Compaq Alpha).
+    This is a ``quick start'' guide for Unix users of the C interface.
+\end{abstract}
+%-------------------------------------------------------------------------------
+
+UMFPACK Version 5.0, Copyright\copyright 1995-2006 by Timothy A. Davis.
+All Rights Reserved.  Refer to the UMFPACK User Guide
+for the License. See \newline
+http://www.cise.ufl.edu/research/sparse/umfpack
+for the code and full documentation.
+
+%-------------------------------------------------------------------------------
+\section{Overview}
+%-------------------------------------------------------------------------------
+
+UMFPACK is a set of routines for solving systems of linear
+equations, $\m{Ax}=\m{b}$, when $\m{A}$ is sparse and unsymmetric.
+The sparse matrix $\m{A}$ can be square or rectangular, singular
+or non-singular, and real or complex (or any combination).  Only square
+matrices $\m{A}$ can be used to solve $\m{Ax}=\m{b}$ or related systems.
+Rectangular matrices can only be factorized.
+
+UMFPACK is a built-in routine in MATLAB used by the forward and
+backslash operator, and the {\tt lu} routine.
+The following is a short
+introduction to Unix users of the C interface of UMFPACK.
+
+%-------------------------------------------------------------------------------
+
+The C-callable UMFPACK library consists of 32 user-callable routines and one
+include file.  Twenty-eight of the routines come in four versions, with
+different sizes of integers and for real or complex floating-point numbers.
+This Quick Start Guide assumes you are working with real matrices
+(not complex) and with {\tt int}'s as integers (not {\tt long}'s).
+Refer to the User Guide for information about the complex and
+long integer versions.  The include file {\tt umfpack.h}
+must be included in any C program that uses UMFPACK.
+
+For more details, see:
+{\em A column pre-ordering strategy for the unsymmetric-pattern multifrontal method},
+Davis, T. A.,
+ACM Trans. Math. Software, vol 30. no 2, 2004, pp. 165-195, and
+{\em Algorithm 832:  {UMFPACK}, an unsymmetric-pattern multifrontal method},
+same issue, pp. 196-199.
+
+%-------------------------------------------------------------------------------
+\section{Primary routines, and a simple example}
+%-------------------------------------------------------------------------------
+
+Five primary UMFPACK routines are required to factorize $\m{A}$ or
+solve $\m{Ax}=\m{b}$.  An overview of the primary features of the routines
+is given in Section~\ref{Primary}.
+Additional routines are available for passing a different column ordering
+to UMFPACK, changing default parameters, manipulating sparse matrices,
+getting the LU factors, save and loading the LU factors from a file,
+computing the determinant,
+and reporting results.  See the User Guide for more information.
+
+\begin{itemize}
+\item {\tt umfpack\_di\_symbolic}:
+
+    Pre-orders the columns of $\m{A}$ to reduce fill-in and performs a
+    symbolic analysis.
+    Returns an opaque {\tt Symbolic} object as a {\tt void *}
+    pointer.  The object contains the symbolic analysis and is needed for the
+    numerical factorization.
+
+\item {\tt umfpack\_di\_numeric}:
+
+    Numerically scales and then factorizes a sparse matrix
+    $\m{PAQ}$, $\m{PRAQ}$, or $\m{PR}^{-1}\m{AQ}$ into the product $\m{LU}$,
+    where
+    $\m{P}$ and $\m{Q}$ are permutation matrices, $\m{R}$ is a diagonal
+    matrix of scale factors, $\m{L}$ is lower triangular with unit diagonal,
+    and $\m{U}$ is upper triangular.  Requires the
+    symbolic ordering and analysis computed by {\tt umfpack\_di\_symbolic}.
+    Returns an opaque {\tt Numeric} object as a
+    {\tt void *} pointer.  The object contains the numerical factorization and
+    is used by {\tt umfpack\_di\_solve}.
+
+\item {\tt umfpack\_di\_solve}:
+
+    Solves a sparse linear system ($\m{Ax}=\m{b}$, $\m{A}\tr\m{x}=\m{b}$, or
+    systems involving just $\m{L}$ or $\m{U}$), using the numeric factorization
+    computed by {\tt umfpack\_di\_numeric}.
+
+\item {\tt umfpack\_di\_free\_symbolic}:
+
+    Frees the {\tt Symbolic} object created by {\tt umfpack\_di\_symbolic}.
+
+\item {\tt umfpack\_di\_free\_numeric}:
+
+    Frees the {\tt Numeric} object created by {\tt umfpack\_di\_numeric}.
+
+\end{itemize}
+
+The matrix $\m{A}$ is represented in compressed column form, which is
+identical to the sparse matrix representation used by MATLAB.  It consists
+of three arrays, where the matrix is {\tt m}-by-{\tt n},
+with {\tt nz} entries:
+
+{\footnotesize
+\begin{verbatim}
+     int Ap [n+1] ;
+     int Ai [nz] ;
+     double Ax [nz] ;
+\end{verbatim}
+}
+
+All nonzeros are entries, but an entry may be numerically zero.  The row indices
+of entries in column {\tt j} are stored in
+    {\tt Ai[Ap[j]} ... {\tt Ap[j+1]-1]}.
+The corresponding numerical values are stored in
+    {\tt Ax[Ap[j]} ... {\tt Ap[j+1]-1]}.
+
+No duplicate row indices may be present, and the row indices in any given
+column must be sorted in ascending order.  The first entry {\tt Ap[0]} must be
+zero.  The total number of entries in the matrix is thus {\tt nz = Ap[n]}.
+Except for the fact that extra zero entries can be included, there is thus a
+unique compressed column representation of any given matrix $\m{A}$.
+
+Here is a simple main program, {\tt umfpack\_simple.c}, that illustrates the
+basic usage of UMFPACK.
+
+{\footnotesize
+\begin{verbatim}
+    #include <stdio.h>
+    #include "umfpack.h"
+
+    int    n = 5 ;
+    int    Ap [ ] = {0, 2, 5, 9, 10, 12} ;
+    int    Ai [ ] = { 0,  1,  0,   2,  4,  1,  2,  3,   4,  2,  1,  4} ;
+    double Ax [ ] = {2., 3., 3., -1., 4., 4., -3., 1., 2., 2., 6., 1.} ;
+    double b [ ] = {8., 45., -3., 3., 19.} ;
+    double x [5] ;
+
+    int main (void)
+    {
+        double *null = (double *) NULL ;
+        int i ;
+        void *Symbolic, *Numeric ;
+        (void) umfpack_di_symbolic (n, n, Ap, Ai, Ax, &Symbolic, null, null) ;
+        (void) umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, null, null) ;
+        umfpack_di_free_symbolic (&Symbolic) ;
+        (void) umfpack_di_solve (UMFPACK_A, Ap, Ai, Ax, x, b, Numeric, null, null) ;
+        umfpack_di_free_numeric (&Numeric) ;
+        for (i = 0 ; i < n ; i++) printf ("x [%d] = %g\n", i, x [i]) ;
+        return (0) ;
+    }
+\end{verbatim}
+}
+
+The {\tt Ap}, {\tt Ai}, and {\tt Ax} arrays represent the matrix
+\[
+\m{A} = \left[
+\begin{array}{rrrrr}
+ 2 &  3 &  0 &  0 &  0 \\
+ 3 &  0 &  4 &  0 &  6 \\
+ 0 & -1 & -3 &  2 &  0 \\
+ 0 &  0 &  1 &  0 &  0 \\
+ 0 &  4 &  2 &  0 &  1 \\
+\end{array}
+\right].
+\]
+and the solution is $\m{x} = [1 \, 2 \, 3 \, 4 \, 5]\tr$.  The program uses
+default control settings and does not return any statistics about the ordering,
+factorization, or solution ({\tt Control} and {\tt Info} are both
+{\tt (double *) NULL}).
+
+For routines to manipulate a simpler ``triplet-form'' data structure for your
+sparse matrix $\m{A}$, refer to the UMFPACK User Guide.
+
+%-------------------------------------------------------------------------------
+\section{Synopsis of primary C-callable routines}
+\label{Synopsis}
+%-------------------------------------------------------------------------------
+
+The matrix $\m{A}$ is {\tt m}-by-{\tt n} with {\tt nz} entries.
+The optional {\tt umfpack\_di\_defaults} routine loads the default control
+parameters into the {\tt Control} array.  The settings can then be modified
+before passing the array to the other routines.  Refer to Section~\ref{Primary}
+for more details.
+
+{\footnotesize
+\begin{verbatim}
+    #include "umfpack.h"
+    int status, sys, n, m, nz, Ap [n+1], Ai [nz] ;
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], Ax [nz], X [n], B [n] ;
+    void *Symbolic, *Numeric ;
+
+    status = umfpack_di_symbolic (m, n, Ap, Ai, Ax, &Symbolic, Control, Info) ;
+    status = umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info) ;
+    status = umfpack_di_solve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info) ;
+    umfpack_di_free_symbolic (&Symbolic) ;
+    umfpack_di_free_numeric (&Numeric) ;
+    umfpack_di_defaults (Control) ;
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\section{Installation}
+\label{Install}
+%-------------------------------------------------------------------------------
+
+You will need to install both UMFPACK v5.0 and AMD v2.0 to use UMFPACK.
+Note that UMFPACK v5.0 cannot use AMD v1.2 or earlier.
+The {\tt UMFPACK} and {\tt AMD} subdirectories must be placed side-by-side
+within the same parent directory.  AMD is a stand-alone package that
+is required by UMFPACK.  UMFPACK can be compiled without the
+BLAS but your performance will be much less than what it should be.
+
+System-dependent configurations are in the {\tt UFconfig/UFconfig.mk}
+file.  The default
+settings will work on most systems, except that UMFPACK will be compiled so
+that it does not use the BLAS.  Sample configurations are provided
+for Linux, Sun Solaris, SGI IRIX, IBM AIX, and the DEC/Compaq Alpha.
+
+To compile and install both packages,
+go to the UMFPACK directory and type {\tt make}.  This will compile the
+libraries ({\tt AMD/Lib/libamd.a} and {\tt UMFPACK/Lib/libumfpack.a}).
+A demo of the AMD ordering routine will be compiled and tested in
+the {\tt AMD/Demo} directory, and five demo programs will then be
+compiled and tested in the {\tt UMFPACK/Demo} directory.
+The outputs of these demo programs will then be compared with output
+files in the distribution.  Expect to see a few differences, such as
+residual norms, compile-time control settings, and perhaps memory usage
+differences.  The AMD and MATLAB mexFunctions for
+use in MATLAB will also be compiled.  If you do not have MATLAB,
+type {\tt make lib} instead.
+
+If you compile UMFPACK and AMD and then later change the
+{\tt UFconfig/UFconfig.mk} file
+then you should type {\tt make purge} and then {\tt make} to recompile.
+
+Here are the various parameters that you can control in your
+{\tt UFconfig/UFconfig.mk} file:
+
+\begin{itemize}
+\item {\tt CC = } your C compiler, such as {\tt cc}.
+\item {\tt RANLIB = } your system's {\tt ranlib} program, if needed.
+\item {\tt CFLAGS = } optimization flags, such as {\tt -O}.
+\item {\tt UMFPACK\_CONFIG = } configuration settings, for the BLAS,
+    memory allocation routines, and timing routines.
+\item {\tt LIB = } your libraries, such as {\tt -lm} or {\tt -lblas}.
+\item {\tt RM =} the command to delete a file.
+\item {\tt MV =} the command to rename a file.
+\item {\tt MEX =} the command to compile a MATLAB mexFunction.
+\item {\tt F77 =} the command to compile a Fortran program (optional).
+\item {\tt F77FLAGS =} the Fortran compiler flags (optional).
+\item {\tt F77LIB =} the Fortran libraries (optional).
+\end{itemize}
+
+The {\tt UMFPACK\_CONFIG} string can include combinations of the following;
+most deal with how the BLAS are called:
+\begin{itemize}
+\item {\tt -DNBLAS} if you do not have any BLAS at all.
+\item {\tt -DNSUNPERF} if you are on Solaris but do not have the Sun
+    Performance Library.
+\item {\tt -DLONGBLAS} if your BLAS takes non-{\tt int} integer arguments.
+\item {\tt -DBLAS\_INT = } the integer used by the BLAS.
+
+\item {\tt -DBLAS\_NO\_UNDERSCORE}
+    for controlling how C calls the Fortran BLAS.
+    This is set automatically for Windows,
+    Sun Solaris, SGI Irix, Red Hat Linux, Compaq Alpha, and
+    AIX (the IBM RS 6000).
+
+\item {\tt -DGETRUSAGE} if you have the {\tt getrusage} function.
+\item {\tt -DNPOSIX} if you do not have the POSIX-compliant
+    {\tt sysconf} and {\tt times} routines.
+\item {\tt -DNRECIPROCAL} controls a trade-off between speed and accuracy.
+    This is off by default (speed preferred over accuracy) except when
+    compiling for MATLAB.
+\end{itemize}
+
+When you compile your program that uses the C-callable UMFPACK library,
+you need to add the both {\tt UMFPACK/Lib/libumfpack.a} and
+{\tt AMD/Lib/libamd.a}
+libraries, and you need to tell your compiler to look in the
+directories {\tt UMFPACK/Include} and {\tt AMD/Include} for include
+files.  See {\tt UMFPACK/Demo/Makefile} for an example.
+You do not need to directly include any AMD include files in your
+program, unless you directly call AMD routines.  You only need the
+\begin{verbatim}
+#include "umfpack.h"
+\end{verbatim}
+statement, as described in Section~\ref{Synopsis}.
+
+%-------------------------------------------------------------------------------
+\newpage
+\section{The primary UMFPACK routines}
+\label{Primary}
+%-------------------------------------------------------------------------------
+
+\subsection{umfpack\_di\_symbolic}
+
+{\footnotesize
+\begin{verbatim}
+int umfpack_di_symbolic
+(
+    int n_row,
+    int n_col,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ],
+    void **Symbolic,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+Purpose:
+
+    Given nonzero pattern of a sparse matrix A in column-oriented form,
+    umfpack_di_symbolic performs a column pre-ordering to reduce fill-in
+    (using COLAMD or AMD) and a symbolic factorization.  This is required
+    before the matrix can be numerically factorized with umfpack_di_numeric.
+
+    For the following discussion, let S be the submatrix of A obtained after
+    eliminating all pivots of zero Markowitz cost.  S has dimension
+    (n_row-n1-nempty_row) -by- (n_col-n1-nempty_col), where
+    n1 = Info [UMFPACK_COL_SINGLETONS] + Info [UMFPACK_ROW_SINGLETONS],
+    nempty_row = Info [UMFPACK_NEMPTY_ROW] and
+    nempty_col = Info [UMFPACK_NEMPTY_COL].
+
+Returns:
+
+    The status code is returned.  See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+    int n_row ;         Input argument, not modified.
+    int n_col ;         Input argument, not modified.
+
+        A is an n_row-by-n_col matrix.  Restriction: n_row > 0 and n_col > 0.
+
+    int Ap [n_col+1] ;  Input argument, not modified.
+
+        Ap is an integer array of size n_col+1.  On input, it holds the
+        "pointers" for the column form of the sparse matrix A.  Column j of
+        the matrix A is held in Ai [(Ap [j]) ... (Ap [j+1]-1)].  The first
+        entry, Ap [0], must be zero, and Ap [j] <= Ap [j+1] must hold for all
+        j in the range 0 to n_col-1.  The value nz = Ap [n_col] is thus the
+        total number of entries in the pattern of the matrix A.  nz must be
+        greater than or equal to zero.
+
+    int Ai [nz] ;       Input argument, not modified, of size nz = Ap [n_col].
+
+        The nonzero pattern (row indices) for column j is stored in
+        Ai [(Ap [j]) ... (Ap [j+1]-1)].  The row indices in a given column j
+        must be in ascending order, and no duplicate row indices may be present.
+        Row indices must be in the range 0 to n_row-1 (the matrix is 0-based).
+
+    double Ax [nz] ;    Optional input argument, not modified.
+
+        The numerical values of the sparse matrix A.  The nonzero pattern (row
+        indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and
+        the corresponding numerical values are stored in
+        Ax [(Ap [j]) ... (Ap [j+1]-1)].  Used only by the 2-by-2 strategy to
+        determine whether entries are "large" or "small".  You do not have to
+        pass the same numerical values to umfpack_di_numeric.  If Ax is not
+        present (a (double *) NULL pointer), then any entry in A is assumed to
+        be "large".
+
+    void **Symbolic ;   Output argument.
+
+        **Symbolic is the address of a (void *) pointer variable in the user's
+        calling routine (see Syntax, above).  On input, the contents of this
+        variable are not defined.  On output, this variable holds a (void *)
+        pointer to the Symbolic object (if successful), or (void *) NULL if
+        a failure occurred.
+
+    double Control [UMFPACK_CONTROL] ;  Input argument, not modified.
+
+        If a (double *) NULL pointer is passed, then the default control
+        settings are used.  Only the primary parameters are listed below:
+
+        Control [UMFPACK_STRATEGY]:  This is the most important control
+            parameter.  It determines what kind of ordering and pivoting
+            strategy that UMFPACK should use.  It is new to Version 4.1
+            There are 4 options:
+
+            UMFPACK_STRATEGY_AUTO:  This is the default.  The input matrix is
+                analyzed to determine how symmetric the nonzero pattern is, and
+                how many entries there are on the diagonal.  It then selects one
+                of the following strategies.  Refer to the User Guide for a
+                description of how the strategy is automatically selected.
+
+            UMFPACK_STRATEGY_UNSYMMETRIC:  Use the unsymmetric strategy.  COLAMD
+                is used to order the columns of A, followed by a postorder of
+                the column elimination tree.  No attempt is made to perform
+                diagonal pivoting.  The column ordering is refined during
+                factorization.  This strategy was the only one provided with
+                UMFPACK V4.0.
+
+                In the numerical factorization, the
+                Control [UMFPACK_SYM_PIVOT_TOLERANCE] parameter is ignored.  A
+                pivot is selected if its magnitude is >=
+                Control [UMFPACK_PIVOT_TOLERANCE] (default 0.1) times the
+                largest entry in its column.
+
+            UMFPACK_STRATEGY_SYMMETRIC:  Use the symmetric strategy (new to
+                Version 4.1).  In this method, the approximate minimum degree
+                ordering (AMD) is applied to A+A', followed by a postorder of
+                the elimination tree of A+A'.  UMFPACK attempts to perform
+                diagonal pivoting during numerical factorization.  No refinement
+                of the column preordering is performed during factorization.
+
+                In the numerical factorization, a nonzero entry on the diagonal
+                is selected as the pivot if its magnitude is >= Control
+                [UMFPACK_SYM_PIVOT_TOLERANCE] (default 0.001) times the largest
+                entry in its column.  If this is not acceptable, then an
+                off-diagonal pivot is selected with magnitude >= Control
+                [UMFPACK_PIVOT_TOLERANCE] (default 0.1) times the largest entry
+                in its column.
+
+            UMFPACK_STRATEGY_2BY2:  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_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.
+
+    double Info [UMFPACK_INFO] ;        Output argument, not defined on input.
+
+        Contains statistics about the symbolic analysis.  If a (double *) NULL
+        pointer is passed, then no statistics are returned in Info (this is not
+        an error condition).  The entire Info array is cleared (all entries set
+        to -1) and then the following statistics are computed (only the
+        primary statistics are listed):
+
+        Info [UMFPACK_STATUS]: status code.  This is also the return value,
+            whether or not Info is present.
+
+            UMFPACK_OK
+
+                Each column of the input matrix contained row indices
+                in increasing order, with no duplicates.  Only in this case
+                does umfpack_di_symbolic compute a valid symbolic factorization.
+                For the other cases below, no Symbolic object is created
+                (*Symbolic is (void *) NULL).
+
+            UMFPACK_ERROR_n_nonpositive
+
+                n is less than or equal to zero.
+
+            UMFPACK_ERROR_invalid_matrix
+
+                Number of entries in the matrix is negative, Ap [0] is nonzero,
+                a column has a negative number of entries, a row index is out of
+                bounds, or the columns of input matrix were jumbled (unsorted
+                columns or duplicate entries).
+
+            UMFPACK_ERROR_out_of_memory
+
+                Insufficient memory to perform the symbolic analysis.  If the
+                analysis requires more than 2GB of memory and you are using
+                the 32-bit ("int") version of UMFPACK, then you are guaranteed
+                to run out of memory.  Try using the 64-bit version of UMFPACK.
+
+            UMFPACK_ERROR_argument_missing
+
+                One or more required arguments is missing.
+
+            UMFPACK_ERROR_internal_error
+
+                Something very serious went wrong.  This is a bug.
+                Please contact the author (davis at cise.ufl.edu).
+
+        Info [UMFPACK_SIZE_OF_UNIT]:  the number of bytes in a Unit,
+            for memory usage statistics below.
+
+        Info [UMFPACK_SYMBOLIC_PEAK_MEMORY]:  the amount of memory (in Units)
+            required for umfpack_di_symbolic to complete.  This count includes
+            the size of the Symbolic object itself, which is also reported in
+            Info [UMFPACK_SYMBOLIC_SIZE].
+
+        Info [UMFPACK_NUMERIC_SIZE_ESTIMATE]:  an estimate of the final size (in
+            Units) of the entire Numeric object (both fixed-size and variable-
+            sized parts), which holds the LU factorization (including the L, U,
+            P and Q matrices).
+
+        Info [UMFPACK_PEAK_MEMORY_ESTIMATE]:  an estimate of the total amount of
+            memory (in Units) required by umfpack_di_symbolic and
+            umfpack_di_numeric to perform both the symbolic and numeric
+            factorization.  This is the larger of the amount of memory needed
+            in umfpack_di_numeric itself, and the amount of memory needed in
+            umfpack_di_symbolic (Info [UMFPACK_SYMBOLIC_PEAK_MEMORY]).  The
+            count includes the size of both the Symbolic and Numeric objects
+            themselves.  It can be a very loose upper bound, particularly when
+            the symmetric or 2-by-2 strategies are used.
+
+        Info [UMFPACK_FLOPS_ESTIMATE]:  an estimate of the total floating-point
+            operations required to factorize the matrix.  This is a "true"
+            theoretical estimate of the number of flops that would be performed
+            by a flop-parsimonious sparse LU algorithm.  It assumes that no
+            extra flops are performed except for what is strictly required to
+            compute the LU factorization.  It ignores, for example, the flops
+            performed by umfpack_di_numeric to add contribution blocks of
+            frontal matrices together.  If L and U are the upper bound on the
+            pattern of the factors, then this flop count estimate can be
+            represented in MATLAB (for real matrices, not complex) as:
+
+                Lnz = full (sum (spones (L))) - 1 ;     % nz in each col of L
+                Unz = full (sum (spones (U')))' - 1 ;   % nz in each row of U
+                flops = 2*Lnz*Unz + sum (Lnz) ;
+
+            The actual "true flop" count found by umfpack_di_numeric will be
+            less than this estimate.
+
+        Info [UMFPACK_LNZ_ESTIMATE]:  an estimate of the number of nonzeros in
+            L, including the diagonal.  Since L is unit-diagonal, the diagonal
+            of L is not stored.  This estimate is a strict upper bound on the
+            actual nonzeros in L to be computed by umfpack_di_numeric.
+
+        Info [UMFPACK_UNZ_ESTIMATE]:  an estimate of the number of nonzeros in
+            U, including the diagonal.  This estimate is a strict upper bound on
+            the actual nonzeros in U to be computed by umfpack_di_numeric.
+
+        Info [UMFPACK_SYMBOLIC_TIME]:  The CPU time taken, in seconds.
+
+        Info [UMFPACK_STRATEGY_USED]: The ordering strategy used:
+            UMFPACK_STRATEGY_SYMMETRIC, UMFPACK_STRATEGY_UNSYMMETRIC, or
+            UMFPACK_STRATEGY_2BY2.
+\end{verbatim}
+}
+
+
+%-------------------------------------------------------------------------------
+\newpage
+\subsection{umfpack\_di\_numeric}
+
+{\footnotesize
+\begin{verbatim}
+int umfpack_di_numeric
+(
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ],
+    void *Symbolic,
+    void **Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+Purpose:
+
+    Given a sparse matrix A in column-oriented form, and a symbolic analysis
+    computed by umfpack_di_symbolic, the umfpack_di_numeric routine performs the
+    numerical factorization, PAQ=LU, PRAQ=LU, or P(R\A)Q=LU, where P and Q are
+    permutation matrices (represented as permutation vectors), R is the row
+    scaling, L is unit-lower triangular, and U is upper triangular.  This is
+    required before the system Ax=b (or other related linear systems) can be
+    solved.  umfpack_di_numeric can be called multiple times for each call to
+    umfpack_di_symbolic, to factorize a sequence of matrices with identical
+    nonzero pattern.  Simply compute the Symbolic object once, with
+    umfpack_di_symbolic, and reuse it for subsequent matrices.
+    umfpack_di_numeric safely detects if the pattern changes, and sets an
+    appropriate error code.
+
+Returns:
+
+    The status code is returned.  See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+    int Ap [n_col+1] ;  Input argument, not modified.
+
+        This must be identical to the Ap array passed to umfpack_di_symbolic.
+        The value of n_col is what was passed to umfpack_di_symbolic (this is
+        held in the Symbolic object).
+
+    int Ai [nz] ;       Input argument, not modified, of size nz = Ap [n_col].
+
+        This must be identical to the Ai array passed to umfpack_di_symbolic.
+
+    double Ax [nz] ;    Input argument, not modified, of size nz = Ap [n_col].
+
+        The numerical values of the sparse matrix A.  The nonzero pattern (row
+        indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and
+        the corresponding numerical values are stored in
+        Ax [(Ap [j]) ... (Ap [j+1]-1)].
+
+    void *Symbolic ;    Input argument, not modified.
+
+        The Symbolic object, which holds the symbolic factorization computed by
+        umfpack_di_symbolic.  The Symbolic object is not modified by
+        umfpack_di_numeric.
+
+    void **Numeric ;    Output argument.
+
+        **Numeric is the address of a (void *) pointer variable in the user's
+        calling routine (see Syntax, above).  On input, the contents of this
+        variable are not defined.  On output, this variable holds a (void *)
+        pointer to the Numeric object (if successful), or (void *) NULL if
+        a failure occurred.
+
+    double Control [UMFPACK_CONTROL] ;   Input argument, not modified.
+
+        If a (double *) NULL pointer is passed, then the default control
+        settings are used.  Only the primary parameters are listed below:
+
+        Control [UMFPACK_PIVOT_TOLERANCE]:  relative pivot tolerance for
+            threshold partial pivoting with row interchanges.  In any given
+            column, an entry is numerically acceptable if its absolute value is
+            greater than or equal to Control [UMFPACK_PIVOT_TOLERANCE] times
+            the largest absolute value in the column.  A value of 1.0 gives true
+            partial pivoting.  If less than or equal to zero, then any nonzero
+            entry is numerically acceptable as a pivot (this is changed from
+            Version 4.0).  Default: 0.1.
+
+            Smaller values tend to lead to sparser LU factors, but the solution
+            to the linear system can become inaccurate.  Larger values can lead
+            to a more accurate solution (but not always), and usually an
+            increase in the total work.
+
+        Control [UMFPACK_SYM_PIVOT_TOLERANCE]:  This parameter is new to V4.1.
+            If diagonal pivoting is attempted (the symmetric or symmetric-2by2
+            strategies are used) then this parameter is used to control when the
+            diagonal entry is selected in a given pivot column.  The absolute
+            value of the entry must be >= Control [UMFPACK_SYM_PIVOT_TOLERANCE]
+            times the largest absolute value in the column.  A value of zero
+            will ensure that no off-diagonal pivoting is performed, except that
+            zero diagonal entries are not selected if there are any off-diagonal
+            nonzero entries.
+
+            If an off-diagonal pivot is selected, an attempt is made to restore
+            symmetry later on.  Suppose A (i,j) is selected, where i != j.
+            If column i has not yet been selected as a pivot column, then
+            the entry A (j,i) is redefined as a "diagonal" entry, except that
+            the tighter tolerance (Control [UMFPACK_PIVOT_TOLERANCE]) is
+            applied.  This strategy has an effect similar to 2-by-2 pivoting
+            for symmetric indefinite matrices.  If a 2-by-2 block pivot with
+            nonzero structure
+
+                       i j
+                    i: 0 x
+                    j: x 0
+
+            is selected in a symmetric indefinite factorization method, the
+            2-by-2 block is inverted and a rank-2 update is applied.  In
+            UMFPACK, this 2-by-2 block would be reordered as
+
+                       j i
+                    i: x 0
+                    j: 0 x
+
+            In both cases, the symmetry of the Schur complement is preserved.
+
+        Control [UMFPACK_SCALE]:  This parameter is new to V4.1.  Version 4.0
+            did not scale the matrix.  Note that the user's input matrix is
+            never modified, only an internal copy is scaled.
+
+            There are three valid settings for this parameter.  If any other
+            value is provided, the default is used.
+
+            UMFPACK_SCALE_NONE:  no scaling is performed.
+
+            UMFPACK_SCALE_SUM:  each row of the input matrix A is divided by
+                the sum of the absolute values of the entries in that row.
+                The scaled matrix has an infinity norm of 1.
+
+            UMFPACK_SCALE_MAX:  each row of the input matrix A is divided by
+                the maximum the absolute values of the entries in that row.
+                In the scaled matrix the largest entry in each row has
+                a magnitude exactly equal to 1.
+
+            Scaling is very important for the "symmetric" strategy when
+            diagonal pivoting is attempted.  It also improves the performance
+            of the "unsymmetric" strategy.
+
+            Default: UMFPACK_SCALE_SUM.
+
+    double Info [UMFPACK_INFO] ;        Output argument.
+
+        Contains statistics about the numeric factorization.  If a
+        (double *) NULL pointer is passed, then no statistics are returned in
+        Info (this is not an error condition).  The following statistics are
+        computed in umfpack_di_numeric (only the primary statistics are listed):
+
+        Info [UMFPACK_STATUS]: status code.  This is also the return value,
+            whether or not Info is present.
+
+            UMFPACK_OK
+
+                Numeric factorization was successful.  umfpack_di_numeric
+                computed a valid numeric factorization.
+
+            UMFPACK_WARNING_singular_matrix
+
+                Numeric factorization was successful, but the matrix is
+                singular.  umfpack_di_numeric computed a valid numeric
+                factorization, but you will get a divide by zero in
+                umfpack_di_solve.  For the other cases below, no Numeric object
+                is created (*Numeric is (void *) NULL).
+
+            UMFPACK_ERROR_out_of_memory
+
+                Insufficient memory to complete the numeric factorization.
+
+            UMFPACK_ERROR_argument_missing
+
+                One or more required arguments are missing.
+
+            UMFPACK_ERROR_invalid_Symbolic_object
+
+                Symbolic object provided as input is invalid.
+
+            UMFPACK_ERROR_different_pattern
+
+                The pattern (Ap and/or Ai) has changed since the call to
+                umfpack_di_symbolic which produced the Symbolic object.
+
+        Info [UMFPACK_NUMERIC_SIZE]:  the actual final size (in Units) of the
+            entire Numeric object, including the final size of the variable
+            part of the object.  Info [UMFPACK_NUMERIC_SIZE_ESTIMATE],
+            an estimate, was computed by umfpack_di_symbolic.  The estimate is
+            normally an upper bound on the actual final size, but this is not
+            guaranteed.
+
+        Info [UMFPACK_PEAK_MEMORY]:  the actual peak memory usage (in Units) of
+            both umfpack_di_symbolic and umfpack_di_numeric.  An estimate,
+            Info [UMFPACK_PEAK_MEMORY_ESTIMATE], was computed by
+            umfpack_di_symbolic.  The estimate is normally an upper bound on the
+            actual peak usage, but this is not guaranteed.  With testing on
+            hundreds of matrix arising in real applications, I have never
+            observed a matrix where this estimate or the Numeric size estimate
+            was less than the actual result, but this is theoretically possible.
+            Please send me one if you find such a matrix.
+
+        Info [UMFPACK_FLOPS]:  the actual count of the (useful) floating-point
+            operations performed.  An estimate, Info [UMFPACK_FLOPS_ESTIMATE],
+            was computed by umfpack_di_symbolic.  The estimate is guaranteed to
+            be an upper bound on this flop count.  The flop count excludes
+            "useless" flops on zero values, flops performed during the pivot
+            search (for tentative updates and assembly of candidate columns),
+            and flops performed to add frontal matrices together.
+
+        Info [UMFPACK_LNZ]: the actual nonzero entries in final factor L,
+            including the diagonal.  This excludes any zero entries in L,
+            although some of these are stored in the Numeric object.  The
+            Info [UMFPACK_LU_ENTRIES] statistic does account for all
+            explicitly stored zeros, however.  Info [UMFPACK_LNZ_ESTIMATE],
+            an estimate, was computed by umfpack_di_symbolic.  The estimate is
+            guaranteed to be an upper bound on Info [UMFPACK_LNZ].
+
+        Info [UMFPACK_UNZ]: the actual nonzero entries in final factor U,
+            including the diagonal.  This excludes any zero entries in U,
+            although some of these are stored in the Numeric object.  The
+            Info [UMFPACK_LU_ENTRIES] statistic does account for all
+            explicitly stored zeros, however.  Info [UMFPACK_UNZ_ESTIMATE],
+            an estimate, was computed by umfpack_di_symbolic.  The estimate is
+            guaranteed to be an upper bound on Info [UMFPACK_UNZ].
+
+        Info [UMFPACK_NUMERIC_TIME]:  The CPU time taken, in seconds.
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\newpage
+\subsection{umfpack\_di\_solve}
+
+{\footnotesize
+\begin{verbatim}
+int umfpack_di_solve
+(
+    int sys,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ],
+    double X [ ],
+    const double B [ ],
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+Purpose:
+
+    Given LU factors computed by umfpack_di_numeric (PAQ=LU, PRAQ=LU, or
+    P(R\A)Q=LU) and the right-hand-side, B, solve a linear system for the
+    solution X.  Iterative refinement is optionally performed.  Only square
+    systems are handled.  Singular matrices result in a divide-by-zero for all
+    systems except those involving just the matrix L.  Iterative refinement is
+    not performed for singular matrices.
+
+    In the discussion below, n is equal to n_row and n_col, because only
+    square systems are handled.
+
+Returns:
+
+    The status code is returned.  See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+    int sys ;           Input argument, not modified.
+
+        Defines which system to solve.  (') is the linear algebraic transpose.
+
+            sys value       system solved
+
+            UMFPACK_A       Ax=b
+            UMFPACK_At      A'x=b
+            UMFPACK_Pt_L    P'Lx=b
+            UMFPACK_L       Lx=b
+            UMFPACK_Lt_P    L'Px=b
+            UMFPACK_Lt      L'x=b
+            UMFPACK_U_Qt    UQ'x=b
+            UMFPACK_U       Ux=b
+            UMFPACK_Q_Ut    QU'x=b
+            UMFPACK_Ut      U'x=b
+
+        Iterative refinement can be optionally performed when sys is any of
+        the following:
+
+            UMFPACK_A       Ax=b
+            UMFPACK_At      A'x=b
+
+        For the other values of the sys argument, iterative refinement is not
+        performed (Control [UMFPACK_IRSTEP], Ap, Ai, and Ax are ignored).
+
+    int Ap [n+1] ;      Input argument, not modified.
+    int Ai [nz] ;       Input argument, not modified.
+    double Ax [nz] ;    Input argument, not modified.
+
+        If iterative refinement is requested (Control [UMFPACK_IRSTEP] >= 1,
+        Ax=b or A'x=b is being solved, and A is nonsingular), then
+        these arrays must be identical to the same ones passed to
+        umfpack_di_numeric.  The umfpack_di_solve routine does not check the
+        contents of these arguments, so the results are undefined if Ap, Ai, Ax,
+        are modified between the calls the umfpack_di_numeric and
+        umfpack_di_solve.  These three arrays do not need to be present (NULL
+        pointers can be passed) if Control [UMFPACK_IRSTEP] is zero, or if a
+        system other than Ax=b or A'x=b is being solved, or if A is
+        singular, since in each of these cases A is not accessed.
+
+    double X [n] ;      Output argument.
+
+        The solution to the linear system, where n = n_row = n_col is the
+        dimension of the matrices A, L, and U.
+
+    double B [n] ;      Input argument, not modified.
+
+        The right-hand side vector, b, stored as a conventional array of size n
+        (or two arrays of size n for complex versions).  This routine does not
+        solve for multiple right-hand-sides, nor does it allow b to be stored in
+        a sparse-column form.
+
+    void *Numeric ;             Input argument, not modified.
+
+        Numeric must point to a valid Numeric object, computed by
+        umfpack_di_numeric.
+
+    double Control [UMFPACK_CONTROL] ;  Input argument, not modified.
+
+        If a (double *) NULL pointer is passed, then the default control
+        settings are used.
+
+        Control [UMFPACK_IRSTEP]:  The maximum number of iterative refinement
+            steps to attempt.  A value less than zero is treated as zero.  If
+            less than 1, or if Ax=b or A'x=b is not being solved, or
+            if A is singular, then the Ap, Ai, and Ax arguments are not
+            accessed.  Default: 2.
+
+    double Info [UMFPACK_INFO] ;        Output argument.
+
+        Contains statistics about the solution factorization.  If a
+        (double *) NULL pointer is passed, then no statistics are returned in
+        Info (this is not an error condition).  The following statistics are
+        computed in umfpack_di_solve (only the primary statistics are listed):
+
+        Info [UMFPACK_STATUS]: status code.  This is also the return value,
+            whether or not Info is present.
+
+            UMFPACK_OK
+
+                The linear system was successfully solved.
+
+            UMFPACK_WARNING_singular_matrix
+
+                A divide-by-zero occurred.  Your solution will contain Inf's
+                and/or NaN's.  Some parts of the solution may be valid.  For
+                example, solving Ax=b with
+
+                A = [2 0]  b = [ 1 ]  returns x = [ 0.5 ]
+                    [0 0]      [ 0 ]              [ Inf ]
+
+            UMFPACK_ERROR_out_of_memory
+
+                Insufficient memory to solve the linear system.
+
+            UMFPACK_ERROR_argument_missing
+
+                One or more required arguments are missing.  The B and X
+                arguments are always required.  Info and Control are not
+                required.  Ap, Ai and Ax are required if Ax=b or
+                A'x=b is to be solved, the (default) iterative
+                refinement is requested, and the matrix A is nonsingular.
+
+            UMFPACK_ERROR_invalid_system
+
+                The sys argument is not valid, or the matrix A is not square.
+
+            UMFPACK_ERROR_invalid_Numeric_object
+
+                The Numeric object is not valid.
+
+        Info [UMFPACK_SOLVE_FLOPS]:  the number of floating point operations
+            performed to solve the linear system.  This includes the work
+            taken for all iterative refinement steps, including the backtrack
+            (if any).
+
+        Info [UMFPACK_SOLVE_TIME]:  The time taken, in seconds.
+\end{verbatim}
+}
+
+
+%-------------------------------------------------------------------------------
+\newpage
+
+\subsection{umfpack\_di\_free\_symbolic}
+{\footnotesize
+\begin{verbatim}
+void umfpack_di_free_symbolic
+(
+    void **Symbolic
+) ;
+
+Purpose:
+
+    Deallocates the Symbolic object and sets the Symbolic handle to NULL.
+
+Arguments:
+
+    void **Symbolic ;           Input argument, deallocated and Symbolic is
+                                set to (void *) NULL on output.
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{umfpack\_di\_free\_numeric}
+
+{\footnotesize
+\begin{verbatim}
+void umfpack_di_free_numeric
+(
+    void **Numeric
+) ;
+
+Purpose:
+
+    Deallocates the Numeric object and sets the Numeric handle to NULL.
+
+Arguments:
+
+    void **Numeric ;            Input argument, deallocated and Numeric is
+                                set to (void *) NULL on output.
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{umfpack\_di\_defaults}
+
+{\footnotesize
+\begin{verbatim}
+void umfpack_di_defaults
+(
+    double Control [UMFPACK_CONTROL]
+) ;
+
+Purpose:
+
+    Sets the default control parameter settings.
+
+Arguments:
+
+    double Control [UMFPACK_CONTROL] ;  Output argument.
+
+        Control is set to the default control parameter settings.
+\end{verbatim}
+}
+\end{document}
diff --git a/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.bib b/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.bib
new file mode 100644
index 0000000..540f12e
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.bib
@@ -0,0 +1,322 @@
+ at string{TOMS = "ACM Trans. Math. Softw."}
+ at string{SIMAX = "SIAM J. Matrix Anal. Applic."}
+ at string{SINUM = "SIAM J. Numer. Anal."}
+ at string{SIAMJSC = "SIAM J. Sci. Comput."}
+ at string{SIAMJSSC = "SIAM J. Sci. Statist. Comput."}
+ at string{IJNME = "Internat. J. Numer. Methods Eng."}
+ at string{SIAMJADM = "SIAM J. Alg. Disc. Meth."}
+
+ at article{AmestoyDavisDuff96,
+	author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.},
+	title={An approximate minimum degree ordering algorithm},
+	journal=SIMAX,
+	year={1996}
+	,volume={17}
+	,number={4}
+	,pages={886-905}}
+
+ at article{AmestoyDavisDuff03,
+	author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.},
+	title={Algorithm 837: {AMD}, an approximate minimum degree ordering algorithm},
+	journal=TOMS,
+	year={2004}
+	,volume={30}
+	,number={3}
+	,pages={381-388}}
+
+ at techreport{AmestoyDavisDuff03_user,
+	author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.},
+	title={{AMD} Version 1.0 User Guide},
+	institution={CISE Dept., Univ. of Florida},
+	year={2003}
+	,number={TR-03-011}
+	,address={Gainesville, FL}
+	,note={www.cise.ufl.edu/tech-reports.}
+	}
+
+ at article{Davis03,
+	author={Davis, T. A.},
+	title={A column pre-ordering strategy for the unsymmetric-pattern multifrontal method},
+	journal=TOMS,
+	year={2004}
+	,volume={30}
+	,number={2}
+	,pages={165-195}}
+
+ at article{Davis03_algo,
+	author={Davis, T. A.},
+	title={Algorithm 832:  {UMFPACK}, an unsymmetric-pattern multifrontal method},
+	journal=TOMS,
+	year={2004}
+	,volume={30}
+	,number={2}
+	,pages={196-199}}
+
+ at techreport{Davis03_umf,
+	author={Davis, T. A.},
+	title={{UMFPACK} User Guide},
+	institution={Univ. of Florida, CISE Dept.},
+	year={2005}
+	,number={TR-04-003 (revised)}
+	,address={Gainesville, FL}
+	,note={(www.cise.ufl.edu/tech-reports)}
+	}
+
+ at techreport{Davis03_umfquick,
+	author={Davis, T. A.},
+	title={{UMFPACK} Quick Start Guide},
+	institution={Univ. of Florida, CISE Dept.},
+	year={2005}
+	,number={TR-04-005 (revised)}
+	,address={Gainesville, FL}
+	,note={(www.cise.ufl.edu/tech-reports)}
+	}
+
+ at article{DavisDuff97,
+	author={Davis, T. A. and Duff, I. S.},
+	title={An unsymmetric-pattern multifrontal method for sparse {LU} factorization},
+	journal=SIMAX,
+	year={1997}
+	,volume={18}
+	,number={1}
+	,pages={140-158}}
+
+ at article{DavisDuff99,
+	author={Davis, T. A. and Duff, I. S.},
+	title={A combined unifrontal/multifrontal method for unsymmetric sparse matrices},
+	journal=TOMS,
+	volume={25},
+	number={1},
+	pages={1-19},
+	year={1999}}
+
+ at article{SuperLU99,
+	author={Demmel, J. W. and Eisenstat, S. C. and Gilbert, J. R. and Li, X. S. and Liu, J. W. H.},
+	title={A supernodal approach to sparse partial pivoting},
+	journal=SIMAX,
+	year={1999}
+	,volume={20}
+	,number={3}
+	,pages={720-755}
+	,note={www.netlib.org}
+	}
+
+ at article{ACM679a,
+	author={Dongarra, J. J. and Du Croz, J. and Duff, I. S. and Hammarling, S.},
+	title={A set of level-3 basic linear algebra subprograms},
+	journal=TOMS,
+	year={1990}
+	,volume={16}
+	,number={1}
+	,pages={1--17}}
+
+ at article{netlib,
+	author={Dongarra, J. J. and Grosse, E.},
+	title={Distribution of mathematical software via electronic mail},
+	journal={Comm. ACM},
+	year={1987}
+	,volume={30}
+	,pages={403-407}
+	,note={www.netlib.org}
+	}
+
+ at article{Duff78b,
+	author={Duff, I. S. and Reid, J. K.},
+	year={1978},
+	title={Algorithm 529: Permutations to Block Triangular Form},
+	journal=TOMS,
+	volume={4},
+	annote={f},
+	number={2},
+	pages={189-192},
+	keywords={102 ordering block triangular form}}
+
+ at article{Duff81b,
+	author={Duff, I. S.},
+	year={1981},
+	title={Algorithm 575: Permutations for a Zero-Free Diagonal},
+	journal=TOMS,
+	annote={f},
+	volume={7},
+	pages={387-390},
+	keywords={ordering, zero-free diagonal}}
+
+ at techreport{GotoVandeGeijn02,
+	author = {Goto, K. and van de Geijn, R.},
+	title = {On Reducing {TLB} Misses in Matrix Multiplication, {FLAME} Working Note 9},
+	institution={The University of Texas at Austin, Department of Computer Sciences},
+	number={TR-2002-55},
+	month={Nov.},
+	year={2002}}
+
+ at article{GeorgeNg85,
+	author={George, A. and Ng, E. G.},
+	year={1985},
+	title={An Implementation of {G}aussian Elimination with
+		Partial Pivoting for Sparse Systems},
+	journal=SIAMJSSC,
+	volume={6},
+	number={2},
+	pages={390-409}}
+
+ at article{GeorgeNg87,
+	author={George, A. and Ng, E. G.},
+	year={1987},
+	title={Symbolic Factorization for Sparse {G}aussian Elimination
+		with Partial Pivoting},
+	journal={SIAM J. Sci. Statist. Comput.},
+	volume={8},
+	number={6},
+	pages={877-898}}
+
+ at article{GilbertMolerSchreiber,
+	author={Gilbert, J. R. and Moler, C. and Schreiber, R.},
+	title={Sparse matrices in {MATLAB}:  design and implementation},
+	journal=SIMAX,
+	year={1992}
+	,volume={13}
+	,number={1}
+	,pages={333-356}}
+
+ at article{GilbertPeierls88,
+	author={Gilbert, J. R. and Peierls, T.},
+	year={1988},
+	title={Sparse Partial Pivoting in Time Proportional to Arithmetic Operations},
+	journal={SIAM J. Sci. Statist. Comput.},
+	volume={9},
+	pages={862-874}}
+
+ at article{Gustavson78,
+	author={Gustavson, F. G.},
+	year={1978},
+	title={Two Fast Algorithms for Sparse Matrices: Multiplication and Permuted Transposition},
+	journal=TOMS,
+	volume={4},
+	number={3},
+	pages={250-269}}
+
+ at techreport{Larimore98,
+	author={Larimore, S. I.},
+	title={An approximate minimum degree column ordering algorithm},
+	institution={Univ. of Florida, CISE Dept.},
+	year={1998}
+	,number={TR-98-016}
+	,address={Gainesville, FL}
+	,note={www.cise.ufl.edu/tech-reports}}
+
+ at article{DavisGilbertLarimoreNg00,
+	author={Davis, T. A. and Gilbert, J. R. and Larimore, S. I. and Ng, E. G.},
+	title={A column approximate minimum degree ordering algorithm},
+	journal=TOMS,
+	year={2004}
+	,volume={30}
+	,number={3}
+	,pages={353-376}}
+
+ at article{DavisGilbertLarimoreNg00_algo,
+	author={Davis, T. A. and Gilbert, J. R. and Larimore, S. I. and Ng, E. G.},
+	title={Algorithm 836:  {COLAMD}, a column approximate minimum degree ordering algorithm},
+	journal=TOMS,
+	year={2004}
+	,volume={30}
+	,number={3}
+	,pages={377-380}}
+
+ at INCOLLECTION{GilbertNg93,
+  author = {J. R. Gilbert and E. G. Ng},
+  editor = {A. George and J. R. Gilbert and J. W.H. Liu},
+  year = 1993,
+  title = {Predicting Structure in Nonsymmetric Sparse Matrix Factorizations},
+  booktitle = {Graph Theory and Sparse Matrix Computation},
+  series = {Volume 56 of the {IMA} Volumes in Mathematics and its Applications},
+  pages = {107-139},
+  publisher = {Springer-Verlag}
+}
+
+
+ at techreport{ATLAS,
+	author={Whaley, R. C and Petitet, A. and Dongarra, J. J.},
+	title={Automated Emperical Optimization of Software and the {ATLAS} Project},
+	institution={Computer Science Department, The University of Tennessee},
+	year={2000}
+	,number={LAPACK Working Note 147}
+	,month={September}
+	,note={www.netlib.org/atlas}
+	}
+
+ at article{DaydeDuff99,
+	author = "M. J. Dayd\'{e} and I. S. Duff",
+	title = "The {RISC} {BLAS}: A Blocked Implementation of Level 3 {BLAS} for {RISC} Processors",
+	journal = TOMS,
+	volume = "25",
+	number = "3",
+	month = {Sept.},
+	year ="1999"
+	}
+
+
+ at article{ardd:89,
+   author = {M. Arioli and J. W. Demmel and I. S. Duff},
+   year = "1989",
+   title = {Solving sparse linear systems with sparse backward error},
+   journal = SIMAX,
+   volume  = {10},
+   pages   = {165-190}
+}
+
+
+ at article{DavisHager99,
+	author={Davis, T. A. and Hager, W. W.},
+	title={Modifying a sparse {C}holesky factorization},
+	journal=SIMAX,
+	year={1999}
+	,volume={20}
+	,number={3}
+	,pages={606-627}
+	}
+
+
+ at article{dusc:96,
+	author = {I. S. Duff and J. A. Scott},
+	title = {The design of a new frontal code for solving sparse unsymmetric systems},
+	journal = TOMS,
+	year = "1996",
+	volume = "22",
+	number = "1",
+	pages = "30-45"
+	}
+
+
+ at article{Duff78a,
+	author={Duff, I. S. and Reid, J. K.},
+	year={1978},
+	title={An Implementation of {T}arjan's Algorithm for the Block Triangularization of a Matrix},
+	journal=TOMS,
+	volume={4},
+	number={2},
+	pages={137-147}
+	}
+
+ at book{GeorgeLiu,
+	author={George, A. and Liu, J. W. H.},
+	year={1981},
+	title={Computer Solution of Large Sparse Positive Definite Systems},
+	publisher={Englewood Cliffs, New Jersey:  Prentice-Hall}
+	}
+
+ at article{GilbertNgPeyton94,
+	author={Gilbert, J. R. and Ng, E. G. and Peyton, B. W.},
+	title={An efficient algorithm to compute row and column counts for sparse {C}holesky factorization},
+	journal=SIMAX,
+	year={1994}
+	,volume={15}
+	,number={4}
+	,pages={1075-1091}
+	}
+
+ at techreport{DuffGrimesLewis87b,
+	author={Duff, I. S. and Grimes, R. G. and Lewis, J. G.},
+	year={1987},
+	title={Users' Guide for the Harwell-Boeing Sparse Matrix Test Collection},
+	institution={AERE Harwell Laboratory, United Kingdom Atomic Energy Authority}}
+
diff --git a/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.pdf b/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.pdf
new file mode 100644
index 0000000..a6087e1
Binary files /dev/null and b/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.pdf differ
diff --git a/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.sed1 b/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.sed1
new file mode 100644
index 0000000..c49e8c1
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.sed1
@@ -0,0 +1,33 @@
+/INCLUDE umfpack_col_to_triplet.h/r ../Include/umfpack_col_to_triplet.h
+/INCLUDE umfpack_defaults.h/r ../Include/umfpack_defaults.h
+/INCLUDE umfpack_free_numeric.h/r ../Include/umfpack_free_numeric.h
+/INCLUDE umfpack_free_symbolic.h/r ../Include/umfpack_free_symbolic.h
+/INCLUDE umfpack_get_lunz.h/r ../Include/umfpack_get_lunz.h
+/INCLUDE umfpack_get_numeric.h/r ../Include/umfpack_get_numeric.h
+/INCLUDE umfpack_get_symbolic.h/r ../Include/umfpack_get_symbolic.h
+/INCLUDE umfpack_get_scale.h/r ../Include/umfpack_get_scale.h
+/INCLUDE umfpack_numeric.h/r ../Include/umfpack_numeric.h
+/INCLUDE umfpack_qsymbolic.h/r ../Include/umfpack_qsymbolic.h
+/INCLUDE umfpack_report_control.h/r ../Include/umfpack_report_control.h
+/INCLUDE umfpack_report_info.h/r ../Include/umfpack_report_info.h
+/INCLUDE umfpack_report_matrix.h/r ../Include/umfpack_report_matrix.h
+/INCLUDE umfpack_report_numeric.h/r ../Include/umfpack_report_numeric.h
+/INCLUDE umfpack_report_perm.h/r ../Include/umfpack_report_perm.h
+/INCLUDE umfpack_report_status.h/r ../Include/umfpack_report_status.h
+/INCLUDE umfpack_report_symbolic.h/r ../Include/umfpack_report_symbolic.h
+/INCLUDE umfpack_report_triplet.h/r ../Include/umfpack_report_triplet.h
+/INCLUDE umfpack_report_vector.h/r ../Include/umfpack_report_vector.h
+/INCLUDE umfpack_simple.c/r ../Demo/umfpack_simple.c
+/INCLUDE umfpack_solve.h/r ../Include/umfpack_solve.h
+/INCLUDE umfpack_scale.h/r ../Include/umfpack_scale.h
+/INCLUDE umfpack_symbolic.h/r ../Include/umfpack_symbolic.h
+/INCLUDE umfpack_timer.h/r ../Include/umfpack_timer.h
+/INCLUDE umfpack_tictoc.h/r ../Include/umfpack_tictoc.h
+/INCLUDE umfpack_transpose.h/r ../Include/umfpack_transpose.h
+/INCLUDE umfpack_triplet_to_col.h/r ../Include/umfpack_triplet_to_col.h
+/INCLUDE umfpack_wsolve.h/r ../Include/umfpack_wsolve.h
+/INCLUDE umfpack_load_numeric.h/r ../Include/umfpack_load_numeric.h
+/INCLUDE umfpack_load_symbolic.h/r ../Include/umfpack_load_symbolic.h
+/INCLUDE umfpack_save_numeric.h/r ../Include/umfpack_save_numeric.h
+/INCLUDE umfpack_save_symbolic.h/r ../Include/umfpack_save_symbolic.h
+/INCLUDE umfpack_get_determinant.h/r ../Include/umfpack_get_determinant.h
diff --git a/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.sed2 b/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.sed2
new file mode 100644
index 0000000..0df47d9
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.sed2
@@ -0,0 +1,3 @@
+/[/][*]/d
+/[*][/]/d
+/INCLUDE umfpack/d
diff --git a/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.stex b/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.stex
new file mode 100644
index 0000000..601857d
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.stex
@@ -0,0 +1,2695 @@
+%-------------------------------------------------------------------------------
+% The UserGuide.stex file.  Processed into UserGuide.tex via sed.
+%-------------------------------------------------------------------------------
+
+\documentclass[11pt]{article}
+
+\newcommand{\m}[1]{{\bf{#1}}}       % for matrices and vectors
+\newcommand{\tr}{^{\sf T}}          % transpose
+\newcommand{\he}{^{\sf H}}          % complex conjugate transpose
+\newcommand{\implies}{\rightarrow}
+
+\topmargin 0in
+\textheight 9in
+\oddsidemargin 0pt
+\evensidemargin 0pt
+\textwidth 6.5in
+
+\begin{document}
+
+\author{Timothy A. Davis \\
+Dept. of Computer and Information Science and Engineering \\
+Univ. of Florida, Gainesville, FL}
+\title{UMFPACK Version 5.0 User Guide}
+\date{May 5, 2006}
+\maketitle
+
+%-------------------------------------------------------------------------------
+\begin{abstract}
+    UMFPACK is a set of routines for solving unsymmetric sparse linear
+    systems, $\m{Ax}=\m{b}$, using the Unsymmetric MultiFrontal method
+    and direct sparse LU factorization.  It is written in ANSI/ISO C, with a
+    MATLAB interface.  UMFPACK relies on the Level-3 Basic
+    Linear Algebra Subprograms (dense matrix multiply) for its performance.
+    This code works on Windows and many versions of Unix (Sun Solaris,
+    Red Hat Linux, IBM AIX, SGI IRIX, and Compaq Alpha).
+\end{abstract}
+%-------------------------------------------------------------------------------
+
+Technical Report TR-04-003 (revised)
+
+UMFPACK Version 5.0, Copyright\copyright 1995-2006 by Timothy A. Davis.
+All Rights Reserved.
+UMFPACK is available under alternate licences; contact T. Davis for details.
+
+{\bf UMFPACK License:}
+    Your use or distribution of UMFPACK or any modified version of
+    UMFPACK implies that you agree to this License.
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+    USA
+
+    Permission is hereby granted to use or copy this program under the
+    terms of the GNU LGPL, provided that the Copyright, this License,
+    and the Availability of the original version is retained on all copies.
+    User documentation of any code that uses this code or any modified
+    version of this code must cite the Copyright, this License, the
+    Availability note, and "Used by permission." Permission to modify
+    the code and to distribute modified code is granted, provided the
+    Copyright, this License, and the Availability note are retained,
+    and a notice that the code was modified is included.
+
+{\bf Availability:}
+    http://www.cise.ufl.edu/research/sparse/umfpack
+
+{\bf Acknowledgments:}
+
+    This work was supported by the National Science Foundation, under
+    grants DMS-9504974, DMS-9803599, and CCR-0203270.
+    The upgrade to Version 4.1 and the inclusion of the
+    symmetric and 2-by-2 pivoting strategies
+    were done while the author was on sabbatical at
+    Stanford University and Lawrence Berkeley National Laboratory.
+
+%-------------------------------------------------------------------------------
+\newpage
+%-------------------------------------------------------------------------------
+
+\tableofcontents
+
+%-------------------------------------------------------------------------------
+\newpage
+\section{Overview}
+%-------------------------------------------------------------------------------
+
+UMFPACK\footnote{Pronounced with two syllables: umph-pack}
+Version 5.0 is a set of routines for solving systems of linear
+equations, $\m{Ax}=\m{b}$, when $\m{A}$ is sparse and unsymmetric.  It is based
+on the Unsymmetric-pattern MultiFrontal method \cite{DavisDuff97,DavisDuff99}.
+UMFPACK factorizes
+$\m{PAQ}$, $\m{PRAQ}$, or $\m{PR}^{-1}\m{AQ}$ into the product $\m{LU}$,
+where $\m{L}$ and $\m{U}$
+are lower and upper triangular, respectively, $\m{P}$ and $\m{Q}$ are
+permutation matrices, and $\m{R}$ is a diagonal matrix of row scaling factors
+(or $\m{R}=\m{I}$ if row-scaling is not used).  Both $\m{P}$ and $\m{Q}$ are
+chosen to reduce fill-in (new nonzeros in $\m{L}$ and $\m{U}$ that are not
+present in $\m{A}$).  The permutation $\m{P}$ has the dual role of reducing
+fill-in and maintaining numerical accuracy (via relaxed partial pivoting
+and row interchanges).
+
+The sparse matrix $\m{A}$ can be square or rectangular, singular
+or non-singular, and real or complex (or any combination).  Only square
+matrices $\m{A}$ can be used to solve $\m{Ax}=\m{b}$ or related systems.
+Rectangular matrices can only be factorized.
+
+UMFPACK first finds a column pre-ordering that reduces fill-in, without regard
+to numerical values.  It scales and analyzes the matrix, and then automatically
+selects one of three strategies for pre-ordering the rows and columns:
+{\em unsymmetric},
+{\em 2-by-2}, and
+{\em symmetric}.  These strategies are described below.
+
+First, all pivots with zero Markowitz cost are eliminated and placed in the
+LU factors.  The remaining submatrix $\m{S}$ is then analyzed.
+The following rules are applied, and the first one that matches defines
+the strategy.
+
+\begin{itemize}
+\item Rule 1: $\m{A}$ rectangular $\implies$ unsymmetric.
+\item Rule 2:
+    If the zero-Markowitz elimination results in a rectangular $\m{S}$,
+    or an $\m{S}$ whose diagonal has not been preserved, the
+    unsymmetric strategy is used.
+\item The symmetry $\sigma_1$ of $\m{S}$ is computed.  It is defined as
+    the number of {\em matched} off-diagonal entries, divided by the
+    total number of off-diagonal entries.  An entry $s_{ij}$ is matched
+    if $s_{ji}$ is also an entry.  They need not be numerically equal.
+    An {\em entry} is a value in $\m{A}$ which is present
+    in the input data structure.  All nonzeros are entries, but some entries
+    may be numerically zero.
+    Rule 3: $\sigma_1 < 0.1 \implies$ unsymmetric.
+    The matrix is very unsymmetric.
+\item Let $d$ be the number of nonzero entries on the diagonal of $\m{S}$.
+    Let $\m{S}$ be $\nu$-by-$\nu$.
+    Rule 4: $(\sigma_1 \ge 0.7) \:\wedge\: (d = \nu) \implies$ symmetric.
+    The matrix has a nearly symmetric nonzero pattern, and a zero-free
+    diagonal.
+\end{itemize}
+
+If the strategy has not yet been determined,
+the 2-by-2 strategy is attempted.  A row permutation $\m{P}_2$
+is found which attempts to reduce the number of small
+diagonal entries of $\m{P}_2 \m{S}$.
+An entry $s_{ij}$ is determined to be small if
+$|s_{ij}| < 0.01 \max |s_{*j}|$, or large otherwise.
+If $s_{ii}$ is numerically small, the method attempts to swap
+two rows $i$ and $j$, such that both $s_{ij}$ and $s_{ji}$ are large.
+Once these rows are swapped,
+they remain in place.  Let $\sigma_2$ be the symmetry of $\m{P}_2 \m{S}$,
+and let $d_2$ be the number of nonzero entries (either small or large)
+on the diagonal of $\m{P}_2 \m{S}$.
+
+\begin{itemize}
+\item Rule 5:
+    ($\sigma_2 > 1.1 \sigma_1) \:\wedge\: (d_2 > 0.9 \nu) \implies$ 2-by-2.
+    The 2-by-2 permutation has made the matrix significantly more symmetric.
+\item Rule 6: $\sigma_2 < 0.7 \sigma_1 \implies$ unsymmetric.
+    The 2-by-2 strategy has significantly deteriorated the symmetry,
+\item Rule 7: $\sigma_2 < 0.25 \implies$ unsymmetric.
+    The matrix is still very unsymmetric.
+\item Rule 8: $\sigma_2 \ge 0.51 \implies$ 2-by-2.
+    The matrix is roughly symmetric.
+\item Rule 9: $\sigma_2 \ge 0.999 \sigma_1 \implies$ 2-by-2.
+    The 2-by-2 permutation has preserved symmetry, or made it only
+    slightly worse.
+\item Rule 10: if no rule has yet triggered, use the unsymmetric strategy.
+\end{itemize}
+
+Each strategy is described below:
+\begin{itemize}
+\item {\em unsymmetric}:
+The column pre-ordering of $\m{S}$ is computed by a modified version of COLAMD
+\cite{DavisGilbertLarimoreNg00_algo,DavisGilbertLarimoreNg00,Larimore98}.
+The method finds a symmetric permutation $\m{Q}$ of the matrix $\m{S}\tr\m{S}$
+(without forming $\m{S}\tr\m{S}$ explicitly).  This is a good choice for
+$\m{Q}$, since the Cholesky factors of $\m{(SQ)\tr(SQ)}$ are an upper bound (in
+terms of nonzero pattern) of the factor $\m{U}$ for the unsymmetric LU
+factorization ($\m{PSQ}=\m{LU}$) regardless of the choice of $\m{P}$
+\cite{GeorgeNg85,GeorgeNg87,GilbertNg93}.  This modified version of
+COLAMD also computes the column elimination tree and post-orders the
+tree.  It finds the upper bound on the number of nonzeros in L and U.
+It also has a different threshold for determining dense rows and columns.
+During factorization, the column pre-ordering can be modified.
+Columns within a single super-column can be reshuffled, to reduce fill-in.
+Threshold partial pivoting is used with no preference given to the diagonal
+entry.  Within a given pivot column $j$, an entry $a_{ij}$ can be chosen if
+$|a_{ij}| \ge 0.1 \max |a_{*j}|$.  Among those numerically acceptable
+entries, the sparsest row $i$ is chosen as the pivot row.
+
+\item {\em 2-by-2}:
+The symmetric strategy (see below) is applied to the matrix $\m{P}_2 \m{S}$,
+rather than $\m{S}$.
+
+\item {\em symmetric}:
+The column ordering is computed from AMD
+\cite{AmestoyDavisDuff96,AmestoyDavisDuff03},
+applied to the pattern of $\m{S}+\m{S}\tr$
+followed by a post-ordering of the supernodal elimination
+tree of $\m{S}+\m{S}\tr$.
+No modification of the column pre-ordering is made during numerical
+factorization.  Threshold partial pivoting is used, with a strong
+preference given to the diagonal entry.  The diagonal entry is chosen if
+$a_{jj} \ge 0.001 \max |a_{*j}|$.  Otherwise, a sparse row is selected,
+using the same method used by the unsymmetric strategy.
+
+\end{itemize}
+
+The symmetric and 2-by-2 strategies, and their automatic selection,
+are new to Version 4.1.  Version 4.0 only used the unsymmetric strategy.
+
+Once the strategy is selected,
+the factorization of the matrix $\m{A}$ is broken down into the factorization
+of a sequence of dense rectangular frontal matrices.  The frontal matrices are
+related to each other by a supernodal column elimination tree, in which each
+node in the tree represents one frontal matrix.  This analysis phase also
+determines upper bounds on the memory usage, the floating-point operation count,
+and the number of nonzeros in the LU factors.
+
+UMFPACK factorizes each {\em chain} of frontal matrices in a single working
+array, similar to how the unifrontal method \cite{dusc:96} factorizes the whole
+matrix.  A chain of frontal matrices is a sequence of fronts where the parent
+of front $i$ is $i$+1 in the supernodal column elimination tree.  For the
+nonsingular matrices factorized with the unsymmetric strategy, there are
+exactly the same number of chains as there are leaves in the supernodal
+column elimination tree.  UMFPACK is an
+outer-product based, right-looking method.  At the $k$-th step of Gaussian
+elimination, it represents the updated submatrix $\m{A}_k$ as an implicit
+summation of a set of dense sub-matrices (referred to as {\em elements},
+borrowing a phrase from finite-element methods) that arise when the frontal
+matrices are factorized and their pivot rows and columns eliminated.
+
+Each frontal matrix represents the elimination of one or more columns;
+each column of $\m{A}$ will be eliminated in a specific frontal matrix,
+and which frontal matrix will be used for which column is determined by
+the pre-analysis phase.  The pre-analysis phase also determines the worst-case
+size of each frontal matrix so that they can hold any candidate pivot column
+and any candidate pivot row.  From the perspective of the analysis phase, any
+candidate pivot column in the frontal matrix is identical (in terms of nonzero
+pattern), and so is any row.  However, the numeric factorization phase has
+more information than the analysis phase.  It uses this information to reorder
+the columns within each frontal matrix to reduce fill-in.  Similarly, since
+the number of nonzeros in each row and column are maintained (more precisely,
+COLMMD-style approximate degrees \cite{GilbertMolerSchreiber}), a pivot row can
+be selected based on sparsity-preserving criteria (low degree) as well as
+numerical considerations (relaxed threshold partial pivoting).
+
+When the symmetric or 2-by-2 strategies are used,
+the column preordering is not refined during numeric factorization.
+Row pivoting for sparsity and numerical accuracy is performed if the
+diagonal entry is too small.
+
+More details of the method, including experimental results, are
+described in \cite{Davis03,Davis03_algo}, available at
+http://www.cise.ufl.edu/tech-reports.
+
+%-------------------------------------------------------------------------------
+\section{Availability}
+%-------------------------------------------------------------------------------
+
+In addition to appearing as a Collected Algorithm of the ACM,
+UMFPACK is available at http://www.cise.ufl.edu/research/sparse.
+It is included as a built-in routine in MATLAB.
+Version 4.0 (in MATLAB 6.5)
+does not have the symmetric or 2-by-2 strategies and it takes
+less advantage of the level-3
+BLAS \cite{DaydeDuff99,ACM679a,ATLAS,GotoVandeGeijn02}.
+Versions 5.0 through v4.1 tend to be much faster than Version 4.0,
+particularly on unsymmetric matrices with mostly symmetric
+nonzero pattern (such as finite element and circuit simulation matrices).
+Version 3.0 and following make
+use of a modified version of COLAMD V2.0 by Timothy A.~Davis, Stefan
+Larimore, John Gilbert, and Esmond Ng.  The original COLAMD V2.1 is available in
+as a built-in routine in MATLAB V6.0 (or later), and at
+http://www.cise.ufl.edu/research/sparse.
+These codes are also available in Netlib \cite{netlib} at
+http://www.netlib.org.
+UMFPACK Versions 2.2.1 and earlier, co-authored with Iain Duff,
+are available at http://www.cise.ufl.edu/research/sparse and as
+MA38 (functionally equivalent to Version 2.2.1) in the Harwell
+Subroutine Library.
+
+%-------------------------------------------------------------------------------
+\section{Primary changes from prior versions}
+%-------------------------------------------------------------------------------
+
+A detailed list of changes is in the {\tt ChangeLog} file.
+
+%-------------------------------------------------------------------------------
+\subsection{Version 5.0.3}
+%-------------------------------------------------------------------------------
+
+Renamed the MATLAB function to {\tt umfpack2}, so as not to confict with
+itself (the MATLAB built-in version of UMFPACK).
+
+%-------------------------------------------------------------------------------
+\subsection{Version 5.0}
+%-------------------------------------------------------------------------------
+
+Changed {\tt long} to {\tt UF\_long}, controlled by the {\tt UFconfig.h}
+file.  A {\tt UF\_long} is normally just {\tt long}, except on the Windows 64
+(WIN64) platform.  In that case, it becomes {\tt \_\_int64}.
+
+%-------------------------------------------------------------------------------
+\subsection{Version 4.6}
+%-------------------------------------------------------------------------------
+
+Added additional options to {\tt umf\_solve.c}.
+
+%-------------------------------------------------------------------------------
+\subsection{Version 4.5}
+%-------------------------------------------------------------------------------
+
+Added function pointers for malloc, calloc, realloc, free, printf, hypot,
+and complex divisiion, so that these functions can be redefined at run-time.
+Added a version number so you can determine the
+version of UMFPACK at run time or compile time.  UMFPACK requires AMD v2.0
+or later.
+
+%-------------------------------------------------------------------------------
+\subsection{Version 4.4}
+%-------------------------------------------------------------------------------
+
+Bug fix in strategy selection in {\tt umfpack\_*\_qsymbolic}.
+Added packed complex case for all complex input/output arguments.
+Added {\tt umfpack\_get\_determinant}.
+Added minimal support for Microsoft Visual Studio
+(the {\tt umf\_multicompile.c} file).
+
+%-------------------------------------------------------------------------------
+\subsection{Version 4.3.1}
+%-------------------------------------------------------------------------------
+
+Minor bug fix in the forward/backsolve.  This bug had the effect of turning
+off iterative refinement when solving $\m{A}\tr\m{x}=\m{b}$ after factorizing
+$\m{A}$.  UMFPACK mexFunction now factorizes $\m{A}\tr$ in its forward-slash
+operation.
+
+%-------------------------------------------------------------------------------
+\subsection{Version 4.3}
+%-------------------------------------------------------------------------------
+
+No changes are visible to the C or MATLAB user, except the presence of
+one new control parameter in the {\tt Control} array,
+and three new statistics in the {\tt Info} array.
+The primary change is the addition of an (optional) drop tolerance.
+
+%-------------------------------------------------------------------------------
+\subsection{Version 4.1}
+%-------------------------------------------------------------------------------
+
+The following is a summary of the main changes that are visible to the C
+or MATLAB user:
+
+\begin{enumerate}
+
+\item New ordering strategies added.  No changes are required in user code
+    (either C or MATLAB) to use the new default strategy, which is an automatic
+    selection of the unsymmetric, symmetric, or 2-by-2 strategies.
+
+\item Row scaling added.  This is only visible to the MATLAB caller when using
+    the form {\tt [L,U,P,Q,R] = umfpack (A)}, to retrieve the LU factors.
+    Likewise, it is only visible to the C caller when the LU factors are
+    retrieved, or when solving systems with just $\m{L}$ or $\m{U}$.
+    New C-callable and MATLAB-callable routines are included to get and to
+    apply the scale factors computed by UMFPACK.  Row scaling is enabled by
+    default, but can be disabled.  Row scaling usually leads to a better
+    factorization, particularly when the symmetric strategy is used.
+
+\item Error code {\tt UMFPACK\_ERROR\_problem\_to\_large} removed.
+    Version 4.0 would generate this error when the upper bound memory usage
+    exceeded 2GB (for the {\tt int} version), even when the actual memory
+    usage was less than this.  The new version properly handles this case,
+    and can successfully factorize the matrix if sufficient memory is
+    available.
+
+\item New control parameters and statistics provided.
+
+\item The AMD symmetric approximate minimum degree ordering routine added
+    \cite{AmestoyDavisDuff96,AmestoyDavisDuff03}.
+    It is used by UMFPACK, and can also be called independently from C or
+    MATLAB.
+
+\item The {\tt umfpack} mexFunction now returns permutation matrices, not
+    permutation vectors, when using the form {\tt [L,U,P,Q] = umfpack (A)}
+    or the new form {\tt [L,U,P,Q,R] = umfpack (A)}.
+
+\item New arguments added to the user-callable routines
+    {\tt umfpack\_*\_symbolic},
+    {\tt umfpack\_*\_qsymbolic},
+    {\tt umfpack\_*\_get\_numeric}, and
+    {\tt umfpack\_*\_get\_symbolic}.
+    The symbolic analysis now makes use of the numerical values of the matrix
+    $\m{A}$, to guide the 2-by-2 strategy.  The subsequent matrix passed to
+    the numeric factorization step does not have to have the same numerical
+    values.  All of the new arguments are optional.  If you do not wish to
+    include them, simply pass {\tt NULL} pointers instead.  The 2-by-2 strategy
+    will assume all entries are numerically large, for example.
+
+\item New routines added to save and load the {\tt Numeric} and {\tt Symbolic}
+    objects to and from a binary file.
+
+\item A Fortran interface added.  It provides access to a subset of
+    UMFPACK's features.
+
+\item You can compute an incomplete LU factorization, by dropping small
+    entries from $\m{L}$ and $\m{U}$.  By default, no nonzero entry is
+    dropped, no matter how small in absolute value.  This feature is new
+    to Version 4.3.
+
+\end{enumerate}
+
+%-------------------------------------------------------------------------------
+\section{Using UMFPACK in MATLAB}
+%-------------------------------------------------------------------------------
+
+The easiest way to use UMFPACK is within MATLAB.  Version 4.3 is a built-in
+routine in MATLAB 7.0.4, and is used in {\tt x = A}$\backslash${\tt b} when
+{\tt A} is sparse, square, unsymmetric (or symmetric but not positive definite),
+and with nonzero entries that are not confined in a narrow band.
+It is also used for the {\tt [L,U,P,Q] = lu (A)} usage of {\tt lu}.
+Type {\tt help lu} in MATLAB 6.5 or later for more details.
+
+To use the UMFPACK mexFunction, you must download and compile it,
+since the mexFunction itself is not part of MATLAB.
+The following discussion assumes that
+you have MATLAB Version 6.0 or later (which includes the BLAS, and the
+{\tt colamd} ordering routine).  To compile both the UMFPACK and AMD
+mexFunctions, just type {\tt make} in the Unix system shell,
+while in the {\tt UMFPACK} directory.
+You can also type {\tt umfpack\_make} in MATLAB, if you are in the
+{\tt UMFPACK/MATLAB} directory, or if that directory is in your MATLAB path.
+This works on any system with MATLAB, including Windows.
+See Section~\ref{Install} for more details on how to install UMFPACK.
+Once installed, the UMFPACK mexFunction can analyze, factor, and solve linear
+systems.  Table~\ref{matlab} summarizes some of the more common uses
+of the UMFPACK mexFunction within MATLAB.
+
+An optional input argument can be used to modify the control parameters for
+UMFPACK, and an optional output argument provides statistics on the 
+factorization.
+
+Refer to the AMD User Guide for more details about the AMD mexFunction.
+
+\begin{table}
+\caption{Using UMFPACK's MATLAB interface}
+\label{matlab}
+\vspace{0.1in}
+{\footnotesize
+\begin{tabular}{l|l|l}
+\hline
+Function & Using UMFPACK & MATLAB 6.0 equivalent \\
+\hline
+ & & \\
+\begin{minipage}[t]{1.5in}
+Solve $\m{Ax}=\m{b}$.
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+x = umfpack (A,'\',b) ;
+\end{verbatim}
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+x = A \ b ;
+\end{verbatim}
+\end{minipage}
+ \\
+ & & \\
+\hline
+ & & \\
+\begin{minipage}[t]{1.5in}
+Solve $\m{Ax}=\m{b}$ using a different row and column pre-ordering
+(symmetric ordering).
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+S = spones (A) ;
+Q = symamd (S+S') ;
+Control = umfpack ;
+Control (6) = 3 ;
+x = umfpack (A,Q,'\',b,Control) ;
+\end{verbatim}
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+spparms ('autommd',0) ;
+S = spones (A) ;
+Q = symamd (S+S') ;
+x = A (Q,Q) \ b (Q) ;
+x (Q) = x ;
+spparms ('autommd',1) ;
+\end{verbatim}
+\end{minipage}
+ \\
+ & & \\
+\hline
+ & & \\
+\begin{minipage}[t]{1.5in}
+Solve $\m{A}\tr\m{x}\tr = \m{b}\tr$.
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+x = umfpack (b,'/',A) ;
+\end{verbatim}
+Note: $\m{A}$ is factorized.
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+x = b / A ;
+\end{verbatim}
+Note: $\m{A}\tr$ is factorized.
+\end{minipage}
+ \\
+ & & \\
+\hline
+ & & \\
+\begin{minipage}[t]{1.5in}
+Scale and factorize $\m{A}$, then solve $\m{Ax}=\m{b}$.
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+[L,U,P,Q,R] = umfpack (A) ;
+c = P * (R \ b) ;
+x = Q * (U \ (L \ c)) ;
+\end{verbatim}
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+[m n] = size (A) ;
+r = full (sum (abs (A), 2)) ;
+r (find (r == 0)) = 1 ;
+R = spdiags (r, 0, m, m) ;
+I = speye (n) ;
+Q = I (:, colamd (A)) ;
+[L,U,P] = lu ((R\A)*Q) ;
+c = P * (R \ b) ;
+x = Q * (U \ (L \ c)) ;
+\end{verbatim}
+\end{minipage}
+ \\
+ & & \\
+\hline
+\end{tabular}
+}
+\end{table}
+
+Note: in MATLAB 6.5 or later, use {\tt spparms ('autoamd',0)} in addition to
+{\tt spparms ('autommd',0)}, in Table~\ref{matlab}, to turn off MATLAB's
+default reordering.
+
+UMFPACK requires
+{\tt b} to be a dense vector (real or complex) of the appropriate dimension.
+This is more restrictive than what you can do with MATLAB's
+backslash or forward slash.  See {\tt umfpack\_solve} for an M-file that
+removes this restriction.
+This restriction does not apply to the built-in backslash operator
+in MATLAB 6.5 or later, which uses UMFPACK to factorize the matrix.
+You can do this yourself in MATLAB:
+
+{\footnotesize
+\begin{verbatim}
+    [L,U,P,Q,R] = umfpack (A) ;
+    x = Q * (U \ (L \ (P * (R \ b)))) ;
+\end{verbatim}
+}
+
+or, with no row scaling:
+
+{\footnotesize
+\begin{verbatim}
+    [L,U,P,Q] = umfpack (A) ;
+    x = Q * (U \ (L \ (P * b))) ;
+\end{verbatim}
+}
+
+The above examples do not make use of the iterative refinement
+that is built into
+{\tt x = }{\tt umfpack (A,'}$\backslash${\tt ',b)}
+however.
+
+MATLAB's {\tt [L,U,P] = lu(A)} returns a lower triangular {\tt L}, an upper
+triangular {\tt U}, and a permutation matrix {\tt P} such that {\tt P*A} is
+equal to {\tt L*U}.  UMFPACK behaves differently.  By default, it scales
+the rows of {\tt A} and reorders the columns of {\tt A} prior to
+factorization, so that {\tt L*U} is equal to {\tt P*(R}$\backslash${\tt A)*Q},
+where {\tt R} is a diagonal sparse matrix of scale factors for the rows
+of {\tt A}.  The scale factors {\tt R} are applied to {\tt A} via the MATLAB
+expression {\tt R}$\backslash${\tt A} to avoid multiplying by
+the reciprocal, which can be numerically inaccurate.
+
+There are more options; you can provide your own column pre-ordering (in which
+case UMFPACK does not call COLAMD or AMD), you can modify other control settings
+(similar to the {\tt spparms} in MATLAB), and you can get various statistics on
+the analysis, factorization, and solution of the linear system.  Type
+{\tt umfpack\_details} and {\tt umfpack\_report} in MATLAB for more
+information.  Two demo M-files are provided.   Just type {\tt umfpack\_simple}
+and {\tt umfpack\_demo} to run them.
+The output of these two programs should be about the same
+as the files {\tt umfpack\_simple.m.out} and {\tt umfpack\_demo.m.out}
+that are provided.
+
+Factorizing {\tt A'} (or {\tt A.'}) and using the transposed factors can
+sometimes be faster than factorizing {\tt A}.  It can also be preferable to
+factorize {\tt A'} if {\tt A} is rectangular.  UMFPACK pre-orders the columns
+to maintain sparsity; the row ordering is not determined until the matrix
+is factorized.  Thus, if {\tt A} is {\tt m} by {\tt n} with rank {\tt m}
+and {\tt m} $<$ {\tt n}, then {\tt umfpack} might not find a factor
+{\tt U} with a zero-free diagonal.  Unless the matrix ill-conditioned or
+poorly scaled, factorizing {\tt A'} in this case will guarantee that both
+factors will have zero-free diagonals.  Here's how you can factorize {\tt A'}
+and get the factors of {\tt A} instead:
+
+\begin{verbatim}
+    [l,u,p,q] = umfpack (A') ;
+    L = u' ;
+    U = l' ;
+    P = q ;
+    Q = p ;
+    clear l u p q
+\end{verbatim}
+
+This is an alternative to {\tt [L,U,P,Q]=umfpack(A)}.
+
+A simple M-file ({\tt umfpack\_btf}) is provided that first permutes the matrix
+to upper block triangular form, using MATLAB's {\tt dmperm} routine, and then
+solves each block.  The LU factors are not returned.  Its usage is simple:
+{\tt x = umfpack\_btf(A,b)}.  Type {\tt help umfpack\_btf} for more options.
+An estimate of the 1-norm of {\tt L*U-P*A*Q} can be computed in MATLAB
+as {\tt lu\_normest(P*A*Q,L,U)}, using the {\tt lu\_normest.m} M-file
+by Hager and Davis \cite{DavisHager99} that is included with the
+UMFPACK distribution.  With row scaling enabled, use
+{\tt lu\_normest(P*(R}$\backslash${\tt A)*Q,L,U)} instead.
+
+One issue you may encounter is how UMFPACK allocates its memory when being used
+in a mexFunction.  One part of its working space is of variable size.   The
+symbolic analysis phase determines an upper bound on the size of this memory,
+but not all of this memory will typically be used in the numerical
+factorization.  UMFPACK tries to allocate a decent amount of working space.
+This is 70\% of the upper bound, by default, for the unsymmetric strategy.
+For the symmetric strategy, the fraction of the upper bound is computed
+automatically (assuming a best-case scenario with no numerical pivoting
+required during numeric factorization).
+If this initial allocation fails, it reduces its request
+and uses less memory.   If the space is not large enough during factorization,
+it is increased via {\tt mxRealloc}.
+
+However, {\tt mxMalloc} and {\tt mxRealloc} abort the {\tt umfpack} mexFunction
+if they fail, so this strategy does not work in MATLAB.
+
+To compute the determinant with UMFPACK:
+
+\begin{verbatim}
+    d = umfpack (A, 'det') ;
+    [d e] = umfpack (A, 'det') ;
+\end{verbatim}
+
+The first case is identical to MATLAB's {\tt det}.
+The second case returns the determinant in the form
+$d \times 10^e$, which avoids overflow if $e$ is large.
+
+%-------------------------------------------------------------------------------
+\section{Using UMFPACK in a C program}
+\label{C}
+%-------------------------------------------------------------------------------
+
+The C-callable UMFPACK library consists of 32 user-callable routines and one
+include file.  All but three of the routines come in four versions, with
+different sizes of integers and for real or complex floating-point numbers:
+\begin{enumerate}
+\item {\tt umfpack\_di\_*}: real double precision, {\tt int} integers.
+\item {\tt umfpack\_dl\_*}: real double precision, {\tt UF\_long} integers.
+\item {\tt umfpack\_zi\_*}: complex double precision, {\tt int} integers.
+\item {\tt umfpack\_zl\_*}: complex double precision, {\tt UF\_long} integers.
+\end{enumerate}
+where {\tt *} denotes the specific name of one of the routines.
+Routine names beginning with {\tt umf\_} are internal to the package,
+and should not be called by the user.  The include file {\tt umfpack.h}
+must be included in any C program that uses UMFPACK.
+The other three routines are the same for all four versions.
+
+In addition, the C-callable AMD library distributed with UMFPACK
+includes 4 user-callable routines (in two versions with {\tt int} and
+{\tt UF\_long} integers) and one include file.  Refer to the AMD documentation
+for more details.
+
+Use only one version for any one problem; do not attempt to use one version
+to analyze the matrix and another version to factorize the matrix, for example.
+
+The notation {\tt umfpack\_di\_*} refers to all user-callable routines
+for the real double precision and {\tt int} integer case.  The notation
+{\tt umfpack\_*\_numeric}, for example, refers all four versions
+(real/complex, int/UF\_long) of a single operation
+(in this case numeric factorization).
+
+%-------------------------------------------------------------------------------
+\subsection{The size of an integer}
+%-------------------------------------------------------------------------------
+
+The {\tt umfpack\_di\_*} and {\tt umfpack\_zi\_*} routines use {\tt int} integer
+arguments; those starting with {\tt umfpack\_dl\_} or {\tt umfpack\_zl\_}
+use {\tt UF\_long} integer arguments.  If you compile UMFPACK in the standard
+ILP32 mode (32-bit {\tt int}'s, {\tt long}'s, and pointers) then the versions
+are essentially identical.  You will be able to solve problems using up to 2GB
+of memory.  If you compile UMFPACK in the standard LP64 mode, the size of an
+{\tt int} remains 32-bits, but the size of a {\tt long} and a pointer both get
+promoted to 64-bits.  In the LP64 mode, the {\tt umfpack\_dl\_*}
+and {\tt umfpack\_zl\_*} routines can solve huge
+problems (not limited to 2GB), limited of course by the amount of available
+memory.  The only drawback to the 64-bit mode is that not all BLAS libraries
+support 64-bit integers.  This limits the performance you will obtain.
+Those that do support 64-bit integers are specific to particular
+architectures, and are not portable.  UMFPACK and AMD should be compiled
+in the same mode.
+If you compile UMFPACK and AMD in the LP64 mode,
+be sure to add {\tt -DLP64} to the compilation command.  See the examples in
+the {\tt UFconfig/UFconfig.mk} file.
+
+%-------------------------------------------------------------------------------
+\subsection{Real and complex floating-point}
+%-------------------------------------------------------------------------------
+
+The {\tt umfpack\_di\_*} and {\tt umfpack\_dl\_*} routines take (real) double
+precision arguments, and return double precision arguments.  In the
+{\tt umfpack\_zi\_*} and {\tt umfpack\_zl\_*} routines, these same arguments
+hold the real part of the matrices; and second double precision arrays hold
+the imaginary part of the input and output matrices.  Internally, complex
+numbers are stored in arrays with their real and imaginary parts interleaved,
+as required by the BLAS (``packed'' complex form).
+
+New to Version 4.4 is the option of providing input/output arguments
+in packed complex form.
+
+%-------------------------------------------------------------------------------
+\subsection{Primary routines, and a simple example}
+%-------------------------------------------------------------------------------
+
+Five primary UMFPACK routines are required to factorize $\m{A}$ or
+solve $\m{Ax}=\m{b}$.  They are fully described in Section~\ref{Primary}:
+
+\begin{itemize}
+\item {\tt umfpack\_*\_symbolic}:
+
+    Pre-orders the columns of $\m{A}$ to reduce fill-in.
+    Returns an opaque {\tt Symbolic} object as a {\tt void *}
+    pointer.  The object contains the symbolic analysis and is needed for the
+    numeric factorization.  This routine requires only $O(|\m{A}|)$ space,
+    where $|\m{A}|$ is the number of nonzero entries in the matrix.  It computes
+    upper bounds on the nonzeros in $\m{L}$ and $\m{U}$, the floating-point
+    operations required, and the memory usage of {\tt umfpack\_*\_numeric}.  The
+    {\tt Symbolic} object is small; it contains just the column pre-ordering,
+    the supernodal column elimination tree, and information about each frontal
+    matrix. It is no larger than about $13n$ integers if $\m{A}$ is
+    $n$-by-$n$.
+
+\item {\tt umfpack\_*\_numeric}:
+
+    Numerically scales and then factorizes a sparse matrix into
+    $\m{PAQ}$, $\m{PRAQ}$, or $\m{PR}^{-1}\m{AQ}$ into the product $\m{LU}$,
+    where
+    $\m{P}$ and $\m{Q}$ are permutation matrices, $\m{R}$ is a diagonal
+    matrix of scale factors, $\m{L}$ is lower triangular with unit diagonal,
+    and $\m{U}$ is upper triangular.  Requires the
+    symbolic ordering and analysis computed by {\tt umfpack\_*\_symbolic}
+    or {\tt umfpack\_*\_qsymbolic}.
+    Returns an opaque {\tt Numeric} object as a
+    {\tt void *} pointer.  The object contains the numerical factorization and
+    is used by {\tt umfpack\_*\_solve}.  You can factorize a new matrix with a
+    different values (but identical pattern) as the matrix analyzed by
+    {\tt umfpack\_*\_symbolic} or {\tt umfpack\_*\_qsymbolic} by re-using the
+    {\tt Symbolic} object (this feature is available when using UMFPACK in a
+    C or Fortran program, but not in MATLAB).
+    The matrix
+    $\m{U}$ will have zeros on the diagonal if $\m{A}$ is singular; this
+    produces a warning, but the factorization is still valid.
+
+\item {\tt umfpack\_*\_solve}:
+
+    Solves a sparse linear system ($\m{Ax}=\m{b}$, $\m{A}\tr\m{x}=\m{b}$, or
+    systems involving just $\m{L}$ or $\m{U}$), using the numeric factorization
+    computed by {\tt umfpack\_*\_numeric}.  Iterative refinement with sparse
+    backward error \cite{ardd:89} is used by default.  The matrix $\m{A}$ must
+    be square.  If it is singular, then a divide-by-zero will occur, and your
+    solution with contain IEEE Inf's or NaN's in the appropriate places.
+
+\item {\tt umfpack\_*\_free\_symbolic}:
+
+    Frees the {\tt Symbolic} object created by {\tt umfpack\_*\_symbolic}
+    or {\tt umfpack\_*\_qsymbolic}.
+
+\item {\tt umfpack\_*\_free\_numeric}:
+
+    Frees the {\tt Numeric} object created by {\tt umfpack\_*\_numeric}.
+
+\end{itemize}
+
+Be careful not to free a {\tt Symbolic} object with
+{\tt umfpack\_*\_free\_numeric}.  Nor should you attempt to free a {\tt Numeric}
+object with {\tt umfpack\_*\_free\_symbolic}.
+Failure to free these objects will lead to memory leaks.
+
+The matrix $\m{A}$ is represented in compressed column form, which is
+identical to the sparse matrix representation used by MATLAB.  It consists
+of three or four arrays, where the matrix is {\tt m}-by-{\tt n},
+with {\tt nz} entries.  For the {\tt int} version of UMFPACK:
+
+{\footnotesize
+\begin{verbatim}
+     int Ap [n+1] ;
+     int Ai [nz] ;
+     double Ax [nz] ;
+\end{verbatim}
+}
+
+For the {\tt UF\_long} version of UMFPACK:
+
+{\footnotesize
+\begin{verbatim}
+     UF_long Ap [n+1] ;
+     UF_long Ai [nz] ;
+     double Ax [nz] ;
+\end{verbatim}
+}
+
+The complex versions add another array for the imaginary part:
+
+{\footnotesize
+\begin{verbatim}
+     double Az [nz] ;
+\end{verbatim}
+}
+
+Alternatively, if {\tt Az} is {\tt NULL},
+the real part of the $k$th entry is located in
+{\tt Ax[2*k]} and the imaginary part is located in
+{\tt Ax[2*k+1]}, and the {\tt Ax} array is of size {\tt 2*nz}.
+
+All nonzeros are entries, but an entry may be numerically zero.  The row indices
+of entries in column {\tt j} are stored in
+    {\tt Ai[Ap[j]} \ldots {\tt Ap[j+1]-1]}.
+The corresponding numerical values are stored in
+    {\tt Ax[Ap[j]} \ldots {\tt Ap[j+1]-1]}.
+The imaginary part, for the complex versions, is stored in
+    {\tt Az[Ap[j]} \ldots {\tt Ap[j+1]-1]}
+    (see above for the packed complex case).
+
+No duplicate row indices may be present, and the row indices in any given
+column must be sorted in ascending order.  The first entry {\tt Ap[0]} must be
+zero.  The total number of entries in the matrix is thus {\tt nz = Ap[n]}.
+Except for the fact that extra zero entries can be included, there is thus a
+unique compressed column representation of any given matrix $\m{A}$.
+For a more flexible method for providing an input matrix to UMFPACK,
+see Section~\ref{triplet}.
+
+Here is a simple main program, {\tt umfpack\_simple.c}, that illustrates the
+basic usage of UMFPACK.  See Section~\ref{Synopsis} for a short description
+of each calling sequence, including a list of options for the first
+argument of {\tt umfpack\_di\_solve}.
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_simple.c via sed
+\end{verbatim}
+}
+
+The {\tt Ap}, {\tt Ai}, and {\tt Ax} arrays represent the matrix
+\[
+\m{A} = \left[
+\begin{array}{rrrrr}
+ 2 &  3 &  0 &  0 &  0 \\
+ 3 &  0 &  4 &  0 &  6 \\
+ 0 & -1 & -3 &  2 &  0 \\
+ 0 &  0 &  1 &  0 &  0 \\
+ 0 &  4 &  2 &  0 &  1 \\
+\end{array}
+\right].
+\]
+and the solution to $\m{Ax}=\m{b}$ is $\m{x} = [1 \, 2 \, 3 \, 4 \, 5]\tr$.
+The program uses default control settings and does not return any statistics
+about the ordering, factorization, or solution ({\tt Control} and {\tt Info}
+are both {\tt (double *) NULL}).  It also ignores the status value returned by
+most user-callable UMFPACK routines.
+
+%-------------------------------------------------------------------------------
+\subsection{A note about zero-sized arrays}
+%-------------------------------------------------------------------------------
+
+UMFPACK uses many user-provided arrays of
+size {\tt m} or {\tt n} (the order of the matrix), and of size
+{\tt nz} (the number of nonzeros in a matrix).  UMFPACK does not handle
+zero-dimensioned arrays;
+it returns an error code if {\tt m} or {\tt n}
+are zero.  However, {\tt nz} can be zero, since all singular matrices are
+handled correctly.  If you attempt to {\tt malloc} an array of size {\tt nz}
+= 0, however, {\tt malloc} will return a null pointer which UMFPACK will report
+as a missing argument.  If you {\tt malloc} an array of
+size {\tt nz} to pass to UMFPACK, make sure that you handle the {\tt nz} = 0
+case correctly (use a size equal to the maximum of {\tt nz} and 1, or use a
+size of {\tt nz+1}).
+
+%-------------------------------------------------------------------------------
+\subsection{Alternative routines}
+%-------------------------------------------------------------------------------
+
+Three alternative routines are provided that modify UMFPACK's default
+behavior.  They are fully described in Section~\ref{Alternative}:
+
+\begin{itemize}
+\item {\tt umfpack\_*\_defaults}:
+
+    Sets the default control parameters in the {\tt Control} array.  These can
+    then be modified as desired before passing the array to the other UMFPACK
+    routines.  Control parameters are summarized in Section~\ref{control_param}.
+    Three particular parameters deserve special notice.
+    UMFPACK uses relaxed partial pivoting, where a candidate pivot entry is
+    numerically acceptable if its magnitude is greater than or equal to a
+    tolerance parameter times the magnitude of the largest entry in the same
+    column.  The parameter {\tt Control [UMFPACK\_PIVOT\_TOLERANCE]} has a
+    default value of 0.1, and is used for the unsymmetric strategy.
+    For complex matrices, a cheap approximation of the absolute value is
+    used for the threshold pivoting test
+    ($|a| \approx |a_{\mbox{real}}|+|a_{\mbox{imag}}|$).
+
+    For the symmetric strategy, a second tolerance is used for diagonal
+    entries: \newline {\tt Control [UMFPACK\_SYM\_PIVOT\_TOLERANCE]}, with
+    a default value of 0.001.  The first parameter (with a default of 0.1)
+    is used for any off-diagonal candidate pivot entries.
+
+    These two parameters may be too small for some matrices, particularly for
+    ill-conditioned or poorly scaled ones.  With the default pivot tolerances
+    and default iterative refinement,
+        {\tt x = umfpack (A,'}$\backslash${\tt ',b)}
+    is just as accurate as (or more accurate) than
+        {\tt x = A}$\backslash${\tt b}
+    in MATLAB 6.1 for nearly all matrices.
+
+    If {\tt Control [UMFPACK\_PIVOT\_TOLERANCE]} is zero, than any
+    nonzero entry is acceptable as a pivot (this is changed from Version 4.0,
+    which treated a value of 0.0 the same as 1.0).  If the symmetric strategy is
+    used, and {\tt Control [UMFPACK\_SYM\_PIVOT\_TOLERANCE]} is zero, then any
+    nonzero entry on the diagonal is accepted as a pivot.  Off-diagonal pivoting
+    will still occur if the diagonal entry is exactly zero.  The
+    {\tt Control [UMFPACK\_SYM\_PIVOT\_TOLERANCE]} parameter is new to Version
+    4.1.  It is similar in function to the pivot tolerance for left-looking
+    methods (the MATLAB {\tt THRESH} option in {\tt [L,U,P] = lu (A, THRESH)},
+    and the pivot tolerance parameter in SuperLU).
+
+    The parameter {\tt Control [UMFPACK\_STRATEGY]} can be used to bypass
+    UMFPACK's automatic strategy selection.  The automatic strategy nearly
+    always selects the best method.  When it does not, the different methods
+    nearly always give about the same quality of results.  There may be
+    cases where the automatic strategy fails to pick a good strategy. Also,
+    you can save some computing time if you know the right strategy for your
+    set of matrix problems.
+
+\item {\tt umfpack\_*\_qsymbolic}:
+
+    An alternative to {\tt umfpack\_*\_symbolic}.  Allows the user to specify
+    his or her own column pre-ordering, rather than using the default COLAMD
+    or AMD pre-orderings.  For example, a graph partitioning-based order
+    of $\m{A}\tr\m{A}$ would be suitable for UMFPACK's unsymmetric strategy.
+    A partitioning of $\m{A}+\m{A}\tr$ would be suitable for UMFPACK's
+    symmetric or 2-by-2 strategies.
+
+\item {\tt umfpack\_*\_wsolve}:
+
+    An alternative to {\tt umfpack\_*\_solve} which does not dynamically
+    allocate any memory.  Requires the user to pass two additional work
+    arrays.
+
+\end{itemize}
+
+%-------------------------------------------------------------------------------
+\subsection{Matrix manipulation routines}
+\label{triplet}
+%-------------------------------------------------------------------------------
+
+The compressed column data structure is compact, and simplifies the UMFPACK
+routines that operate on the sparse matrix $\m{A}$.  However, it can be
+inconvenient for the user to generate.  Section~\ref{Manipulate} presents the
+details of routines for manipulating sparse matrices in {\em triplet} form,
+compressed column form, and compressed row form (the transpose of the
+compressed column form).  The triplet form of a matrix consists of three or
+four arrays.  For the {\tt int} version of UMFPACK:
+
+{\footnotesize
+\begin{verbatim}
+     int Ti [nz] ;
+     int Tj [nz] ;
+     double Tx [nz] ;
+\end{verbatim}
+}
+
+For the {\tt UF\_long} version:
+
+{\footnotesize
+\begin{verbatim}
+     UF_long Ti [nz] ;
+     UF_long Tj [nz] ;
+     double Tx [nz] ;
+\end{verbatim}
+}
+
+The complex versions use another array to hold the imaginary part:
+
+{\footnotesize
+\begin{verbatim}
+     double Tz [nz] ;
+\end{verbatim}
+}
+
+The {\tt k}-th triplet is $(i,j,a_{ij})$, where $i =$ {\tt Ti[k]},
+$j =$ {\tt Tj[k]}, and $a_{ij} =$ {\tt Tx[k]}.  For the complex versions,
+{\tt Tx[k]} is the real part of $a_{ij}$ and
+{\tt Tz[k]} is the imaginary part.
+The triplets can be in any
+order in the {\tt Ti}, {\tt Tj}, and {\tt Tx} arrays (and {\tt Tz} for
+the complex versions), and duplicate entries may
+exist.  
+If {\tt Tz} is NULL, then the array {\tt Tx} becomes of size {\tt 2*nz},
+and the real and imaginary parts of the
+{\tt k}-th triplet are located in {\tt Tx[2*k]} and {\tt Tx[2*k+1]},
+respectively.
+Any duplicate entries are summed when the triplet form is converted to
+compressed column form.  This is a convenient way to create a matrix arising in
+finite-element methods, for example.
+
+Four routines are provided for manipulating sparse matrices:
+
+\begin{itemize}
+\item {\tt umfpack\_*\_triplet\_to\_col}:
+
+    Converts a triplet form of a matrix to compressed column form (ready for
+    input to \newline
+    {\tt umfpack\_*\_symbolic}, {\tt umfpack\_*\_qsymbolic}, and
+    {\tt umfpack\_*\_numeric}).  Identical to {\tt A = spconvert(i,j,x)} in
+    MATLAB, except that zero entries are not removed, so that the pattern of
+    entries in the compressed column form of $\m{A}$ are fully under user
+    control.  This is important if you want to factorize a new matrix with the
+    {\tt Symbolic} object from a prior matrix with the same pattern as the new
+    one.
+
+\item {\tt umfpack\_*\_col\_to\_triplet}:
+
+    The opposite of {\tt umfpack\_*\_triplet\_to\_col}.  Identical to
+    {\tt [i,j,x] = find(A)} in MATLAB, except that numerically zero entries
+    may be included.
+
+\item {\tt umfpack\_*\_transpose}:
+
+    Transposes and optionally permutes a column form matrix \cite{Gustavson78}.
+    Identical to
+    {\tt R = A(P,Q)'} (linear algebraic transpose, using the complex conjugate)
+    or {\tt R = A(P,Q).'} (the array transpose)
+    in MATLAB, except for the presence of numerically zero entries.
+
+    Factorizing $\m{A}\tr$ and then solving $\m{Ax}=\m{b}$ with the transposed
+    factors can sometimes be much faster or much slower than factorizing
+    $\m{A}$.  It is highly dependent on your particular matrix.
+
+\item {\tt umfpack\_*\_scale}:
+
+    Applies the row scale factors to a user-provided vector.  This is not
+    required to solve the sparse linear system $\m{Ax}=\m{b}$ or
+    $\m{A}\tr\m{x}=\m{b}$, since {\tt umfpack\_*\_solve} applies the scale
+    factors for those systems.
+
+\end{itemize}
+
+It is quite easy to add matrices in triplet form, subtract them, transpose
+them, permute them, construct a submatrix, and multiply a triplet-form matrix
+times a vector.  UMFPACK does not provide code for these basic operations,
+however.  Refer to the discussion of
+{\tt umfpack\_*\_triplet\_to\_col} in Section~\ref{Manipulate} for more details
+on how to compute these operations in your own code.
+The only primary matrix operation not provided by UMFPACK is the
+multiplication of two sparse matrices \cite{Gustavson78}.
+The CHOLMOD provides many of these matrix operations, which
+can then be used in conjunction with UMFPACK.
+See my web page for details.
+
+%-------------------------------------------------------------------------------
+\subsection{Getting the contents of opaque objects}
+%-------------------------------------------------------------------------------
+
+There are cases where you may wish to do more with the LU factorization
+of a matrix than solve a linear system.  The opaque {\tt Symbolic} and
+{\tt Numeric} objects are just that - opaque.  You cannot do anything with them
+except to pass them back to subsequent calls to UMFPACK.  Three routines
+are provided for copying their contents into user-provided arrays using simpler
+data structures.  Four routines are provided for saving and loading the
+{\tt Numeric} and {\tt Symbolic} objects to/from binary files.
+An additional routine is provided that computes the determinant.
+They are fully described in Section~\ref{Get}:
+
+\begin{itemize}
+\item {\tt umfpack\_*\_get\_lunz}:
+
+    Returns the number of nonzeros in $\m{L}$ and $\m{U}$.
+
+\item {\tt umfpack\_*\_get\_numeric}:
+
+    Copies $\m{L}$, $\m{U}$, $\m{P}$, $\m{Q}$, and $\m{R}$
+    from the {\tt Numeric} object
+    into arrays provided by the user.  The matrix $\m{L}$ is returned in
+    compressed row form (with the column indices in each row sorted in ascending
+    order).  The matrix $\m{U}$ is returned in compressed column form (with
+    sorted columns).  There are no explicit zero entries in $\m{L}$ and $\m{U}$,
+    but such entries may exist in the {\tt Numeric} object.  The permutations
+    $\m{P}$ and $\m{Q}$ are represented as permutation vectors, where
+    {\tt P[k] = i} means that row {\tt i} of the original matrix is the
+    the {\tt k}-th row of $\m{PAQ}$, and where
+    {\tt Q[k] = j} means that column {\tt j} of the original matrix is the
+    {\tt k}-th column of $\m{PAQ}$.  This is identical to how MATLAB uses
+    permutation vectors (type {\tt help colamd} in MATLAB 6.1 or later).
+
+\item {\tt umfpack\_*\_get\_symbolic}:
+
+    Copies the contents of the {\tt Symbolic} object (the initial row and column
+    preordering, supernodal column elimination tree, and information
+    about each frontal matrix) into arrays provided by the user.
+
+\item {\tt umfpack\_*\_get\_determinant}:
+
+    Computes the determinant from the diagonal of $\m{U}$ and the permutations
+    $\m{P}$ and $\m{Q}$.  This is mostly of theoretical interest.
+    It is not a good test to determine if your matrix is singular or not.
+
+\item {\tt umfpack\_*\_save\_numeric}:
+
+    Saves a copy of the {\tt Numeric} object to a file, in binary format.
+
+\item {\tt umfpack\_*\_load\_numeric}:
+
+    Creates a {\tt Numeric} object by loading it from a file created
+    by {\tt umfpack\_*\_save\_numeric}.
+
+\item {\tt umfpack\_*\_save\_symbolic}:
+
+    Saves a copy of the {\tt Symbolic} object to a file, in binary format.
+
+\item {\tt umfpack\_*\_load\_symbolic}:
+
+    Creates a {\tt Symbolic} object by loading it from a file created
+    by {\tt umfpack\_*\_save\_symbolic}.
+
+\end{itemize}
+
+UMFPACK itself does not make use of these routines;
+they are provided solely for returning the contents of the opaque
+{\tt Symbolic} and {\tt Numeric} objects to the user, and saving/loading
+them to/from a binary file.  None of them do any computation, except for
+{\tt umfpack\_*\_get\_determinant}.
+
+%-------------------------------------------------------------------------------
+\subsection{Reporting routines}
+\label{Reporting}
+%-------------------------------------------------------------------------------
+
+None of the UMFPACK routines discussed so far prints anything, even when an
+error occurs.  UMFPACK provides you with nine routines for printing the input
+and output arguments (including the {\tt Control} settings and {\tt Info}
+statistics) of UMFPACK routines discussed above.  They are fully described in
+Section~\ref{Report}:
+
+\begin{itemize}
+\item {\tt umfpack\_*\_report\_status}:
+
+    Prints the status (return value) of other {\tt umfpack\_*} routines.
+
+\item {\tt umfpack\_*\_report\_info}:
+
+    Prints the statistics returned in the {\tt Info} array by
+    {\tt umfpack\_*\_*symbolic},
+    {\tt umfpack\_*\_numeric}, and {\tt umfpack\_*\_*solve}.
+
+\item {\tt umfpack\_*\_report\_control}:
+
+    Prints the {\tt Control} settings.
+
+\item {\tt umfpack\_*\_report\_matrix}:
+
+    Verifies and prints a compressed column-form or compressed row-form sparse
+    matrix.
+
+\item {\tt umfpack\_*\_report\_triplet}:
+
+    Verifies and prints a matrix in triplet form.
+
+\item {\tt umfpack\_*\_report\_symbolic}:
+
+    Verifies and prints a {\tt Symbolic} object.
+
+\item {\tt umfpack\_*\_report\_numeric}:
+
+    Verifies and prints a {\tt Numeric} object.
+
+\item {\tt umfpack\_*\_report\_perm}:
+
+    Verifies and prints a permutation vector.
+
+\item {\tt umfpack\_*\_report\_vector}:
+
+    Verifies and prints a real or complex vector.
+
+\end{itemize}
+
+The {\tt umfpack\_*\_report\_*} routines behave slightly differently when
+compiled
+into the C-callable UMFPACK library than when used in the MATLAB mexFunction.
+MATLAB stores its sparse matrices using the same compressed column data
+structure discussed above, where row and column indices of an $m$-by-$n$
+matrix are in the range 0 to $m-1$ or $n-1$, respectively\footnote{Complex
+matrices in MATLAB use the split array form, with one {\tt double} array
+for the real part and another array for the imaginary part.  UMFPACK
+supports that format, as well as the packed complex format (new to Version 4.4).}
+It prints them as if they are in the range 1 to $m$ or $n$.
+The UMFPACK mexFunction behaves the same way.
+
+You can control how much the {\tt umfpack\_*\_report\_*} routines print by
+modifying the {\tt Control [UMFPACK\_PRL]} parameter.  Its default value is 1.
+Here is a summary of how the routines use this print level parameter:
+
+\begin{itemize}
+\item {\tt umfpack\_*\_report\_status}:
+
+    No output if the print level is 0 or less, even when an error occurs.
+    If 1, then error messages are printed, and nothing is printed if
+    the status is {\tt UMFPACK\_OK}.  A warning message is printed if
+    the matrix is singular.  If 2 or more, then the status is always
+    printed.  If 4 or more, then the UMFPACK Copyright is printed.
+    If 6 or more, then the UMFPACK License is printed.  See also the first page
+    of this User Guide for the Copyright and License.
+
+\item {\tt umfpack\_*\_report\_control}:
+
+    No output if the print level is 1 or less.  If 2 or more, all of
+    {\tt Control} is printed.
+
+\item {\tt umfpack\_*\_report\_info}:
+
+    No output if the print level is 1 or less.  If 2 or more, all of
+    {\tt Info} is printed.
+
+\item all other {\tt umfpack\_*\_report\_*} routines:
+
+    If the print level is 2 or less, then these routines return silently without
+    checking their inputs.  If 3 or more, the inputs are fully verified and a
+    short status summary is printed.  If 4, then the first few entries of the
+    input arguments are printed.  If 5, then all of the input arguments are
+    printed.
+
+\end{itemize}
+
+This print level parameter has an additional effect on the MATLAB mexFunction.
+If zero, then no warnings of singular or nearly singular matrices are
+printed (similar to the MATLAB commands
+{\tt warning off MATLAB:singularMatrix} and
+{\tt warning off MATLAB:nearlySingularMatrix}).
+
+%-------------------------------------------------------------------------------
+\subsection{Utility routines}
+%-------------------------------------------------------------------------------
+
+UMFPACK v4.0 included a routine that returns the time used by the process,
+{\tt umfpack\_timer}.  The routine uses either {\tt getrusage} (which is
+preferred), or the ANSI C {\tt clock} routine if that is not available.
+It is fully described in Section~\ref{Utility}.  It is still available in
+UMFPACK v4.1 and following, but not used internally.
+Two new timing routines are provided in UMFPACK Version 4.1 and following,
+{\tt umfpack\_tic} and {\tt umfpack\_toc}.  They use POSIX-compliant
+{\tt sysconf} and {\tt times} routines to find both the CPU time
+and wallclock time.
+These three routines are the only user-callable
+routine that is identical in all four {\tt int}/{\tt UF\_long}, real/complex
+versions (there is no {\tt umfpack\_di\_timer} routine, for example).
+
+%-------------------------------------------------------------------------------
+\subsection{Control parameters}
+\label{control_param}
+%-------------------------------------------------------------------------------
+
+UMFPACK uses an optional {\tt double} array (currently of size 20)
+to modify its control parameters.  If you pass {\tt (double *) NULL} instead
+of a {\tt Control} array, then defaults are used.  These defaults provide
+nearly optimal performance (both speed, memory usage, and numerical accuracy)
+for a wide range of matrices from real applications.
+
+This array will almost certainly grow in size in future releases,
+so be sure to dimension your {\tt Control} array to be of size
+{\tt UMFPACK\_CONTROL}.  That constant is currently defined to be 20,
+but may increase in future versions, since all 20 entries are in use.
+
+The contents of this array may be modified by the user
+(see {\tt umfpack\_*\_defaults}).  Each
+user-callable routine includes a complete description of how each control
+setting modifies its behavior.  Table~\ref{control} summarizes the entire
+contents of the {\tt Control} array.
+Note that ANSI C uses 0-based indexing, while MATLAB uses 1-based
+indexing.  Thus, {\tt Control(1)} in MATLAB is the same as
+{\tt Control[0]} or {\tt Control[UMFPACK\_PRL]} in ANSI C.
+
+\begin{table}
+\caption{UMFPACK Control parameters}
+\label{control}
+{\footnotesize
+\begin{tabular}{llll}
+\hline
+
+MATLAB & ANSI C & default & description \\
+\hline
+{\tt Control(1)}  & {\tt Control[UMFPACK\_PRL]} & 1 & printing level \\
+{\tt Control(2)}  & {\tt Control[UMFPACK\_DENSE\_ROW]} & 0.2 & dense row parameter \\
+{\tt Control(3)}  & {\tt Control[UMFPACK\_DENSE\_COL]} & 0.2 & dense column parameter \\
+{\tt Control(4)}  & {\tt Control[UMFPACK\_PIVOT\_TOLERANCE]} & 0.1 & partial pivoting tolerance \\
+{\tt Control(5)}  & {\tt Control[UMFPACK\_BLOCK\_SIZE]} & 32 & BLAS block size \\
+{\tt Control(6)}  & {\tt Control[UMFPACK\_STRATEGY]} & 0 (auto) & select strategy \\
+{\tt Control(7)}  & {\tt Control[UMFPACK\_ALLOC\_INIT]} & 0.7 & initial memory allocation  \\
+{\tt Control(8)}  & {\tt Control[UMFPACK\_IRSTEP]} & 2 & max iter. refinement steps \\
+{\tt Control(13)} & {\tt Control[UMFPACK\_2BY2\_TOLERANCE]} & 0.01 & defines ``large'' entries \\
+{\tt Control(14)} & {\tt Control[UMFPACK\_FIXQ]} & 0 (auto) & fix or modify Q \\
+{\tt Control(15)} & {\tt Control[UMFPACK\_AMD\_DENSE]} & 10 & AMD dense row/column parameter \\
+{\tt Control(16)} & {\tt Control[UMFPACK\_SYM\_PIVOT\_TOLERANCE]} & 0.001 & for diagonal entries \\
+{\tt Control(17)} & {\tt Control[UMFPACK\_SCALE]} & 1 (sum) & row scaling (none, sum, or max) \\
+{\tt Control(18)} & {\tt Control[UMFPACK\_FRONT\_ALLOC\_INIT]} & 0.5 & frontal matrix allocation ratio \\
+{\tt Control(19)} & {\tt Control[UMFPACK\_DROPTOL]} & 0 & drop tolerance \\
+{\tt Control(20)} & {\tt Control[UMFPACK\_AGGRESSIVE]} & 1 (yes) & aggressive absorption \\
+ & & & in AMD and COLAMD \\
+%
+\hline
+\multicolumn{4}{l}{Can only be changed at compile time:} \\
+{\tt Control(9)}  & {\tt Control[UMFPACK\_COMPILED\_WITH\_BLAS]} & - & true if BLAS is used \\
+{\tt Control(10)} & {\tt Control[UMFPACK\_COMPILED\_FOR\_MATLAB]} & - & true for mexFunction \\
+{\tt Control(11)} & {\tt Control[UMFPACK\_COMPILED\_WITH\_GETRUSAGE]} & - & 1 if {\tt getrusage} used \\
+{\tt Control(12)} & {\tt Control[UMFPACK\_COMPILED\_IN\_DEBUG\_MODE]} & - & true if debug mode enabled \\
+\hline
+\end{tabular}
+}
+\end{table}
+
+Let $\alpha_r = ${\tt Control [UMFPACK\_DENSE\_ROW]},
+    $\alpha_c = ${\tt Control [UMFPACK\_DENSE\_COL]}, and
+    $\alpha = ${\tt Control [UMFPACK\_AMD\_DENSE]}.
+Suppose the submatrix $\m{S}$, obtained after eliminating pivots with
+zero Markowitz cost, is $m$-by-$n$.
+Then a row is considered ``dense'' if it has more than
+$\max (16, 16 \alpha_r \sqrt{n})$ entries.
+A column is considered ``dense'' if it has more than
+$\max (16, 16 \alpha_c \sqrt{m})$ entries.
+These rows and columns are treated different in COLAMD and during numerical
+factorization.   In COLAMD, dense columns are placed last in their natural
+order, and dense rows are ignored.  During numerical factorization, dense
+rows are stored differently.
+In AMD, a row/column of the square matrix $\m{S}+\m{S}\tr$ is
+considered ``dense'' if it has more than $\max (16, \alpha \sqrt{n})$ entries.
+These rows/columns are placed last in AMD's output ordering.
+For more details on the control parameters, refer to the documentation of
+{\tt umfpack\_*\_qsymbolic}, {\tt umfpack\_*\_numeric}, {\tt umfpack\_*\_solve},
+and the {\tt umfpack\_*\_report\_*} routines,
+in Sections~\ref{Primary}~through~\ref{Report}, below.
+
+%-------------------------------------------------------------------------------
+\subsection{Error codes}
+\label{error_codes}
+%-------------------------------------------------------------------------------
+
+Many of the routines return a {\tt status} value.
+This is also returned as the first entry in the {\tt Info} array, for
+those routines with that argument.  The following list summarizes
+all of the error codes in UMFPACK.  Each error code is given a
+specific name in the {\tt umfpack.h} include file, so you can use
+those constants instead of hard-coded values in your program.
+Future versions may report additional error codes.
+
+A value of zero means everything was successful, and the matrix is
+non-singular.  A value greater than zero means the routine was successful,
+but a warning occurred.
+A negative value means the routine was not successful.
+In this case, no {\tt Symbolic} or {\tt Numeric} object was created.
+
+\begin{itemize}
+\item {\tt UMFPACK\_OK},  (0):  UMFPACK was successful.
+
+\item {\tt UMFPACK\_WARNING\_singular\_matrix},  (1):  Matrix is singular.
+    There are exact zeros on the diagonal of $\m{U}$.
+
+\item {\tt UMFPACK\_WARNING\_determinant\_underflow}, (2):
+    The determinant is nonzero, but smaller in magnitude than
+    the smallest positive floating-point number.
+
+\item {\tt UMFPACK\_WARNING\_determinant\_overflow}, (3):
+    The determinant is larger in magnitude than
+    the largest positive floating-point number (IEEE Inf).
+
+\item {\tt UMFPACK\_ERROR\_out\_of\_memory},  (-1):  Not enough memory.
+    The ANSI C {\tt malloc} or {\tt realloc} routine failed.
+
+\item {\tt UMFPACK\_ERROR\_invalid\_Numeric\_object},  (-3):  
+    Routines that take a {\tt Numeric} object as input (or load it
+    from a file) check this object and return this error code if it is
+    invalid.  This can be caused by a memory leak or overrun in your
+    program, which can overwrite part of the Numeric object.  It can also
+    be caused by passing a Symbolic object by mistake, or some other pointer.
+    If you try to factorize a matrix using one version of UMFPACK and
+    then use the factors in another version, this error code will trigger as
+    well.  You cannot factor your matrix using
+    version 4.0 and then solve with version 4.1, for example.\footnote{
+    Exception: v4.3, v4.3.1, and v4.4 use identical data structures
+    for the {\tt Numeric} and {\tt Symbolic} objects}.
+    You cannot use different precisions of the same version
+    (real and complex, for example).
+    It is possible for the {\tt Numeric} object to be corrupted by your
+    program in subtle ways that are not detectable by this quick check.
+    In this case, you may see an
+    {\tt UMFPACK\_ERROR\_different\_pattern} error code, or even an
+    {\tt UMFPACK\_ERROR\_internal\_error}.
+
+\item {\tt UMFPACK\_ERROR\_invalid\_Symbolic\_object},  (-4):  
+    Routines that take a {\tt Symbolic} object as input (or load it
+    from a file) check this object and return this error code if it is
+    invalid.  The causes of this error are analogous to the
+    {\tt UMFPACK\_ERROR\_invalid\_Numeric\_object} error described above.
+
+\item {\tt UMFPACK\_ERROR\_argument\_missing},  (-5):  
+    Some arguments of some are optional (you can pass a {\tt NULL} pointer
+    instead of an array).  This error code occurs if you pass a {\tt NULL}
+    pointer when that argument is required to be present.
+
+\item {\tt UMFPACK\_ERROR\_n\_nonpositive}  (-6):  
+    The number of rows or columns of the matrix must be greater than zero.
+
+\item {\tt UMFPACK\_ERROR\_invalid\_matrix}  (-8):  
+    The matrix is invalid.  For the column-oriented input, this error
+    code will occur if the contents of {\tt Ap} and/or {\tt Ai} are invalid.
+
+    {\tt Ap} is an integer array of size {\tt n\_col+1}.
+    On input, it holds the
+    ``pointers'' for the column form of the sparse matrix $\m{A}$.
+    Column {\tt j} of
+    the matrix A is held in {\tt Ai [(Ap [j])} \ldots {\tt (Ap [j+1]-1)]}.
+    The first entry, {\tt Ap [0]}, must be zero,
+    and {\tt Ap [j]} $\le$ {\tt Ap [j+1]} must hold for all
+    {\tt j} in the range 0 to {\tt n\_col-1}.
+    The value {\tt nz = Ap [n\_col]} is thus the
+    total number of entries in the pattern of the matrix A.
+    {\tt nz} must be greater than or equal to zero.
+
+    The nonzero pattern (row indices) for column {\tt j} is stored in
+    {\tt Ai [(Ap [j])} \ldots {\tt (Ap [j+1]-1)]}.  The row indices in a given
+    column {\tt j}
+    must be in ascending order, and no duplicate row indices may be present.
+    Row indices must be in the range 0 to {\tt n\_row-1}
+    (the matrix is 0-based).
+
+    Some routines take a triplet-form input, with arguments
+    {\tt nz}, {\tt Ti}, and {\tt Tj}.  This error code is returned
+    if {\tt nz} is less than zero,
+    if any row    index in {\tt Ti} is outside the range 0 to {\tt n\_col-1}, or
+    if any column index in {\tt Tj} is outside the range 0 to {\tt n\_row-1}.
+
+\item {\tt UMFPACK\_ERROR\_different\_pattern},  (-11):  
+    The most common cause of this error is that the pattern of the
+    matrix has changed between the symbolic and numeric factorization.
+    It can also occur if the {\tt Numeric} or {\tt Symbolic} object has
+    been subtly corrupted by your program.
+
+\item {\tt UMFPACK\_ERROR\_invalid\_system},  (-13):  
+    The {\tt sys} argument provided to one of the solve routines is invalid.
+
+\item {\tt UMFPACK\_ERROR\_invalid\_permutation},  (-15):  
+    The permutation vector provided as input is invalid.
+
+\item {\tt UMFPACK\_ERROR\_file\_IO},  (-17):  
+    This error code is returned by the routines that save and load
+    the {\tt Numeric} or {\tt Symbolic} objects to/from a file, if a
+    file I/O error has occurred.  The file may not exist or may not be readable,
+    you may be trying to create a file that you don't have permission to create,
+    or you may be out of disk space.  The file you are trying to read might
+    be the wrong one, and an earlier end-of-file condition would then result
+    in this error.
+
+\item {\tt UMFPACK\_ERROR\_internal\_error},  (-911):  
+    An internal error has occurred, of unknown cause.  This is either a bug
+    in UMFPACK, or the result of a memory overrun from your program.
+    Try modifying the file {\tt AMD/Source/amd\_internal.h} and adding
+    the statement {\tt \#undef NDEBUG}, to enable the debugging mode.
+    Recompile UMFPACK and rerun your program.
+    A failed assertion might occur which
+    can give you a better indication as to what is going wrong.  Be aware that
+    UMFPACK will be extraordinarily slow when running in debug mode.
+    If all else fails, contact the developer (davis at cise.ufl.edu) with
+    as many details as possible.
+
+\end{itemize}
+
+%-------------------------------------------------------------------------------
+\subsection{Larger examples}
+%-------------------------------------------------------------------------------
+
+Full examples of all user-callable UMFPACK routines
+are available in four stand-alone C main programs, {\tt umfpack\_*\_demo.c}.
+Another example is
+the UMFPACK mexFunction, {\tt umfpackmex.c}.  The mexFunction accesses only the
+user-callable C interface to UMFPACK.  The only features that it does not use
+are the support for the triplet form (MATLAB's sparse arrays are already in the
+compressed column form) and the ability to reuse the {\tt Symbolic} object to
+numerically factorize a matrix whose pattern is the same as a prior matrix
+analyzed by {\tt umfpack\_*\_symbolic} or {\tt umfpack\_*\_qsymbolic}.  The
+latter is an important feature, but the mexFunction does not return its opaque
+{\tt Symbolic} and {\tt Numeric} objects to MATLAB.  Instead, it gets the
+contents of these objects after extracting them via the {\tt umfpack\_*\_get\_*}
+routines, and returns them as MATLAB sparse matrices.
+
+The {\tt umf4.c} program for reading matrices in Harwell/Boeing format
+\cite{DuffGrimesLewis87b} is provided.  It requires three Fortran 77 programs
+({\tt readhb.f}, {\tt readhb\_nozeros.f}, and {\tt readhb\_size.f})
+for reading in the sample Harwell/Boeing files in the {\tt UMFPACK/Demo/HB}
+directory.  More matrices are available at
+http://www.cise.ufl.edu/research/sparse/matrices.
+Type {\tt make hb} in the {\tt UMFPACK/Demo/HB} directory
+to compile and run this demo.  This program was used for the experimental
+results in \cite{Davis03}.
+
+%-------------------------------------------------------------------------------
+\section{Synopsis of C-callable routines}
+\label{Synopsis}
+%-------------------------------------------------------------------------------
+
+Each subsection, below, summarizes the input variables, output variables, return
+values, and calling sequences of the routines in one category.  Variables with
+the same name as those already listed in a prior category have the same size
+and type.
+
+The real, {\tt UF\_long} integer {\tt umfpack\_dl\_*} routines are
+identical to the real, {\tt int} routines, except that {\tt \_di\_} is replaced
+with {\tt \_dl\_} in the name, and all {\tt int} arguments become
+{\tt UF\_long}.
+Similarly, the complex, {\tt UF\_long} integer {\tt umfpack\_zl\_*} routines are
+identical to the complex, {\tt int} routines, except that {\tt \_zi\_} is
+replaced
+with {\tt \_zl\_} in the name, and all {\tt int} arguments become
+{\tt UF\_long}.
+Only the real and complex {\tt int} versions are listed in the synopsis below.
+
+The matrix $\m{A}$ is {\tt m}-by-{\tt n} with {\tt nz} entries.
+
+The {\tt sys} argument of {\tt umfpack\_*\_solve}
+is an integer in the range 0 to 14 which defines which linear system is
+to be solved.
+\footnote{Integer values for {\tt sys} are used instead of strings (as in LINPACK
+and LAPACK) to avoid C-to-Fortran portability issues.}
+Valid values are listed in Table~\ref{sys}.
+The notation $\m{A}\he$ refers to the matrix transpose, which is the
+complex conjugate transpose for complex matrices ({\tt A'} in MATLAB).
+The array transpose is $\m{A}\tr$, which is {\tt A.'} in MATLAB.
+
+\begin{table}
+\begin{center}
+\caption{UMFPACK {\tt sys} parameter}
+\label{sys}
+{\footnotesize
+\begin{tabular}{ll|l}
+\hline
+Value & & system \\
+\hline
+& & \\
+{\tt UMFPACK\_A}      &  (0) & $\m{Ax}=\m{b}$ \\
+{\tt UMFPACK\_At}     &  (1) & $\m{A}\he\m{x}=\m{b}$ \\
+{\tt UMFPACK\_Aat}    &  (2) & $\m{A}\tr\m{x}=\m{b}$ \\
+& & \\
+\hline
+& & \\
+{\tt UMFPACK\_Pt\_L}  &  (3) & $\m{P}\tr\m{Lx}=\m{b}$ \\
+{\tt UMFPACK\_L}      &  (4) & $\m{Lx}=\m{b}$ \\
+{\tt UMFPACK\_Lt\_P}  &  (5) & $\m{L}\he\m{Px}=\m{b}$ \\
+{\tt UMFPACK\_Lat\_P} &  (6) & $\m{L}\tr\m{Px}=\m{b}$ \\
+{\tt UMFPACK\_Lt}     &  (7) & $\m{L}\he\m{x}=\m{b}$ \\
+{\tt UMFPACK\_Lat}    &  (8) & $\m{L}\tr\m{x}=\m{b}$ \\
+& & \\
+\hline
+& & \\
+{\tt UMFPACK\_U\_Qt}  &  (9) & $\m{UQ}\tr\m{x}=\m{b}$ \\
+{\tt UMFPACK\_U}      & (10) & $\m{Ux}=\m{b}$ \\
+{\tt UMFPACK\_Q\_Ut}  & (11) & $\m{QU}\he\m{x}=\m{b}$ \\
+{\tt UMFPACK\_Q\_Uat} & (12) & $\m{QU}\tr\m{x}=\m{b}$ \\
+{\tt UMFPACK\_Ut}     & (13) & $\m{U}\he\m{x}=\m{b}$ \\
+{\tt UMFPACK\_Uat}    & (14) & $\m{U}\tr\m{x}=\m{b}$ \\
+& & \\
+\hline
+\end{tabular}
+}
+\end{center}
+\end{table}
+
+%-------------------------------------------------------------------------------
+\subsection{Primary routines: real/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+#include "umfpack.h"
+int status, sys, n, m, nz, Ap [n+1], Ai [nz] ;
+double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], Ax [nz], X [n], B [n] ;
+void *Symbolic, *Numeric ;
+
+status = umfpack_di_symbolic (m, n, Ap, Ai, Ax, &Symbolic, Control, Info) ;
+status = umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info) ;
+status = umfpack_di_solve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info) ;
+umfpack_di_free_symbolic (&Symbolic) ;
+umfpack_di_free_numeric (&Numeric) ;
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{Alternative routines: real/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+int Qinit [n], Wi [n] ;
+double W [5*n] ;
+
+umfpack_di_defaults (Control) ;
+status = umfpack_di_qsymbolic (m, n, Ap, Ai, Ax, Qinit, &Symbolic, Control, Info) ;
+status = umfpack_di_wsolve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info, Wi, W) ;
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{Matrix manipulation routines: real/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+int Ti [nz], Tj [nz], P [m], Q [n], Rp [m+1], Ri [nz], Map [nz] ;
+double Tx [nz], Rx [nz], Y [m], Z [m] ;
+
+status = umfpack_di_col_to_triplet (n, Ap, Tj) ;
+status = umfpack_di_triplet_to_col (m, n, nz, Ti, Tj, Tx, Ap, Ai, Ax, Map) ;
+status = umfpack_di_transpose (m, n, Ap, Ai, Ax, P, Q, Rp, Ri, Rx) ;
+status = umfpack_di_scale (Y, Z, Numeric) ;
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{Getting the contents of opaque objects: real/{\tt int}}
+%-------------------------------------------------------------------------------
+
+The {\tt filename} string should be large enough to hold the name of a file.
+
+{\footnotesize
+\begin{verbatim}
+int lnz, unz, Lp [m+1], Lj [lnz], Up [n+1], Ui [unz], do_recip ;
+double Lx [lnz], Ux [unz], D [min (m,n)], Rs [m], Mx [1], Ex [1] ;
+int nfr, nchains, P1 [m], Q1 [n], Front_npivcol [n+1], Front_parent [n+1], Front_1strow [n+1],
+    Front_leftmostdesc [n+1], Chain_start [n+1], Chain_maxrows [n+1], Chain_maxcols [n+1] ;
+char filename [100] ;
+
+status = umfpack_di_get_lunz (&lnz, &unz, &m, &n, &nz_udiag, Numeric) ;
+status = umfpack_di_get_numeric (Lp, Lj, Lx, Up, Ui, Ux, P, Q, D,
+    &do_recip, Rs, Numeric) ;
+status = umfpack_di_get_symbolic (&m, &n, &n1, &nz, &nfr, &nchains, P1, Q1,
+    Front_npivcol, Front_parent, Front_1strow, Front_leftmostdesc,
+    Chain_start, Chain_maxrows, Chain_maxcols, Symbolic) ;
+status = umfpack_di_load_numeric (&Numeric, filename) ;
+status = umfpack_di_save_numeric (Numeric, filename) ;
+status = umfpack_di_load_symbolic (&Symbolic, filename) ;
+status = umfpack_di_save_symbolic (Symbolic, filename) ;
+status = umfapck_di_get_determinant (Mx, Ex, Numeric, Info) ;
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{Reporting routines: real/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+
+umfpack_di_report_status (Control, status) ;
+umfpack_di_report_control (Control) ;
+umfpack_di_report_info (Control, Info) ;
+status = umfpack_di_report_matrix (m, n, Ap, Ai, Ax, 1, Control) ;
+status = umfpack_di_report_matrix (m, n, Rp, Ri, Rx, 0, Control) ;
+status = umfpack_di_report_numeric (Numeric, Control) ;
+status = umfpack_di_report_perm (m, P, Control) ;
+status = umfpack_di_report_perm (n, Q, Control) ;
+status = umfpack_di_report_symbolic (Symbolic, Control) ;
+status = umfpack_di_report_triplet (m, n, nz, Ti, Tj, Tx, Control) ;
+status = umfpack_di_report_vector (n, X, Control) ;
+\end{verbatim}
+}
+
+
+
+
+
+
+%-------------------------------------------------------------------------------
+\subsection{Primary routines: complex/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+double Az [nz], Xx [n], Xz [n], Bx [n], Bz [n] ;
+
+status = umfpack_zi_symbolic (m, n, Ap, Ai, Ax, Az, &Symbolic, Control, Info) ;
+status = umfpack_zi_numeric (Ap, Ai, Ax, Az, Symbolic, &Numeric, Control, Info) ;
+status = umfpack_zi_solve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric, Control, Info) ;
+umfpack_zi_free_symbolic (&Symbolic) ;
+umfpack_zi_free_numeric (&Numeric) ;
+\end{verbatim}
+}
+
+The arrays {\tt Ax}, {\tt Bx}, and {\tt Xx} double in size if
+any imaginary argument ({\tt Az}, {\tt Xz}, or {\tt Bz}) is {\tt NULL}.
+
+%-------------------------------------------------------------------------------
+\subsection{Alternative routines: complex/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+double Wz [10*n] ;
+
+umfpack_zi_defaults (Control) ;
+status = umfpack_zi_qsymbolic (m, n, Ap, Ai, Ax, Az, Qinit, &Symbolic, Control, Info) ;
+status = umfpack_zi_wsolve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric, Control, Info, Wi, Wz) ;
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{Matrix manipulation routines: complex/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+double Tz [nz], Rz [nz], Yx [m], Yz [m], Zx [m], Zz [m] ;
+
+status = umfpack_zi_col_to_triplet (n, Ap, Tj) ;
+status = umfpack_zi_triplet_to_col (m, n, nz, Ti, Tj, Tx, Tz, Ap, Ai, Ax, Az, Map) ;
+status = umfpack_zi_transpose (m, n, Ap, Ai, Ax, Az, P, Q, Rp, Ri, Rx, Rz, 1) ;
+status = umfpack_zi_transpose (m, n, Ap, Ai, Ax, Az, P, Q, Rp, Ri, Rx, Rz, 0) ;
+status = umfpack_zi_scale (Yx, Yz, Zx, Zz, Numeric) ;
+\end{verbatim}
+}
+
+The arrays {\tt Tx}, {\tt Rx}, {\tt Yx}, and {\tt Zx} double in size if
+any imaginary argument ({\tt Tz}, {\tt Rz}, {\tt Yz}, or {\tt Zz}) is {\tt NULL}.
+
+%-------------------------------------------------------------------------------
+\subsection{Getting the contents of opaque objects: complex/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+double Lz [lnz], Uz [unz], Dx [min (m,n)], Dz [min (m,n)], Mz [1] ;
+
+status = umfpack_zi_get_lunz (&lnz, &unz, &m, &n, &nz_udiag, Numeric) ;
+status = umfpack_zi_get_numeric (Lp, Lj, Lx, Lz, Up, Ui, Ux, Uz, P, Q, Dx, Dz,
+    &do_recip, Rs, Numeric) ;
+status = umfpack_zi_get_symbolic (&m, &n, &n1, &nz, &nfr, &nchains, P1, Q1,
+    Front_npivcol, Front_parent, Front_1strow, Front_leftmostdesc,
+    Chain_start, Chain_maxrows, Chain_maxcols, Symbolic) ;
+status = umfpack_zi_load_numeric (&Numeric, filename) ;
+status = umfpack_zi_save_numeric (Numeric, filename) ;
+status = umfpack_zi_load_symbolic (&Symbolic, filename) ;
+status = umfpack_zi_save_symbolic (Symbolic, filename) ;
+status = umfapck_zi_get_determinant (Mx, Mz, Ex, Numeric, Info) ;
+\end{verbatim}
+}
+
+The arrays {\tt Lx}, {\tt Ux}, {\tt Dx}, and {\tt Mx} double in size if
+any imaginary argument ({\tt Lz}, {\tt Uz}, {\tt Dz}, or {\tt Mz}) is {\tt NULL}.
+
+%-------------------------------------------------------------------------------
+\subsection{Reporting routines: complex/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+
+umfpack_zi_report_status (Control, status) ;
+umfpack_zi_report_control (Control) ;
+umfpack_zi_report_info (Control, Info) ;
+status = umfpack_zi_report_matrix (m, n, Ap, Ai, Ax, Az, 1, Control) ;
+status = umfpack_zi_report_matrix (m, n, Rp, Ri, Rx, Rz, 0, Control) ;
+status = umfpack_zi_report_numeric (Numeric, Control) ;
+status = umfpack_zi_report_perm (m, P, Control) ;
+status = umfpack_zi_report_perm (n, Q, Control) ;
+status = umfpack_zi_report_symbolic (Symbolic, Control) ;
+status = umfpack_zi_report_triplet (m, n, nz, Ti, Tj, Tx, Tz, Control) ;
+status = umfpack_zi_report_vector (n, Xx, Xz, Control) ;
+\end{verbatim}
+}
+
+The arrays {\tt Ax}, {\tt Rx}, {\tt Tx}, and {\tt Xx} double in size if
+any imaginary argument ({\tt Az}, {\tt Rz}, {\tt Tz}, or {\tt Xz}) is {\tt NULL}.
+
+
+
+
+%-------------------------------------------------------------------------------
+\subsection{Utility routines}
+%-------------------------------------------------------------------------------
+
+These routines are the same in all four versions of UMFPACK.
+
+{\footnotesize
+\begin{verbatim}
+double t, s [2] ;
+
+t = umfpack_timer ( ) ;
+umfpack_tic (s) ;
+umfpack_toc (s) ;
+
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{AMD ordering routines}
+%-------------------------------------------------------------------------------
+
+UMFPACK makes use of the AMD ordering package for its symmetric ordering
+strategy.  You may also use these four user-callable routines in your own C
+programs.  You need to include the {\tt amd.h} file only if you make direct
+calls to the AMD routines themselves.  The {\tt int} versions are summarized
+below; {\tt UF\_long} versions are also available.  Refer to the AMD User Guide
+for more information, or to the file {\tt amd.h} which documents these routines.
+
+{\footnotesize
+\begin{verbatim}
+#include "amd.h"
+double amd_control [AMD_CONTROL], amd_info [AMD_INFO] ;
+
+amd_defaults (amd_control) ;
+status = amd_order (n, Ap, Ai, P, amd_control, amd_info) ;
+amd_control (amd_control) ;
+amd_info (amd_info) ;
+
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\section{Using UMFPACK in a Fortran program}
+%-------------------------------------------------------------------------------
+
+UMFPACK includes a basic Fortran 77 interface to some of the C-callable
+UMFPACK routines.
+Since interfacing C and Fortran programs is not portable, this interface might
+not work with all C and Fortran compilers.  Refer to Section~\ref{Install} for
+more details.  The following Fortran routines are provided.
+The list includes the C-callable routines that the Fortran interface
+routine calls.  Refer to the corresponding C routines in Section~\ref{C} for
+more details on what the Fortran routine does.
+
+\begin{itemize}
+\item {\tt umf4def}: sets the default control parameters
+    ({\tt umfpack\_di\_defaults}).
+
+\item {\tt umf4sym}: pre-ordering and symbolic factorization
+    ({\tt umfpack\_di\_symbolic}).
+
+\item {\tt umf4num}: numeric factorization
+    ({\tt umfpack\_di\_numeric}).
+
+\item {\tt umf4solr}: solve a linear system with iterative refinement
+    ({\tt umfpack\_di\_solve}).
+
+\item {\tt umf4sol}: solve a linear system without iterative refinement
+    ({\tt umfpack\_di\_solve}).  Sets {\tt Control [UMFPACK\_IRSTEP]}
+    to zero, and does not require the matrix $\m{A}$.
+
+\item {\tt umf4scal}: scales a vector using UMFPACK's scale factors
+    ({\tt umfpack\_di\_scale}).
+
+\item {\tt umf4fnum}: free the {\tt Numeric} object
+    ({\tt umfpack\_di\_free\_numeric}).
+
+\item {\tt umf4fsym}: free the {\tt Symbolic} object
+    ({\tt umfpack\_di\_free\_symbolic}).
+
+\item {\tt umf4pcon}: prints the control parameters
+    ({\tt umfpack\_di\_report\_control}).
+
+\item {\tt umf4pinf}: print statistics
+    ({\tt umfpack\_di\_report\_info}).
+
+\item {\tt umf4snum}: save the {\tt Numeric} object to a file
+    ({\tt umfpack\_di\_save\_numeric}).
+
+\item {\tt umf4ssym}: save the {\tt Symbolic} object to a file
+    ({\tt umfpack\_di\_save\_symbolic}).
+
+\item {\tt umf4lnum}: load the {\tt Numeric} object from a file
+    ({\tt umfpack\_di\_load\_numeric}).
+
+\item {\tt umf4lsym}: load the {\tt Symbolic} object from a file
+    ({\tt umfpack\_di\_load\_symbolic}).
+\end{itemize}
+
+The matrix $\m{A}$ is passed to UMFPACK in compressed column form, with 0-based
+indices.  In Fortran, for an {\tt m}-by-{\tt n} matrix $\m{A}$ with {\tt nz}
+entries, the row indices of the first column (column 1) are in
+{\tt Ai (Ap(1)+1} \ldots {\tt Ap(2))}, with values in
+{\tt Ax (Ap(1)+1} \ldots {\tt Ap(2))}.  The last column (column {\tt n}) is in
+{\tt Ai (Ap(n)+1} \ldots {\tt Ap(n+1))} and
+{\tt Ax (Ap(n)+1} \ldots {\tt Ap(n+1))}.
+The number of entries in the matrix is thus {\tt nz = Ap (n+1)}.
+The row indices in {\tt Ai} are in the range 0 to {\tt m}-1.  They must be
+sorted, with no duplicate entries allowed.  None of the UMFPACK routines
+modify the input matrix $\m{A}$.
+The following definitions apply for the Fortran routines:
+
+{\footnotesize
+\begin{verbatim}
+    integer m, n, Ap (n+1), Ai (nz), symbolic, numeric, filenum, status
+    double precision Ax (nz), control (20), info (90), x (n), b (n)
+\end{verbatim}
+}
+
+UMFPACK's status is returned in either a {\tt status} argument, or in
+{\tt info (1)}.
+It is zero if UMFPACK was successful, 1 if the matrix is singular (this is a
+warning, not an error), and negative if an error occurred.
+Section~\ref{error_codes} summarizes the possible values of {\tt status}
+and {\tt info (1)}.
+See Table~\ref{sys} for a list of the values of the {\tt sys} argument.
+See Table~\ref{control} for a list of the control parameters (the
+Fortran usage is the same as the MATLAB usage for this array).
+
+For the {\tt Numeric} and {\tt Symbolic} handles, it is probably safe to
+assume that a Fortran {\tt integer} is sufficient to store a C pointer.  If
+that does not work, try defining {\tt numeric} and {\tt symbolic} in your
+Fortran program as integer arrays of size 2.  You will need to define them
+as {\tt integer*8} if you compile UMFPACK in the 64-bit mode.
+
+To avoid passing strings between C and Fortran in the load/save routines,
+a file number is passed instead, and the C interface constructs a file name
+(if {\tt filenum} is 42, the {\tt Numeric} file name is {\tt n42.umf}, and
+the {\tt Symbolic} file name is {\tt s42.umf}).
+
+The following is a summary of the calling sequence of each Fortran
+interface routine.  An example of their use is in the {\tt Demo/umf4hb.f}
+file.  That routine also includes an example of how to convert a 1-based
+sparse matrix into 0-based form.  For more details on the arguments of each
+routine, refer to the arguments of the same name in the corresponding
+C-callable routine, in Sections~\ref{Primary}~through~\ref{Utility}.
+The only exception is the {\tt control} argument of {\tt umf4sol},
+which sets {\tt control (8)} to zero to disable iterative refinement.
+Note that the solve routines do not overwrite {\tt b} with the solution,
+but return their solution in a different array, {\tt x}.
+
+{\footnotesize
+\begin{verbatim}
+    call umf4def (control)
+    call umf4sym (m, n, Ap, Ai, Ax, symbolic, control, info)
+    call umf4num (Ap, Ai, Ax, symbolic, numeric, control, info)
+    call umf4solr (sys, Ap, Ai, Ax, x, b, numeric, control, info)
+    call umf4sol (sys, x, b, numeric, control, info)
+    call umf4scal (x, b, numeric, status)
+    call umf4fnum (numeric)
+    call umf4fsym (symbolic)
+    call umf4pcon (control)
+    call umf4pinf (control)
+    call umf4snum (numeric, filenum, status)
+    call umf4ssym (symbolic, filenum, status)
+    call umf4lnum (numeric, filenum, status)
+    call umf4lsym (symbolic, filenum, status)
+\end{verbatim}
+}
+
+Access to the complex routines in UMFPACK is provided by the interface
+routines in {\tt umf4\_f77zwrapper.c}.  The following is a synopsis
+of each routine.  All the arguments are the same as the real versions,
+except {\tt Az}, {\tt xz}, and {\tt bz} are the imaginary parts of
+the matrix, solution, and right-hand side, respectively.  The
+{\tt Ax}, {\tt x}, and {\tt b} are the real parts.
+
+{\footnotesize
+\begin{verbatim}
+    call umf4zdef (control)
+    call umf4zsym (m, n, Ap, Ai, Ax, Az, symbolic, control, info)
+    call umf4znum (Ap, Ai, Ax, Az, symbolic, numeric, control, info)
+    call umf4zsolr (sys, Ap, Ai, Ax, Az, x, xz, b, bz, numeric, control, info)
+    call umf4zsol (sys, x, xz, b, bz, numeric, control, info)
+    call umf4zscal (x, xz, b, bz, numeric, status)
+    call umf4zfnum (numeric)
+    call umf4zfsym (symbolic)
+    call umf4zpcon (control)
+    call umf4zpinf (control)
+    call umf4zsnum (numeric, filenum, status)
+    call umf4zssym (symbolic, filenum, status)
+    call umf4zlnum (numeric, filenum, status)
+    call umf4zlsym (symbolic, filenum, status)
+\end{verbatim}
+}
+
+The Fortran interface does not support the packed complex case.
+
+%-------------------------------------------------------------------------------
+\section{Installation}
+\label{Install}
+%-------------------------------------------------------------------------------
+
+%-------------------------------------------------------------------------------
+\subsection{Installing the C library}
+%-------------------------------------------------------------------------------
+
+The following discussion assumes you have the {\tt make} program, either in
+Unix, or in Windows with Cygwin\footnote{www.cygwin.com}.
+You can skip this section and go to next one if all you want to use is
+the UMFPACK and AMD mexFunctions in MATLAB.
+
+You will need to install both UMFPACK v5.0 and AMD v2.0 to use UMFPACK.
+The {\tt UMFPACK} and {\tt AMD} subdirectories must be placed side-by-side
+within the same directory.  AMD is a stand-alone package that
+is required by UMFPACK.  UMFPACK can be compiled without the
+BLAS \cite{DaydeDuff99,ACM679a,ATLAS,GotoVandeGeijn02},
+but your performance will be much less than what it should be.
+
+System-dependent configurations are in the {\tt UFconfig/UFconfig.mk}
+file.  The default
+settings will work on most systems, except that UMFPACK will be compiled so
+that it does not use the BLAS.  Sample configurations are provided
+for Linux, Sun Solaris, SGI IRIX, IBM AIX, and the DEC/Compaq Alpha.
+
+To compile and install both packages,
+go to the {\tt UMFPACK} directory and type {\tt make}.  This will compile the
+libraries ({\tt AMD/Lib/libamd.a} and {\tt UMFPACK/Lib/libumfpack.a}).
+A demo of the AMD ordering routine will be compiled and tested in
+the {\tt AMD/Demo} directory, and five demo programs will then be
+compiled and tested in the {\tt UMFPACK/Demo} directory.
+The outputs of these demo programs will then be compared with output
+files in the distribution.  Expect to see a few differences, such as
+residual norms, compile-time control settings, and perhaps memory usage
+differences.  The AMD and UMFPACK mexFunctions for
+use in MATLAB will also be compiled.  If you do not have MATLAB 6.0 or
+later, type {\tt make lib} instead.
+
+If you have the GNU version of {\tt make}, the {\tt Source/GNUmakefile} and
+{\tt MATLAB/GNUmakefile} files are used.  These are much more concise than
+what the ``old'' version of {\tt make} can handle.  If you do not have
+GNU {\tt make}, the {\tt Source/Makefile} and {\tt MATLAB/Makefile} files
+are used instead.  Each UMFPACK source file is compiled into four
+versions ({\tt double} / complex, and {\tt int} / {\tt UF\_long}).  A proper
+old-style {\tt Makefile} is cumbersome in this case, so these two
+{\tt Makefile}'s have been constructed by brute force.  They ignore
+dependencies, and simply compile everything.  I highly recommend using GNU
+{\tt make} if you wish to modify UMFPACK.
+
+If you compile UMFPACK and AMD and then later change the
+{\tt UFconfig/UFconfig.mk} file
+then you should type {\tt make purge} and then {\tt make} to recompile.
+
+Here are the various parameters that you can control in your
+{\tt UFconfig/UFconfig.mk} file:
+
+\begin{itemize}
+\item {\tt CC = } your C compiler, such as {\tt cc}.
+\item {\tt RANLIB = } your system's {\tt ranlib} program, if needed.
+\item {\tt CFLAGS = } optimization flags, such as {\tt -O}.
+\item {\tt UMFPACK\_CONFIG = } configuration settings for the BLAS,
+    memory allocation routines, and timing routines.
+\item {\tt LIB = } your libraries, such as {\tt -lm} or {\tt -lblas}.
+\item {\tt RM =} the command to delete a file.
+\item {\tt MV =} the command to rename a file.
+\item {\tt MEX =} the command to compile a MATLAB mexFunction.
+    If you are using MATLAB 5, you need to add {\tt -DNBLAS} and
+    {\tt -DNUTIL} to this command.
+\item {\tt F77 =} the command to compile a Fortran program (optional).
+\item {\tt F77FLAGS =} the Fortran compiler flags (optional).
+\item {\tt F77LIB =} the Fortran libraries (optional).
+\end{itemize}
+
+The {\tt UMFPACK\_CONFIG} string can include combinations of the following;
+most deal with how the BLAS are called:
+\begin{itemize}
+\item {\tt -DNBLAS} if you do not have any BLAS at all.
+\item {\tt -DNSUNPERF} if you are on Solaris but do not have the Sun
+    Performance Library (for the BLAS).
+\item {\tt -DLONGBLAS} if your BLAS takes non-{\tt int} integer arguments.
+\item {\tt -DBLAS\_INT = } the integer used by the BLAS.
+
+\item {\tt -DBLAS\_NO\_UNDERSCORE}
+    for controlling how C calls the Fortran BLAS.
+    This is set automatically for Windows,
+    Sun Solaris, SGI Irix, Red Hat Linux, Compaq Alpha, and
+    AIX (the IBM RS 6000).
+
+\item {\tt -DGETRUSAGE} if you have the {\tt getrusage} function.
+\item {\tt -DNPOSIX} if you do not have the POSIX-compliant
+    {\tt sysconf} and {\tt times} routines used by
+    {\tt umfpack\_tic} and {\tt umfpack\_toc}.
+\item {\tt -DNRECIPROCAL} controls a trade-off between speed and accuracy.
+    If defined (or if the pivot value itself is less than $10^{-12}$),
+    then the pivot column is divided by the pivot value during numeric
+    factorization.  Otherwise, it is multiplied by the reciprocal of the
+    pivot, which is faster but can be less accurate.  The default is
+    to multiply by the reciprocal unless the pivot value is small.
+    This option also modifies how the rows of the matrix $\m{A}$ are
+    scaled.  If {\tt -DNRECIPROCAL} is defined (or if any scale factor is
+    less than $10^{-12}$), entries in the rows of $\m{A}$ are divided
+    by the scale factors.  Otherwise, they are multiplied by the reciprocal.
+    When compiling the complex routines with the GNU {\tt gcc} compiler, the
+    pivot column is always divided by the pivot entry, because of a
+    numerical accuracy issue encountered with {\tt gcc} version 3.2 with a
+    few complex matrices on a Pentium 4M (running Linux).  You can still
+    use {\tt -DNRECIPROCAL} to control how the scale factors
+    for the rows of $\m{A}$ are applied.
+\item {\tt -DNO\_DIVIDE\_BY\_ZERO} controls how UMFPACK treats zeros
+    on the diagonal of $\m{U}$, for a singular matrix $\m{A}$.
+    If defined, then no division by
+    zero is performed (a zero entry on the diagonal of $\m{U}$ is
+    treated as if it were equal to one).  By default,
+    UMFPACK will divide by zero.
+\item {\tt -DNO\_TIMER} controls whether or not timing routines
+    are to be called.  If defined, no timers are used.
+    Timers are included by default.
+\end{itemize}
+
+If a Fortran BLAS package is used you may see compiler warnings.  The BLAS
+routines
+{\tt dgemm}, {\tt dgemv}, {\tt dger}, {\tt dtrsm}, {\tt dtrsv}, {\tt dscal}
+and their corresponding complex versions are used.
+Header files are not provided for the Fortran
+BLAS.  You may safely ignore all of these warnings.
+
+I highly recommend the recent BLAS by Goto and van de Geijn
+\cite{GotoVandeGeijn02}.  Using this BLAS increased the performance
+of UMFPACK by up to 50\% on a Dell Latitude C840 laptop (2GHz Pentium 4M,
+512K L2 cache, 1GB main memory).  The peak performance of
+{\tt umfpack\_di\_numeric} with Goto and van de Geijn's BLAS is 1.6 Gflops
+on this computer.  In MATLAB, the peak performance of UMFPACK on
+a dense matrix (stored in sparse format) is 900 Mflops, as compared to
+1 Gflop for {\tt x = A}$\backslash${\tt b}
+when {\tt A} is stored as a regular full matrix.
+
+When you compile your program that uses the C-callable UMFPACK library,
+you need to link your program with both libraries
+({\tt UMFPACK/Lib/libumfpack.a} and {\tt AMD/Lib/libamd.a})
+and you need to tell your compiler to look in the
+directories {\tt UMFPACK/Include} and {\tt AMD/Include} for include
+files.  See {\tt UMFPACK/Demo/Makefile} for an example.
+You do not need to directly include any AMD include files in your
+program, unless you directly call AMD routines.  You only need the
+\begin{verbatim}
+#include "umfpack.h"
+\end{verbatim}
+statement, as described in Section~\ref{Synopsis}.
+
+If you would like to compile both 32-bit and 64-bit versions of the libraries,
+you will need to do it in two steps.  Modify your {\tt UFconfig/UFconfig.mk}
+file, and select the 32-bit option.  Type {\tt make} in the {\tt UMFPACK}
+directory, which creates the {\tt UMFPACK/Lib/libumfpack.a} and
+{\tt AMD/Lib/libamd.a} libraries.  Rename those two files.  Edit your
+{\tt UFconfig/UFconfig.mk} file and select the 64-bit option.
+Type {\tt make purge},
+and then {\tt make}, and you will create the 64-bit libraries.
+You can use the same {\tt umfpack.h} include file for both 32-bit and
+64-bit versions.  Simply link your program with the appropriate 32-bit
+or 64-bit compiled version of the UMFPACK and AMD libraries.
+
+Type {\tt make hb} in the {\tt UMFPACK/Demo/HB} directory
+to compile and run a C program that reads in and factorizes
+Harwell/Boeing matrices.  Note that this uses a stand-alone Fortran
+program to read in the Fortran-formatted Harwell/Boeing matrices and
+write them to a file which can be read by a C program.
+
+The {\tt umf\_multicompile.c} file has been added to assist in the
+compilation of UMFPACK in Microsoft Visual Studio, for Windows.
+
+%-------------------------------------------------------------------------------
+\subsection{Installing the MATLAB interface}
+%-------------------------------------------------------------------------------
+
+If all you want to do is use the UMFPACK mexFunction in MATLAB, you can skip
+the use of the {\tt make} command described above.  Simply type
+{\tt umfpack\_make} in MATLAB while in the {\tt UMFPACK/MATLAB} directory.
+You can also type {\tt amd\_make} in the {\tt AMD/MATLAB} directory
+to compile the stand-alone AMD mexFunction (this is not required to
+compile the UMFPACK mexFunction).  This works on any computer with MATLAB,
+including Windows.
+
+You will be prompted to select several configuration options, including
+whether or not to use the BLAS.
+MATLAB 5.3 (or earlier) does not include the BLAS, so you either have to
+compile UMFPACK without the BLAS (UMFPACK will be slow), or modify your
+{\tt <matlab>/bin/mexopts.sh} by adding your BLAS library
+to the {\tt CLIBS} string,
+where {\tt <matlab>} is the directory in which MATLAB is installed.
+
+If you are using Windows and the {\tt lcc} compiler bundled with
+MATLAB 6.1, then you may need to copy the
+{\tt UMFPACK}$\backslash${\tt MATLAB}$\backslash${\tt lcc\_lib}$\backslash${\tt libmwlapack.lib}
+file into the
+{\tt <matlab>}$\backslash${\tt extern}$\backslash${\tt lib}$\backslash${\tt win32}$\backslash${\tt lcc}$\backslash$
+directory.
+Next, type {\tt mex -setup}
+at the MATLAB prompt, and ask MATLAB to select the {\tt lcc} compiler.
+MATLAB 6.1 has built-in BLAS, but in that version of MATLAB the BLAS
+cannot be accessed by a mexFunction compiled by {\tt lcc} without first copying
+this file to the location listed above.
+If you have MATLAB 6.5 or later, you can probably skip this step.
+
+%-------------------------------------------------------------------------------
+\subsection{Installing the Fortran interface}
+%-------------------------------------------------------------------------------
+
+Once the 32-bit C-callable UMFPACK library is compiled, you can also compile
+the Fortran interface, by typing {\tt make fortran}.  This will create
+the {\tt umf4hb} program, test it, and compare the output with the
+file {\tt umf4hb.out} in the distribution.
+If you compiled UMFPACK in 64-bit mode, you need to use {\tt make fortran64}
+instead, which compiles the {\tt umf4hb64} program and compares its output
+with the file {\tt umf4hb64.out}.
+Refer to the comments in the {\tt Demo/umf4\_f77wrapper.c} file
+for more details.
+
+This interface is {\bf highly} non-portable, since it depends
+on how C and Fortran are interfaced.
+Because of this issue, the interface is included in the {\tt Demo} directory,
+and not as a primary part of the UMFPACK library.  The interface routines are
+not included in the compiled {\tt UMFPACK/Lib/libumfpack.a} library, but left
+as stand-alone compiled files ({\tt umf4\_f77wrapper.o} and
+{\tt umf4\_f77wrapper64.o} in the {\tt Demo} directory).
+You may need to modify the interface routines in the file
+{\tt umf4\_f77wrapper.c} if you are using compilers for which this interface
+has not been tested.
+
+%-------------------------------------------------------------------------------
+\subsection{Known Issues}
+%-------------------------------------------------------------------------------
+
+The Microsoft C or C++ compilers on a Pentium badly break the IEEE 754 standard,
+and do not treat NaN's properly.  According to IEEE 754, the expression
+{\tt (x != x)} is supposed to be true if and only if {\tt x} is NaN.  For
+non-compliant compilers in Windows that expression is always false, and another
+test must be used: {\tt (x < x)} is true if and only if {\tt x}
+is NaN.  For compliant compilers, {\tt (x < x)} is always false, for any
+value of {\tt x} (including NaN).
+To cover both cases, UMFPACK when running under Microsoft Windows
+defines the following macro, which is true if and only if {\tt x} is NaN,
+regardless of whether your compiler is compliant or not:
+
+\begin{verbatim}
+#define SCALAR_IS_NAN(x) (((x) != (x)) || ((x) < (x)))
+\end{verbatim}
+
+If your compiler breaks this test, then UMFPACK will fail catastrophically
+if it encounters a NaN.  You will not just see NaN's in your output; UMFPACK
+will probably crash with a segmentation fault.  In that case, you might try to
+see if the common (but non-ANSI C) routine {\tt isnan} is available, and modify
+the macro {\tt SCALAR\_IS\_NAN} in {\tt umf\_version.h} accordingly.  The
+simpler (and IEEE 754-compliant) test {\tt (x != x)} is always true with Linux
+on a PC, and on every Unix compiler I have tested.
+
+Some compilers will complain about the Fortran BLAS being defined implicitly.
+C prototypes for the BLAS are not used, except the C-BLAS.  Some compilers
+will complain about unrecognized {\tt \#pragma}'s.  You may safely ignore
+all of these warnings.
+
+%-------------------------------------------------------------------------------
+\section{Future work}
+\label{Future}
+%-------------------------------------------------------------------------------
+
+Here are a few features that are not in the current version of UMFPACK,
+in no particular
+order.  They may appear in a future release of UMFPACK.  If you are interested,
+let me know and I could consider including them:
+
+\begin{enumerate}
+
+\item Remove the restriction that the column-oriented form be given with
+    sorted columns.  This has already been done in AMD Version 2.0.
+
+\item Future versions may have different default {\tt Control} parameters.
+    Future versions may return more statistics in the {\tt Info} array, and
+    they may use more entries in the {\tt Control} array.
+    These two arrays will probably become larger, since there are very few
+    unused entries.  If they change in size, the constants
+    {\tt UMFPACK\_CONTROL} and {\tt UMFPACK\_INFO} defined in {\tt umfpack.h}
+    will be changed to reflect their new size.  Your C program should use
+    these constants when declaring the size of these two arrays.  Do not
+    define them as {\tt Control [20]} and {\tt Info [90]}.
+
+\item Forward/back solvers for the conventional row or column-form data
+    structure for $\m{L}$ and $\m{U}$ (the output of
+    {\tt umfpack\_*\_di\_get\_numeric}).  This would enable a separate
+    solver that could be used to write a MATLAB mexFunction
+    {\tt x = lu\_refine (A, b, L, U, P, Q, R)} that gives MATLAB access
+    to the iterative refinement algorithm with sparse backward error
+    analysis.  It would also be easier to handle sparse right-hand sides
+    in this data structure, and end up with good asymptotic run-time
+    in this case
+    (particularly for $\m{Lx}=\m{b}$; see \cite{GilbertPeierls88}).
+    See also CSparse and 
+    CXSparse for software for handling sparse right-hand sides.
+
+\item Complex absolute value computations could be
+    based on FDLIBM (see \newline
+    http://www.netlib.org/fdlibm),
+    using the {\tt hypot(x,y)} routine.
+
+\item When using iterative refinement, the residual $\m{Ax}-\m{b}$ could be
+    returned by {\tt umfpack\_solve}.
+
+\item The solve routines could handle multiple right-hand sides, and sparse
+    right-hand sides.  See {\tt umfpack\_solve} for the MATLAB version
+    of this feature.
+    See also CSparse and 
+    CXSparse for software for handling sparse right-hand sides.
+
+\item An option to redirect the error and diagnostic output.
+
+\item Permutation to block-triangular-form \cite{Duff78a} for the C-callable
+    interface.  There are two routines in the ACM Collected
+    Algorithms (529 and 575) \cite{Duff81b,Duff78b}
+    that could be translated from Fortran
+    to C and included in UMFPACK.  This would result in better performance
+    for matrices from circuit simulation and
+    chemical process engineering.  See {\tt umfpack\_btf.m} for the MATLAB
+    version of this feature.  KLU includes this feature.
+    See also {\tt cs\_dmperm} in CSparse and CXSparse.
+
+\item The ability to use user-provided work arrays, so that {\tt malloc},
+    {\tt free}, and {\tt realloc} realloc are not called.  The
+    {\tt umfpack\_*\_wsolve} routine is one example.
+
+\item A method that takes time proportional to the number of nonzeros in
+    $\m{A}$ to compute the symbolic factorization \cite{GilbertNgPeyton94}.
+    This would improve the performance of the symmetric and 2-by-2 strategies,
+    and the unsymmetric strategy when dense rows are present.
+    The current method takes
+    time proportional to the number of nonzeros in the upper bound of $\m{U}$.
+    The method used in UMFPACK exploits super-columns, however, so this
+    bound is rarely reached.
+    See {\tt cs\_counts} in CSparse and CXSparse,
+    and {\tt cholmod\_analyze} in CHOLMOD.
+
+\item Other basic sparse matrix operations, such as sparse matrix
+    multiplication, could be included.
+
+\item A more complete Fortran interface.
+
+\item A C++ interface.
+
+\item A parallel version using MPI.  This would require a large amount
+    of effort.
+
+\end{enumerate}
+
+
+%-------------------------------------------------------------------------------
+\newpage
+\section{The primary UMFPACK routines}
+\label{Primary}
+%-------------------------------------------------------------------------------
+
+The include files are the same for all four versions of
+UMFPACK.  The generic integer type is {\tt Int}, which is an {\tt int} or
+{\tt UF\_long}, depending on which version of UMFPACK you are using.
+
+\subsection{umfpack\_*\_symbolic}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_symbolic.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_numeric}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_numeric.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_solve}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_solve.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_free\_symbolic}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_free_symbolic.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_free\_numeric}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_free_numeric.h via sed
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\newpage
+\section{Alternative routines}
+\label{Alternative}
+%-------------------------------------------------------------------------------
+
+\subsection{umfpack\_*\_defaults}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_defaults.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_qsymbolic}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_qsymbolic.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_wsolve}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_wsolve.h via sed
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\newpage
+\section{Matrix manipulation routines}
+\label{Manipulate}
+%-------------------------------------------------------------------------------
+
+\subsection{umfpack\_*\_col\_to\_triplet}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_col_to_triplet.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_triplet\_to\_col}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_triplet_to_col.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_transpose}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_transpose.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_scale}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_scale.h via sed
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\newpage
+\section{Getting the contents of opaque objects}
+\label{Get}
+%-------------------------------------------------------------------------------
+
+\subsection{umfpack\_*\_get\_lunz}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_get_lunz.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_get\_numeric}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_get_numeric.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_get\_symbolic}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_get_symbolic.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_save\_numeric}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_save_numeric.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_load\_numeric}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_load_numeric.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_save\_symbolic}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_save_symbolic.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_load\_symbolic}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_load_symbolic.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_get\_determinant}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_get_determinant.h via sed
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\newpage
+\section{Reporting routines}
+\label{Report}
+%-------------------------------------------------------------------------------
+
+\subsection{umfpack\_*\_report\_status}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_status.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_report\_control}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_control.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_report\_info}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_info.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_report\_matrix}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_matrix.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_report\_numeric}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_numeric.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_report\_perm}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_perm.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_report\_symbolic}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_symbolic.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_report\_triplet}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_triplet.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_report\_vector}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_vector.h via sed
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\newpage
+\section{Utility routines}
+\label{Utility}
+%-------------------------------------------------------------------------------
+
+\subsection{umfpack\_timer}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_timer.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_tic and umfpack\_toc}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_tictoc.h via sed
+\end{verbatim}
+}
+
+
+%-------------------------------------------------------------------------------
+\newpage
+% References
+%-------------------------------------------------------------------------------
+
+\bibliographystyle{plain}
+\bibliography{UserGuide}
+
+\end{document}
diff --git a/src/C/SuiteSparse/UMFPACK/Doc/lesser.txt b/src/C/SuiteSparse/UMFPACK/Doc/lesser.txt
new file mode 100644
index 0000000..8add30a
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Doc/lesser.txt
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+

+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+

+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+

+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+

+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+

+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+

+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+

+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+

+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack.h
new file mode 100644
index 0000000..f128f43
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack.h
@@ -0,0 +1,438 @@
+/* ========================================================================== */
+/* === umfpack.h ============================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    This is the umfpack.h include file, and should be included in all user code
+    that uses UMFPACK.  Do not include any of the umf_* header files in user
+    code.  All routines in UMFPACK starting with "umfpack_" are user-callable.
+    All other routines are prefixed "umf_XY_", (where X is d or z, and Y is
+    i or l) and are not user-callable.
+*/
+
+#ifndef UMFPACK_H
+#define UMFPACK_H
+
+/* -------------------------------------------------------------------------- */
+/* Make it easy for C++ programs to include UMFPACK */
+/* -------------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* define UF_long */
+#include "UFconfig.h"
+
+/* -------------------------------------------------------------------------- */
+/* size of Info and Control arrays */
+/* -------------------------------------------------------------------------- */
+
+/* These might be larger in future versions, since there are only 3 unused
+ * entries in Info, and no unused entries in Control. */
+
+#define UMFPACK_INFO 90
+#define UMFPACK_CONTROL 20
+
+/* -------------------------------------------------------------------------- */
+/* User-callable routines */
+/* -------------------------------------------------------------------------- */
+
+/* Primary routines: */
+#include "umfpack_symbolic.h"
+#include "umfpack_numeric.h"
+#include "umfpack_solve.h"
+#include "umfpack_free_symbolic.h"
+#include "umfpack_free_numeric.h"
+
+/* Alternative routines: */
+#include "umfpack_defaults.h"
+#include "umfpack_qsymbolic.h"
+#include "umfpack_wsolve.h"
+
+/* Matrix manipulation routines: */
+#include "umfpack_triplet_to_col.h"
+#include "umfpack_col_to_triplet.h"
+#include "umfpack_transpose.h"
+#include "umfpack_scale.h"
+
+/* Getting the contents of the Symbolic and Numeric opaque objects: */
+#include "umfpack_get_lunz.h"
+#include "umfpack_get_numeric.h"
+#include "umfpack_get_symbolic.h"
+#include "umfpack_save_numeric.h"
+#include "umfpack_load_numeric.h"
+#include "umfpack_save_symbolic.h"
+#include "umfpack_load_symbolic.h"
+#include "umfpack_get_determinant.h"
+
+/* Reporting routines (the above 14 routines print nothing): */
+#include "umfpack_report_status.h"
+#include "umfpack_report_info.h"
+#include "umfpack_report_control.h"
+#include "umfpack_report_matrix.h"
+#include "umfpack_report_triplet.h"
+#include "umfpack_report_vector.h"
+#include "umfpack_report_symbolic.h"
+#include "umfpack_report_numeric.h"
+#include "umfpack_report_perm.h"
+
+/* Utility routines: */
+#include "umfpack_timer.h"
+#include "umfpack_tictoc.h"
+
+/* AMD */
+#include "amd.h"
+
+/* global function pointers */
+#include "umfpack_global.h"
+
+/* -------------------------------------------------------------------------- */
+/* Version, copyright, and license */
+/* -------------------------------------------------------------------------- */
+
+#define UMFPACK_VERSION "UMFPACK V5.0.3 (Dec 12, 2006)"
+
+#define UMFPACK_COPYRIGHT \
+"UMFPACK:  Copyright (c) 2005-2006 by Timothy A. Davis.  All Rights Reserved.\n"
+
+#define UMFPACK_LICENSE_PART1 \
+"\nUMFPACK License:\n" \
+"\n" \
+"   UMFPACK is available under alternate licenses,\n" \
+"   contact T. Davis for details.\n" \
+"\n" \
+"   Your use or distribution of UMFPACK or any modified version of\n" \
+"   UMFPACK implies that you agree to this License.\n" \
+"\n" \
+"   This library is free software; you can redistribute it and/or\n" \
+"   modify it under the terms of the GNU Lesser General Public\n" \
+"   License as published by the Free Software Foundation; either\n" \
+"   version 2.1 of the License, or (at your option) any later version.\n" \
+"\n" \
+"   This library is distributed in the hope that it will be useful,\n" \
+"   but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \
+"   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" \
+"   Lesser General Public License for more details.\n" \
+"\n" \
+"   You should have received a copy of the GNU Lesser General Public\n" \
+"   License along with this library; if not, write to the Free Software\n" \
+"   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301\n" \
+"   USA\n" \
+
+#define UMFPACK_LICENSE_PART2 \
+"\n" \
+"   Permission is hereby granted to use or copy this program under the\n" \
+"   terms of the GNU LGPL, provided that the Copyright, this License,\n" \
+"   and the Availability of the original version is retained on all copies.\n" \
+"   User documentation of any code that uses this code or any modified\n" \
+"   version of this code must cite the Copyright, this License, the\n" \
+"   Availability note, and \"Used by permission.\" Permission to modify\n" \
+"   the code and to distribute modified code is granted, provided the\n" \
+"   Copyright, this License, and the Availability note are retained,\n" \
+"   and a notice that the code was modified is included.\n"
+
+#define UMFPACK_LICENSE_PART3 \
+"\n" \
+"Availability: http://www.cise.ufl.edu/research/sparse/umfpack\n" \
+"\n"
+
+/* UMFPACK Version 4.5 and later will include the following definitions.
+ * As an example, to test if the version you are using is 4.5 or later:
+ *
+ * #ifdef UMFPACK_VER
+ *	if (UMFPACK_VER >= UMFPACK_VER_CODE (4,5)) ...
+ * #endif
+ *
+ * This also works during compile-time:
+ *
+ *	#if defined(UMFPACK_VER) && (UMFPACK >= UMFPACK_VER_CODE (4,5))
+ *	    printf ("This is version 4.5 or later\n") ;
+ *	#else
+ *	    printf ("This is an early version\n") ;
+ *	#endif
+ *
+ * Versions 4.4 and earlier of UMFPACK do not include a #define'd version
+ * number, although they do include the UMFPACK_VERSION string, defined
+ * above.
+ */
+
+#define UMFPACK_DATE "Dec 12, 2006"
+#define UMFPACK_VER_CODE(main,sub) ((main) * 1000 + (sub))
+#define UMFPACK_MAIN_VERSION 5
+#define UMFPACK_SUB_VERSION 0
+#define UMFPACK_SUBSUB_VERSION 3
+#define UMFPACK_VER UMFPACK_VER_CODE(UMFPACK_MAIN_VERSION,UMFPACK_SUB_VERSION)
+
+/* -------------------------------------------------------------------------- */
+/* contents of Info */
+/* -------------------------------------------------------------------------- */
+
+/* Note that umfpack_report.m must coincide with these definitions.  S is
+ * the submatrix of A after removing row/col singletons and empty rows/cols. */
+
+/* returned by all routines that use Info: */
+#define UMFPACK_STATUS 0	/* UMFPACK_OK, or other result */
+#define UMFPACK_NROW 1		/* n_row input value */
+#define UMFPACK_NCOL 16		/* n_col input value */
+#define UMFPACK_NZ 2		/* # of entries in A */
+
+/* computed in UMFPACK_*symbolic and UMFPACK_numeric: */
+#define UMFPACK_SIZE_OF_UNIT 3		/* sizeof (Unit) */
+
+/* computed in UMFPACK_*symbolic: */
+#define UMFPACK_SIZE_OF_INT 4		/* sizeof (int) */
+#define UMFPACK_SIZE_OF_LONG 5		/* sizeof (UF_long) */
+#define UMFPACK_SIZE_OF_POINTER 6	/* sizeof (void *) */
+#define UMFPACK_SIZE_OF_ENTRY 7		/* sizeof (Entry), real or complex */
+#define UMFPACK_NDENSE_ROW 8		/* number of dense rows */
+#define UMFPACK_NEMPTY_ROW 9		/* number of empty rows */
+#define UMFPACK_NDENSE_COL 10		/* number of dense rows */
+#define UMFPACK_NEMPTY_COL 11		/* number of empty rows */
+#define UMFPACK_SYMBOLIC_DEFRAG 12	/* # of memory compactions */
+#define UMFPACK_SYMBOLIC_PEAK_MEMORY 13	/* memory used by symbolic analysis */
+#define UMFPACK_SYMBOLIC_SIZE 14	/* size of Symbolic object, in Units */
+#define UMFPACK_SYMBOLIC_TIME 15	/* time (sec.) for symbolic analysis */
+#define UMFPACK_SYMBOLIC_WALLTIME 17	/* wall clock time for sym. analysis */
+#define UMFPACK_STRATEGY_USED 18	/* strategy used: sym, unsym, 2by2 */
+#define UMFPACK_ORDERING_USED 19	/* ordering used: colamd, amd, given */
+#define UMFPACK_QFIXED 31		/* whether Q is fixed or refined */
+#define UMFPACK_DIAG_PREFERRED 32	/* whether diagonal pivoting attempted*/
+#define UMFPACK_PATTERN_SYMMETRY 33	/* symmetry of pattern of S */
+#define UMFPACK_NZ_A_PLUS_AT 34		/* nnz (S+S'), excl. diagonal */
+#define UMFPACK_NZDIAG 35		/* nnz (diag (S)) */
+
+/* AMD statistics, computed in UMFPACK_*symbolic: */
+#define UMFPACK_SYMMETRIC_LUNZ 36	/* nz in L+U, if AMD ordering used */
+#define UMFPACK_SYMMETRIC_FLOPS 37	/* flops for LU, if AMD ordering used */
+#define UMFPACK_SYMMETRIC_NDENSE 38	/* # of "dense" rows/cols in S+S' */
+#define UMFPACK_SYMMETRIC_DMAX 39	/* max nz in cols of L, for AMD */
+
+/* statistics for 2-by-2 strategy */
+#define UMFPACK_2BY2_NWEAK 51		    /* number of weak diagonal entries*/
+#define UMFPACK_2BY2_UNMATCHED 52	    /* # of weak diagonals not matched*/
+#define UMFPACK_2BY2_PATTERN_SYMMETRY 53    /* symmetry of pattern of P*S */
+#define UMFPACK_2BY2_NZ_PA_PLUS_PAT 54	    /* nz in PS+(PS)' */
+#define UMFPACK_2BY2_NZDIAG 55		    /* nz on diagonal of PS+(PS)' */
+
+/* statistcs for singleton pruning */
+#define UMFPACK_COL_SINGLETONS 56	/* # of column singletons */
+#define UMFPACK_ROW_SINGLETONS 57	/* # of row singletons */
+#define UMFPACK_N2 58			/* size of S */
+#define UMFPACK_S_SYMMETRIC 59		/* 1 if S square and symmetricly perm.*/
+
+/* estimates computed in UMFPACK_*symbolic: */
+#define UMFPACK_NUMERIC_SIZE_ESTIMATE 20    /* final size of Numeric->Memory */
+#define UMFPACK_PEAK_MEMORY_ESTIMATE 21	    /* for symbolic & numeric */
+#define UMFPACK_FLOPS_ESTIMATE 22	    /* flop count */
+#define UMFPACK_LNZ_ESTIMATE 23		    /* nz in L, incl. diagonal */
+#define UMFPACK_UNZ_ESTIMATE 24		    /* nz in U, incl. diagonal */
+#define UMFPACK_VARIABLE_INIT_ESTIMATE 25   /* initial size of Numeric->Memory*/
+#define UMFPACK_VARIABLE_PEAK_ESTIMATE 26   /* peak size of Numeric->Memory */
+#define UMFPACK_VARIABLE_FINAL_ESTIMATE 27  /* final size of Numeric->Memory */
+#define UMFPACK_MAX_FRONT_SIZE_ESTIMATE 28  /* max frontal matrix size */
+#define UMFPACK_MAX_FRONT_NROWS_ESTIMATE 29 /* max # rows in any front */
+#define UMFPACK_MAX_FRONT_NCOLS_ESTIMATE 30 /* max # columns in any front */
+
+/* exact values, (estimates shown above) computed in UMFPACK_numeric: */
+#define UMFPACK_NUMERIC_SIZE 40		    /* final size of Numeric->Memory */
+#define UMFPACK_PEAK_MEMORY 41		    /* for symbolic & numeric */
+#define UMFPACK_FLOPS 42		    /* flop count */
+#define UMFPACK_LNZ 43			    /* nz in L, incl. diagonal */
+#define UMFPACK_UNZ 44			    /* nz in U, incl. diagonal */
+#define UMFPACK_VARIABLE_INIT 45	    /* initial size of Numeric->Memory*/
+#define UMFPACK_VARIABLE_PEAK 46	    /* peak size of Numeric->Memory */
+#define UMFPACK_VARIABLE_FINAL 47	    /* final size of Numeric->Memory */
+#define UMFPACK_MAX_FRONT_SIZE 48	    /* max frontal matrix size */
+#define UMFPACK_MAX_FRONT_NROWS 49	    /* max # rows in any front */
+#define UMFPACK_MAX_FRONT_NCOLS 50	    /* max # columns in any front */
+
+/* computed in UMFPACK_numeric: */
+#define UMFPACK_NUMERIC_DEFRAG 60	    /* # of garbage collections */
+#define UMFPACK_NUMERIC_REALLOC 61	    /* # of memory reallocations */
+#define UMFPACK_NUMERIC_COSTLY_REALLOC 62   /* # of costlly memory realloc's */
+#define UMFPACK_COMPRESSED_PATTERN 63	    /* # of integers in LU pattern */
+#define UMFPACK_LU_ENTRIES 64		    /* # of reals in LU factors */
+#define UMFPACK_NUMERIC_TIME 65		    /* numeric factorization time */
+#define UMFPACK_UDIAG_NZ 66		    /* nz on diagonal of U */
+#define UMFPACK_RCOND 67		    /* est. reciprocal condition # */
+#define UMFPACK_WAS_SCALED 68		    /* none, max row, or sum row */
+#define UMFPACK_RSMIN 69		    /* min (max row) or min (sum row) */
+#define UMFPACK_RSMAX 70		    /* max (max row) or max (sum row) */
+#define UMFPACK_UMIN 71			    /* min abs diagonal entry of U */
+#define UMFPACK_UMAX 72			    /* max abs diagonal entry of U */
+#define UMFPACK_ALLOC_INIT_USED 73	    /* alloc_init parameter used */
+#define UMFPACK_FORCED_UPDATES 74	    /* # of forced updates */
+#define UMFPACK_NUMERIC_WALLTIME 75	    /* numeric wall clock time */
+#define UMFPACK_NOFF_DIAG 76		    /* number of off-diagonal pivots */
+
+#define UMFPACK_ALL_LNZ 77		    /* nz in L, if no dropped entries */
+#define UMFPACK_ALL_UNZ 78		    /* nz in U, if no dropped entries */
+#define UMFPACK_NZDROPPED 79		    /* # of dropped small entries */
+
+/* computed in UMFPACK_solve: */
+#define UMFPACK_IR_TAKEN 80	    /* # of iterative refinement steps taken */
+#define UMFPACK_IR_ATTEMPTED 81	    /* # of iter. refinement steps attempted */
+#define UMFPACK_OMEGA1 82	    /* omega1, sparse backward error estimate */
+#define UMFPACK_OMEGA2 83	    /* omega2, sparse backward error estimate */
+#define UMFPACK_SOLVE_FLOPS 84	    /* flop count for solve */
+#define UMFPACK_SOLVE_TIME 85	    /* solve time (seconds) */
+#define UMFPACK_SOLVE_WALLTIME 86   /* solve time (wall clock, seconds) */
+
+/* Info [87, 88, 89] unused */
+
+/* Unused parts of Info may be used in future versions of UMFPACK. */
+
+/* -------------------------------------------------------------------------- */
+
+/* Info [UMFPACK_ORDERING_USED] is one of the following: */
+#define UMFPACK_ORDERING_COLAMD 0	/* COLAMD(A) */
+#define UMFPACK_ORDERING_AMD 1		/* AMD(A+A') */
+#define UMFPACK_ORDERING_GIVEN 2	/* Q is provided on input */
+
+/* -------------------------------------------------------------------------- */
+/* contents of Control */
+/* -------------------------------------------------------------------------- */
+
+/* used in all UMFPACK_report_* routines: */
+#define UMFPACK_PRL 0			/* print level */
+
+/* used in UMFPACK_*symbolic only: */
+#define UMFPACK_DENSE_ROW 1		/* dense row parameter */
+#define UMFPACK_DENSE_COL 2		/* dense col parameter */
+#define UMFPACK_BLOCK_SIZE 4		/* BLAS-3 block size */
+#define UMFPACK_STRATEGY 5		/* auto, symmetric, unsym., or 2by2 */
+#define UMFPACK_2BY2_TOLERANCE 12	/* 2-by-2 pivot tolerance */
+#define UMFPACK_FIXQ 13			/* -1: no fixQ, 0: default, 1: fixQ */
+#define UMFPACK_AMD_DENSE 14		/* for AMD ordering */
+#define UMFPACK_AGGRESSIVE 19		/* whether or not to use aggressive
+					 * absorption in AMD and COLAMD */
+
+/* used in UMFPACK_numeric only: */
+#define UMFPACK_PIVOT_TOLERANCE 3	/* threshold partial pivoting setting */
+#define UMFPACK_ALLOC_INIT 6		/* initial allocation ratio */
+#define UMFPACK_SYM_PIVOT_TOLERANCE 15	/* threshold, only for diag. entries */
+#define UMFPACK_SCALE 16		/* what row scaling to do */
+#define UMFPACK_FRONT_ALLOC_INIT 17	/* frontal matrix allocation ratio */
+#define UMFPACK_DROPTOL 18		/* drop tolerance for entries in L,U */
+
+/* used in UMFPACK_*solve only: */
+#define UMFPACK_IRSTEP 7		/* max # of iterative refinements */
+
+/* compile-time settings - Control [8..11] cannot be changed at run time: */
+#define UMFPACK_COMPILED_WITH_BLAS 8	    /* uses the BLAS */
+#define UMFPACK_COMPILED_FOR_MATLAB 9	    /* 1 if MATLAB mexFunction, etc. */
+#define UMFPACK_COMPILED_WITH_GETRUSAGE 10  /* uses getrusage timer, or not */
+#define UMFPACK_COMPILED_IN_DEBUG_MODE 11   /* debugging enabled (very slow!) */
+
+/* -------------------------------------------------------------------------- */
+
+/* Control [UMFPACK_STRATEGY] is one of the following: */
+#define UMFPACK_STRATEGY_AUTO 0		/* use sym. or unsym. strategy */
+#define UMFPACK_STRATEGY_UNSYMMETRIC 1	/* COLAMD(A), coletree postorder,
+					   not prefer diag*/
+#define UMFPACK_STRATEGY_2BY2 2		/* AMD(PA+PA'), no coletree postorder,
+					   prefer diag(PA) where P is pseudo
+					   max transversal */
+#define UMFPACK_STRATEGY_SYMMETRIC 3	/* AMD(A+A'), no coletree postorder,
+					   prefer diagonal */
+
+/* Control [UMFPACK_SCALE] is one of the following: */
+#define UMFPACK_SCALE_NONE 0	/* no scaling */
+#define UMFPACK_SCALE_SUM 1	/* default: divide each row by sum (abs (row))*/
+#define UMFPACK_SCALE_MAX 2	/* divide each row by max (abs (row)) */
+
+/* -------------------------------------------------------------------------- */
+/* default values of Control: */
+/* -------------------------------------------------------------------------- */
+
+#define UMFPACK_DEFAULT_PRL 1
+#define UMFPACK_DEFAULT_DENSE_ROW 0.2
+#define UMFPACK_DEFAULT_DENSE_COL 0.2
+#define UMFPACK_DEFAULT_PIVOT_TOLERANCE 0.1
+#define UMFPACK_DEFAULT_2BY2_TOLERANCE 0.01
+#define UMFPACK_DEFAULT_SYM_PIVOT_TOLERANCE 0.001
+#define UMFPACK_DEFAULT_BLOCK_SIZE 32
+#define UMFPACK_DEFAULT_ALLOC_INIT 0.7
+#define UMFPACK_DEFAULT_FRONT_ALLOC_INIT 0.5
+#define UMFPACK_DEFAULT_IRSTEP 2
+#define UMFPACK_DEFAULT_SCALE UMFPACK_SCALE_SUM
+#define UMFPACK_DEFAULT_STRATEGY UMFPACK_STRATEGY_AUTO
+#define UMFPACK_DEFAULT_AMD_DENSE AMD_DEFAULT_DENSE
+#define UMFPACK_DEFAULT_FIXQ 0
+#define UMFPACK_DEFAULT_AGGRESSIVE 1
+#define UMFPACK_DEFAULT_DROPTOL 0
+
+/* default values of Control may change in future versions of UMFPACK. */
+
+/* -------------------------------------------------------------------------- */
+/* status codes */
+/* -------------------------------------------------------------------------- */
+
+#define UMFPACK_OK (0)
+
+/* status > 0 means a warning, but the method was successful anyway. */
+/* A Symbolic or Numeric object was still created. */
+#define UMFPACK_WARNING_singular_matrix (1)
+
+/* The following warnings were added in umfpack_*_get_determinant */
+#define UMFPACK_WARNING_determinant_underflow (2)
+#define UMFPACK_WARNING_determinant_overflow (3)
+
+/* status < 0 means an error, and the method was not successful. */
+/* No Symbolic of Numeric object was created. */
+#define UMFPACK_ERROR_out_of_memory (-1)
+#define UMFPACK_ERROR_invalid_Numeric_object (-3)
+#define UMFPACK_ERROR_invalid_Symbolic_object (-4)
+#define UMFPACK_ERROR_argument_missing (-5)
+#define UMFPACK_ERROR_n_nonpositive (-6)
+#define UMFPACK_ERROR_invalid_matrix (-8)
+#define UMFPACK_ERROR_different_pattern (-11)
+#define UMFPACK_ERROR_invalid_system (-13)
+#define UMFPACK_ERROR_invalid_permutation (-15)
+#define UMFPACK_ERROR_internal_error (-911) /* yes, call me if you get this! */
+#define UMFPACK_ERROR_file_IO (-17)
+
+/* -------------------------------------------------------------------------- */
+/* solve codes */
+/* -------------------------------------------------------------------------- */
+
+/* Solve the system ( )x=b, where ( ) is defined below.  "t" refers to the */
+/* linear algebraic transpose (complex conjugate if A is complex), or the (') */
+/* operator in MATLAB.  "at" refers to the array transpose, or the (.') */
+/* operator in MATLAB. */
+
+#define UMFPACK_A	(0)	/* Ax=b    */
+#define UMFPACK_At	(1)	/* A'x=b   */
+#define UMFPACK_Aat	(2)	/* A.'x=b  */
+
+#define UMFPACK_Pt_L	(3)	/* P'Lx=b  */
+#define UMFPACK_L	(4)	/* Lx=b    */
+#define UMFPACK_Lt_P	(5)	/* L'Px=b  */
+#define UMFPACK_Lat_P	(6)	/* L.'Px=b */
+#define UMFPACK_Lt	(7)	/* L'x=b   */
+#define UMFPACK_Lat	(8)	/* L.'x=b  */
+
+#define UMFPACK_U_Qt	(9)	/* UQ'x=b  */
+#define UMFPACK_U	(10)	/* Ux=b    */
+#define UMFPACK_Q_Ut	(11)	/* QU'x=b  */
+#define UMFPACK_Q_Uat	(12)	/* QU.'x=b */
+#define UMFPACK_Ut	(13)	/* U'x=b   */
+#define UMFPACK_Uat	(14)	/* U.'x=b  */
+
+/* -------------------------------------------------------------------------- */
+
+/* Integer constants are used for status and solve codes instead of enum */
+/* to make it easier for a Fortran code to call UMFPACK. */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UMFPACK_H */
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_col_to_triplet.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_col_to_triplet.h
new file mode 100644
index 0000000..427571e
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_col_to_triplet.h
@@ -0,0 +1,110 @@
+/* ========================================================================== */
+/* === umfpack_col_to_triplet =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_col_to_triplet
+(
+    int n_col,
+    const int Ap [ ],
+    int Tj [ ]
+) ;
+
+UF_long umfpack_dl_col_to_triplet
+(
+    UF_long n_col,
+    const UF_long Ap [ ],
+    UF_long Tj [ ]
+) ;
+
+int umfpack_zi_col_to_triplet
+(
+    int n_col,
+    const int Ap [ ],
+    int Tj [ ]
+) ;
+
+UF_long umfpack_zl_col_to_triplet
+(
+    UF_long n_col,
+    const UF_long Ap [ ],
+    UF_long Tj [ ]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int n_col, *Tj, *Ap, status ;
+    status = umfpack_di_col_to_triplet (n_col, Ap, Tj) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long n_col, *Tj, *Ap, status ;
+    status = umfpack_dl_col_to_triplet (n_col, Ap, Tj) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int n_col, *Tj, *Ap, status ;
+    status = umfpack_zi_col_to_triplet (n_col, Ap, Tj) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long n_col, *Tj, *Ap, status ;
+    status = umfpack_zl_col_to_triplet (n_col, Ap, Tj) ;
+
+Purpose:
+
+    Converts a column-oriented matrix to a triplet form.  Only the column
+    pointers, Ap, are required, and only the column indices of the triplet form
+    are constructed.   This routine is the opposite of umfpack_*_triplet_to_col.
+    The matrix may be singular and/or rectangular.  Analogous to [i, Tj, x] =
+    find (A) in MATLAB, except that zero entries present in the column-form of
+    A are present in the output, and i and x are not created (those are just Ai
+    and Ax+Az*1i, respectively, for a column-form matrix A).
+
+Returns:
+
+    UMFPACK_OK if successful
+    UMFPACK_ERROR_argument_missing if Ap or Tj is missing
+    UMFPACK_ERROR_n_nonpositive if n_col <= 0
+    UMFPACK_ERROR_invalid_matrix if Ap [n_col] < 0, Ap [0] != 0, or
+	Ap [j] > Ap [j+1] for any j in the range 0 to n-1.
+    Unsorted columns and duplicate entries do not cause an error (these would
+    only be evident by examining Ai).  Empty rows and columns are OK.
+
+Arguments:
+
+    Int n_col ;		Input argument, not modified.
+
+	A is an n_row-by-n_col matrix.  Restriction: n_col > 0.
+	(n_row is not required)
+
+    Int Ap [n_col+1] ;	Input argument, not modified.
+
+	The column pointers of the column-oriented form of the matrix.  See
+	umfpack_*_*symbolic for a description.  The number of entries in
+	the matrix is nz = Ap [n_col].  Restrictions on Ap are the same as those
+	for umfpack_*_transpose.  Ap [0] must be zero, nz must be >= 0, and
+	Ap [j] <= Ap [j+1] and Ap [j] <= Ap [n_col] must be true for all j in
+	the range 0 to n_col-1.  Empty columns are OK (that is, Ap [j] may equal
+	Ap [j+1] for any j in the range 0 to n_col-1).
+
+    Int Tj [nz] ;	Output argument.
+
+	Tj is an integer array of size nz on input, where nz = Ap [n_col].
+	Suppose the column-form of the matrix is held in Ap, Ai, Ax, and Az
+	(see umfpack_*_*symbolic for a description).  Then on output, the
+	triplet form of the same matrix is held in Ai (row indices), Tj (column
+	indices), and Ax (numerical values).  Note, however, that this routine
+	does not require Ai and Ax (or Az for the complex version) in order to
+	do the conversion.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_defaults.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_defaults.h
new file mode 100644
index 0000000..bc40313
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_defaults.h
@@ -0,0 +1,69 @@
+/* ========================================================================== */
+/* === umfpack_defaults ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_defaults
+(
+    double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_dl_defaults
+(
+    double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_zi_defaults
+(
+    double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_zl_defaults
+(
+    double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    umfpack_di_defaults (Control) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    umfpack_dl_defaults (Control) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    umfpack_zi_defaults (Control) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    umfpack_zl_defaults (Control) ;
+
+Purpose:
+
+    Sets the default control parameter settings.
+
+Arguments:
+
+    double Control [UMFPACK_CONTROL] ;	Output argument.
+
+	Control is set to the default control parameter settings.  You can
+	then modify individual settings by changing specific entries in the
+	Control array.  If Control is a (double *) NULL pointer, then
+	umfpack_*_defaults returns silently (no error is generated, since
+	passing a NULL pointer for Control to any UMFPACK routine is valid).
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_free_numeric.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_free_numeric.h
new file mode 100644
index 0000000..94bbf98
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_free_numeric.h
@@ -0,0 +1,67 @@
+/* ========================================================================== */
+/* === umfpack_free_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_free_numeric
+(
+    void **Numeric
+) ;
+
+void umfpack_dl_free_numeric
+(
+    void **Numeric
+) ;
+
+void umfpack_zi_free_numeric
+(
+    void **Numeric
+) ;
+
+void umfpack_zl_free_numeric
+(
+    void **Numeric
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    umfpack_di_free_numeric (&Numeric) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    umfpack_dl_free_numeric (&Numeric) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    umfpack_zi_free_numeric (&Numeric) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    umfpack_zl_free_numeric (&Numeric) ;
+
+Purpose:
+
+    Deallocates the Numeric object and sets the Numeric handle to NULL.  This
+    routine is the only valid way of destroying the Numeric object.
+
+Arguments:
+
+    void **Numeric ;	    Input argument, set to (void *) NULL on output.
+
+	Numeric points to a valid Numeric object, computed by umfpack_*_numeric.
+	No action is taken if Numeric is a (void *) NULL pointer.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_free_symbolic.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_free_symbolic.h
new file mode 100644
index 0000000..cf9262e
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_free_symbolic.h
@@ -0,0 +1,67 @@
+/* ========================================================================== */
+/* === umfpack_free_symbolic ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_free_symbolic
+(
+    void **Symbolic
+) ;
+
+void umfpack_dl_free_symbolic
+(
+    void **Symbolic
+) ;
+
+void umfpack_zi_free_symbolic
+(
+    void **Symbolic
+) ;
+
+void umfpack_zl_free_symbolic
+(
+    void **Symbolic
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    umfpack_di_free_symbolic (&Symbolic) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    umfpack_dl_free_symbolic (&Symbolic) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    umfpack_zi_free_symbolic (&Symbolic) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    umfpack_zl_free_symbolic (&Symbolic) ;
+
+Purpose:
+
+    Deallocates the Symbolic object and sets the Symbolic handle to NULL.  This
+    routine is the only valid way of destroying the Symbolic object.
+
+Arguments:
+
+    void **Symbolic ;	    Input argument, set to (void *) NULL on output.
+
+	Points to a valid Symbolic object computed by umfpack_*_symbolic.
+	No action is taken if Symbolic is a (void *) NULL pointer.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_get_determinant.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_get_determinant.h
new file mode 100644
index 0000000..71b4158
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_get_determinant.h
@@ -0,0 +1,196 @@
+/* ========================================================================== */
+/* === UMFPACK_get_determinant ============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* UMFPACK_get_determinant contributed by David Bateman, Motorola, Paris. */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_get_determinant
+(
+    double *Mx,
+    double *Ex,
+    void *NumericHandle,
+    double User_Info [UMFPACK_INFO]
+) ;
+
+UF_long umfpack_dl_get_determinant
+(
+    double *Mx,
+    double *Ex,
+    void *NumericHandle,
+    double User_Info [UMFPACK_INFO]
+) ;
+
+int umfpack_zi_get_determinant
+(
+    double *Mx,
+    double *Mz,
+    double *Ex,
+    void *NumericHandle,
+    double User_Info [UMFPACK_INFO]
+) ;
+
+UF_long umfpack_zl_get_determinant
+(
+    double *Mx,
+    double *Mz,
+    double *Ex,
+    void *NumericHandle,
+    double User_Info [UMFPACK_INFO]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int status ;
+    double Mx, Ex, Info [UMFPACK_INFO] ;
+    status = umfpack_di_get_determinant (&Mx, &Ex, Numeric, Info) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    UF_long status ;
+    double Mx, Ex, Info [UMFPACK_INFO] ;
+    status = umfpack_dl_get_determinant (&Mx, &Ex, Numeric, Info) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int status ;
+    double Mx, Mz, Ex, Info [UMFPACK_INFO] ;
+    status = umfpack_zi_get_determinant (&Mx, &Mz, &Ex, Numeric, Info) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    UF_long status ;
+    double *Mx, *Mz, *Ex, Info [UMFPACK_INFO] ;
+    status = umfpack_zl_get_determinant (&Mx, &Mz, &Ex, Numeric, Info) ;
+
+packed complex int Syntax:
+
+    Same as above, except Mz is NULL.
+
+Author: Contributed by David Bateman, Motorola, Paris
+
+Purpose:
+
+    Using the LU factors and the permutation vectors contained in the Numeric
+    object, calculate the determinant of the matrix A.
+
+    The value of the determinant can be returned in two forms, depending on
+    whether Ex is NULL or not.  If Ex is NULL then the value of the determinant
+    is returned on Mx and Mz for the real and imaginary parts.  However, to
+    avoid over- or underflows, the determinant can be split into a mantissa
+    and exponent, and the parts returned separately, in which case Ex is not
+    NULL.  The actual determinant is then given by
+
+      double det ;
+      det = Mx * pow (10.0, Ex) ;
+
+    for the double case, or
+
+      double det [2] ;
+      det [0] = Mx * pow (10.0, Ex) ;	    // real part
+      det [1] = Mz * pow (10.0, Ex) ;	    // imaginary part
+
+    for the complex case.  Information on if the determinant will or has
+    over or under-flowed is given by Info [UMFPACK_STATUS].
+
+    In the "packed complex" syntax, Mx [0] holds the real part and Mx [1]
+    holds the imaginary part.  Mz is not used (it is NULL).
+
+Returns:
+
+    Returns UMFPACK_OK if sucessful.  Returns UMFPACK_ERROR_out_of_memory if
+    insufficient memory is available for the n_row integer workspace that
+    umfpack_*_get_determinant allocates to construct pivots from the
+    permutation vectors.  Returns UMFPACK_ERROR_invalid_Numeric_object if the
+    Numeric object provided as input is invalid.  Returns
+    UMFPACK_WARNING_singular_matrix if the determinant is zero.  Returns
+    UMFPACK_WARNING_determinant_underflow or
+    UMFPACK_WARNING_determinant_overflow if the determinant has underflowed
+    overflowed (for the case when Ex is NULL), or will overflow if Ex is not
+    NULL and det is computed (see above) in the user program.
+
+Arguments:
+
+    double *Mx ;   Output argument (array of size 1, or size 2 if Mz is NULL)
+    double *Mz ;   Output argument (optional)
+    double *Ex ;   Output argument (optional)
+
+        The determinant returned in mantissa/exponent form, as discussed above.
+	If Mz is NULL, then both the original and imaginary parts will be
+	returned in Mx. If Ex is NULL then the determinant is returned directly
+	in Mx and Mz (or Mx [0] and Mx [1] if Mz is NULL), rather than in
+	mantissa/exponent form.
+
+    void *Numeric ;	Input argument, not modified.
+
+	Numeric must point to a valid Numeric object, computed by
+	umfpack_*_numeric.
+
+    double Info [UMFPACK_INFO] ;	Output argument.
+
+	Contains information about the calculation of the determinant. If a
+	(double *) NULL pointer is passed, then no statistics are returned in
+	Info (this is not an error condition).  The following statistics are
+	computed in umfpack_*_determinant:
+
+	Info [UMFPACK_STATUS]: status code.  This is also the return value,
+	    whether or not Info is present.
+
+	    UMFPACK_OK
+
+	        The determinant was successfully found.
+
+	    UMFPACK_ERROR_out_of_memory
+
+		Insufficient memory to solve the linear system.
+
+	    UMFPACK_ERROR_argument_missing
+
+		Mx is missing (NULL).
+
+	    UMFPACK_ERROR_invalid_Numeric_object
+
+		The Numeric object is not valid.
+
+	    UMFPACK_ERROR_invalid_system
+
+		The matrix is rectangular.  Only square systems can be
+		handled.
+
+	    UMFPACK_WARNING_singluar_matrix
+
+		The determinant is zero or NaN.  The matrix is singular.
+
+	    UMFPACK_WARNING_determinant_underflow
+
+	        When passing from mantissa/exponent form to the determinant
+		an underflow has or will occur.  If the mantissa/exponent from
+		of obtaining the determinant is used, the underflow will occur
+		in the user program.  If the single argument method of
+		obtaining the determinant is used, the underflow has already
+		occurred.
+
+	    UMFPACK_WARNING_determinant_overflow
+
+	        When passing from mantissa/exponent form to the determinant
+		an overflow has or will occur.  If the mantissa/exponent from
+		of obtaining the determinant is used, the overflow will occur
+		in the user program.  If the single argument method of
+		obtaining the determinant is used, the overflow has already
+		occurred.
+
+
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_get_lunz.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_get_lunz.h
new file mode 100644
index 0000000..8e53520
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_get_lunz.h
@@ -0,0 +1,137 @@
+/* ========================================================================== */
+/* === umfpack_get_lunz ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_get_lunz
+(
+    int *lnz,
+    int *unz,
+    int *n_row,
+    int *n_col,
+    int *nz_udiag,
+    void *Numeric
+) ;
+
+UF_long umfpack_dl_get_lunz
+(
+    UF_long *lnz,
+    UF_long *unz,
+    UF_long *n_row,
+    UF_long *n_col,
+    UF_long *nz_udiag,
+    void *Numeric
+) ;
+
+int umfpack_zi_get_lunz
+(
+    int *lnz,
+    int *unz,
+    int *n_row,
+    int *n_col,
+    int *nz_udiag,
+    void *Numeric
+) ;
+
+UF_long umfpack_zl_get_lunz
+(
+    UF_long *lnz,
+    UF_long *unz,
+    UF_long *n_row,
+    UF_long *n_col,
+    UF_long *nz_udiag,
+    void *Numeric
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int status, lnz, unz, n_row, n_col, nz_udiag ;
+    status = umfpack_di_get_lunz (&lnz, &unz, &n_row, &n_col, &nz_udiag,
+	Numeric) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    UF_long status, lnz, unz, n_row, n_col, nz_udiag ;
+    status = umfpack_dl_get_lunz (&lnz, &unz, &n_row, &n_col, &nz_udiag,
+	Numeric) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int status, lnz, unz, n_row, n_col, nz_udiag ;
+    status = umfpack_zi_get_lunz (&lnz, &unz, &n_row, &n_col, &nz_udiag,
+	Numeric) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    UF_long status, lnz, unz, n_row, n_col, nz_udiag ;
+    status = umfpack_zl_get_lunz (&lnz, &unz, &n_row, &n_col, &nz_udiag,
+	Numeric) ;
+
+Purpose:
+
+    Determines the size and number of nonzeros in the LU factors held by the
+    Numeric object.  These are also the sizes of the output arrays required
+    by umfpack_*_get_numeric.
+
+    The matrix L is n_row -by- min(n_row,n_col), with lnz nonzeros, including
+    the entries on the unit diagonal of L.
+
+    The matrix U is min(n_row,n_col) -by- n_col, with unz nonzeros, including
+    nonzeros on the diagonal of U.
+
+Returns:
+
+    UMFPACK_OK if successful.
+    UMFPACK_ERROR_invalid_Numeric_object if Numeric is not a valid object.
+    UMFPACK_ERROR_argument_missing if any other argument is (Int *) NULL.
+
+Arguments:
+
+    Int *lnz ;		Output argument.
+
+	The number of nonzeros in L, including the diagonal (which is all
+	one's).  This value is the required size of the Lj and Lx arrays as
+	computed by umfpack_*_get_numeric.  The value of lnz is identical to
+	Info [UMFPACK_LNZ], if that value was returned by umfpack_*_numeric.
+
+    Int *unz ;		Output argument.
+
+	The number of nonzeros in U, including the diagonal.  This value is the
+	required size of the Ui and Ux arrays as computed by
+	umfpack_*_get_numeric.  The value of unz is identical to
+	Info [UMFPACK_UNZ], if that value was returned by umfpack_*_numeric.
+
+    Int *n_row ;	Output argument.
+    Int *n_col ;	Output argument.
+
+	The order of the L and U matrices.  L is n_row -by- min(n_row,n_col)
+	and U is min(n_row,n_col) -by- n_col.
+
+    Int *nz_udiag ;	Output argument.
+
+	The number of numerically nonzero values on the diagonal of U.  The
+	matrix is singular if nz_diag < min(n_row,n_col).  A divide-by-zero
+	will occur if nz_diag < n_row == n_col when solving a sparse system
+	involving the matrix U in umfpack_*_*solve.  The value of nz_udiag is
+	identical to Info [UMFPACK_UDIAG_NZ] if that value was returned by
+	umfpack_*_numeric.
+
+    void *Numeric ;	Input argument, not modified.
+
+	Numeric must point to a valid Numeric object, computed by
+	umfpack_*_numeric.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_get_numeric.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_get_numeric.h
new file mode 100644
index 0000000..07c8252
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_get_numeric.h
@@ -0,0 +1,254 @@
+/* ========================================================================== */
+/* === umfpack_get_numeric ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_get_numeric
+(
+    int Lp [ ],
+    int Lj [ ],
+    double Lx [ ],
+    int Up [ ],
+    int Ui [ ],
+    double Ux [ ],
+    int P [ ],
+    int Q [ ],
+    double Dx [ ],
+    int *do_recip,
+    double Rs [ ],
+    void *Numeric
+) ;
+
+UF_long umfpack_dl_get_numeric
+(
+    UF_long Lp [ ],
+    UF_long Lj [ ],
+    double Lx [ ],
+    UF_long Up [ ],
+    UF_long Ui [ ],
+    double Ux [ ],
+    UF_long P [ ],
+    UF_long Q [ ],
+    double Dx [ ],
+    UF_long *do_recip,
+    double Rs [ ],
+    void *Numeric
+) ;
+
+int umfpack_zi_get_numeric
+(
+    int Lp [ ],
+    int Lj [ ],
+    double Lx [ ], double Lz [ ],
+    int Up [ ],
+    int Ui [ ],
+    double Ux [ ], double Uz [ ],
+    int P [ ],
+    int Q [ ],
+    double Dx [ ], double Dz [ ],
+    int *do_recip,
+    double Rs [ ],
+    void *Numeric
+) ;
+
+UF_long umfpack_zl_get_numeric
+(
+    UF_long Lp [ ],
+    UF_long Lj [ ],
+    double Lx [ ], double Lz [ ],
+    UF_long Up [ ],
+    UF_long Ui [ ],
+    double Ux [ ], double Uz [ ],
+    UF_long P [ ],
+    UF_long Q [ ],
+    double Dx [ ], double Dz [ ],
+    UF_long *do_recip,
+    double Rs [ ],
+    void *Numeric
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int *Lp, *Lj, *Up, *Ui, *P, *Q, status, do_recip ;
+    double *Lx, *Ux, *Dx, *Rs ;
+    status = umfpack_di_get_numeric (Lp, Lj, Lx, Up, Ui, Ux, P, Q, Dx,
+	&do_recip, Rs, Numeric) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    UF_long *Lp, *Lj, *Up, *Ui, *P, *Q, status, do_recip ;
+    double *Lx, *Ux, *Dx, *Rs ;
+    status = umfpack_dl_get_numeric (Lp, Lj, Lx, Up, Ui, Ux, P, Q, Dx,
+	&do_recip, Rs, Numeric) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int *Lp, *Lj, *Up, *Ui, *P, *Q, status, do_recip ;
+    double *Lx, *Lz, *Ux, *Uz, *Dx, *Dz, *Rs ;
+    status = umfpack_zi_get_numeric (Lp, Lj, Lx, Lz, Up, Ui, Ux, Uz, P, Q,
+	Dx, Dz, &do_recip, Rs, Numeric) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    UF_long *Lp, *Lj, *Up, *Ui, *P, *Q, status, do_recip ;
+    double *Lx, *Lz, *Ux, *Uz, *Dx, *Dz, *Rs ;
+    status = umfpack_zl_get_numeric (Lp, Lj, Lx, Lz, Up, Ui, Ux, Uz, P, Q,
+	Dx, Dz, &do_recip, Rs, Numeric) ;
+
+packed complex int/UF_long Syntax:
+
+    Same as above, except Lz, Uz, and Dz are all NULL.
+
+Purpose:
+
+    This routine copies the LU factors and permutation vectors from the Numeric
+    object into user-accessible arrays.  This routine is not needed to solve a
+    linear system.  Note that the output arrays Lp, Lj, Lx, Up, Ui, Ux, P, Q,
+    Dx, and Rs are not allocated by umfpack_*_get_numeric; they must exist on
+    input.
+
+    All output arguments are optional.  If any of them are NULL
+    on input, then that part of the LU factorization is not copied.  You can
+    use this routine to extract just the parts of the LU factorization that
+    you want.  For example, to retrieve just the column permutation Q, use:
+
+    #define noD (double *) NULL
+    #define noI (int *) NULL
+    status = umfpack_di_get_numeric (noI, noI, noD, noI, noI, noD, noI,
+	Q, noD, noI, noD, Numeric) ;
+
+Returns:
+
+    Returns UMFPACK_OK if successful.  Returns UMFPACK_ERROR_out_of_memory
+    if insufficient memory is available for the 2*max(n_row,n_col) integer
+    workspace that umfpack_*_get_numeric allocates to construct L and/or U.
+    Returns UMFPACK_ERROR_invalid_Numeric_object if the Numeric object provided
+    as input is invalid.
+
+Arguments:
+
+    Int Lp [n_row+1] ;	Output argument.
+    Int Lj [lnz] ;	Output argument.
+    double Lx [lnz] ;	Output argument.  Size 2*lnz for packed complex case.
+    double Lz [lnz] ;	Output argument for complex versions.
+
+	The n_row-by-min(n_row,n_col) matrix L is returned in compressed-row
+	form.  The column indices of row i and corresponding numerical values
+	are in:
+
+	    Lj [Lp [i] ... Lp [i+1]-1]
+	    Lx [Lp [i] ... Lp [i+1]-1]	real part
+	    Lz [Lp [i] ... Lp [i+1]-1]	imaginary part (complex versions)
+
+	respectively.  Each row is stored in sorted order, from low column
+	indices to higher.  The last entry in each row is the diagonal, which
+	is numerically equal to one.  The sizes of Lp, Lj, Lx, and Lz are
+	returned by umfpack_*_get_lunz.    If Lp, Lj, or Lx are not present,
+	then the matrix L is not returned.  This is not an error condition.
+	The L matrix can be printed if n_row, Lp, Lj, Lx (and Lz for the split
+	complex case) are passed to umfpack_*_report_matrix (using the
+	"row" form).
+
+	If Lx is present and Lz is NULL, then both real
+	and imaginary parts are returned in Lx[0..2*lnz-1], with Lx[2*k]
+	and Lx[2*k+1] being the real and imaginary part of the kth entry.
+
+    Int Up [n_col+1] ;	Output argument.
+    Int Ui [unz] ;	Output argument.
+    double Ux [unz] ;	Output argument. Size 2*unz for packed complex case.
+    double Uz [unz] ;	Output argument for complex versions.
+
+	The min(n_row,n_col)-by-n_col matrix U is returned in compressed-column
+	form.  The row indices of column j and corresponding numerical values
+	are in
+
+	    Ui [Up [j] ... Up [j+1]-1]
+	    Ux [Up [j] ... Up [j+1]-1]	real part
+	    Uz [Up [j] ... Up [j+1]-1]	imaginary part (complex versions)
+
+	respectively.  Each column is stored in sorted order, from low row
+	indices to higher.  The last entry in each column is the diagonal
+	(assuming that it is nonzero).  The sizes of Up, Ui, Ux, and Uz are
+	returned by umfpack_*_get_lunz.  If Up, Ui, or Ux are not present,
+	then the matrix U is not returned.  This is not an error condition.
+	The U matrix can be printed if n_col, Up, Ui, Ux (and Uz for the
+	split complex case) are passed to umfpack_*_report_matrix (using the
+	"column" form).
+
+	If Ux is present and Uz is NULL, then both real
+	and imaginary parts are returned in Ux[0..2*unz-1], with Ux[2*k]
+	and Ux[2*k+1] being the real and imaginary part of the kth entry.
+
+    Int P [n_row] ;		Output argument.
+
+	The permutation vector P is defined as P [k] = i, where the original
+	row i of A is the kth pivot row in PAQ.  If you do not want the P vector
+	to be returned, simply pass (Int *) NULL for P.  This is not an error
+	condition.  You can print P and Q with umfpack_*_report_perm.
+
+    Int Q [n_col] ;		Output argument.
+
+	The permutation vector Q is defined as Q [k] = j, where the original
+	column j of A is the kth pivot column in PAQ.  If you not want the Q
+	vector to be returned, simply pass (Int *) NULL for Q.  This is not
+	an error condition.  Note that Q is not necessarily identical to
+	Qtree, the column pre-ordering held in the Symbolic object.  Refer to
+	the description of Qtree and Front_npivcol in umfpack_*_get_symbolic for
+	details.
+
+    double Dx [min(n_row,n_col)] ;	Output argument.  Size 2*n for
+					the packed complex case.
+    double Dz [min(n_row,n_col)] ;	Output argument for complex versions.
+
+	The diagonal of U is also returned in Dx and Dz.  You can extract the
+	diagonal of U without getting all of U by passing a non-NULL Dx (and
+	Dz for the complex version) and passing Up, Ui, and Ux as NULL.  Dx is
+	the real part of the diagonal, and Dz is the imaginary part.
+
+	If Dx is present and Dz is NULL, then both real
+	and imaginary parts are returned in Dx[0..2*min(n_row,n_col)-1],
+	with Dx[2*k] and Dx[2*k+1] being the real and imaginary part of the kth
+	entry.
+
+    Int *do_recip ;		Output argument.
+
+	This argument defines how the scale factors Rs are to be interpretted.
+
+	If do_recip is TRUE (one), then the scale factors Rs [i] are to be used
+	by multiplying row i by Rs [i].  Otherwise, the entries in row i are to
+	be divided by Rs [i].
+
+	If UMFPACK has been compiled with gcc, or for MATLAB as either a
+	built-in routine or as a mexFunction, then the NRECIPROCAL flag is
+	set, and do_recip will always be FALSE (zero).
+
+    double Rs [n_row] ;		Output argument.
+
+	The row scale factors are returned in Rs [0..n_row-1].  Row i of A is
+	scaled by dividing or multiplying its values by Rs [i].  If default
+	scaling is in use, Rs [i] is the sum of the absolute values of row i
+	(or its reciprocal).  If max row scaling is in use, then Rs [i] is the
+	maximum absolute value in row i (or its reciprocal).
+	Otherwise, Rs [i] = 1.  If row i is all zero, Rs [i] = 1 as well.  For
+	the complex version, an approximate absolute value is used
+	(|x_real|+|x_imag|).
+
+    void *Numeric ;	Input argument, not modified.
+
+	Numeric must point to a valid Numeric object, computed by
+	umfpack_*_numeric.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_get_symbolic.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_get_symbolic.h
new file mode 100644
index 0000000..545825e
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_get_symbolic.h
@@ -0,0 +1,339 @@
+/* ========================================================================== */
+/* === umfpack_get_symbolic ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_get_symbolic
+(
+    int *n_row,
+    int *n_col,
+    int *n1,
+    int *nz,
+    int *nfr,
+    int *nchains,
+    int P [ ],
+    int Q [ ],
+    int Front_npivcol [ ],
+    int Front_parent [ ],
+    int Front_1strow [ ],
+    int Front_leftmostdesc [ ],
+    int Chain_start [ ],
+    int Chain_maxrows [ ],
+    int Chain_maxcols [ ],
+    void *Symbolic
+) ;
+
+UF_long umfpack_dl_get_symbolic
+(
+    UF_long *n_row,
+    UF_long *n_col,
+    UF_long *n1,
+    UF_long *nz,
+    UF_long *nfr,
+    UF_long *nchains,
+    UF_long P [ ],
+    UF_long Q [ ],
+    UF_long Front_npivcol [ ],
+    UF_long Front_parent [ ],
+    UF_long Front_1strow [ ],
+    UF_long Front_leftmostdesc [ ],
+    UF_long Chain_start [ ],
+    UF_long Chain_maxrows [ ],
+    UF_long Chain_maxcols [ ],
+    void *Symbolic
+) ;
+
+int umfpack_zi_get_symbolic
+(
+    int *n_row,
+    int *n_col,
+    int *n1,
+    int *nz,
+    int *nfr,
+    int *nchains,
+    int P [ ],
+    int Q [ ],
+    int Front_npivcol [ ],
+    int Front_parent [ ],
+    int Front_1strow [ ],
+    int Front_leftmostdesc [ ],
+    int Chain_start [ ],
+    int Chain_maxrows [ ],
+    int Chain_maxcols [ ],
+    void *Symbolic
+) ;
+
+UF_long umfpack_zl_get_symbolic
+(
+    UF_long *n_row,
+    UF_long *n_col,
+    UF_long *n1,
+    UF_long *nz,
+    UF_long *nfr,
+    UF_long *nchains,
+    UF_long P [ ],
+    UF_long Q [ ],
+    UF_long Front_npivcol [ ],
+    UF_long Front_parent [ ],
+    UF_long Front_1strow [ ],
+    UF_long Front_leftmostdesc [ ],
+    UF_long Chain_start [ ],
+    UF_long Chain_maxrows [ ],
+    UF_long Chain_maxcols [ ],
+    void *Symbolic
+) ;
+
+/*
+
+double int Syntax:
+
+    #include "umfpack.h"
+    int status, n_row, n_col, nz, nfr, nchains, *P, *Q,
+	*Front_npivcol, *Front_parent, *Front_1strow, *Front_leftmostdesc,
+	*Chain_start, *Chain_maxrows, *Chain_maxcols ;
+    void *Symbolic ;
+    status = umfpack_di_get_symbolic (&n_row, &n_col, &nz, &nfr, &nchains,
+	P, Q, Front_npivcol, Front_parent, Front_1strow,
+	Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols,
+	Symbolic) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long status, n_row, n_col, nz, nfr, nchains, *P, *Q,
+	*Front_npivcol, *Front_parent, *Front_1strow, *Front_leftmostdesc,
+	*Chain_start, *Chain_maxrows, *Chain_maxcols ;
+    void *Symbolic ;
+    status = umfpack_dl_get_symbolic (&n_row, &n_col, &nz, &nfr, &nchains,
+	P, Q, Front_npivcol, Front_parent, Front_1strow,
+	Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols,
+	Symbolic) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int status, n_row, n_col, nz, nfr, nchains, *P, *Q,
+	*Front_npivcol, *Front_parent, *Front_1strow, *Front_leftmostdesc,
+	*Chain_start, *Chain_maxrows, *Chain_maxcols ;
+    void *Symbolic ;
+    status = umfpack_zi_get_symbolic (&n_row, &n_col, &nz, &nfr, &nchains,
+	P, Q, Front_npivcol, Front_parent, Front_1strow,
+	Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols,
+	Symbolic) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long status, n_row, n_col, nz, nfr, nchains, *P, *Q,
+	*Front_npivcol, *Front_parent, *Front_1strow, *Front_leftmostdesc,
+	*Chain_start, *Chain_maxrows, *Chain_maxcols ;
+    void *Symbolic ;
+    status = umfpack_zl_get_symbolic (&n_row, &n_col, &nz, &nfr, &nchains,
+	P, Q, Front_npivcol, Front_parent, Front_1strow,
+	Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols,
+	Symbolic) ;
+
+Purpose:
+
+    Copies the contents of the Symbolic object into simple integer arrays
+    accessible to the user.  This routine is not needed to factorize and/or
+    solve a sparse linear system using UMFPACK.  Note that the output arrays
+    P, Q, Front_npivcol, Front_parent, Front_1strow, Front_leftmostdesc,
+    Chain_start, Chain_maxrows, and Chain_maxcols are not allocated by
+    umfpack_*_get_symbolic; they must exist on input.
+
+    All output arguments are optional.  If any of them are NULL
+    on input, then that part of the symbolic analysis is not copied.  You can
+    use this routine to extract just the parts of the symbolic analysis that
+    you want.  For example, to retrieve just the column permutation Q, use:
+
+    #define noI (int *) NULL
+    status = umfpack_di_get_symbolic (noI, noI, noI, noI, noI, noI, noI,
+	    Q, noI, noI, noI, noI, noI, noI, noI, Symbolic) ;
+
+    The only required argument the last one, the pointer to the Symbolic object.
+
+    The Symbolic object is small.  Its size for an n-by-n square matrix varies
+    from 4*n to 13*n, depending on the matrix.  The object holds the initial
+    column permutation, the supernodal column elimination tree, and information
+    about each frontal matrix.  You can print it with umfpack_*_report_symbolic.
+
+Returns:
+
+    Returns UMFPACK_OK if successful, UMFPACK_ERROR_invalid_Symbolic_object
+    if Symbolic is an invalid object.
+
+Arguments:
+
+    Int *n_row ;	Output argument.
+    Int *n_col ;	Output argument.
+
+	The dimensions of the matrix A analyzed by the call to
+	umfpack_*_symbolic that generated the Symbolic object.
+
+    Int *n1 ;		Output argument.
+
+	The number of pivots with zero Markowitz cost (they have just one entry
+	in the pivot row, or the pivot column, or both).  These appear first in
+	the output permutations P and Q.
+
+    Int *nz ;		Output argument.
+
+	The number of nonzeros in A.
+
+    Int *nfr ;	Output argument.
+
+	The number of frontal matrices that will be used by umfpack_*_numeric
+	to factorize the matrix A.  It is in the range 0 to n_col.
+
+    Int *nchains ;	Output argument.
+
+	The frontal matrices are related to one another by the supernodal
+	column elimination tree.  Each node in this tree is one frontal matrix.
+	The tree is partitioned into a set of disjoint paths, and a frontal
+	matrix chain is one path in this tree.  Each chain is factorized using
+	a unifrontal technique, with a single working array that holds each
+	frontal matrix in the chain, one at a time.  nchains is in the range
+	0 to nfr.
+
+    Int P [n_row] ;	Output argument.
+
+	The initial row permutation.  If P [k] = i, then this means that
+	row i is the kth row in the pre-ordered matrix.  In general, this P is
+	not the same as the final row permutation computed by umfpack_*_numeric.
+
+	For the unsymmetric strategy, P defines the row-merge order.  Let j be
+	the column index of the leftmost nonzero entry in row i of A*Q.  Then
+	P defines a sort of the rows according to this value.  A row can appear
+	earlier in this ordering if it is aggressively absorbed before it can
+	become a pivot row.  If P [k] = i, row i typically will not be the kth
+	pivot row.
+
+	For the symmetric strategy, P = Q.  For the 2-by-2 strategy, P is the
+	row permutation that places large entries on the diagonal of P*A*Q.
+	If no pivoting occurs during numerical factorization, P [k] = i also
+	defines the final permutation of umfpack_*_numeric, for either the
+	symmetric or 2-by-2 strategies.
+
+    Int Q [n_col] ;	Output argument.
+
+	The initial column permutation.  If Q [k] = j, then this means that
+	column j is the kth pivot column in the pre-ordered matrix.  Q is
+	not necessarily the same as the final column permutation Q, computed by
+	umfpack_*_numeric.  The numeric factorization may reorder the pivot
+	columns within each frontal matrix to reduce fill-in.  If the matrix is
+	structurally singular, and if the symmetric or 2-by-2 strategies or
+	used (or if Control [UMFPACK_FIXQ] > 0), then this Q will be the same
+	as the final column permutation computed in umfpack_*_numeric.
+
+    Int Front_npivcol [n_col+1] ;	Output argument.
+
+	This array should be of size at least n_col+1, in order to guarantee
+	that it will be large enough to hold the output.  Only the first nfr+1
+	entries are used, however.
+
+	The kth frontal matrix holds Front_npivcol [k] pivot columns.  Thus, the
+	first frontal matrix, front 0, is used to factorize the first
+	Front_npivcol [0] columns; these correspond to the original columns
+	Q [0] through Q [Front_npivcol [0]-1].  The next frontal matrix
+	is used to factorize the next Front_npivcol [1] columns, which are thus
+	the original columns Q [Front_npivcol [0]] through
+	Q [Front_npivcol [0] + Front_npivcol [1] - 1], and so on.  Columns
+	with no entries at all are put in a placeholder "front",
+	Front_npivcol [nfr].  The sum of Front_npivcol [0..nfr] is equal to
+	n_col.
+
+	Any modifications that umfpack_*_numeric makes to the initial column
+	permutation are constrained to within each frontal matrix.  Thus, for
+	the first frontal matrix, Q [0] through Q [Front_npivcol [0]-1] is some
+	permutation of the columns Q [0] through
+	Q [Front_npivcol [0]-1].  For second frontal matrix,
+	Q [Front_npivcol [0]] through Q [Front_npivcol [0] + Front_npivcol[1]-1]
+	is some permutation of the same portion of Q, and so on.  All pivot
+	columns are numerically factorized within the frontal matrix originally
+	determined by the symbolic factorization; there is no delayed pivoting
+	across frontal matrices.
+
+    Int Front_parent [n_col+1] ;	Output argument.
+
+	This array should be of size at least n_col+1, in order to guarantee
+	that it will be large enough to hold the output.  Only the first nfr+1
+	entries are used, however.
+
+	Front_parent [0..nfr] holds the supernodal column elimination tree
+	(including the placeholder front nfr, which may be empty).  Each node in
+	the tree corresponds to a single frontal matrix.  The parent of node f
+	is Front_parent [f].
+
+    Int Front_1strow [n_col+1] ;	Output argument.
+
+	This array should be of size at least n_col+1, in order to guarantee
+	that it will be large enough to hold the output.  Only the first nfr+1
+	entries are used, however.
+
+	Front_1strow [k] is the row index of the first row in A (P,Q)
+	whose leftmost entry is in a pivot column for the kth front.  This is
+	necessary only to properly factorize singular matrices.  Rows in the
+	range Front_1strow [k] to Front_1strow [k+1]-1 first become pivot row
+	candidates at the kth front.  Any rows not eliminated in the kth front
+	may be selected as pivot rows in the parent of k (Front_parent [k])
+	and so on up the tree.
+
+    Int Front_leftmostdesc [n_col+1] ;	Output argument.
+
+	This array should be of size at least n_col+1, in order to guarantee
+	that it will be large enough to hold the output.  Only the first nfr+1
+	entries are used, however.
+
+	Front_leftmostdesc [k] is the leftmost descendant of front k, or k
+	if the front has no children in the tree.  Since the rows and columns
+	(P and Q) have been post-ordered via a depth-first-search of
+	the tree, rows in the range Front_1strow [Front_leftmostdesc [k]] to
+	Front_1strow [k+1]-1 form the entire set of candidate pivot rows for
+	the kth front (some of these will typically have already been selected
+	by fronts in the range Front_leftmostdesc [k] to front k-1, before
+	the factorization reaches front k).
+
+    Chain_start [n_col+1] ;	Output argument.
+
+	This array should be of size at least n_col+1, in order to guarantee
+	that it will be large enough to hold the output.  Only the first
+	nchains+1 entries are used, however.
+
+	The kth frontal matrix chain consists of frontal matrices Chain_start[k]
+	through Chain_start [k+1]-1.  Thus, Chain_start [0] is always 0, and
+	Chain_start [nchains] is the total number of frontal matrices, nfr.  For
+	two adjacent fronts f and f+1 within a single chain, f+1 is always the
+	parent of f (that is, Front_parent [f] = f+1).
+
+    Int Chain_maxrows [n_col+1] ;	Output argument.
+    Int Chain_maxcols [n_col+1] ;	Output argument.
+
+	These arrays should be of size at least n_col+1, in order to guarantee
+	that they will be large enough to hold the output.  Only the first
+	nchains entries are used, however.
+
+	The kth frontal matrix chain requires a single working array of
+	dimension Chain_maxrows [k] by Chain_maxcols [k], for the unifrontal
+	technique that factorizes the frontal matrix chain.  Since the symbolic
+	factorization only provides an upper bound on the size of each frontal
+	matrix, not all of the working array is necessarily used during the
+	numerical factorization.
+
+	Note that the upper bound on the number of rows and columns of each
+	frontal matrix is computed by umfpack_*_symbolic, but all that is
+	required by umfpack_*_numeric is the maximum of these two sets of
+	values for each frontal matrix chain.  Thus, the size of each
+	individual frontal matrix is not preserved in the Symbolic object.
+
+    void *Symbolic ;			Input argument, not modified.
+
+	The Symbolic object, which holds the symbolic factorization computed by
+	umfpack_*_symbolic.  The Symbolic object is not modified by
+	umfpack_*_get_symbolic.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_global.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_global.h
new file mode 100644
index 0000000..c2c946b
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_global.h
@@ -0,0 +1,22 @@
+/* ========================================================================== */
+/* === umfpack_global ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* prototypes for global variables, and basic operators for complex values  */
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+EXTERN double (*umfpack_hypot) (double, double) ;
+EXTERN int (*umfpack_divcomplex) (double, double, double, double, double *, double *) ;
+
+double umf_hypot (double x, double y) ;
+int umf_divcomplex (double, double, double, double, double *, double *) ;
+
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_load_numeric.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_load_numeric.h
new file mode 100644
index 0000000..4473821
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_load_numeric.h
@@ -0,0 +1,95 @@
+/* ========================================================================== */
+/* === umfpack_load_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_load_numeric
+(
+    void **Numeric,
+    char *filename
+) ;
+
+UF_long umfpack_dl_load_numeric
+(
+    void **Numeric,
+    char *filename
+) ;
+
+int umfpack_zi_load_numeric
+(
+    void **Numeric,
+    char *filename
+) ;
+
+UF_long umfpack_zl_load_numeric
+(
+    void **Numeric,
+    char *filename
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int status ;
+    char *filename ;
+    void *Numeric ;
+    status = umfpack_di_load_numeric (&Numeric, filename) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long status ;
+    char *filename ;
+    void *Numeric ;
+    status = umfpack_dl_load_numeric (&Numeric, filename) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int status ;
+    char *filename ;
+    void *Numeric ;
+    status = umfpack_zi_load_numeric (&Numeric, filename) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long status ;
+    char *filename ;
+    void *Numeric ;
+    status = umfpack_zl_load_numeric (&Numeric, filename) ;
+
+Purpose:
+
+    Loads a Numeric object from a file created by umfpack_*_save_numeric.  The
+    Numeric handle passed to this routine is overwritten with the new object.
+    If that object exists prior to calling this routine, a memory leak will
+    occur.  The contents of Numeric are ignored on input.
+
+Returns:
+
+    UMFPACK_OK if successful.
+    UMFPACK_ERROR_out_of_memory if not enough memory is available.
+    UMFPACK_ERROR_file_IO if an I/O error occurred.
+
+Arguments:
+
+    void **Numeric ;	    Output argument.
+
+	**Numeric is the address of a (void *) pointer variable in the user's
+	calling routine (see Syntax, above).  On input, the contents of this
+	variable are not defined.  On output, this variable holds a (void *)
+	pointer to the Numeric object (if successful), or (void *) NULL if
+	a failure occurred.
+
+    char *filename ;	    Input argument, not modified.
+
+	A string that contains the filename from which to read the Numeric
+	object.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_load_symbolic.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_load_symbolic.h
new file mode 100644
index 0000000..8952445
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_load_symbolic.h
@@ -0,0 +1,95 @@
+/* ========================================================================== */
+/* === umfpack_load_symbolic ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_load_symbolic
+(
+    void **Symbolic,
+    char *filename
+) ;
+
+UF_long umfpack_dl_load_symbolic
+(
+    void **Symbolic,
+    char *filename
+) ;
+
+int umfpack_zi_load_symbolic
+(
+    void **Symbolic,
+    char *filename
+) ;
+
+UF_long umfpack_zl_load_symbolic
+(
+    void **Symbolic,
+    char *filename
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int status ;
+    char *filename ;
+    void *Symbolic ;
+    status = umfpack_di_load_symbolic (&Symbolic, filename) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long status ;
+    char *filename ;
+    void *Symbolic ;
+    status = umfpack_dl_load_symbolic (&Symbolic, filename) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int status ;
+    char *filename ;
+    void *Symbolic ;
+    status = umfpack_zi_load_symbolic (&Symbolic, filename) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long status ;
+    char *filename ;
+    void *Symbolic ;
+    status = umfpack_zl_load_symbolic (&Symbolic, filename) ;
+
+Purpose:
+
+    Loads a Symbolic object from a file created by umfpack_*_save_symbolic. The
+    Symbolic handle passed to this routine is overwritten with the new object.
+    If that object exists prior to calling this routine, a memory leak will
+    occur.  The contents of Symbolic are ignored on input.
+
+Returns:
+
+    UMFPACK_OK if successful.
+    UMFPACK_ERROR_out_of_memory if not enough memory is available.
+    UMFPACK_ERROR_file_IO if an I/O error occurred.
+
+Arguments:
+
+    void **Symbolic ;	    Output argument.
+
+	**Symbolic is the address of a (void *) pointer variable in the user's
+	calling routine (see Syntax, above).  On input, the contents of this
+	variable are not defined.  On output, this variable holds a (void *)
+	pointer to the Symbolic object (if successful), or (void *) NULL if
+	a failure occurred.
+
+    char *filename ;	    Input argument, not modified.
+
+	A string that contains the filename from which to read the Symbolic
+	object.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_numeric.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_numeric.h
new file mode 100644
index 0000000..0f437b9
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_numeric.h
@@ -0,0 +1,543 @@
+/* ========================================================================== */
+/* === umfpack_numeric ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_numeric
+(
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ],
+    void *Symbolic,
+    void **Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+UF_long umfpack_dl_numeric
+(
+    const UF_long Ap [ ],
+    const UF_long Ai [ ],
+    const double Ax [ ],
+    void *Symbolic,
+    void **Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+int umfpack_zi_numeric
+(
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    void *Symbolic,
+    void **Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+UF_long umfpack_zl_numeric
+(
+    const UF_long Ap [ ],
+    const UF_long Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    void *Symbolic,
+    void **Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic, *Numeric ;
+    int *Ap, *Ai, status ;
+    double *Ax, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+    status = umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info);
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic, *Numeric ;
+    UF_long *Ap, *Ai, status ;
+    double *Ax, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+    status = umfpack_dl_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info);
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic, *Numeric ;
+    int *Ap, *Ai, status ;
+    double *Ax, *Az, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+    status = umfpack_zi_numeric (Ap, Ai, Ax, Az, Symbolic, &Numeric,
+	Control, Info) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic, *Numeric ;
+    UF_long *Ap, *Ai, status ;
+    double *Ax, *Az, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+    status = umfpack_zl_numeric (Ap, Ai, Ax, Az, Symbolic, &Numeric,
+	Control, Info) ;
+
+packed complex Syntax:
+
+    Same as above, except that Az is NULL.
+
+Purpose:
+
+    Given a sparse matrix A in column-oriented form, and a symbolic analysis
+    computed by umfpack_*_*symbolic, the umfpack_*_numeric routine performs the
+    numerical factorization, PAQ=LU, PRAQ=LU, or P(R\A)Q=LU, where P and Q are
+    permutation matrices (represented as permutation vectors), R is the row
+    scaling, L is unit-lower triangular, and U is upper triangular.  This is
+    required before the system Ax=b (or other related linear systems) can be
+    solved.  umfpack_*_numeric can be called multiple times for each call to
+    umfpack_*_*symbolic, to factorize a sequence of matrices with identical
+    nonzero pattern.  Simply compute the Symbolic object once, with
+    umfpack_*_*symbolic, and reuse it for subsequent matrices.  This routine
+    safely detects if the pattern changes, and sets an appropriate error code.
+
+Returns:
+
+    The status code is returned.  See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+    Int Ap [n_col+1] ;	Input argument, not modified.
+
+	This must be identical to the Ap array passed to umfpack_*_*symbolic.
+	The value of n_col is what was passed to umfpack_*_*symbolic (this is
+	held in the Symbolic object).
+
+    Int Ai [nz] ;	Input argument, not modified, of size nz = Ap [n_col].
+
+	This must be identical to the Ai array passed to umfpack_*_*symbolic.
+
+    double Ax [nz] ;	Input argument, not modified, of size nz = Ap [n_col].
+			Size 2*nz for packed complex case.
+
+	The numerical values of the sparse matrix A.  The nonzero pattern (row
+	indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and
+	the corresponding numerical values are stored in
+	Ax [(Ap [j]) ... (Ap [j+1]-1)].
+
+    double Az [nz] ;	Input argument, not modified, for complex versions.
+
+	For the complex versions, this holds the imaginary part of A.  The
+	imaginary part of column j is held in Az [(Ap [j]) ... (Ap [j+1]-1)].
+
+	If Az is NULL, then both real
+	and imaginary parts are contained in Ax[0..2*nz-1], with Ax[2*k]
+	and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+    void *Symbolic ;	Input argument, not modified.
+
+	The Symbolic object, which holds the symbolic factorization computed by
+	umfpack_*_*symbolic.  The Symbolic object is not modified by
+	umfpack_*_numeric.
+
+    void **Numeric ;	Output argument.
+
+	**Numeric is the address of a (void *) pointer variable in the user's
+	calling routine (see Syntax, above).  On input, the contents of this
+	variable are not defined.  On output, this variable holds a (void *)
+	pointer to the Numeric object (if successful), or (void *) NULL if
+	a failure occurred.
+
+    double Control [UMFPACK_CONTROL] ;   Input argument, not modified.
+
+	If a (double *) NULL pointer is passed, then the default control
+	settings are used.  Otherwise, the settings are determined from the
+	Control array.  See umfpack_*_defaults on how to fill the Control
+	array with the default settings.  If Control contains NaN's, the
+	defaults are used.  The following Control parameters are used:
+
+	Control [UMFPACK_PIVOT_TOLERANCE]:  relative pivot tolerance for
+	    threshold partial pivoting with row interchanges.  In any given
+	    column, an entry is numerically acceptable if its absolute value is
+	    greater than or equal to Control [UMFPACK_PIVOT_TOLERANCE] times
+	    the largest absolute value in the column.  A value of 1.0 gives true
+	    partial pivoting.  If less than or equal to zero, then any nonzero
+	    entry is numerically acceptable as a pivot.  Default: 0.1.
+
+	    Smaller values tend to lead to sparser LU factors, but the solution
+	    to the linear system can become inaccurate.  Larger values can lead
+	    to a more accurate solution (but not always), and usually an
+	    increase in the total work.
+
+	    For complex matrices, a cheap approximate of the absolute value
+	    is used for the threshold partial pivoting test (|a_real| + |a_imag|
+	    instead of the more expensive-to-compute exact absolute value
+	    sqrt (a_real^2 + a_imag^2)).
+
+	Control [UMFPACK_SYM_PIVOT_TOLERANCE]:
+	    If diagonal pivoting is attempted (the symmetric or symmetric-2by2
+	    strategies are used) then this parameter is used to control when the
+	    diagonal entry is selected in a given pivot column.  The absolute
+	    value of the entry must be >= Control [UMFPACK_SYM_PIVOT_TOLERANCE]
+	    times the largest absolute value in the column.  A value of zero
+	    will ensure that no off-diagonal pivoting is performed, except that
+	    zero diagonal entries are not selected if there are any off-diagonal
+	    nonzero entries.
+
+	    If an off-diagonal pivot is selected, an attempt is made to restore
+	    symmetry later on.  Suppose A (i,j) is selected, where i != j.
+	    If column i has not yet been selected as a pivot column, then
+	    the entry A (j,i) is redefined as a "diagonal" entry, except that
+	    the tighter tolerance (Control [UMFPACK_PIVOT_TOLERANCE]) is
+	    applied.  This strategy has an effect similar to 2-by-2 pivoting
+	    for symmetric indefinite matrices.  If a 2-by-2 block pivot with
+	    nonzero structure
+
+		       i j
+		    i: 0 x
+		    j: x 0
+
+	    is selected in a symmetric indefinite factorization method, the
+	    2-by-2 block is inverted and a rank-2 update is applied.  In
+	    UMFPACK, this 2-by-2 block would be reordered as
+
+		       j i
+		    i: x 0
+		    j: 0 x
+
+	    In both cases, the symmetry of the Schur complement is preserved.
+
+	Control [UMFPACK_SCALE]:  Note that the user's input matrix is
+	    never modified, only an internal copy is scaled.
+
+	    There are three valid settings for this parameter.  If any other
+	    value is provided, the default is used.
+
+	    UMFPACK_SCALE_NONE:  no scaling is performed.
+
+	    UMFPACK_SCALE_SUM:  each row of the input matrix A is divided by
+		the sum of the absolute values of the entries in that row.
+		The scaled matrix has an infinity norm of 1.
+
+	    UMFPACK_SCALE_MAX:  each row of the input matrix A is divided by
+		the maximum the absolute values of the entries in that row.
+		In the scaled matrix the largest entry in each row has
+		a magnitude exactly equal to 1.
+
+	    Note that for complex matrices, a cheap approximate absolute value
+	    is used, |a_real| + |a_imag|, instead of the exact absolute value
+	    sqrt ((a_real)^2 + (a_imag)^2).
+
+	    Scaling is very important for the "symmetric" strategy when
+	    diagonal pivoting is attempted.  It also improves the performance
+	    of the "unsymmetric" strategy.
+
+	    Default: UMFPACK_SCALE_SUM.
+
+	Control [UMFPACK_ALLOC_INIT]:
+
+	    When umfpack_*_numeric starts, it allocates memory for the Numeric
+	    object.  Part of this is of fixed size (approximately n double's +
+	    12*n integers).  The remainder is of variable size, which grows to
+	    hold the LU factors and the frontal matrices created during
+	    factorization.  A estimate of the upper bound is computed by
+	    umfpack_*_*symbolic, and returned by umfpack_*_*symbolic in
+	    Info [UMFPACK_VARIABLE_PEAK_ESTIMATE] (in Units).
+
+	    If Control [UMFPACK_ALLOC_INIT] is >= 0, umfpack_*_numeric initially
+	    allocates space for the variable-sized part equal to this estimate
+	    times Control [UMFPACK_ALLOC_INIT].  Typically, for matrices for
+	    which the "unsymmetric" strategy applies, umfpack_*_numeric needs
+	    only about half the estimated memory space, so a setting of 0.5 or
+	    0.6 often provides enough memory for umfpack_*_numeric to factorize
+	    the matrix with no subsequent increases in the size of this block.
+
+	    If the matrix is ordered via AMD, then this non-negative parameter
+	    is ignored.  The initial allocation ratio computed automatically,
+	    as 1.2 * (nz + Info [UMFPACK_SYMMETRIC_LUNZ]) /
+	    (Info [UMFPACK_LNZ_ESTIMATE] + Info [UMFPACK_UNZ_ESTIMATE] -
+	    min (n_row, n_col)).
+
+	    If Control [UMFPACK_ALLOC_INIT] is negative, then umfpack_*_numeric
+	    allocates a space with initial size (in Units) equal to
+	    (-Control [UMFPACK_ALLOC_INIT]).
+
+	    Regardless of the value of this parameter, a space equal to or
+	    greater than the the bare minimum amount of memory needed to start
+	    the factorization is always initially allocated.  The bare initial
+	    memory required is returned by umfpack_*_*symbolic in
+	    Info [UMFPACK_VARIABLE_INIT_ESTIMATE] (an exact value, not an
+	    estimate).
+
+	    If the variable-size part of the Numeric object is found to be too
+	    small sometime after numerical factorization has started, the memory
+	    is increased in size by a factor of 1.2.   If this fails, the
+	    request is reduced by a factor of 0.95 until it succeeds, or until
+	    it determines that no increase in size is possible.  Garbage
+	    collection then occurs.
+
+	    The strategy of attempting to "malloc" a working space, and
+	    re-trying with a smaller space, may not work when UMFPACK is used
+	    as a mexFunction MATLAB, since mxMalloc aborts the mexFunction if it
+	    fails.  This issue does not affect the use of UMFPACK as a part of
+	    the built-in x=A\b in MATLAB 6.5 and later.
+
+	    If you are using the umfpack mexFunction, decrease the magnitude of
+	    Control [UMFPACK_ALLOC_INIT] if you run out of memory in MATLAB.
+
+	    Default initial allocation size: 0.7.  Thus, with the default
+	    control settings and the "unsymmetric" strategy, the upper-bound is
+	    reached after two reallocations (0.7 * 1.2 * 1.2 = 1.008).
+
+	    Changing this parameter has little effect on fill-in or operation
+	    count.  It has a small impact on run-time (the extra time required
+	    to do the garbage collection and memory reallocation).
+
+	Control [UMFPACK_FRONT_ALLOC_INIT]:
+
+	    When UMFPACK starts the factorization of each "chain" of frontal
+	    matrices, it allocates a working array to hold the frontal matrices
+	    as they are factorized.  The symbolic factorization computes the
+	    size of the largest possible frontal matrix that could occur during
+	    the factorization of each chain.
+
+	    If Control [UMFPACK_FRONT_ALLOC_INIT] is >= 0, the following
+	    strategy is used.  If the AMD ordering was used, this non-negative
+	    parameter is ignored.  A front of size (d+2)*(d+2) is allocated,
+	    where d = Info [UMFPACK_SYMMETRIC_DMAX].  Otherwise, a front of
+	    size Control [UMFPACK_FRONT_ALLOC_INIT] times the largest front
+	    possible for this chain is allocated.
+
+	    If Control [UMFPACK_FRONT_ALLOC_INIT] is negative, then a front of
+	    size (-Control [UMFPACK_FRONT_ALLOC_INIT]) is allocated (where the
+	    size is in terms of the number of numerical entries).  This is done
+	    regardless of the ordering method or ordering strategy used.
+
+	    Default: 0.5.
+
+	Control [UMFPACK_DROPTOL]:
+
+	    Entries in L and U with absolute value less than or equal to the
+	    drop tolerance are removed from the data structures (unless leaving
+	    them there reduces memory usage by reducing the space required
+	    for the nonzero pattern of L and U).
+
+	    Default: 0.0.
+
+    double Info [UMFPACK_INFO] ;	Output argument.
+
+	Contains statistics about the numeric factorization.  If a
+	(double *) NULL pointer is passed, then no statistics are returned in
+	Info (this is not an error condition).  The following statistics are
+	computed in umfpack_*_numeric:
+
+	Info [UMFPACK_STATUS]: status code.  This is also the return value,
+	    whether or not Info is present.
+
+	    UMFPACK_OK
+
+		Numeric factorization was successful.  umfpack_*_numeric
+		computed a valid numeric factorization.
+
+	    UMFPACK_WARNING_singular_matrix
+
+		Numeric factorization was successful, but the matrix is
+		singular.  umfpack_*_numeric computed a valid numeric
+		factorization, but you will get a divide by zero in
+		umfpack_*_*solve.  For the other cases below, no Numeric object
+		is created (*Numeric is (void *) NULL).
+
+	    UMFPACK_ERROR_out_of_memory
+
+		Insufficient memory to complete the numeric factorization.
+
+	    UMFPACK_ERROR_argument_missing
+
+		One or more required arguments are missing.
+
+	    UMFPACK_ERROR_invalid_Symbolic_object
+
+		Symbolic object provided as input is invalid.
+
+	    UMFPACK_ERROR_different_pattern
+
+		The pattern (Ap and/or Ai) has changed since the call to
+		umfpack_*_*symbolic which produced the Symbolic object.
+
+	Info [UMFPACK_NROW]:  the value of n_row stored in the Symbolic object.
+
+	Info [UMFPACK_NCOL]:  the value of n_col stored in the Symbolic object.
+
+	Info [UMFPACK_NZ]:  the number of entries in the input matrix.
+	    This value is obtained from the Symbolic object.
+
+	Info [UMFPACK_SIZE_OF_UNIT]:  the number of bytes in a Unit, for memory
+	    usage statistics below.
+
+	Info [UMFPACK_VARIABLE_INIT]: the initial size (in Units) of the
+	    variable-sized part of the Numeric object.  If this differs from
+	    Info [UMFPACK_VARIABLE_INIT_ESTIMATE], then the pattern (Ap and/or
+	    Ai) has changed since the last call to umfpack_*_*symbolic, which is
+	    an error condition.
+
+	Info [UMFPACK_VARIABLE_PEAK]: the peak size (in Units) of the
+	    variable-sized part of the Numeric object.  This size is the amount
+	    of space actually used inside the block of memory, not the space
+	    allocated via UMF_malloc.  You can reduce UMFPACK's memory
+	    requirements by setting Control [UMFPACK_ALLOC_INIT] to the ratio
+	    Info [UMFPACK_VARIABLE_PEAK] / Info[UMFPACK_VARIABLE_PEAK_ESTIMATE].
+	    This will ensure that no memory reallocations occur (you may want to
+	    add 0.001 to make sure that integer roundoff does not lead to a
+	    memory size that is 1 Unit too small; otherwise, garbage collection
+	    and reallocation will occur).
+
+	Info [UMFPACK_VARIABLE_FINAL]: the final size (in Units) of the
+	    variable-sized part of the Numeric object.  It holds just the
+	    sparse LU factors.
+
+	Info [UMFPACK_NUMERIC_SIZE]:  the actual final size (in Units) of the
+	    entire Numeric object, including the final size of the variable
+	    part of the object.  Info [UMFPACK_NUMERIC_SIZE_ESTIMATE],
+	    an estimate, was computed by umfpack_*_*symbolic.  The estimate is
+	    normally an upper bound on the actual final size, but this is not
+	    guaranteed.
+
+	Info [UMFPACK_PEAK_MEMORY]:  the actual peak memory usage (in Units) of
+	    both umfpack_*_*symbolic and umfpack_*_numeric.  An estimate,
+	    Info [UMFPACK_PEAK_MEMORY_ESTIMATE], was computed by
+	    umfpack_*_*symbolic.  The estimate is normally an upper bound on the
+	    actual peak usage, but this is not guaranteed.  With testing on
+	    hundreds of matrix arising in real applications, I have never
+	    observed a matrix where this estimate or the Numeric size estimate
+	    was less than the actual result, but this is theoretically possible.
+	    Please send me one if you find such a matrix.
+
+	Info [UMFPACK_FLOPS]:  the actual count of the (useful) floating-point
+	    operations performed.  An estimate, Info [UMFPACK_FLOPS_ESTIMATE],
+	    was computed by umfpack_*_*symbolic.  The estimate is guaranteed to
+	    be an upper bound on this flop count.  The flop count excludes
+	    "useless" flops on zero values, flops performed during the pivot
+	    search (for tentative updates and assembly of candidate columns),
+	    and flops performed to add frontal matrices together.
+
+	    For the real version, only (+ - * /) are counted.  For the complex
+	    version, the following counts are used:
+
+		operation	flops
+	    	c = 1/b		6
+		c = a*b		6
+		c -= a*b	8
+
+	Info [UMFPACK_LNZ]: the actual nonzero entries in final factor L,
+	    including the diagonal.  This excludes any zero entries in L,
+	    although some of these are stored in the Numeric object.  The
+	    Info [UMFPACK_LU_ENTRIES] statistic does account for all
+	    explicitly stored zeros, however.  Info [UMFPACK_LNZ_ESTIMATE],
+	    an estimate, was computed by umfpack_*_*symbolic.  The estimate is
+	    guaranteed to be an upper bound on Info [UMFPACK_LNZ].
+
+	Info [UMFPACK_UNZ]: the actual nonzero entries in final factor U,
+	    including the diagonal.  This excludes any zero entries in U,
+	    although some of these are stored in the Numeric object.  The
+	    Info [UMFPACK_LU_ENTRIES] statistic does account for all
+	    explicitly stored zeros, however.  Info [UMFPACK_UNZ_ESTIMATE],
+	    an estimate, was computed by umfpack_*_*symbolic.  The estimate is
+	    guaranteed to be an upper bound on Info [UMFPACK_UNZ].
+
+	Info [UMFPACK_NUMERIC_DEFRAG]:  The number of garbage collections
+	    performed during umfpack_*_numeric, to compact the contents of the
+	    variable-sized workspace used by umfpack_*_numeric.  No estimate was
+	    computed by umfpack_*_*symbolic.  In the current version of UMFPACK,
+	    garbage collection is performed and then the memory is reallocated,
+	    so this statistic is the same as Info [UMFPACK_NUMERIC_REALLOC],
+	    below.  It may differ in future releases.
+
+	Info [UMFPACK_NUMERIC_REALLOC]:  The number of times that the Numeric
+	    object was increased in size from its initial size.  A rough upper
+	    bound on the peak size of the Numeric object was computed by
+	    umfpack_*_*symbolic, so reallocations should be rare.  However, if
+	    umfpack_*_numeric is unable to allocate that much storage, it
+	    reduces its request until either the allocation succeeds, or until
+	    it gets too small to do anything with.  If the memory that it
+	    finally got was small, but usable, then the reallocation count
+	    could be high.  No estimate of this count was computed by
+	    umfpack_*_*symbolic.
+
+	Info [UMFPACK_NUMERIC_COSTLY_REALLOC]:  The number of times that the
+	    system realloc library routine (or mxRealloc for the mexFunction)
+	    had to move the workspace.  Realloc can sometimes increase the size
+	    of a block of memory without moving it, which is much faster.  This
+	    statistic will always be <= Info [UMFPACK_NUMERIC_REALLOC].  If your
+	    memory space is fragmented, then the number of "costly" realloc's
+	    will be equal to Info [UMFPACK_NUMERIC_REALLOC].
+
+	Info [UMFPACK_COMPRESSED_PATTERN]:  The number of integers used to
+	    represent the pattern of L and U.
+
+	Info [UMFPACK_LU_ENTRIES]:  The total number of numerical values that
+	    are stored for the LU factors.  Some of the values may be explicitly
+	    zero in order to save space (allowing for a smaller compressed
+	    pattern).
+
+	Info [UMFPACK_NUMERIC_TIME]:  The CPU time taken, in seconds.
+
+	Info [UMFPACK_RCOND]:  A rough estimate of the condition number, equal
+	    to min (abs (diag (U))) / max (abs (diag (U))), or zero if the
+	    diagonal of U is all zero.
+
+	Info [UMFPACK_UDIAG_NZ]:  The number of numerically nonzero values on
+	    the diagonal of U.
+
+	Info [UMFPACK_UMIN]:  the smallest absolute value on the diagonal of U.
+
+	Info [UMFPACK_UMAX]:  the smallest absolute value on the diagonal of U.
+
+	Info [UMFPACK_MAX_FRONT_SIZE]: the size of the
+	    largest frontal matrix (number of entries).
+
+	Info [UMFPACK_NUMERIC_WALLTIME]:  The wallclock time taken, in seconds.
+
+	Info [UMFPACK_MAX_FRONT_NROWS]: the max number of
+	    rows in any frontal matrix.
+
+	Info [UMFPACK_MAX_FRONT_NCOLS]: the max number of
+	    columns in any frontal matrix.
+
+	Info [UMFPACK_WAS_SCALED]:  the scaling used, either UMFPACK_SCALE_NONE,
+	    UMFPACK_SCALE_SUM, or UMFPACK_SCALE_MAX.
+
+	Info [UMFPACK_RSMIN]: if scaling is performed, the smallest scale factor
+	    for any row (either the smallest sum of absolute entries, or the
+	    smallest maximum of absolute entries).
+
+	Info [UMFPACK_RSMAX]: if scaling is performed, the largest scale factor
+	    for any row (either the largest sum of absolute entries, or the
+	    largest maximum of absolute entries).
+
+	Info [UMFPACK_ALLOC_INIT_USED]:  the initial allocation parameter used.
+
+	Info [UMFPACK_FORCED_UPDATES]:  the number of BLAS-3 updates to the
+	    frontal matrices that were required because the frontal matrix
+	    grew larger than its current working array.
+
+	Info [UMFPACK_NOFF_DIAG]: number of off-diagonal pivots selected, if the
+	    symmetric or 2-by-2 strategies are used.
+
+	Info [UMFPACK_NZDROPPED]: the number of entries smaller in absolute
+	    value than Control [UMFPACK_DROPTOL] that were dropped from L and U.
+	    Note that entries on the diagonal of U are never dropped.
+
+	Info [UMFPACK_ALL_LNZ]: the number of entries in L, including the
+	    diagonal, if no small entries are dropped.
+
+	Info [UMFPACK_ALL_UNZ]: the number of entries in U, including the
+	    diagonal, if no small entries are dropped.
+
+	Only the above listed Info [...] entries are accessed.  The remaining
+	entries of Info are not accessed or modified by umfpack_*_numeric.
+	Future versions might modify different parts of Info.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_qsymbolic.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_qsymbolic.h
new file mode 100644
index 0000000..28362f2
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_qsymbolic.h
@@ -0,0 +1,150 @@
+/* ========================================================================== */
+/* === umfpack_qsymbolic ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_qsymbolic
+(
+    int n_row,
+    int n_col,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ],
+    const int Qinit [ ],
+    void **Symbolic,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+UF_long umfpack_dl_qsymbolic
+(
+    UF_long n_row,
+    UF_long n_col,
+    const UF_long Ap [ ],
+    const UF_long Ai [ ],
+    const double Ax [ ],
+    const UF_long Qinit [ ],
+    void **Symbolic,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+int umfpack_zi_qsymbolic
+(
+    int n_row,
+    int n_col,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    const int Qinit [ ],
+    void **Symbolic,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+UF_long umfpack_zl_qsymbolic
+(
+    UF_long n_row,
+    UF_long n_col,
+    const UF_long Ap [ ],
+    const UF_long Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    const UF_long Qinit [ ],
+    void **Symbolic,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    int n_row, n_col, *Ap, *Ai, *Qinit, status ;
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax ;
+    status = umfpack_di_qsymbolic (n_row, n_col, Ap, Ai, Ax, Qinit,
+	&Symbolic, Control, Info) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    UF_long n_row, n_col, *Ap, *Ai, *Qinit, status ;
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax ;
+    status = umfpack_dl_qsymbolic (n_row, n_col, Ap, Ai, Ax, Qinit,
+	&Symbolic, Control, Info) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    int n_row, n_col, *Ap, *Ai, *Qinit, status ;
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax, *Az ;
+    status = umfpack_zi_qsymbolic (n_row, n_col, Ap, Ai, Ax, Az, Qinit,
+	&Symbolic, Control, Info) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    UF_long n_row, n_col, *Ap, *Ai, *Qinit, status ;
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax, *Az ;
+    status = umfpack_zl_qsymbolic (n_row, n_col, Ap, Ai, Ax, Az, Qinit,
+	&Symbolic, Control, Info) ;
+
+packed complex Syntax:
+
+    Same as above, except Az is NULL.
+
+Purpose:
+
+    Given the nonzero pattern of a sparse matrix A in column-oriented form, and
+    a sparsity preserving column pre-ordering Qinit, umfpack_*_qsymbolic
+    performs the symbolic factorization of A*Qinit (or A (:,Qinit) in MATLAB
+    notation).  This is identical to umfpack_*_symbolic, except that neither
+    COLAMD nor AMD are called and the user input column order Qinit is used
+    instead.  Note that in general, the Qinit passed to umfpack_*_qsymbolic
+    can differ from the final Q found in umfpack_*_numeric.  The unsymmetric
+    strategy will perform a column etree postordering done in
+    umfpack_*_qsymbolic and sparsity-preserving modifications are made within
+    each frontal matrix during umfpack_*_numeric.  The symmetric and 2-by-2
+    strategies will preserve Qinit, unless the matrix is structurally singular.
+
+    See umfpack_*_symbolic for more information.
+
+    *** WARNING ***  A poor choice of Qinit can easily cause umfpack_*_numeric
+    to use a huge amount of memory and do a lot of work.  The "default" symbolic
+    analysis method is umfpack_*_symbolic, not this routine.  If you use this
+    routine, the performance of UMFPACK is your responsibility;  UMFPACK will
+    not try to second-guess a poor choice of Qinit.
+
+Returns:
+
+    The value of Info [UMFPACK_STATUS]; see umfpack_*_symbolic.
+    Also returns UMFPACK_ERROR_invalid_permuation if Qinit is not a valid
+    permutation vector.
+
+Arguments:
+
+    All arguments are the same as umfpack_*_symbolic, except for the following:
+
+    Int Qinit [n_col] ;		Input argument, not modified.
+
+	The user's fill-reducing initial column pre-ordering.  This must be a
+	permutation of 0..n_col-1.  If Qinit [k] = j, then column j is the kth
+	column of the matrix A (:,Qinit) to be factorized.  If Qinit is an
+	(Int *) NULL pointer, then COLAMD or AMD are called instead.
+
+    double Control [UMFPACK_CONTROL] ;	Input argument, not modified.
+
+	If Qinit is not NULL, then only two strategies are recognized:
+	the unsymmetric strategy and the symmetric strategy.
+	If Control [UMFPACK_STRATEGY] is UMFPACK_STRATEGY_SYMMETRIC,
+	then the symmetric strategy is used.  Otherwise the unsymmetric
+	strategy is used.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_control.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_control.h
new file mode 100644
index 0000000..2084409
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_control.h
@@ -0,0 +1,76 @@
+/* ========================================================================== */
+/* === umfpack_report_control =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_report_control
+(
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_dl_report_control
+(
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_zi_report_control
+(
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_zl_report_control
+(
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    umfpack_di_report_control (Control) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    umfpack_dl_report_control (Control) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    umfpack_zi_report_control (Control) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    umfpack_zl_report_control (Control) ;
+
+Purpose:
+
+    Prints the current control settings.  Note that with the default print
+    level, nothing is printed.  Does nothing if Control is (double *) NULL.
+
+Arguments:
+
+    double Control [UMFPACK_CONTROL] ;   Input argument, not modified.
+
+	If a (double *) NULL pointer is passed, then the default control
+	settings are used.  Otherwise, the settings are determined from the
+	Control array.  See umfpack_*_defaults on how to fill the Control
+	array with the default settings.  If Control contains NaN's, the
+	defaults are used.  The following Control parameters are used:
+
+	Control [UMFPACK_PRL]:  printing level.
+
+	    1 or less: no output
+	    2 or more: print all of Control
+	    Default: 1
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_info.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_info.h
new file mode 100644
index 0000000..e78ae44
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_info.h
@@ -0,0 +1,86 @@
+/* ========================================================================== */
+/* === umfpack_report_info ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_report_info
+(
+    const double Control [UMFPACK_CONTROL],
+    const double Info [UMFPACK_INFO]
+) ;
+
+void umfpack_dl_report_info
+(
+    const double Control [UMFPACK_CONTROL],
+    const double Info [UMFPACK_INFO]
+) ;
+
+void umfpack_zi_report_info
+(
+    const double Control [UMFPACK_CONTROL],
+    const double Info [UMFPACK_INFO]
+) ;
+
+void umfpack_zl_report_info
+(
+    const double Control [UMFPACK_CONTROL],
+    const double Info [UMFPACK_INFO]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+    umfpack_di_report_info (Control, Info) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+    umfpack_dl_report_info (Control, Info) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+    umfpack_zi_report_info (Control, Info) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+    umfpack_zl_report_info (Control, Info) ;
+
+Purpose:
+
+    Reports statistics from the umfpack_*_*symbolic, umfpack_*_numeric, and
+    umfpack_*_*solve routines.
+
+Arguments:
+
+    double Control [UMFPACK_CONTROL] ;   Input argument, not modified.
+
+	If a (double *) NULL pointer is passed, then the default control
+	settings are used.  Otherwise, the settings are determined from the
+	Control array.  See umfpack_*_defaults on how to fill the Control
+	array with the default settings.  If Control contains NaN's, the
+	defaults are used.  The following Control parameters are used:
+
+	Control [UMFPACK_PRL]:  printing level.
+
+	    0 or less: no output, even when an error occurs
+	    1: error messages only
+	    2 or more: error messages, and print all of Info
+	    Default: 1
+
+    double Info [UMFPACK_INFO] ;		Input argument, not modified.
+
+	Info is an output argument of several UMFPACK routines.
+	The contents of Info are printed on standard output.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_matrix.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_matrix.h
new file mode 100644
index 0000000..7148896
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_matrix.h
@@ -0,0 +1,203 @@
+/* ========================================================================== */
+/* === umfpack_report_matrix ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_matrix
+(
+    int n_row,
+    int n_col,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ],
+    int col_form,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+UF_long umfpack_dl_report_matrix
+(
+    UF_long n_row,
+    UF_long n_col,
+    const UF_long Ap [ ],
+    const UF_long Ai [ ],
+    const double Ax [ ],
+    UF_long col_form,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_matrix
+(
+    int n_row,
+    int n_col,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    int col_form,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+UF_long umfpack_zl_report_matrix
+(
+    UF_long n_row,
+    UF_long n_col,
+    const UF_long Ap [ ],
+    const UF_long Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    UF_long col_form,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int n_row, n_col, *Ap, *Ai, status ;
+    double *Ax, Control [UMFPACK_CONTROL] ;
+    status = umfpack_di_report_matrix (n_row, n_col, Ap, Ai, Ax, 1, Control) ;
+or:
+    status = umfpack_di_report_matrix (n_row, n_col, Ap, Ai, Ax, 0, Control) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long n_row, n_col, *Ap, *Ai, status ;
+    double *Ax, Control [UMFPACK_CONTROL] ;
+    status = umfpack_dl_report_matrix (n_row, n_col, Ap, Ai, Ax, 1, Control) ;
+or:
+    status = umfpack_dl_report_matrix (n_row, n_col, Ap, Ai, Ax, 0, Control) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int n_row, n_col, *Ap, *Ai, status ;
+    double *Ax, *Az, Control [UMFPACK_CONTROL] ;
+    status = umfpack_zi_report_matrix (n_row, n_col, Ap, Ai, Ax, Az, 1,
+        Control) ;
+or:
+    status = umfpack_zi_report_matrix (n_row, n_col, Ap, Ai, Ax, Az, 0,
+        Control) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long n_row, n_col, *Ap, *Ai, status ;
+    double *Ax, Control [UMFPACK_CONTROL] ;
+    status = umfpack_zl_report_matrix (n_row, n_col, Ap, Ai, Ax, Az, 1,
+	Control) ;
+or:
+    status = umfpack_zl_report_matrix (n_row, n_col, Ap, Ai, Ax, Az, 0,
+	Control) ;
+
+packed complex Syntax:
+
+    Same as above, except Az is NULL.
+
+Purpose:
+
+    Verifies and prints a row or column-oriented sparse matrix.
+
+Returns:
+
+    UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked).
+
+    Otherwise (where n is n_col for the column form and n_row for row
+    and let ni be n_row for the column form and n_col for row):
+
+    UMFPACK_OK if the matrix is valid.
+
+    UMFPACK_ERROR_n_nonpositive if n_row <= 0 or n_col <= 0.
+    UMFPACK_ERROR_argument_missing if Ap and/or Ai are missing.
+    UMFPACK_ERROR_invalid_matrix if Ap [n] < 0, if Ap [0] is not zero,
+	if Ap [j+1] < Ap [j] for any j in the range 0 to n-1,
+	if any row index in Ai is not in the range 0 to ni-1, or
+	if the row indices in any column are not in
+	ascending order, or contain duplicates.
+    UMFPACK_ERROR_out_of_memory if out of memory.
+
+Arguments:
+
+    Int n_row ;		Input argument, not modified.
+    Int n_col ;		Input argument, not modified.
+
+	A is an n_row-by-n_row matrix.  Restriction: n_row > 0 and n_col > 0.
+
+    Int Ap [n+1] ;	Input argument, not modified.
+
+	n is n_row for a row-form matrix, and n_col for a column-form matrix.
+
+	Ap is an integer array of size n+1.  If col_form is true (nonzero),
+	then on input, it holds the "pointers" for the column form of the
+	sparse matrix A.  The row indices of column j of the matrix A are held
+	in Ai [(Ap [j]) ... (Ap [j+1]-1)].  Otherwise, Ap holds the
+	row pointers, and the column indices of row j of the matrix are held
+	in Ai [(Ap [j]) ... (Ap [j+1]-1)].
+
+	The first entry, Ap [0], must be zero, and Ap [j] <= Ap [j+1] must hold
+	for all j in the range 0 to n-1.  The value nz = Ap [n] is thus the
+	total number of entries in the pattern of the matrix A.
+
+    Int Ai [nz] ;	Input argument, not modified, of size nz = Ap [n].
+
+	If col_form is true (nonzero), then the nonzero pattern (row indices)
+	for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)].  Row indices
+	must be in the range 0 to n_row-1 (the matrix is 0-based).
+
+	Otherwise, the nonzero pattern (column indices) for row j is stored in
+	Ai [(Ap [j]) ... (Ap [j+1]-1)]. Column indices must be in the range 0
+	to n_col-1 (the matrix is 0-based).
+
+    double Ax [nz] ;	Input argument, not modified, of size nz = Ap [n].
+			Size 2*nz for packed complex case.
+
+	The numerical values of the sparse matrix A.
+
+	If col_form is true (nonzero), then the nonzero pattern (row indices)
+	for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and the
+	corresponding (real) numerical values are stored in
+	Ax [(Ap [j]) ... (Ap [j+1]-1)].  The imaginary parts are stored in
+	Az [(Ap [j]) ... (Ap [j+1]-1)], for the complex versions
+	(see below if Az is NULL).
+
+	Otherwise, the nonzero pattern (column indices) for row j
+	is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and the corresponding
+	(real) numerical values are stored in Ax [(Ap [j]) ... (Ap [j+1]-1)].
+	The imaginary parts are stored in Az [(Ap [j]) ... (Ap [j+1]-1)],
+	for the complex versions (see below if Az is NULL).
+
+	No numerical values are printed if Ax is NULL.
+
+    double Az [nz] ;	Input argument, not modified, for complex versions.
+
+	The imaginary values of the sparse matrix A.   See the description
+	of Ax, above.
+
+	If Az is NULL, then both real
+	and imaginary parts are contained in Ax[0..2*nz-1], with Ax[2*k]
+	and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+    Int col_form ;	Input argument, not modified.
+
+	The matrix is in row-oriented form if form is col_form is false (0).
+	Otherwise, the matrix is in column-oriented form.
+
+    double Control [UMFPACK_CONTROL] ;	Input argument, not modified.
+
+	If a (double *) NULL pointer is passed, then the default control
+	settings are used.  Otherwise, the settings are determined from the
+	Control array.  See umfpack_*_defaults on how to fill the Control
+	array with the default settings.  If Control contains NaN's, the
+	defaults are used.  The following Control parameters are used:
+
+	Control [UMFPACK_PRL]:  printing level.
+
+	    2 or less: no output.  returns silently without checking anything.
+	    3: fully check input, and print a short summary of its status
+	    4: as 3, but print first few entries of the input
+	    5: as 3, but print all of the input
+	    Default: 1
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_numeric.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_numeric.h
new file mode 100644
index 0000000..635f8cd
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_numeric.h
@@ -0,0 +1,112 @@
+/* ========================================================================== */
+/* === umfpack_report_numeric =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_numeric
+(
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+UF_long umfpack_dl_report_numeric
+(
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_numeric
+(
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+UF_long umfpack_zl_report_numeric
+(
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    double Control [UMFPACK_CONTROL] ;
+    int status ;
+    status = umfpack_di_report_numeric (Numeric, Control) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    double Control [UMFPACK_CONTROL] ;
+    UF_long status ;
+    status = umfpack_dl_report_numeric (Numeric, Control) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    double Control [UMFPACK_CONTROL] ;
+    int status ;
+    status = umfpack_zi_report_numeric (Numeric, Control) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    double Control [UMFPACK_CONTROL] ;
+    UF_long status ;
+    status = umfpack_zl_report_numeric (Numeric, Control) ;
+
+Purpose:
+
+    Verifies and prints a Numeric object (the LU factorization, both its pattern
+    numerical values, and permutation vectors P and Q).  This routine checks the
+    object more carefully than the computational routines.  Normally, this check
+    is not required, since umfpack_*_numeric either returns (void *) NULL, or a
+    valid Numeric object.  However, if you suspect that your own code has
+    corrupted the Numeric object (by overruning memory bounds, for example),
+    then this routine might be able to detect a corrupted Numeric object.  Since
+    this is a complex object, not all such user-generated errors are guaranteed
+    to be caught by this routine.
+
+Returns:
+
+    UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked).
+
+    Otherwise:
+
+    UMFPACK_OK if the Numeric object is valid.
+    UMFPACK_ERROR_invalid_Numeric_object if the Numeric object is invalid.
+    UMFPACK_ERROR_out_of_memory if out of memory.
+
+Arguments:
+
+    void *Numeric ;			Input argument, not modified.
+
+	The Numeric object, which holds the numeric factorization computed by
+	umfpack_*_numeric.
+
+    double Control [UMFPACK_CONTROL] ;	Input argument, not modified.
+
+	If a (double *) NULL pointer is passed, then the default control
+	settings are used.  Otherwise, the settings are determined from the
+	Control array.  See umfpack_*_defaults on how to fill the Control
+	array with the default settings.  If Control contains NaN's, the
+	defaults are used.  The following Control parameters are used:
+
+	Control [UMFPACK_PRL]:  printing level.
+
+	    2 or less: no output.  returns silently without checking anything.
+	    3: fully check input, and print a short summary of its status
+	    4: as 3, but print first few entries of the input
+	    5: as 3, but print all of the input
+	    Default: 1
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_perm.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_perm.h
new file mode 100644
index 0000000..0bf0865
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_perm.h
@@ -0,0 +1,112 @@
+/* ========================================================================== */
+/* === umfpack_report_perm ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_perm
+(
+    int np,
+    const int Perm [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+UF_long umfpack_dl_report_perm
+(
+    UF_long np,
+    const UF_long Perm [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_perm
+(
+    int np,
+    const int Perm [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+UF_long umfpack_zl_report_perm
+(
+    UF_long np,
+    const UF_long Perm [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int np, *Perm, status ;
+    double Control [UMFPACK_CONTROL] ;
+    status = umfpack_di_report_perm (np, Perm, Control) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long np, *Perm, status ;
+    double Control [UMFPACK_CONTROL] ;
+    status = umfpack_dl_report_perm (np, Perm, Control) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int np, *Perm, status ;
+    double Control [UMFPACK_CONTROL] ;
+    status = umfpack_zi_report_perm (np, Perm, Control) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long np, *Perm, status ;
+    double Control [UMFPACK_CONTROL] ;
+    status = umfpack_zl_report_perm (np, Perm, Control) ;
+
+Purpose:
+
+    Verifies and prints a permutation vector.
+
+Returns:
+
+    UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked).
+
+    Otherwise:
+    UMFPACK_OK if the permutation vector is valid (this includes that case
+	when Perm is (Int *) NULL, which is not an error condition).
+    UMFPACK_ERROR_n_nonpositive if np <= 0.
+    UMFPACK_ERROR_out_of_memory if out of memory.
+    UMFPACK_ERROR_invalid_permutation if Perm is not a valid permutation vector.
+
+Arguments:
+
+    Int np ;		Input argument, not modified.
+
+	Perm is an integer vector of size np.  Restriction: np > 0.
+
+    Int Perm [np] ;	Input argument, not modified.
+
+	A permutation vector of size np.  If Perm is not present (an (Int *)
+	NULL pointer), then it is assumed to be the identity permutation.  This
+	is consistent with its use as an input argument to umfpack_*_qsymbolic,
+	and is not an error condition.  If Perm is present, the entries in Perm
+	must range between 0 and np-1, and no duplicates may exist.
+
+    double Control [UMFPACK_CONTROL] ;	Input argument, not modified.
+
+	If a (double *) NULL pointer is passed, then the default control
+	settings are used.  Otherwise, the settings are determined from the
+	Control array.  See umfpack_*_defaults on how to fill the Control
+	array with the default settings.  If Control contains NaN's, the
+	defaults are used.  The following Control parameters are used:
+
+	Control [UMFPACK_PRL]:  printing level.
+
+	    2 or less: no output.  returns silently without checking anything.
+	    3: fully check input, and print a short summary of its status
+	    4: as 3, but print first few entries of the input
+	    5: as 3, but print all of the input
+	    Default: 1
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_status.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_status.h
new file mode 100644
index 0000000..5acf73c
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_status.h
@@ -0,0 +1,90 @@
+/* ========================================================================== */
+/* === umfpack_report_status ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_report_status
+(
+    const double Control [UMFPACK_CONTROL],
+    int status
+) ;
+
+void umfpack_dl_report_status
+(
+    const double Control [UMFPACK_CONTROL],
+    UF_long status
+) ;
+
+void umfpack_zi_report_status
+(
+    const double Control [UMFPACK_CONTROL],
+    int status
+) ;
+
+void umfpack_zl_report_status
+(
+    const double Control [UMFPACK_CONTROL],
+    UF_long status
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    int status ;
+    umfpack_di_report_status (Control, status) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    UF_long status ;
+    umfpack_dl_report_status (Control, status) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    int status ;
+    umfpack_zi_report_status (Control, status) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    UF_long status ;
+    umfpack_zl_report_status (Control, status) ;
+
+Purpose:
+
+    Prints the status (return value) of other umfpack_* routines.
+
+Arguments:
+
+    double Control [UMFPACK_CONTROL] ;   Input argument, not modified.
+
+	If a (double *) NULL pointer is passed, then the default control
+	settings are used.  Otherwise, the settings are determined from the
+	Control array.  See umfpack_*_defaults on how to fill the Control
+	array with the default settings.  If Control contains NaN's, the
+	defaults are used.  The following Control parameters are used:
+
+	Control [UMFPACK_PRL]:  printing level.
+
+	    0 or less: no output, even when an error occurs
+	    1: error messages only
+	    2 or more: print status, whether or not an error occurred
+	    4 or more: also print the UMFPACK Copyright
+	    6 or more: also print the UMFPACK License
+	    Default: 1
+
+    Int status ;			Input argument, not modified.
+
+	The return value from another umfpack_* routine.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_symbolic.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_symbolic.h
new file mode 100644
index 0000000..a3a9413
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_symbolic.h
@@ -0,0 +1,111 @@
+/* ========================================================================== */
+/* === umfpack_report_symbolic ============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_symbolic
+(
+    void *Symbolic,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+UF_long umfpack_dl_report_symbolic
+(
+    void *Symbolic,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_symbolic
+(
+    void *Symbolic,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+UF_long umfpack_zl_report_symbolic
+(
+    void *Symbolic,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    double Control [UMFPACK_CONTROL] ;
+    int status ;
+    status = umfpack_di_report_symbolic (Symbolic, Control) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    double Control [UMFPACK_CONTROL] ;
+    UF_long status ;
+    status = umfpack_dl_report_symbolic (Symbolic, Control) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    double Control [UMFPACK_CONTROL] ;
+    int status ;
+    status = umfpack_zi_report_symbolic (Symbolic, Control) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    double Control [UMFPACK_CONTROL] ;
+    UF_long status ;
+    status = umfpack_zl_report_symbolic (Symbolic, Control) ;
+
+Purpose:
+
+    Verifies and prints a Symbolic object.  This routine checks the object more
+    carefully than the computational routines.  Normally, this check is not
+    required, since umfpack_*_*symbolic either returns (void *) NULL, or a valid
+    Symbolic object.  However, if you suspect that your own code has corrupted
+    the Symbolic object (by overruning memory bounds, for example), then this
+    routine might be able to detect a corrupted Symbolic object.  Since this is
+    a complex object, not all such user-generated errors are guaranteed to be
+    caught by this routine.
+
+Returns:
+
+    UMFPACK_OK if Control [UMFPACK_PRL] is <= 2 (no inputs are checked).
+
+    Otherwise:
+
+    UMFPACK_OK if the Symbolic object is valid.
+    UMFPACK_ERROR_invalid_Symbolic_object if the Symbolic object is invalid.
+    UMFPACK_ERROR_out_of_memory if out of memory.
+
+Arguments:
+
+    void *Symbolic ;			Input argument, not modified.
+
+	The Symbolic object, which holds the symbolic factorization computed by
+	umfpack_*_*symbolic.
+
+    double Control [UMFPACK_CONTROL] ;	Input argument, not modified.
+
+	If a (double *) NULL pointer is passed, then the default control
+	settings are used.  Otherwise, the settings are determined from the
+	Control array.  See umfpack_*_defaults on how to fill the Control
+	array with the default settings.  If Control contains NaN's, the
+	defaults are used.  The following Control parameters are used:
+
+	Control [UMFPACK_PRL]:  printing level.
+
+	    2 or less: no output.  returns silently without checking anything.
+	    3: fully check input, and print a short summary of its status
+	    4: as 3, but print first few entries of the input
+	    5: as 3, but print all of the input
+	    Default: 1
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_triplet.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_triplet.h
new file mode 100644
index 0000000..0f4f60a
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_triplet.h
@@ -0,0 +1,153 @@
+/* ========================================================================== */
+/* === umfpack_report_triplet =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_triplet
+(
+    int n_row,
+    int n_col,
+    int nz,
+    const int Ti [ ],
+    const int Tj [ ],
+    const double Tx [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+UF_long umfpack_dl_report_triplet
+(
+    UF_long n_row,
+    UF_long n_col,
+    UF_long nz,
+    const UF_long Ti [ ],
+    const UF_long Tj [ ],
+    const double Tx [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_triplet
+(
+    int n_row,
+    int n_col,
+    int nz,
+    const int Ti [ ],
+    const int Tj [ ],
+    const double Tx [ ], const double Tz [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+UF_long umfpack_zl_report_triplet
+(
+    UF_long n_row,
+    UF_long n_col,
+    UF_long nz,
+    const UF_long Ti [ ],
+    const UF_long Tj [ ],
+    const double Tx [ ], const double Tz [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int n_row, n_col, nz, *Ti, *Tj, status ;
+    double *Tx, Control [UMFPACK_CONTROL] ;
+    status = umfpack_di_report_triplet (n_row, n_col, nz, Ti, Tj, Tx, Control) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long n_row, n_col, nz, *Ti, *Tj, status ;
+    double *Tx, Control [UMFPACK_CONTROL] ;
+    status = umfpack_dl_report_triplet (n_row, n_col, nz, Ti, Tj, Tx, Control) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int n_row, n_col, nz, *Ti, *Tj, status ;
+    double *Tx, *Tz, Control [UMFPACK_CONTROL] ;
+    status = umfpack_zi_report_triplet (n_row, n_col, nz, Ti, Tj, Tx, Tz,
+	Control) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long n_row, n_col, nz, *Ti, *Tj, status ;
+    double *Tx, *Tz, Control [UMFPACK_CONTROL] ;
+    status = umfpack_zl_report_triplet (n_row, n_col, nz, Ti, Tj, Tx, Tz,
+	Control) ;
+
+packed complex Syntax:
+
+    Same as above, except Tz is NULL.
+
+Purpose:
+
+    Verifies and prints a matrix in triplet form.
+
+Returns:
+
+    UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked).
+
+    Otherwise:
+
+    UMFPACK_OK if the Triplet matrix is OK.
+    UMFPACK_ERROR_argument_missing if Ti and/or Tj are missing.
+    UMFPACK_ERROR_n_nonpositive if n_row <= 0 or n_col <= 0.
+    UMFPACK_ERROR_invalid_matrix if nz < 0, or
+	if any row or column index in Ti and/or Tj
+	is not in the range 0 to n_row-1 or 0 to n_col-1, respectively.
+
+Arguments:
+
+    Int n_row ;		Input argument, not modified.
+    Int n_col ;		Input argument, not modified.
+
+	A is an n_row-by-n_col matrix.
+
+    Int nz ;		Input argument, not modified.
+
+	The number of entries in the triplet form of the matrix.
+
+    Int Ti [nz] ;	Input argument, not modified.
+    Int Tj [nz] ;	Input argument, not modified.
+    double Tx [nz] ;	Input argument, not modified.
+			Size 2*nz for packed complex case.
+    double Tz [nz] ;	Input argument, not modified, for complex versions.
+
+	Ti, Tj, Tx (and Tz for complex versions) hold the "triplet" form of a
+	sparse matrix.  The kth nonzero entry is in row i = Ti [k], column
+	j = Tj [k], the real numerical value of a_ij is Tx [k], and the
+	imaginary part of a_ij is Tz [k] (for complex versions).  The row and
+	column indices i and j must be in the range 0 to n_row-1 or 0 to
+	n_col-1, respectively.  Duplicate entries may be present.  The
+	"triplets" may be in any order.  Tx and Tz are optional; if Tx is
+	not present ((double *) NULL), then the numerical values are
+	not printed.
+
+	If Tx is present and Tz is NULL, then both real
+	and imaginary parts are contained in Tx[0..2*nz-1], with Tx[2*k]
+	and Tx[2*k+1] being the real and imaginary part of the kth entry.
+
+    double Control [UMFPACK_CONTROL] ;	Input argument, not modified.
+
+	If a (double *) NULL pointer is passed, then the default control
+	settings are used.  Otherwise, the settings are determined from the
+	Control array.  See umfpack_*_defaults on how to fill the Control
+	array with the default settings.  If Control contains NaN's, the
+	defaults are used.  The following Control parameters are used:
+
+	Control [UMFPACK_PRL]:  printing level.
+
+	    2 or less: no output.  returns silently without checking anything.
+	    3: fully check input, and print a short summary of its status
+	    4: as 3, but print first few entries of the input
+	    5: as 3, but print all of the input
+	    Default: 1
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_vector.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_vector.h
new file mode 100644
index 0000000..d930b1e
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_vector.h
@@ -0,0 +1,133 @@
+/* ========================================================================== */
+/* === umfpack_report_vector ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_vector
+(
+    int n,
+    const double X [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+UF_long umfpack_dl_report_vector
+(
+    UF_long n,
+    const double X [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_vector
+(
+    int n,
+    const double Xx [ ], const double Xz [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+UF_long umfpack_zl_report_vector
+(
+    UF_long n,
+    const double Xx [ ], const double Xz [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int n, status ;
+    double *X, Control [UMFPACK_CONTROL] ;
+    status = umfpack_di_report_vector (n, X, Control) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long n, status ;
+    double *X, Control [UMFPACK_CONTROL] ;
+    status = umfpack_dl_report_vector (n, X, Control) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int n, status ;
+    double *Xx, *Xz, Control [UMFPACK_CONTROL] ;
+    status = umfpack_zi_report_vector (n, Xx, Xz, Control) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long n, status ;
+    double *Xx, *Xz, Control [UMFPACK_CONTROL] ;
+    status = umfpack_zl_report_vector (n, Xx, Xz, Control) ;
+
+Purpose:
+
+    Verifies and prints a dense vector.
+
+Returns:
+
+    UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked).
+
+    Otherwise:
+
+    UMFPACK_OK if the vector is valid.
+    UMFPACK_ERROR_argument_missing if X or Xx is missing.
+    UMFPACK_ERROR_n_nonpositive if n <= 0.
+
+Arguments:
+
+    Int n ;		Input argument, not modified.
+
+	X is a real or complex vector of size n.  Restriction: n > 0.
+
+    double X [n] ;	Input argument, not modified.  For real versions.
+
+	A real vector of size n.  X must not be (double *) NULL.
+
+    double Xx [n or 2*n] ; Input argument, not modified.  For complex versions.
+    double Xz [n or 0] ;   Input argument, not modified.  For complex versions.
+
+	A complex vector of size n, in one of two storage formats.
+	Xx must not be (double *) NULL.
+
+	If Xz is not (double *) NULL, then Xx [i] is the real part of X (i) and
+	Xz [i] is the imaginary part of X (i).  Both vectors are of length n.
+	This is the "split" form of the complex vector X.
+
+	If Xz is (double *) NULL, then Xx holds both real and imaginary parts,
+	where Xx [2*i] is the real part of X (i) and Xx [2*i+1] is the imaginary
+	part of X (i).  Xx is of length 2*n doubles.  If you have an ANSI C99
+	compiler with the intrinsic double _Complex type, then Xx can be of
+	type double _Complex in the calling routine and typecast to (double *)
+	when passed to umfpack_*_report_vector (this is untested, however).
+	This is the "merged" form of the complex vector X.
+
+	Note that all complex routines in UMFPACK V4.4 and later use this same
+	strategy for their complex arguments.  The split format is useful for
+	MATLAB, which holds its real and imaginary parts in seperate arrays.
+	The packed format is compatible with the intrinsic double _Complex
+	type in ANSI C99, and is also compatible with SuperLU's method of
+	storing complex matrices.  In Version 4.3, this routine was the only
+	one that allowed for packed complex arguments.
+
+    double Control [UMFPACK_CONTROL] ;	Input argument, not modified.
+
+	If a (double *) NULL pointer is passed, then the default control
+	settings are used.  Otherwise, the settings are determined from the
+	Control array.  See umfpack_*_defaults on how to fill the Control
+	array with the default settings.  If Control contains NaN's, the
+	defaults are used.  The following Control parameters are used:
+
+	Control [UMFPACK_PRL]:  printing level.
+
+	    2 or less: no output.  returns silently without checking anything.
+	    3: fully check input, and print a short summary of its status
+	    4: as 3, but print first few entries of the input
+	    5: as 3, but print all of the input
+	    Default: 1
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_save_numeric.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_save_numeric.h
new file mode 100644
index 0000000..72eb3b1
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_save_numeric.h
@@ -0,0 +1,90 @@
+/* ========================================================================== */
+/* === umfpack_save_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_save_numeric
+(
+    void *Numeric,
+    char *filename
+) ;
+
+UF_long umfpack_dl_save_numeric
+(
+    void *Numeric,
+    char *filename
+) ;
+
+int umfpack_zi_save_numeric
+(
+    void *Numeric,
+    char *filename
+) ;
+
+UF_long umfpack_zl_save_numeric
+(
+    void *Numeric,
+    char *filename
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int status ;
+    char *filename ;
+    void *Numeric ;
+    status = umfpack_di_save_numeric (Numeric, filename) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long status ;
+    char *filename ;
+    void *Numeric ;
+    status = umfpack_dl_save_numeric (Numeric, filename) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int status ;
+    char *filename ;
+    void *Numeric ;
+    status = umfpack_zi_save_numeric (Numeric, filename) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long status ;
+    char *filename ;
+    void *Numeric ;
+    status = umfpack_zl_save_numeric (Numeric, filename) ;
+
+Purpose:
+
+    Saves a Numeric object to a file, which can later be read by
+    umfpack_*_load_numeric.  The Numeric object is not modified.
+
+Returns:
+
+    UMFPACK_OK if successful.
+    UMFPACK_ERROR_invalid_Numeric_object if Numeric is not valid.
+    UMFPACK_ERROR_file_IO if an I/O error occurred.
+
+Arguments:
+
+    void *Numeric ;	    Input argument, not modified.
+
+	Numeric must point to a valid Numeric object, computed by
+	umfpack_*_numeric or loaded by umfpack_*_load_numeric.
+
+    char *filename ;	    Input argument, not modified.
+
+	A string that contains the filename to which the Numeric
+	object is written.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_save_symbolic.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_save_symbolic.h
new file mode 100644
index 0000000..3e64a26
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_save_symbolic.h
@@ -0,0 +1,90 @@
+/* ========================================================================== */
+/* === umfpack_save_symbolic================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_save_symbolic
+(
+    void *Symbolic,
+    char *filename
+) ;
+
+UF_long umfpack_dl_save_symbolic
+(
+    void *Symbolic,
+    char *filename
+) ;
+
+int umfpack_zi_save_symbolic
+(
+    void *Symbolic,
+    char *filename
+) ;
+
+UF_long umfpack_zl_save_symbolic
+(
+    void *Symbolic,
+    char *filename
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int status ;
+    char *filename ;
+    void *Symbolic ;
+    status = umfpack_di_save_symbolic (Symbolic, filename) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long status ;
+    char *filename ;
+    void *Symbolic ;
+    status = umfpack_dl_save_symbolic (Symbolic, filename) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int status ;
+    char *filename ;
+    void *Symbolic ;
+    status = umfpack_zi_save_symbolic (Symbolic, filename) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long status ;
+    char *filename ;
+    void *Symbolic ;
+    status = umfpack_zl_save_symbolic (Symbolic, filename) ;
+
+Purpose:
+
+    Saves a Symbolic object to a file, which can later be read by
+    umfpack_*_load_symbolic.  The Symbolic object is not modified.
+
+Returns:
+
+    UMFPACK_OK if successful.
+    UMFPACK_ERROR_invalid_Symbolic_object if Symbolic is not valid.
+    UMFPACK_ERROR_file_IO if an I/O error occurred.
+
+Arguments:
+
+    void *Symbolic ;	    Input argument, not modified.
+
+	Symbolic must point to a valid Symbolic object, computed by
+	umfpack_*_symbolic or loaded by umfpack_*_load_symbolic.
+
+    char *filename ;	    Input argument, not modified.
+
+	A string that contains the filename to which the Symbolic
+	object is written.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_scale.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_scale.h
new file mode 100644
index 0000000..6f698b1
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_scale.h
@@ -0,0 +1,112 @@
+/* ========================================================================== */
+/* === umfpack_scale ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_scale
+(
+    double X [ ],
+    const double B [ ],
+    void *Numeric
+) ;
+
+UF_long umfpack_dl_scale
+(
+    double X [ ],
+    const double B [ ],
+    void *Numeric
+) ;
+
+int umfpack_zi_scale
+(
+    double Xx [ ],	 double Xz [ ],
+    const double Bx [ ], const double Bz [ ],
+    void *Numeric
+) ;
+
+UF_long umfpack_zl_scale
+(
+    double Xx [ ],	 double Xz [ ],
+    const double Bx [ ], const double Bz [ ],
+    void *Numeric
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    double *B, *X ;
+    status = umfpack_di_scale (X, B, Numeric) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    double *B, *X ;
+    status = umfpack_dl_scale (X, B, Numeric) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    double *Bx, *Bz, *Xx, *Xz ;
+    status = umfpack_zi_scale (Xx, Xz, Bx, Bz, Numeric) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    double *Bx, *Bz, *Xx, *Xz ;
+    status = umfpack_zl_scale (Xx, Xz, Bx, Bz, Numeric) ;
+
+packed complex Syntax:
+
+    Same as above, except both Xz and Bz are NULL.
+
+Purpose:
+
+    Given LU factors computed by umfpack_*_numeric (PAQ=LU, PRAQ=LU, or
+    P(R\A)Q=LU), and a vector B, this routine computes X = B, X = R*B, or
+    X = R\B, as appropriate.  X and B must be vectors equal in length to the
+    number of rows of A.
+
+Returns:
+
+    The status code is returned.  UMFPACK_OK is returned if successful.
+    UMFPACK_ERROR_invalid_Numeric_object is returned in the Numeric
+    object is invalid.  UMFPACK_ERROR_argument_missing is returned if
+    any of the input vectors are missing (X and B for the real version,
+    and Xx and Bx for the complex version).
+
+Arguments:
+
+    double X [n_row] ;	Output argument.
+    or:
+    double Xx [n_row] ;	Output argument, real part.
+			Size 2*n_row for packed complex case.
+    double Xz [n_row] ;	Output argument, imaginary part.
+
+	The output vector X.  If either Xz or Bz are NULL, the vector
+	X is in packed complex form, with the kth entry in Xx [2*k] and
+	Xx [2*k+1], and likewise for B.
+
+    double B [n_row] ;	Input argument, not modified.
+    or:
+    double Bx [n_row] ;	Input argument, not modified, real part.
+			Size 2*n_row for packed complex case.
+    double Bz [n_row] ;	Input argument, not modified, imaginary part.
+
+	The input vector B.  See above if either Xz or Bz are NULL.
+
+    void *Numeric ;		Input argument, not modified.
+
+	Numeric must point to a valid Numeric object, computed by
+	umfpack_*_numeric.
+
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_solve.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_solve.h
new file mode 100644
index 0000000..a4b984b
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_solve.h
@@ -0,0 +1,301 @@
+/* ========================================================================== */
+/* === umfpack_solve ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_solve
+(
+    int sys,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ],
+    double X [ ],
+    const double B [ ],
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+UF_long umfpack_dl_solve
+(
+    UF_long sys,
+    const UF_long Ap [ ],
+    const UF_long Ai [ ],
+    const double Ax [ ],
+    double X [ ],
+    const double B [ ],
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+int umfpack_zi_solve
+(
+    int sys,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    double Xx [ ],	 double Xz [ ],
+    const double Bx [ ], const double Bz [ ],
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+UF_long umfpack_zl_solve
+(
+    UF_long sys,
+    const UF_long Ap [ ],
+    const UF_long Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    double Xx [ ],	 double Xz [ ],
+    const double Bx [ ], const double Bz [ ],
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int status, *Ap, *Ai, sys ;
+    double *B, *X, *Ax, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+    status = umfpack_di_solve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    UF_long status, *Ap, *Ai, sys ;
+    double *B, *X, *Ax, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+    status = umfpack_dl_solve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int status, *Ap, *Ai, sys ;
+    double *Bx, *Bz, *Xx, *Xz, *Ax, *Az, Info [UMFPACK_INFO],
+	Control [UMFPACK_CONTROL] ;
+    status = umfpack_zi_solve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric,
+	Control, Info) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    UF_long status, *Ap, *Ai, sys ;
+    double *Bx, *Bz, *Xx, *Xz, *Ax, *Az, Info [UMFPACK_INFO],
+	Control [UMFPACK_CONTROL] ;
+    status = umfpack_zl_solve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric,
+	Control, Info) ;
+
+packed complex Syntax:
+
+    Same as above, Xz, Bz, and Az are NULL.
+
+Purpose:
+
+    Given LU factors computed by umfpack_*_numeric (PAQ=LU, PRAQ=LU, or
+    P(R\A)Q=LU) and the right-hand-side, B, solve a linear system for the
+    solution X.  Iterative refinement is optionally performed.  Only square
+    systems are handled.  Singular matrices result in a divide-by-zero for all
+    systems except those involving just the matrix L.  Iterative refinement is
+    not performed for singular matrices.  In the discussion below, n is equal
+    to n_row and n_col, because only square systems are handled.
+
+Returns:
+
+    The status code is returned.  See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+    Int sys ;		Input argument, not modified.
+
+	Defines which system to solve.  (') is the linear algebraic transpose
+	(complex conjugate if A is complex), and (.') is the array transpose.
+
+	    sys value	    system solved
+	    UMFPACK_A       Ax=b
+	    UMFPACK_At      A'x=b
+	    UMFPACK_Aat     A.'x=b
+	    UMFPACK_Pt_L    P'Lx=b
+	    UMFPACK_L       Lx=b
+	    UMFPACK_Lt_P    L'Px=b
+	    UMFPACK_Lat_P   L.'Px=b
+	    UMFPACK_Lt      L'x=b
+	    UMFPACK_U_Qt    UQ'x=b
+	    UMFPACK_U       Ux=b
+	    UMFPACK_Q_Ut    QU'x=b
+	    UMFPACK_Q_Uat   QU.'x=b
+	    UMFPACK_Ut      U'x=b
+	    UMFPACK_Uat     U.'x=b
+
+	Iterative refinement can be optionally performed when sys is any of
+	the following:
+
+	    UMFPACK_A       Ax=b
+	    UMFPACK_At      A'x=b
+	    UMFPACK_Aat     A.'x=b
+
+	For the other values of the sys argument, iterative refinement is not
+	performed (Control [UMFPACK_IRSTEP], Ap, Ai, Ax, and Az are ignored).
+
+    Int Ap [n+1] ;	Input argument, not modified.
+    Int Ai [nz] ;	Input argument, not modified.
+    double Ax [nz] ;	Input argument, not modified.
+			Size 2*nz for packed complex case.
+    double Az [nz] ;	Input argument, not modified, for complex versions.
+
+	If iterative refinement is requested (Control [UMFPACK_IRSTEP] >= 1,
+	Ax=b, A'x=b, or A.'x=b is being solved, and A is nonsingular), then
+	these arrays must be identical to the same ones passed to
+	umfpack_*_numeric.  The umfpack_*_solve routine does not check the
+	contents of these arguments, so the results are undefined if Ap, Ai, Ax,
+	and/or Az are modified between the calls the umfpack_*_numeric and
+	umfpack_*_solve.  These three arrays do not need to be present (NULL
+	pointers can be passed) if Control [UMFPACK_IRSTEP] is zero, or if a
+	system other than Ax=b, A'x=b, or A.'x=b is being solved, or if A is
+	singular, since in each of these cases A is not accessed.
+
+	If Az, Xz, or Bz are NULL, then both real
+	and imaginary parts are contained in Ax[0..2*nz-1], with Ax[2*k]
+	and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+    double X [n] ;	Output argument.
+    or:
+    double Xx [n] ;	Output argument, real part
+			Size 2*n for packed complex case.
+    double Xz [n] ;	Output argument, imaginary part.
+
+	The solution to the linear system, where n = n_row = n_col is the
+	dimension of the matrices A, L, and U.
+
+	If Az, Xz, or Bz are NULL, then both real
+	and imaginary parts are returned in Xx[0..2*n-1], with Xx[2*k] and
+	Xx[2*k+1] being the real and imaginary part of the kth entry.
+
+    double B [n] ;	Input argument, not modified.
+    or:
+    double Bx [n] ;	Input argument, not modified, real part.
+			Size 2*n for packed complex case.
+    double Bz [n] ;	Input argument, not modified, imaginary part.
+
+	The right-hand side vector, b, stored as a conventional array of size n
+	(or two arrays of size n for complex versions).  This routine does not
+	solve for multiple right-hand-sides, nor does it allow b to be stored in
+	a sparse-column form.
+
+	If Az, Xz, or Bz are NULL, then both real
+	and imaginary parts are contained in Bx[0..2*n-1], with Bx[2*k]
+	and Bx[2*k+1] being the real and imaginary part of the kth entry.
+
+    void *Numeric ;		Input argument, not modified.
+
+	Numeric must point to a valid Numeric object, computed by
+	umfpack_*_numeric.
+
+    double Control [UMFPACK_CONTROL] ;	Input argument, not modified.
+
+	If a (double *) NULL pointer is passed, then the default control
+	settings are used.  Otherwise, the settings are determined from the
+	Control array.  See umfpack_*_defaults on how to fill the Control
+	array with the default settings.  If Control contains NaN's, the
+	defaults are used.  The following Control parameters are used:
+
+	Control [UMFPACK_IRSTEP]:  The maximum number of iterative refinement
+	    steps to attempt.  A value less than zero is treated as zero.  If
+	    less than 1, or if Ax=b, A'x=b, or A.'x=b is not being solved, or
+	    if A is singular, then the Ap, Ai, Ax, and Az arguments are not
+	    accessed.  Default: 2.
+
+    double Info [UMFPACK_INFO] ;	Output argument.
+
+	Contains statistics about the solution factorization.  If a
+	(double *) NULL pointer is passed, then no statistics are returned in
+	Info (this is not an error condition).  The following statistics are
+	computed in umfpack_*_solve:
+
+	Info [UMFPACK_STATUS]: status code.  This is also the return value,
+	    whether or not Info is present.
+
+	    UMFPACK_OK
+
+		The linear system was successfully solved.
+
+	    UMFPACK_WARNING_singular_matrix
+
+		A divide-by-zero occurred.  Your solution will contain Inf's
+		and/or NaN's.  Some parts of the solution may be valid.  For
+		example, solving Ax=b with
+
+		A = [2 0]  b = [ 1 ]  returns x = [ 0.5 ]
+		    [0 0]      [ 0 ]              [ Inf ]
+
+	    UMFPACK_ERROR_out_of_memory
+
+		Insufficient memory to solve the linear system.
+
+	    UMFPACK_ERROR_argument_missing
+
+		One or more required arguments are missing.  The B, X, (or
+		Bx and Xx for the complex versions) arguments
+		are always required.  Info and Control are not required.  Ap,
+		Ai, Ax are required if Ax=b,
+		A'x=b, A.'x=b is to be solved, the (default) iterative
+		refinement is requested, and the matrix A is nonsingular.
+
+	    UMFPACK_ERROR_invalid_system
+
+		The sys argument is not valid, or the matrix A is not square.
+
+	    UMFPACK_ERROR_invalid_Numeric_object
+
+		The Numeric object is not valid.
+
+	Info [UMFPACK_NROW], Info [UMFPACK_NCOL]:
+		The dimensions of the matrix A (L is n_row-by-n_inner and
+		U is n_inner-by-n_col, with n_inner = min(n_row,n_col)).
+
+	Info [UMFPACK_NZ]:  the number of entries in the input matrix, Ap [n],
+	    if iterative refinement is requested (Ax=b, A'x=b, or A.'x=b is
+	    being solved, Control [UMFPACK_IRSTEP] >= 1, and A is nonsingular).
+
+	Info [UMFPACK_IR_TAKEN]:  The number of iterative refinement steps
+	    effectively taken.  The number of steps attempted may be one more
+	    than this; the refinement algorithm backtracks if the last
+	    refinement step worsens the solution.
+
+	Info [UMFPACK_IR_ATTEMPTED]:   The number of iterative refinement steps
+	    attempted.  The number of times a linear system was solved is one
+	    more than this (once for the initial Ax=b, and once for each Ay=r
+	    solved for each iterative refinement step attempted).
+
+	Info [UMFPACK_OMEGA1]:  sparse backward error estimate, omega1, if
+	    iterative refinement was performed, or -1 if iterative refinement
+	    not performed.
+
+	Info [UMFPACK_OMEGA2]:  sparse backward error estimate, omega2, if
+	    iterative refinement was performed, or -1 if iterative refinement
+	    not performed.
+
+	Info [UMFPACK_SOLVE_FLOPS]:  the number of floating point operations
+	    performed to solve the linear system.  This includes the work
+	    taken for all iterative refinement steps, including the backtrack
+	    (if any).
+
+	Info [UMFPACK_SOLVE_TIME]:  The time taken, in seconds.
+
+        Info [UMFPACK_SOLVE_WALLTIME]:  The wallclock time taken, in seconds.
+
+	Only the above listed Info [...] entries are accessed.  The remaining
+	entries of Info are not accessed or modified by umfpack_*_solve.
+	Future versions might modify different parts of Info.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_symbolic.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_symbolic.h
new file mode 100644
index 0000000..52ed167
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_symbolic.h
@@ -0,0 +1,536 @@
+/* ========================================================================== */
+/* === umfpack_symbolic ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_symbolic
+(
+    int n_row,
+    int n_col,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ],
+    void **Symbolic,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+UF_long umfpack_dl_symbolic
+(
+    UF_long n_row,
+    UF_long n_col,
+    const UF_long Ap [ ],
+    const UF_long Ai [ ],
+    const double Ax [ ],
+    void **Symbolic,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+int umfpack_zi_symbolic
+(
+    int n_row,
+    int n_col,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    void **Symbolic,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+UF_long umfpack_zl_symbolic
+(
+    UF_long n_row,
+    UF_long n_col,
+    const UF_long Ap [ ],
+    const UF_long Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    void **Symbolic,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    int n_row, n_col, *Ap, *Ai, status ;
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax ;
+    status = umfpack_di_symbolic (n_row, n_col, Ap, Ai, Ax,
+	&Symbolic, Control, Info) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    UF_long n_row, n_col, *Ap, *Ai, status ;
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax ;
+    status = umfpack_dl_symbolic (n_row, n_col, Ap, Ai, Ax,
+	&Symbolic, Control, Info) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    int n_row, n_col, *Ap, *Ai, status ;
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax, *Az ;
+    status = umfpack_zi_symbolic (n_row, n_col, Ap, Ai, Ax, Az,
+	&Symbolic, Control, Info) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    UF_long n_row, n_col, *Ap, *Ai, status ;
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax, *Az ;
+    status = umfpack_zl_symbolic (n_row, n_col, Ap, Ai, Ax, Az,
+	&Symbolic, Control, Info) ;
+
+packed complex Syntax:
+
+    Same as above, except Az is NULL.
+
+Purpose:
+
+    Given nonzero pattern of a sparse matrix A in column-oriented form,
+    umfpack_*_symbolic performs a column pre-ordering to reduce fill-in
+    (using COLAMD or AMD) and a symbolic factorization.  This is required
+    before the matrix can be numerically factorized with umfpack_*_numeric.
+    If you wish to bypass the COLAMD or AMD pre-ordering and provide your own
+    ordering, use umfpack_*_qsymbolic instead.
+
+    Since umfpack_*_symbolic and umfpack_*_qsymbolic are very similar, options
+    for both routines are discussed below.
+
+    For the following discussion, let S be the submatrix of A obtained after
+    eliminating all pivots of zero Markowitz cost.  S has dimension
+    (n_row-n1-nempty_row) -by- (n_col-n1-nempty_col), where
+    n1 = Info [UMFPACK_COL_SINGLETONS] + Info [UMFPACK_ROW_SINGLETONS],
+    nempty_row = Info [UMFPACK_NEMPTY_ROW] and
+    nempty_col = Info [UMFPACK_NEMPTY_COL].
+
+Returns:
+
+    The status code is returned.  See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+    Int n_row ;		Input argument, not modified.
+    Int n_col ;		Input argument, not modified.
+
+	A is an n_row-by-n_col matrix.  Restriction: n_row > 0 and n_col > 0.
+
+    Int Ap [n_col+1] ;	Input argument, not modified.
+
+	Ap is an integer array of size n_col+1.  On input, it holds the
+	"pointers" for the column form of the sparse matrix A.  Column j of
+	the matrix A is held in Ai [(Ap [j]) ... (Ap [j+1]-1)].  The first
+	entry, Ap [0], must be zero, and Ap [j] <= Ap [j+1] must hold for all
+	j in the range 0 to n_col-1.  The value nz = Ap [n_col] is thus the
+	total number of entries in the pattern of the matrix A.  nz must be
+	greater than or equal to zero.
+
+    Int Ai [nz] ;	Input argument, not modified, of size nz = Ap [n_col].
+
+	The nonzero pattern (row indices) for column j is stored in
+	Ai [(Ap [j]) ... (Ap [j+1]-1)].  The row indices in a given column j
+	must be in ascending order, and no duplicate row indices may be present.
+	Row indices must be in the range 0 to n_row-1 (the matrix is 0-based).
+	See umfpack_*_triplet_to_col for how to sort the columns of a matrix
+	and sum up the duplicate entries.  See umfpack_*_report_matrix for how
+	to print the matrix A.
+
+    double Ax [nz] ;	Optional input argument, not modified.
+			Size 2*nz for packed complex case.
+
+	The numerical values of the sparse matrix A.  The nonzero pattern (row
+	indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and
+	the corresponding numerical values are stored in
+	Ax [(Ap [j]) ... (Ap [j+1]-1)].  Used only by the 2-by-2 strategy to
+	determine whether entries are "large" or "small".  You do not have to
+	pass the same numerical values to umfpack_*_numeric.  If Ax is not
+	present (a (double *) NULL pointer), then any entry in A is assumed to
+	be "large".
+
+    double Az [nz] ;	Optional input argument, not modified, for complex
+			versions.
+
+	For the complex versions, this holds the imaginary part of A.  The
+	imaginary part of column j is held in Az [(Ap [j]) ... (Ap [j+1]-1)].
+
+	If Az is NULL, then both real
+	and imaginary parts are contained in Ax[0..2*nz-1], with Ax[2*k]
+	and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+	Used by the 2-by-2 strategy only.  See the description of Ax, above.
+
+    void **Symbolic ;	Output argument.
+
+	**Symbolic is the address of a (void *) pointer variable in the user's
+	calling routine (see Syntax, above).  On input, the contents of this
+	variable are not defined.  On output, this variable holds a (void *)
+	pointer to the Symbolic object (if successful), or (void *) NULL if
+	a failure occurred.
+
+    double Control [UMFPACK_CONTROL] ;	Input argument, not modified.
+
+	If a (double *) NULL pointer is passed, then the default control
+	settings are used (the defaults are suitable for all matrices,
+	ranging from those with highly unsymmetric nonzero pattern, to
+	symmetric matrices).  Otherwise, the settings are determined from the
+	Control array.  See umfpack_*_defaults on how to fill the Control
+	array with the default settings.  If Control contains NaN's, the
+	defaults are used.  The following Control parameters are used:
+
+	Control [UMFPACK_STRATEGY]:  This is the most important control
+	    parameter.  It determines what kind of ordering and pivoting
+	    strategy that UMFPACK should use.  There are 4 options:
+
+	    UMFPACK_STRATEGY_AUTO:  This is the default.  The input matrix is
+		analyzed to determine how symmetric the nonzero pattern is, and
+		how many entries there are on the diagonal.  It then selects one
+		of the following strategies.  Refer to the User Guide for a
+		description of how the strategy is automatically selected.
+
+	    UMFPACK_STRATEGY_UNSYMMETRIC:  Use the unsymmetric strategy.  COLAMD
+		is used to order the columns of A, followed by a postorder of
+		the column elimination tree.  No attempt is made to perform
+		diagonal pivoting.  The column ordering is refined during
+		factorization.
+
+		In the numerical factorization, the
+		Control [UMFPACK_SYM_PIVOT_TOLERANCE] parameter is ignored.  A
+		pivot is selected if its magnitude is >=
+		Control [UMFPACK_PIVOT_TOLERANCE] (default 0.1) times the
+		largest entry in its column.
+
+	    UMFPACK_STRATEGY_SYMMETRIC:  Use the symmetric strategy
+		In this method, the approximate minimum degree
+		ordering (AMD) is applied to A+A', followed by a postorder of
+		the elimination tree of A+A'.  UMFPACK attempts to perform
+		diagonal pivoting during numerical factorization.  No refinement
+		of the column pre-ordering is performed during factorization.
+
+		In the numerical factorization, a nonzero entry on the diagonal
+		is selected as the pivot if its magnitude is >= Control
+		[UMFPACK_SYM_PIVOT_TOLERANCE] (default 0.001) times the largest
+		entry in its column.  If this is not acceptable, then an
+		off-diagonal pivot is selected with magnitude >= Control
+		[UMFPACK_PIVOT_TOLERANCE] (default 0.1) times the largest entry
+		in its column.
+
+	    UMFPACK_STRATEGY_2BY2:  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.
+	    Assuming 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]:  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 at cise.ufl.edu).
+
+	Info [UMFPACK_NROW]:  the value of the input argument n_row.
+
+	Info [UMFPACK_NCOL]:  the value of the input argument n_col.
+
+	Info [UMFPACK_NZ]:  the number of entries in the input matrix
+	    (Ap [n_col]).
+
+	Info [UMFPACK_SIZE_OF_UNIT]:  the number of bytes in a Unit,
+	    for memory usage statistics below.
+
+	Info [UMFPACK_SIZE_OF_INT]:  the number of bytes in an int.
+
+	Info [UMFPACK_SIZE_OF_LONG]:  the number of bytes in a UF_long.
+
+	Info [UMFPACK_SIZE_OF_POINTER]:  the number of bytes in a void *
+	    pointer.
+
+	Info [UMFPACK_SIZE_OF_ENTRY]:  the number of bytes in a numerical entry.
+
+	Info [UMFPACK_NDENSE_ROW]:  number of "dense" rows in A.  These rows are
+	    ignored when the column pre-ordering is computed in COLAMD.  They
+	    are also treated differently during numeric factorization.  If > 0,
+	    then the matrix had to be re-analyzed by UMF_analyze, which does
+	    not ignore these rows.
+
+	Info [UMFPACK_NEMPTY_ROW]:  number of "empty" rows in A, as determined
+	    These are rows that either have no entries, or whose entries are
+	    all in pivot columns of zero-Markowitz-cost pivots.
+
+	Info [UMFPACK_NDENSE_COL]:  number of "dense" columns in A.  COLAMD
+	    orders these columns are ordered last in the factorization, but
+	    before "empty" columns.
+
+	Info [UMFPACK_NEMPTY_COL]:  number of "empty" columns in A.  These are
+	    columns that either have no entries, or whose entries are all in
+	    pivot rows of zero-Markowitz-cost pivots.  These columns are
+	    ordered last in the factorization, to the right of "dense" columns.
+
+	Info [UMFPACK_SYMBOLIC_DEFRAG]:  number of garbage collections
+	    performed during ordering and symbolic pre-analysis.
+
+	Info [UMFPACK_SYMBOLIC_PEAK_MEMORY]:  the amount of memory (in Units)
+	    required for umfpack_*_symbolic to complete.  This count includes
+	    the size of the Symbolic object itself, which is also reported in
+	    Info [UMFPACK_SYMBOLIC_SIZE].
+
+	Info [UMFPACK_SYMBOLIC_SIZE]: the final size of the Symbolic object (in
+	    Units).  This is fairly small, roughly 2*n to 13*n integers,
+	    depending on the matrix.
+
+	Info [UMFPACK_VARIABLE_INIT_ESTIMATE]: the Numeric object contains two
+	    parts.  The first is fixed in size (O (n_row+n_col)).  The
+	    second part holds the sparse LU factors and the contribution blocks
+	    from factorized frontal matrices.  This part changes in size during
+	    factorization.  Info [UMFPACK_VARIABLE_INIT_ESTIMATE] is the exact
+	    size (in Units) required for this second variable-sized part in
+	    order for the numerical factorization to start.
+
+	Info [UMFPACK_VARIABLE_PEAK_ESTIMATE]: the estimated peak size (in
+	    Units) of the variable-sized part of the Numeric object.  This is
+	    usually an upper bound, but that is not guaranteed.
+
+	Info [UMFPACK_VARIABLE_FINAL_ESTIMATE]: the estimated final size (in
+	    Units) of the variable-sized part of the Numeric object.  This is
+	    usually an upper bound, but that is not guaranteed.  It holds just
+	    the sparse LU factors.
+
+	Info [UMFPACK_NUMERIC_SIZE_ESTIMATE]:  an estimate of the final size (in
+	    Units) of the entire Numeric object (both fixed-size and variable-
+	    sized parts), which holds the LU factorization (including the L, U,
+	    P and Q matrices).
+
+	Info [UMFPACK_PEAK_MEMORY_ESTIMATE]:  an estimate of the total amount of
+	    memory (in Units) required by umfpack_*_symbolic and
+	    umfpack_*_numeric to perform both the symbolic and numeric
+	    factorization.  This is the larger of the amount of memory needed
+	    in umfpack_*_numeric itself, and the amount of memory needed in
+	    umfpack_*_symbolic (Info [UMFPACK_SYMBOLIC_PEAK_MEMORY]).  The
+	    count includes the size of both the Symbolic and Numeric objects
+	    themselves.  It can be a very loose upper bound, particularly when
+	    the symmetric or 2-by-2 strategies are used.
+
+	Info [UMFPACK_FLOPS_ESTIMATE]:  an estimate of the total floating-point
+	    operations required to factorize the matrix.  This is a "true"
+	    theoretical estimate of the number of flops that would be performed
+	    by a flop-parsimonious sparse LU algorithm.  It assumes that no
+	    extra flops are performed except for what is strictly required to
+	    compute the LU factorization.  It ignores, for example, the flops
+            performed by umfpack_di_numeric to add contribution blocks of
+	    frontal matrices together.  If L and U are the upper bound on the
+	    pattern of the factors, then this flop count estimate can be
+	    represented in MATLAB (for real matrices, not complex) as:
+
+		Lnz = full (sum (spones (L))) - 1 ;	% nz in each col of L
+		Unz = full (sum (spones (U')))' - 1 ;	% nz in each row of U
+		flops = 2*Lnz*Unz + sum (Lnz) ;
+
+	    The actual "true flop" count found by umfpack_*_numeric will be
+	    less than this estimate.
+
+	    For the real version, only (+ - * /) are counted.  For the complex
+	    version, the following counts are used:
+
+		operation	flops
+	    	c = 1/b		6
+		c = a*b		6
+		c -= a*b	8
+
+	Info [UMFPACK_LNZ_ESTIMATE]:  an estimate of the number of nonzeros in
+	    L, including the diagonal.  Since L is unit-diagonal, the diagonal
+	    of L is not stored.  This estimate is a strict upper bound on the
+	    actual nonzeros in L to be computed by umfpack_*_numeric.
+
+	Info [UMFPACK_UNZ_ESTIMATE]:  an estimate of the number of nonzeros in
+	    U, including the diagonal.  This estimate is a strict upper bound on
+	    the actual nonzeros in U to be computed by umfpack_*_numeric.
+
+	Info [UMFPACK_MAX_FRONT_SIZE_ESTIMATE]: estimate of the size of the
+	    largest frontal matrix (# of entries), for arbitrary partial
+	    pivoting during numerical factorization.
+
+	Info [UMFPACK_SYMBOLIC_TIME]:  The CPU time taken, in seconds.
+
+	Info [UMFPACK_SYMBOLIC_WALLTIME]:  The wallclock time taken, in seconds.
+
+	Info [UMFPACK_STRATEGY_USED]: The ordering strategy used:
+	    UMFPACK_STRATEGY_SYMMETRIC, 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.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_tictoc.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_tictoc.h
new file mode 100644
index 0000000..c2d7e57
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_tictoc.h
@@ -0,0 +1,60 @@
+/* ========================================================================== */
+/* === umfpack_tictoc ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_tic (double stats [2]) ;
+
+void umfpack_toc (double stats [2]) ;
+
+
+/*
+Syntax (for all versions: di, dl, zi, and zl):
+
+    #include "umfpack.h"
+    double stats [2] ;
+    umfpack_tic (stats) ;
+    ...
+    umfpack_toc (stats) ;
+
+Purpose:
+
+    umfpack_tic returns the CPU time and wall clock time used by the process.
+    The CPU time includes both "user" and "system" time (the latter is time
+    spent by the system on behalf of the process, and is thus charged to the
+    process).  umfpack_toc returns the CPU time and wall clock time since the
+    last call to umfpack_tic with the same stats array.
+
+    Typical usage:
+
+	umfpack_tic (stats) ;
+	... do some work ...
+	umfpack_toc (stats) ;
+
+    then stats [1] contains the time in seconds used by the code between
+    umfpack_tic and umfpack_toc, and stats [0] contains the wall clock time
+    elapsed between the umfpack_tic and umfpack_toc.  These two routines act
+    just like tic and toc in MATLAB, except that the both process time and
+    wall clock time are returned.
+
+    This routine normally uses the sysconf and times routines in the POSIX
+    standard.  If -DNPOSIX is defined at compile time, then the ANSI C clock
+    routine is used instead, and only the CPU time is returned (stats [0]
+    is set to zero).
+
+    umfpack_tic and umfpack_toc are the routines used internally in UMFPACK
+    to time the symbolic analysis, numerical factorization, and the forward/
+    backward solve.
+
+Arguments:
+
+    double stats [2]:
+
+	stats [0]:  wall clock time, in seconds
+	stats [1]:  CPU time, in seconds
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_timer.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_timer.h
new file mode 100644
index 0000000..7284a08
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_timer.h
@@ -0,0 +1,39 @@
+/* ========================================================================== */
+/* === umfpack_timer ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+double umfpack_timer ( void ) ;
+
+/*
+Syntax (for all versions: di, dl, zi, and zl):
+
+    #include "umfpack.h"
+    double t ;
+    t = umfpack_timer ( ) ;
+
+Purpose:
+
+    Returns the CPU time used by the process.  Includes both "user" and "system"
+    time (the latter is time spent by the system on behalf of the process, and
+    is thus charged to the process).  It does not return the wall clock time.
+    See umfpack_tic and umfpack_toc (the file umfpack_tictoc.h) for the timer
+    used internally by UMFPACK.
+
+    This routine uses the Unix getrusage routine, if available.  It is less
+    subject to overflow than the ANSI C clock routine.  If getrusage is not
+    available, the portable ANSI C clock routine is used instead.
+    Unfortunately, clock ( ) overflows if the CPU time exceeds 2147 seconds
+    (about 36 minutes) when sizeof (clock_t) is 4 bytes.  If you have getrusage,
+    be sure to compile UMFPACK with the -DGETRUSAGE flag set; see umf_config.h
+    and the User Guide for details.  Even the getrusage routine can overlow.
+
+Arguments:
+
+    None.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_transpose.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_transpose.h
new file mode 100644
index 0000000..15aa60d
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_transpose.h
@@ -0,0 +1,216 @@
+/* ========================================================================== */
+/* === umfpack_transpose ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_transpose
+(
+    int n_row,
+    int n_col,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ],
+    const int P [ ],
+    const int Q [ ],
+    int Rp [ ],
+    int Ri [ ],
+    double Rx [ ]
+) ;
+
+UF_long umfpack_dl_transpose
+(
+    UF_long n_row,
+    UF_long n_col,
+    const UF_long Ap [ ],
+    const UF_long Ai [ ],
+    const double Ax [ ],
+    const UF_long P [ ],
+    const UF_long Q [ ],
+    UF_long Rp [ ],
+    UF_long Ri [ ],
+    double Rx [ ]
+) ;
+
+int umfpack_zi_transpose
+(
+    int n_row,
+    int n_col,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    const int P [ ],
+    const int Q [ ],
+    int Rp [ ],
+    int Ri [ ],
+    double Rx [ ], double Rz [ ],
+    int do_conjugate
+) ;
+
+UF_long umfpack_zl_transpose
+(
+    UF_long n_row,
+    UF_long n_col,
+    const UF_long Ap [ ],
+    const UF_long Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    const UF_long P [ ],
+    const UF_long Q [ ],
+    UF_long Rp [ ],
+    UF_long Ri [ ],
+    double Rx [ ], double Rz [ ],
+    UF_long do_conjugate
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int n_row, n_col, status, *Ap, *Ai, *P, *Q, *Rp, *Ri ;
+    double *Ax, *Rx ;
+    status = umfpack_di_transpose (n_row, n_col, Ap, Ai, Ax, P, Q, Rp, Ri, Rx) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long n_row, n_col, status, *Ap, *Ai, *P, *Q, *Rp, *Ri ;
+    double *Ax, *Rx ;
+    status = umfpack_dl_transpose (n_row, n_col, Ap, Ai, Ax, P, Q, Rp, Ri, Rx) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int n_row, n_col, status, *Ap, *Ai, *P, *Q, *Rp, *Ri, do_conjugate ;
+    double *Ax, *Az, *Rx, *Rz ;
+    status = umfpack_zi_transpose (n_row, n_col, Ap, Ai, Ax, Az, P, Q,
+	Rp, Ri, Rx, Rz, do_conjugate) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long n_row, n_col, status, *Ap, *Ai, *P, *Q, *Rp, *Ri, do_conjugate ;
+    double *Ax, *Az, *Rx, *Rz ;
+    status = umfpack_zl_transpose (n_row, n_col, Ap, Ai, Ax, Az, P, Q,
+	Rp, Ri, Rx, Rz, do_conjugate) ;
+
+packed complex Syntax:
+
+    Same as above, except Az are Rz are NULL.
+
+Purpose:
+
+    Transposes and optionally permutes a sparse matrix in row or column-form,
+    R = (PAQ)'.  In MATLAB notation, R = (A (P,Q))' or R = (A (P,Q)).' doing
+    either the linear algebraic transpose or the array transpose. Alternatively,
+    this routine can be viewed as converting A (P,Q) from column-form to
+    row-form, or visa versa (for the array transpose).  Empty rows and columns
+    may exist.  The matrix A may be singular and/or rectangular.
+
+    umfpack_*_transpose is useful if you want to factorize A' or A.' instead of
+    A.  Factorizing A' or A.' instead of A can be much better, particularly if
+    AA' is much sparser than A'A.  You can still solve Ax=b if you factorize
+    A' or A.', by solving with the sys argument UMFPACK_At or UMFPACK_Aat,
+    respectively, in umfpack_*_*solve.
+
+Returns:
+
+    UMFPACK_OK if successful.
+    UMFPACK_ERROR_out_of_memory if umfpack_*_transpose fails to allocate a
+	size-max (n_row,n_col) workspace.
+    UMFPACK_ERROR_argument_missing if Ai, Ap, Ri, and/or Rp are missing.
+    UMFPACK_ERROR_n_nonpositive if n_row <= 0 or n_col <= 0
+    UMFPACK_ERROR_invalid_permutation if P and/or Q are invalid.
+    UMFPACK_ERROR_invalid_matrix if Ap [n_col] < 0, if Ap [0] != 0,
+	if Ap [j] > Ap [j+1] for any j in the range 0 to n_col-1,
+	if any row index i is < 0 or >= n_row, or if the row indices
+	in any column are not in ascending order.
+
+Arguments:
+
+    Int n_row ;		Input argument, not modified.
+    Int n_col ;		Input argument, not modified.
+
+	A is an n_row-by-n_col matrix.  Restriction: n_row > 0 and n_col > 0.
+
+    Int Ap [n_col+1] ;	Input argument, not modified.
+
+	The column pointers of the column-oriented form of the matrix A.  See
+	umfpack_*_symbolic for a description.  The number of entries in
+	the matrix is nz = Ap [n_col].  Ap [0] must be zero, Ap [n_col] must be
+	=> 0, and Ap [j] <= Ap [j+1] and Ap [j] <= Ap [n_col] must be true for
+	all j in the range 0 to n_col-1.  Empty columns are OK (that is, Ap [j]
+	may equal Ap [j+1] for any j in the range 0 to n_col-1).
+
+    Int Ai [nz] ;	Input argument, not modified, of size nz = Ap [n_col].
+
+	The nonzero pattern (row indices) for column j is stored in
+	Ai [(Ap [j]) ... (Ap [j+1]-1)].  The row indices in a given column j
+	must be in ascending order, and no duplicate row indices may be present.
+	Row indices must be in the range 0 to n_row-1 (the matrix is 0-based).
+
+    double Ax [nz] ;	Input argument, not modified, of size nz = Ap [n_col].
+			Size 2*nz if Az or Rz are NULL.
+    double Az [nz] ;	Input argument, not modified, for complex versions.
+
+	If present, these are the numerical values of the sparse matrix A.
+	The nonzero pattern (row indices) for column j is stored in
+	Ai [(Ap [j]) ... (Ap [j+1]-1)], and the corresponding real numerical
+	values are stored in Ax [(Ap [j]) ... (Ap [j+1]-1)].  The imaginary
+	values are stored in Az [(Ap [j]) ... (Ap [j+1]-1)].  The values are
+	transposed only if Ax and Rx are present.
+	This is not an error conditions; you are able to transpose
+	and permute just the pattern of a matrix.
+
+	If Az or Rz are NULL, then both real
+	and imaginary parts are contained in Ax[0..2*nz-1], with Ax[2*k]
+	and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+    Int P [n_row] ;		Input argument, not modified.
+
+	The permutation vector P is defined as P [k] = i, where the original
+	row i of A is the kth row of PAQ.  If you want to use the identity
+	permutation for P, simply pass (Int *) NULL for P.  This is not an error
+	condition.  P is a complete permutation of all the rows of A; this
+	routine does not support the creation of a transposed submatrix of A
+	(R = A (1:3,:)' where A has more than 3 rows, for example, cannot be
+	done; a future version might support this operation).
+
+    Int Q [n_col] ;		Input argument, not modified.
+
+	The permutation vector Q is defined as Q [k] = j, where the original
+	column j of A is the kth column of PAQ.  If you want to use the identity
+	permutation for Q, simply pass (Int *) NULL for Q.  This is not an error
+	condition.  Q is a complete permutation of all the columns of A; this
+	routine does not support the creation of a transposed submatrix of A.
+
+    Int Rp [n_row+1] ;	Output argument.
+
+	The column pointers of the matrix R = (A (P,Q))' or (A (P,Q)).', in the
+	same form as the column pointers Ap for the matrix A.
+
+    Int Ri [nz] ;	Output argument.
+
+	The row indices of the matrix R = (A (P,Q))' or (A (P,Q)).' , in the
+	same form as the row indices Ai for the matrix A.
+
+    double Rx [nz] ;	Output argument.
+			Size 2*nz if Az or Rz are NULL.
+    double Rz [nz] ;	Output argument, imaginary part for complex versions.
+
+	If present, these are the numerical values of the sparse matrix R,
+	in the same form as the values Ax and Az of the matrix A.
+
+	If Az or Rz are NULL, then both real
+	and imaginary parts are contained in Rx[0..2*nz-1], with Rx[2*k]
+	and Rx[2*k+1] being the real and imaginary part of the kth entry.
+
+    Int do_conjugate ;	Input argument for complex versions only.
+
+	If true, and if Ax and Rx are present, then the linear
+	algebraic transpose is computed (complex conjugate).  If false, the
+	array transpose is computed instead.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_triplet_to_col.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_triplet_to_col.h
new file mode 100644
index 0000000..b519d86
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_triplet_to_col.h
@@ -0,0 +1,263 @@
+/* ========================================================================== */
+/* === umfpack_triplet_to_col =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_triplet_to_col
+(
+    int n_row,
+    int n_col,
+    int nz,
+    const int Ti [ ],
+    const int Tj [ ],
+    const double Tx [ ],
+    int Ap [ ],
+    int Ai [ ],
+    double Ax [ ],
+    int Map [ ]
+) ;
+
+UF_long umfpack_dl_triplet_to_col
+(
+    UF_long n_row,
+    UF_long n_col,
+    UF_long nz,
+    const UF_long Ti [ ],
+    const UF_long Tj [ ],
+    const double Tx [ ],
+    UF_long Ap [ ],
+    UF_long Ai [ ],
+    double Ax [ ],
+    UF_long Map [ ]
+) ;
+
+int umfpack_zi_triplet_to_col
+(
+    int n_row,
+    int n_col,
+    int nz,
+    const int Ti [ ],
+    const int Tj [ ],
+    const double Tx [ ], const double Tz [ ],
+    int Ap [ ],
+    int Ai [ ],
+    double Ax [ ], double Az [ ],
+    int Map [ ]
+) ;
+
+UF_long umfpack_zl_triplet_to_col
+(
+    UF_long n_row,
+    UF_long n_col,
+    UF_long nz,
+    const UF_long Ti [ ],
+    const UF_long Tj [ ],
+    const double Tx [ ], const double Tz [ ],
+    UF_long Ap [ ],
+    UF_long Ai [ ],
+    double Ax [ ], double Az [ ],
+    UF_long Map [ ]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int n_row, n_col, nz, *Ti, *Tj, *Ap, *Ai, status, *Map ;
+    double *Tx, *Ax ;
+    status = umfpack_di_triplet_to_col (n_row, n_col, nz, Ti, Tj, Tx,
+	Ap, Ai, Ax, Map) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long n_row, n_col, nz, *Ti, *Tj, *Ap, *Ai, status, *Map ;
+    double *Tx, *Ax ;
+    status = umfpack_dl_triplet_to_col (n_row, n_col, nz, Ti, Tj, Tx,
+	Ap, Ai, Ax, Map) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int n_row, n_col, nz, *Ti, *Tj, *Ap, *Ai, status, *Map ;
+    double *Tx, *Tz, *Ax, *Az ;
+    status = umfpack_zi_triplet_to_col (n_row, n_col, nz, Ti, Tj, Tx, Tz,
+	Ap, Ai, Ax, Az, Map) ;
+
+UF_long Syntax:
+
+    #include "umfpack.h"
+    UF_long n_row, n_col, nz, *Ti, *Tj, *Ap, *Ai, status, *Map ;
+    double *Tx, *Tz, *Ax, *Az ;
+    status = umfpack_zl_triplet_to_col (n_row, n_col, nz, Ti, Tj, Tx, Tz,
+	Ap, Ai, Ax, Az, Map) ;
+
+packed complex Syntax:
+
+    Same as above, except Tz and Az are NULL.
+
+Purpose:
+
+    Converts a sparse matrix from "triplet" form to compressed-column form.
+    Analogous to A = spconvert (Ti, Tj, Tx + Tz*1i) in MATLAB, except that
+    zero entries present in the triplet form are present in A.
+
+    The triplet form of a matrix is a very simple data structure for basic
+    sparse matrix operations.  For example, suppose you wish to factorize a
+    matrix A coming from a finite element method, in which A is a sum of
+    dense submatrices, A = E1 + E2 + E3 + ... .  The entries in each element
+    matrix Ei can be concatenated together in the three triplet arrays, and
+    any overlap between the elements will be correctly summed by
+    umfpack_*_triplet_to_col.
+
+    Transposing a matrix in triplet form is simple; just interchange the
+    use of Ti and Tj.  You can construct the complex conjugate transpose by
+    negating Tz, for the complex versions.
+
+    Permuting a matrix in triplet form is also simple.  If you want the matrix
+    PAQ, or A (P,Q) in MATLAB notation, where P [k] = i means that row i of
+    A is the kth row of PAQ and Q [k] = j means that column j of A is the kth
+    column of PAQ, then do the following.  First, create inverse permutations
+    Pinv and Qinv such that Pinv [i] = k if P [k] = i and Qinv [j] = k if
+    Q [k] = j.  Next, for the mth triplet (Ti [m], Tj [m], Tx [m], Tz [m]),
+    replace Ti [m] with Pinv [Ti [m]] and replace Tj [m] with Qinv [Tj [m]].
+
+    If you have a column-form matrix with duplicate entries or unsorted
+    columns, you can sort it and sum up the duplicates by first converting it
+    to triplet form with umfpack_*_col_to_triplet, and then converting it back
+    with umfpack_*_triplet_to_col.
+
+    Constructing a submatrix is also easy.  Just scan the triplets and remove
+    those entries outside the desired subset of 0...n_row-1 and 0...n_col-1,
+    and renumber the indices according to their position in the subset.
+
+    You can do all these operations on a column-form matrix by first
+    converting it to triplet form with umfpack_*_col_to_triplet, doing the
+    operation on the triplet form, and then converting it back with
+    umfpack_*_triplet_to_col.
+
+    The only operation not supported easily in the triplet form is the
+    multiplication of two sparse matrices (UMFPACK does not provide this
+    operation).
+
+    You can print the input triplet form with umfpack_*_report_triplet, and
+    the output matrix with umfpack_*_report_matrix.
+
+    The matrix may be singular (nz can be zero, and empty rows and/or columns
+    may exist).  It may also be rectangular and/or complex.
+
+Returns:
+
+    UMFPACK_OK if successful.
+    UMFPACK_ERROR_argument_missing if Ap, Ai, Ti, and/or Tj are missing.
+    UMFPACK_ERROR_n_nonpositive if n_row <= 0 or n_col <= 0.
+    UMFPACK_ERROR_invalid_matrix if nz < 0, or if for any k, Ti [k] and/or
+	Tj [k] are not in the range 0 to n_row-1 or 0 to n_col-1, respectively.
+    UMFPACK_ERROR_out_of_memory if unable to allocate sufficient workspace.
+
+Arguments:
+
+    Int n_row ;		Input argument, not modified.
+    Int n_col ;		Input argument, not modified.
+
+	A is an n_row-by-n_col matrix.  Restriction: n_row > 0 and n_col > 0.
+	All row and column indices in the triplet form must be in the range
+	0 to n_row-1 and 0 to n_col-1, respectively.
+
+    Int nz ;		Input argument, not modified.
+
+	The number of entries in the triplet form of the matrix.  Restriction:
+	nz >= 0.
+
+    Int Ti [nz] ;	Input argument, not modified.
+    Int Tj [nz] ;	Input argument, not modified.
+    double Tx [nz] ;	Input argument, not modified.
+			Size 2*nz if Tz or Az are NULL.
+    double Tz [nz] ;	Input argument, not modified, for complex versions.
+
+	Ti, Tj, Tx, and Tz hold the "triplet" form of a sparse matrix.  The kth
+	nonzero entry is in row i = Ti [k], column j = Tj [k], and the real part
+	of a_ij is Tx [k].  The imaginary part of a_ij is Tz [k], for complex
+	versions.  The row and column indices i and j must be in the range 0 to
+	n_row-1 and 0 to n_col-1, respectively.  Duplicate entries may be
+	present; they are summed in the output matrix.  This is not an error
+	condition.  The "triplets" may be in any order.  Tx, Tz, Ax, and Az
+	are optional.  Ax is computed only if both Ax and Tx are present
+	(not (double *) NULL).  This is not error condition; the routine can
+	create just the pattern of the output matrix from the pattern of the
+	triplets.
+
+	If Az or Tz are NULL, then both real
+	and imaginary parts are contained in Tx[0..2*nz-1], with Tx[2*k]
+	and Tx[2*k+1] being the real and imaginary part of the kth entry.
+
+    Int Ap [n_col+1] ;	Output argument.
+
+	Ap is an integer array of size n_col+1 on input.  On output, Ap holds
+	the "pointers" for the column form of the sparse matrix A.  Column j of
+	the matrix A is held in Ai [(Ap [j]) ... (Ap [j+1]-1)].  The first
+	entry, Ap [0], is zero, and Ap [j] <= Ap [j+1] holds for all j in the
+	range 0 to n_col-1.  The value nz2 = Ap [n_col] is thus the total
+	number of entries in the pattern of the matrix A.  Equivalently, the
+	number of duplicate triplets is nz - Ap [n_col].
+
+    Int Ai [nz] ;	Output argument.
+
+	Ai is an integer array of size nz on input.  Note that only the first
+	Ap [n_col] entries are used.
+
+	The nonzero pattern (row indices) for column j is stored in
+	Ai [(Ap [j]) ... (Ap [j+1]-1)].  The row indices in a given column j
+	are in ascending order, and no duplicate row indices are present.
+	Row indices are in the range 0 to n_col-1 (the matrix is 0-based).
+
+    double Ax [nz] ;	Output argument.  Size 2*nz if Tz or Az are NULL.
+    double Az [nz] ;	Output argument for complex versions.
+
+	Ax and Az (for the complex versions) are double arrays of size nz on
+	input.  Note that only the first Ap [n_col] entries are used
+	in both arrays.
+
+	Ax is optional; if Tx and/or Ax are not present (a (double *) NULL
+	pointer), then Ax is not computed.  If present, Ax holds the
+	numerical values of the the real part of the sparse matrix A and Az
+	holds the imaginary parts.  The nonzero pattern (row indices) for
+	column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and the
+	corresponding numerical values are stored in
+	Ax [(Ap [j]) ... (Ap [j+1]-1)].  The imaginary parts are stored in
+	Az [(Ap [j]) ... (Ap [j+1]-1)], for the complex versions.
+
+	If Az or Tz are NULL, then both real
+	and imaginary parts are returned in Ax[0..2*nz2-1], with Ax[2*k]
+	and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+    int Map [nz] ;	Optional output argument.
+
+	If Map is present (a non-NULL pointer to an Int array of size nz), then
+	on output it holds the position of the triplets in the column-form
+	matrix.  That is, suppose p = Map [k], and the k-th triplet is i=Ti[k],
+	j=Tj[k], and aij=Tx[k].  Then i=Ai[p], and aij will have been summed
+	into Ax[p] (or simply aij=Ax[p] if there were no duplicate entries also
+	in row i and column j).  Also, Ap[j] <= p < Ap[j+1].  The Map array is
+	not computed if it is (Int *) NULL.  The Map array is useful for
+	converting a subsequent triplet form matrix with the same pattern as the
+	first one, without calling this routine.  If Ti and Tj do not change,
+	then Ap, and Ai can be reused from the prior call to
+	umfpack_*_triplet_to_col.  You only need to recompute Ax (and Az for the
+	split complex version).  This code excerpt properly sums up all
+	duplicate values (for the real version):
+
+	    for (p = 0 ; p < Ap [n_col] ; p++) Ax [p] = 0 ;
+	    for (k = 0 ; k < nz ; k++) Ax [Map [k]] += Tx [k] ;
+
+	This feature is useful (along with the reuse of the Symbolic object) if
+	you need to factorize a sequence of triplet matrices with identical
+	nonzero pattern (the order of the triplets in the Ti,Tj,Tx arrays must
+	also remain unchanged).  It is faster than calling this routine for
+	each matrix, and requires no workspace.
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Include/umfpack_wsolve.h b/src/C/SuiteSparse/UMFPACK/Include/umfpack_wsolve.h
new file mode 100644
index 0000000..c2ed033
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Include/umfpack_wsolve.h
@@ -0,0 +1,172 @@
+/* ========================================================================== */
+/* === umfpack_wsolve ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_wsolve
+(
+    int sys,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ],
+    double X [ ],
+    const double B [ ],
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO],
+    int Wi [ ],
+    double W [ ]
+) ;
+
+UF_long umfpack_dl_wsolve
+(
+    UF_long sys,
+    const UF_long Ap [ ],
+    const UF_long Ai [ ],
+    const double Ax [ ],
+    double X [ ],
+    const double B [ ],
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO],
+    UF_long Wi [ ],
+    double W [ ]
+) ;
+
+int umfpack_zi_wsolve
+(
+    int sys,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    double Xx [ ],	 double Xz [ ],
+    const double Bx [ ], const double Bz [ ],
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO],
+    int Wi [ ],
+    double W [ ]
+) ;
+
+UF_long umfpack_zl_wsolve
+(
+    UF_long sys,
+    const UF_long Ap [ ],
+    const UF_long Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    double Xx [ ],	 double Xz [ ],
+    const double Bx [ ], const double Bz [ ],
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO],
+    UF_long Wi [ ],
+    double W [ ]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int status, *Ap, *Ai, *Wi, sys ;
+    double *B, *X, *Ax, *W, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+    status = umfpack_di_wsolve (sys, Ap, Ai, Ax, X, B, Numeric,
+	Control, Info, Wi, W) ;
+
+double UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    UF_long status, *Ap, *Ai, *Wi, sys ;
+    double *B, *X, *Ax, *W, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+    status = umfpack_dl_wsolve (sys, Ap, Ai, Ax, X, B, Numeric,
+	Control, Info, Wi, W) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int status, *Ap, *Ai, *Wi, sys ;
+    double *Bx, *Bz, *Xx, *Xz, *Ax, *Az, *W,
+	Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+    status = umfpack_zi_wsolve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric,
+	Control, Info, Wi, W) ;
+
+complex UF_long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    UF_long status, *Ap, *Ai, *Wi, sys ;
+    double *Bx, *Bz, *Xx, *Xz, *Ax, *Az, *W,
+	Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+    status = umfpack_zl_wsolve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric,
+	Control, Info, Wi, W) ;
+
+packed complex Syntax:
+
+    Same as above, except Az, Xz, and Bz are NULL.
+
+Purpose:
+
+    Given LU factors computed by umfpack_*_numeric (PAQ=LU) and the
+    right-hand-side, B, solve a linear system for the solution X.  Iterative
+    refinement is optionally performed.  This routine is identical to
+    umfpack_*_solve, except that it does not dynamically allocate any workspace.
+    When you have many linear systems to solve, this routine is faster than
+    umfpack_*_solve, since the workspace (Wi, W) needs to be allocated only
+    once, prior to calling umfpack_*_wsolve.
+
+Returns:
+
+    The status code is returned.  See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+    Int sys ;		Input argument, not modified.
+    Int Ap [n+1] ;	Input argument, not modified.
+    Int Ai [nz] ;	Input argument, not modified.
+    double Ax [nz] ;	Input argument, not modified.
+			Size 2*nz in packed complex case.
+    double X [n] ;	Output argument.
+    double B [n] ;	Input argument, not modified.
+    void *Numeric ;	Input argument, not modified.
+    double Control [UMFPACK_CONTROL] ;	Input argument, not modified.
+    double Info [UMFPACK_INFO] ;	Output argument.
+
+    for complex versions:
+    double Az [nz] ;	Input argument, not modified, imaginary part
+    double Xx [n] ;	Output argument, real part.
+			Size 2*n in packed complex case.
+    double Xz [n] ;	Output argument, imaginary part
+    double Bx [n] ;	Input argument, not modified, real part.
+			Size 2*n in packed complex case.
+    double Bz [n] ;	Input argument, not modified, imaginary part
+
+	The above arguments are identical to umfpack_*_solve, except that the
+	error code UMFPACK_ERROR_out_of_memory will not be returned in
+	Info [UMFPACK_STATUS], since umfpack_*_wsolve does not allocate any
+	memory.
+
+    Int Wi [n] ;		Workspace.
+    double W [c*n] ;		Workspace, where c is defined below.
+
+	The Wi and W arguments are workspace used by umfpack_*_wsolve.  They
+	need not be initialized on input, and their contents are undefined on
+	output.  The size of W depends on whether or not iterative refinement is
+	used, and which version (real or complex) is called.  Iterative
+	refinement is performed if Ax=b, A'x=b, or A.'x=b is being solved,
+	Control [UMFPACK_IRSTEP] > 0, and A is nonsingular.  The size of W is
+	given below:
+
+				no iter.	with iter.
+				refinement	refinement
+	umfpack_di_wsolve	n		5*n
+	umfpack_dl_wsolve	n		5*n
+	umfpack_zi_wsolve	4*n		10*n
+	umfpack_zl_wsolve	4*n		10*n
+*/
diff --git a/src/C/SuiteSparse/UMFPACK/Lib/libumfpack.def b/src/C/SuiteSparse/UMFPACK/Lib/libumfpack.def
new file mode 100644
index 0000000..72e6991
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Lib/libumfpack.def
@@ -0,0 +1,105 @@
+LIBRARY libumfpack.dll
+EXPORTS
+umfpack_di_col_to_triplet
+umfpack_di_defaults
+umfpack_di_free_numeric
+umfpack_di_free_symbolic
+umfpack_di_get_numeric
+umfpack_di_get_lunz
+umfpack_di_get_symbolic
+umfpack_di_get_determinant
+umfpack_di_numeric
+umfpack_di_qsymbolic
+umfpack_di_report_control
+umfpack_di_report_info
+umfpack_di_report_matrix
+umfpack_di_report_numeric
+umfpack_di_report_perm
+umfpack_di_report_status
+umfpack_di_report_symbolic
+umfpack_di_report_triplet
+umfpack_di_report_vector
+umfpack_di_solve
+umfpack_di_wsolve
+umfpack_di_symbolic
+umfpack_di_transpose
+umfpack_di_triplet_to_col
+umfpack_di_scale
+umfpack_dl_col_to_triplet
+umfpack_dl_defaults
+umfpack_dl_free_numeric
+umfpack_dl_free_symbolic
+umfpack_dl_get_numeric
+umfpack_dl_get_lunz
+umfpack_dl_get_symbolic
+umfpack_dl_get_determinant
+umfpack_dl_numeric
+umfpack_dl_qsymbolic
+umfpack_dl_report_control
+umfpack_dl_report_info
+umfpack_dl_report_matrix
+umfpack_dl_report_numeric
+umfpack_dl_report_perm
+umfpack_dl_report_status
+umfpack_dl_report_symbolic
+umfpack_dl_report_triplet
+umfpack_dl_report_vector
+umfpack_dl_solve
+umfpack_dl_wsolve
+umfpack_dl_symbolic
+umfpack_dl_transpose
+umfpack_dl_triplet_to_col
+umfpack_dl_scale
+umfpack_zi_col_to_triplet
+umfpack_zi_defaults
+umfpack_zi_free_numeric
+umfpack_zi_free_symbolic
+umfpack_zi_get_numeric
+umfpack_zi_get_lunz
+umfpack_zi_get_symbolic
+umfpack_zi_get_determinant
+umfpack_zi_numeric
+umfpack_zi_qsymbolic
+umfpack_zi_report_control
+umfpack_zi_report_info
+umfpack_zi_report_matrix
+umfpack_zi_report_numeric
+umfpack_zi_report_perm
+umfpack_zi_report_status
+umfpack_zi_report_symbolic
+umfpack_zi_report_triplet
+umfpack_zi_report_vector
+umfpack_zi_solve
+umfpack_zi_wsolve
+umfpack_zi_symbolic
+umfpack_zi_transpose
+umfpack_zi_triplet_to_col
+umfpack_zi_scale
+umfpack_zl_col_to_triplet
+umfpack_zl_defaults
+umfpack_zl_free_numeric
+umfpack_zl_free_symbolic
+umfpack_zl_get_numeric
+umfpack_zl_get_lunz
+umfpack_zl_get_symbolic
+umfpack_zl_get_determinant
+umfpack_zl_numeric
+umfpack_zl_qsymbolic
+umfpack_zl_report_control
+umfpack_zl_report_info
+umfpack_zl_report_matrix
+umfpack_zl_report_numeric
+umfpack_zl_report_perm
+umfpack_zl_report_status
+umfpack_zl_report_symbolic
+umfpack_zl_report_triplet
+umfpack_zl_report_vector
+umfpack_zl_solve
+umfpack_zl_wsolve
+umfpack_zl_symbolic
+umfpack_zl_transpose
+umfpack_zl_triplet_to_col
+umfpack_zl_scale
+umfpack_timer
+umfpack_tic
+umfpack_toc
diff --git a/src/C/SuiteSparse/UMFPACK/Makefile b/src/C/SuiteSparse/UMFPACK/Makefile
new file mode 100644
index 0000000..07afd04
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Makefile
@@ -0,0 +1,74 @@
+#-------------------------------------------------------------------------------
+# UMFPACK makefile (for GNU make or original make)
+#-------------------------------------------------------------------------------
+
+# UMFPACK requires the AMD package to be in ../AMD
+
+default: library
+
+include ../UFconfig/UFconfig.mk
+
+# compile all C code (except hb, fortran, and fortran64), including AMD and the
+# MATLAB mexFunctions
+all:
+	( cd ../AMD ; $(MAKE) )
+	( cd ../AMD/MATLAB ; $(MAKE) )
+	( cd Source ; $(MAKE) )
+	( cd Demo   ; $(MAKE) )
+	( cd MATLAB ; $(MAKE) )
+	- cat Doc/License
+
+# compile just the C-callable libraries and demo programs (not mexFunctions)
+library:
+	( cd ../AMD ; $(MAKE) )
+	( cd Source ; $(MAKE) )
+	( cd Demo   ; $(MAKE) )
+	- cat Doc/License
+
+# compile the FORTRAN interface and demo program
+fortran:
+	( cd Demo   ; $(MAKE) fortran )
+
+# compile the 64-bit FORTRAN interface and demo program
+fortran64:
+	( cd Demo   ; $(MAKE) fortran64 )
+
+# compile the Harwell/Boeing demo program
+hb:
+	( cd Demo   ; $(MAKE) hb )
+
+# remove object files, but keep the compiled programs and library archives
+clean:
+	( cd ../AMD ; $(MAKE) clean )
+	( cd Source ; $(MAKE) clean )
+	( cd Demo   ; $(MAKE) clean )
+	( cd MATLAB ; $(MAKE) clean )
+	( cd Doc    ; $(MAKE) clean )
+
+# clean, and then remove compiled programs and library archives
+purge:
+	( cd ../AMD ; $(MAKE) purge )
+	( cd Source ; $(MAKE) purge )
+	( cd Demo   ; $(MAKE) purge )
+	( cd MATLAB ; $(MAKE) purge )
+	( cd Doc    ; $(MAKE) purge )
+
+# create PDF documents for the original distribution
+doc:
+	( cd ../AMD ; $(MAKE) doc )
+	( cd Doc    ; $(MAKE) )
+
+# get ready for distribution
+dist: purge
+	( cd ../AMD ; $(MAKE) dist )
+	( cd Demo   ; $(MAKE) dist )
+	( cd Doc    ; $(MAKE) )
+
+distclean: purge
+
+ccode: library
+
+# compile the MATLAB mexFunction
+mex:
+	( cd ../AMD/MATLAB ; $(MAKE) )
+	( cd MATLAB ; $(MAKE) )
diff --git a/src/C/SuiteSparse/UMFPACK/README.txt b/src/C/SuiteSparse/UMFPACK/README.txt
new file mode 100644
index 0000000..61ed73c
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/README.txt
@@ -0,0 +1,409 @@
+UMFPACK Version 5.0.2:  a set of routines solving sparse linear systems via LU
+    factorization.  Requires three other packages:  the BLAS (dense matrix
+    operations), AMD (sparse matrix minimum degree ordering), and UFconfig.
+    Includes a C-callable and MATLAB interface, and a basic FORTRAN 77
+    interface to a subset of the C-callable routines.  Requires AMD Version
+    2.0 or later.
+
+The AMD, UFconfig, and UMFPACK directories must all reside in the same parent
+directory.
+
+Quick start (Unix, or Windows with Cygwin):
+
+    To compile, test, and install both UMFPACK and AMD, the UMFPACK and AMD
+    directories must be in the same parent directory.  To configure, edit
+    the UFconfig/UFconfig.mk file (otherwise, you may get warnings that the
+    BLAS (dgemm, etc) are not found).  You may use UMFPACK_CONFIG = -DNBLAS in
+    the UFconfig/UFconfig.mk file, to avoid using the BLAS, but UMFPACK will be
+    slow.  Next, cd to this directory (UMFPACK) and type "make".  To compile
+    and run a FORTRAN demo program for Harwell/Boeing matrices, type "make hb".
+    To compile a FORTRAN main program that calls the 32-bit C-callable UMFPACK
+    library, type "make fortran".  When done, type "make clean" to remove
+    unused *.o files (keeps the compiled libraries and demo programs).  See
+    the User Guide (Doc/UserGuide.pdf), or ../UFconfig/UFconfig.mk for more
+    details (including options for compiling in 64-bit mode).
+
+Quick start (for MATLAB users):
+
+    To compile, test, and install the UMFPACK mexFunction, cd to the
+    UMFPACK/MATLAB directory and type umfpack_make at the MATLAB prompt.
+
+    NOTE: DO NOT ATTEMPT TO USE THIS CODE IN 64-BIT MATLAB (v7.3).
+    It is not yet ported to that version of MATLAB.
+
+--------------------------------------------------------------------------------
+
+UMFPACK, Copyright (c) 1995-2006 by Timothy A.  Davis.  All Rights Reserved.
+UMFPACK is available under alternate licences; contact T. Davis for details.
+
+UMFPACK License:
+
+    Your use or distribution of UMFPACK or any modified version of
+    UMFPACK implies that you agree to this License.
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+    USA
+
+    Permission is hereby granted to use or copy this program under the
+    terms of the GNU LGPL, provided that the Copyright, this License,
+    and the Availability of the original version is retained on all copies.
+    User documentation of any code that uses this code or any modified
+    version of this code must cite the Copyright, this License, the
+    Availability note, and "Used by permission." Permission to modify
+    the code and to distribute modified code is granted, provided the
+    Copyright, this License, and the Availability note are retained,
+    and a notice that the code was modified is included.
+
+Availability:
+
+    http://www.cise.ufl.edu/research/sparse/umfpack
+
+    UMFPACK (including versions 2.2.1 and earlier, in FORTRAN) is available at
+    http://www.cise.ufl.edu/research/sparse.  MA38 is available in the Harwell
+    Subroutine Library.  This version of UMFPACK includes a modified form of
+    COLAMD Version 2.0, originally released on Jan. 31, 2000, also available at
+    http://www.cise.ufl.edu/research/sparse.  COLAMD V2.0 is also incorporated
+    as a built-in function in MATLAB version 6.1, by The MathWorks, Inc.
+    (http://www.mathworks.com).  COLAMD V1.0 appears as a column-preordering
+    in SuperLU (SuperLU is available at http://www.netlib.org).
+    UMFPACK v4.0 is a built-in routine in MATLAB 6.5.
+    UMFPACK v4.3 is a built-in routine in MATLAB 7.1.
+
+--------------------------------------------------------------------------------
+
+Refer to ../AMD/README for the License for AMD, which is a separate
+package for ordering sparse matrices that is required by UMFPACK.
+UMFPACK v4.5 cannot use AMD v1.1 or earlier.  UMFPACK 5.0
+requires AMD v2.0 or later.
+
+--------------------------------------------------------------------------------
+
+This is the UMFPACK README.txt file.  It is a terse overview of UMFPACK.
+Refer to the User Guide (Doc/UserGuide.pdf) for how to install and use UMFPACK,
+or to the Quick Start Guide, QuickStart.pdf.
+
+Description:
+
+    UMFPACK is a set of routines for solving unsymmetric sparse linear systems,
+    Ax=b, using the Unsymmetric MultiFrontal method.  Written in ANSI/ISO C,
+    with a MATLAB (Version 6.0 or later) interface.
+
+    For best performance, UMFPACK requires an optimized BLAS library.  It can
+    also be compiled without any BLAS at all.  UMFPACK requires AMD Version 2.0.
+
+Authors:
+
+    Timothy A. Davis (davis at cise.ufl.edu), University of Florida.
+
+    Includes a modified version of COLAMD V2.0, by Stefan I. Larimore and
+    Timothy A. Davis, University of Florida.  The COLAMD algorithm was developed
+    in collaboration with John Gilbert, Xerox Palo Alto Research Center, and
+    Esmond Ng, Lawrence Berkeley National Laboratory.
+
+    Includes AMD, by Timothy A. Davis, Patrick R. Amestoy, and Iain S. Duff.
+
+    UMFPACK Version 2.2.1 (MA38 in the Harwell Subroutine Library) is
+    co-authored with Iain S. Duff, Rutherford Appleton Laboratory.
+
+Acknowledgements:
+
+    This work was supported by the National Science Foundation, under
+    grants DMS-9504974, DMS-9803599, and CCR-0203270.
+
+    Portions of this work were done while on sabbatical at Stanford University
+    and Lawrence Berkeley National Laboratory (with funding from the SciDAC
+    program).  I would like to thank Gene Golub, Esmond Ng, and Horst Simon
+    for making this sabbatical possible.
+
+    I would also like to thank the many researchers who provided sparse
+    matrices from a wide range of domains and used earlier versions of UMFPACK/
+    MA38 in their applications, and thus assisted in the practical development
+    of the algorithm (see http://www.cise.ufl.edu/research/sparse, future
+    contributions of matrices are always welcome).
+
+    The MathWorks, Inc., provided a pre-release of MATLAB V6 which allowed me
+    to release the first umfpack mexFunction (v3.0) about 6 months earlier than
+    I had originally planned.  They also supported the extension of UMFPACK to
+    complex, singular, and rectangular matrices (UMFPACK v4.0).
+
+    Penny Anderson (The MathWorks, Inc.), Anshul Gupta (IBM), and Friedrich
+    Grund (WAIS) assisted in porting UMFPACK to different platforms.  Penny
+    Anderson also incorporated UMFPACK v4.0 into MATLAB, for lu, backslash (\),
+    and forward slash (/).
+
+    David Bateman (Motorola) wrote the initial version of the packed complex
+    input option, and umfpack_get_determinant.
+
+--------------------------------------------------------------------------------
+Files and directories in the UMFPACK distribution:
+--------------------------------------------------------------------------------
+
+    ----------------------------------------------------------------------------
+    Subdirectories of the UMFPACK directory:
+    ----------------------------------------------------------------------------
+
+    Doc		documentation
+    Source	primary source code
+    Include	include files for use in your code that calls UMFPACK
+    Demo	demo programs.  also serves as test of the UMFPACK installation.
+    MATLAB	UMFPACK mexFunction for MATLAB, and supporting m-files
+    Lib		where the compiled C-callable UMFPACK library is placed.
+
+    ----------------------------------------------------------------------------
+    Files in the UMFPACK directory:
+    ----------------------------------------------------------------------------
+
+    Makefile	top-level Makefile for GNU make or original make.
+		Windows users would require Cygwin to use "make"
+
+    README.txt	this file
+
+    ----------------------------------------------------------------------------
+    Doc directory: documentation
+    ----------------------------------------------------------------------------
+
+    ChangeLog			change log
+    License			the UMFPACK License
+    Makefile			for creating the documentation
+    QuickStart.tex		Quick Start guide (source)
+    QuickStart.pdf		Quick Start guide (PDF)
+    UserGuide.bib		User Guide (references)
+    UserGuide.sed1		sed script for processing UserGuide.stex
+    UserGuide.sed2		sed script for processing UserGuide.stex
+    UserGuide.stex		User Guide (LaTeX)
+    UserGuide.pdf		User Guide (PDF)
+
+    ----------------------------------------------------------------------------
+    Source directory:
+    ----------------------------------------------------------------------------
+
+    GNUmakefile			a nice Makefile, for GNU make
+    Makefile			an ugly Unix Makefile (for older make's)
+
+    cholmod_blas.h		an exact copy of CHOLMOD/Include/cholmod_blas.h
+
+    umfpack_col_to_triplet.c	convert col form to triplet
+    umfpack_defaults.c		set Control defaults
+    umfpack_free_numeric.c	free Numeric object
+    umfpack_free_symbolic.c	free Symbolic object
+    umfpack_get_determinant.c	compute determinant from Numeric object
+    umfpack_get_lunz.c		get nz's in L and U
+    umfpack_get_numeric.c	get Numeric object
+    umfpack_get_symbolic.c	get Symbolic object
+    umfpack_load_numeric.c	load Numeric object from file
+    umfpack_load_symbolic.c	load Symbolic object from file
+    umfpack_numeric.c		numeric factorization
+    umfpack_qsymbolic.c		symbolic factorization, user Q
+    umfpack_report_control.c	print Control settings
+    umfpack_report_info.c	print Info statistics
+    umfpack_report_matrix.c	print col or row-form sparse matrix
+    umfpack_report_numeric.c	print Numeric object
+    umfpack_report_perm.c	print permutation
+    umfpack_report_status.c	print return status
+    umfpack_report_symbolic.c	print Symbolic object
+    umfpack_report_triplet.c	print triplet matrix
+    umfpack_report_vector.c	print dense vector
+    umfpack_save_numeric.c	save Numeric object to file
+    umfpack_save_symbolic.c	save Symbolic object to file
+    umfpack_scale.c		scale a vector
+    umfpack_solve.c		solve a linear system
+    umfpack_symbolic.c		symbolic factorization
+    umfpack_tictoc.c		timer
+    umfpack_timer.c		timer
+    umfpack_transpose.c		transpose a matrix
+    umfpack_triplet_to_col.c	convert triplet to col form
+
+    umf_config.h		configuration file (BLAS, memory, timer)
+    umf_internal.h		definitions internal to UMFPACK
+    umf_version.h		version definitions (int/UF_long, real/complex)
+
+    umf_2by2.[ch]
+    umf_analyze.[ch]		symbolic factorization of A'*A
+    umf_apply_order.[ch]	apply column etree postorder
+    umf_assemble.[ch]		assemble elements into current front
+    umf_blas3_update.[ch]	rank-k update.  Uses level-3 BLAS
+    umf_build_tuples.[ch]	construct tuples for elements
+    umf_colamd.[ch]		COLAMD pre-ordering, modified for UMFPACK
+    umf_create_element.[ch]	create a new element
+    umf_dump.[ch]		debugging routines, not normally active
+    umf_extend_front.[ch]	extend the current frontal matrix
+    umf_free.[ch]		free memory
+    umf_fsize.[ch]		determine largest front in each subtree
+    umf_garbage_collection.[ch]	compact Numeric->Memory
+    umf_get_memory.[ch]		make Numeric->Memory bigger
+    umf_grow_front.[ch]		make current frontal matrix bigger
+    umf_init_front.[ch]		initialize a new frontal matrix
+    umf_is_permutation.[ch]	checks the validity of a permutation vector
+    umf_kernel.[ch]		the main numeric factorization kernel
+    umf_kernel_init.[ch]	initializations for umf_kernel
+    umf_kernel_wrapup.[ch]	wrapup for umf_kernel
+    umf_local_search.[ch]	local row and column pivot search
+    umf_lsolve.[ch]		solve Lx=b
+    umf_ltsolve.[ch]		solve L'x=b and L.'x=b
+    umf_malloc.[ch]		malloc some memory
+    umf_mem_alloc_element.[ch]		allocate element in Numeric->Memory
+    umf_mem_alloc_head_block.[ch]	alloc. block at head of Numeric->Memory
+    umf_mem_alloc_tail_block.[ch]	alloc. block at tail of Numeric->Memory
+    umf_mem_free_tail_block.[ch]	free block at tail of Numeric->Memory
+    umf_mem_init_memoryspace.[ch]	initialize Numeric->Memory
+    umf_realloc.[ch]		realloc memory
+    umf_report_perm.[ch]	print a permutation vector
+    umf_report_vector.[ch]	print a double vector
+    umf_row_search.[ch]		look for a pivot row
+    umf_scale.[ch]		scale the pivot column
+    umf_scale_column.[ch]	move pivot row & column into place, log P and Q
+    umf_set_stats.[ch]		set statistics (final or estimates)
+    umf_singletons.[ch]		find all zero-cost pivots
+    umf_solve.[ch]		solve a linear system
+    umf_start_front.[ch]	start a new frontal matrix for one frontal chain
+    umf_store_lu.[ch]		store LU factors of current front
+    umf_symbolic_usage.[ch]	determine memory usage for Symbolic object
+    umf_transpose.[ch]		transpose a matrix in row or col form
+    umf_triplet.[ch]		convert triplet to column form
+    umf_tuple_lengths.[ch]	determine the tuple list lengths
+    umf_usolve.[ch]		solve Ux=b
+    umf_utsolve.[ch]		solve U'x=b and U.'x=b
+    umf_valid_numeric.[ch]	checks the validity of a Numeric object
+    umf_valid_symbolic.[ch]	check the validity of a Symbolic object
+
+    ----------------------------------------------------------------------------
+    Include directory:
+    ----------------------------------------------------------------------------
+
+    umfpack.h			include file for user programs.  Includes all of
+				the following files.  This serves are source-
+				code level documenation.  These files are also
+				used to construct the User Guide.
+
+    umfpack_col_to_triplet.h
+    umfpack_defaults.h
+    umfpack_free_numeric.h
+    umfpack_free_symbolic.h
+    umfpack_get_determinant.h
+    umfpack_get_lunz.h
+    umfpack_get_numeric.h
+    umfpack_get_symbolic.h
+    umfpack_load_numeric.h
+    umfpack_load_symbolic.h
+    umfpack_numeric.h
+    umfpack_qsymbolic.h
+    umfpack_report_control.h
+    umfpack_report_info.h
+    umfpack_report_matrix.h
+    umfpack_report_numeric.h
+    umfpack_report_perm.h
+    umfpack_report_status.h
+    umfpack_report_symbolic.h
+    umfpack_report_triplet.h
+    umfpack_report_vector.h
+    umfpack_save_numeric.h
+    umfpack_save_symbolic.h
+    umfpack_scale.h
+    umfpack_solve.h
+    umfpack_symbolic.h
+    umfpack_tictoc.h
+    umfpack_timer.h
+    umfpack_transpose.h
+    umfpack_triplet_to_col.h
+
+    umfpack_wsolve.h		note that there is no umfpack_wsolve.c.  The
+				umfpack_*_wsolve routines are created from the
+				umfpack_solve.c file.
+
+    ----------------------------------------------------------------------------
+    Demo directory:
+    ----------------------------------------------------------------------------
+
+    Makefile			for GNU make or original make
+
+    umfpack_simple.c		a simple demo
+    umpack_xx_demo.c		template to create the demo codes below
+
+    umfpack_di_demo.sed		for creating umfpack_di_demo.c
+    umfpack_dl_demo.sed		for creating umfpack_dl_demo.c
+    umfpack_zi_demo.sed		for creating umfpack_zi_demo.c
+    umfpack_zl_demo.sed		for creating umfpack_zl_demo.c
+
+    umfpack_di_demo.c		a full demo (real/int version)
+    umfpack_dl_demo.c		a full demo (real/UF_long version)
+    umfpack_zi_demo.c		a full demo (complex/int version)
+    umfpack_zl_demo.c		a full demo (complex/UF_long version)
+
+    umfpack_di_demo.out		umfpack_di_demo output
+    umfpack_dl_demo.out		umfpack_dl_demo output
+    umfpack_zi_demo.out		umfpack_zi_demo output
+    umfpack_zl_demo.out		umfpack_zl_demo output
+
+    umf4.c			a demo (real/int) for Harwell/Boeing matrices
+    umf4.out			output of "make hb"
+    HB				directory of sample Harwell/Boeing matrices
+    readhb.f			reads HB matrices, keeps zero entries
+    readhb_nozeros.f		reads HB matrices, removes zero entries
+    readhb_size.f		reads HB matrix dimension, nnz
+    tmp				empty directory for umf4.c demo
+
+    umf4_f77wrapper.c		a simple FORTRAN interface for UMFPACK.
+				compile with "make fortran"
+    umf4hb.f			a demo of the FORTRAN interface
+    umf4hb.out			output of "make fortran"
+
+    umf4_f77zwrapper.c		a simple FORTRAN interface for the complex
+				UMFPACK routines.  compile with "make fortran"
+    umf4zhb.f			a demo of the FORTRAN interface (complex)
+    umf4zhb.out			output of umf4zhb with HB/qc324.cua
+
+    umf4hb64.f			64-bit version of umf4hb.f
+
+    simple_compile		a single command that compiles the double/int
+				version of UMFPACK (useful prototype for
+				Microsoft Visual Studio project)
+
+    Opteron64/			demo output files on an AMD Opteron
+
+    ----------------------------------------------------------------------------
+    MATLAB directory:
+    ----------------------------------------------------------------------------
+
+    Contents.m			for "help umfpack" listing of toolbox contents
+    GNUmakefile			a nice Makefile, for GNU make
+    Makefile			an ugly Unix Makefile (for older make's)
+
+    lu_normest.m		1-norm estimate of A-L*U (by Hager & Davis).
+    luflop.m			for "help luflop"
+    luflopmex.c			luflop mexFunction, for computing LU flop count
+    umfpack.m			for "help umfpack"
+    umfpack_btf.m		solve Ax=b using umfpack and dmperm
+    umfpack_demo.m		a full umfpack demo
+    umfpack_details.m		the details of how to use umfpack
+    umfpack_make.m		compile the umfpack mexFunction within MATLAB
+    umfpack_report.m		report statistics
+    umfpack_simple.m		a simple umfpack demo
+    umfpack_solve.m		x=A\b or b/A for arbitrary b
+    umfpack_test.m		extensive test, requires UF sparse matrices
+    umfpackmex.c		the umfpack mexFunction
+    west0067.mat		sparse matrix for umfpack_demo.m
+
+    umfpack_demo.m.out		output of umfpack_demo.m
+    umfpack_demo.m.out_verbose	ditto, but with print level 2, on AMD Opteron
+    umfpack_simple.m.out	output of umfpack_simple
+
+    lcc_lib/lapacksyms.def	LAPACK definitions for lcc compiler (Windows)
+    lcc_lib/libmwlapack.lib	LAPACK definitions for lcc compiler (Windows)
+
+    ----------------------------------------------------------------------------
+    Lib directory:  libumfpack.a library placed here
+    ----------------------------------------------------------------------------
+
+    libumfpack.def		UMPFACK definitions for Windows
diff --git a/src/C/SuiteSparse/UMFPACK/Source/GNUmakefile b/src/C/SuiteSparse/UMFPACK/Source/GNUmakefile
new file mode 100644
index 0000000..1326653
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/GNUmakefile
@@ -0,0 +1,257 @@
+#-------------------------------------------------------------------------------
+# UMFPACK Makefile for compiling on Unix systems (for GNU Make)
+#-------------------------------------------------------------------------------
+
+default: ../Lib/libumfpack.a
+
+include ../../UFconfig/UFconfig.mk
+
+C = $(CC) $(CFLAGS) $(UMFPACK_CONFIG) \
+    -I../Include -I../../AMD/Include -I../../UFconfig
+
+#-------------------------------------------------------------------------------
+# source files
+#-------------------------------------------------------------------------------
+
+# non-user-callable umf_*.[ch] files:
+UMFCH = umf_assemble umf_blas3_update umf_build_tuples umf_create_element \
+	umf_dump umf_extend_front umf_garbage_collection umf_get_memory \
+	umf_init_front umf_kernel umf_kernel_init umf_kernel_wrapup \
+	umf_local_search umf_lsolve umf_ltsolve umf_mem_alloc_element \
+	umf_mem_alloc_head_block umf_mem_alloc_tail_block \
+	umf_mem_free_tail_block umf_mem_init_memoryspace \
+	umf_report_vector umf_row_search umf_scale_column \
+	umf_set_stats umf_solve umf_symbolic_usage umf_transpose \
+	umf_tuple_lengths umf_usolve umf_utsolve umf_valid_numeric \
+	umf_valid_symbolic umf_grow_front umf_start_front umf_2by2 \
+	umf_store_lu umf_scale
+
+# non-user-callable umf_*.[ch] files, int/UF_long versions only (no real/complex):
+UMFINT = umf_analyze umf_apply_order umf_colamd umf_free umf_fsize \
+	umf_is_permutation umf_malloc umf_realloc umf_report_perm \
+	umf_singletons
+
+# non-user-callable, created from umf_ltsolve.c, umf_utsolve.c,
+# umf_triplet.c, and umf_assemble.c , with int/UF_long and real/complex versions:
+UMF_CREATED = umf_lhsolve umf_uhsolve umf_triplet_map_nox \
+	umf_triplet_nomap_x umf_triplet_nomap_nox umf_triplet_map_x \
+	umf_assemble_fixq umf_store_lu_drop
+
+# non-user-callable, int/UF_long and real/complex versions:
+UMF = $(UMF_CREATED) $(UMFCH)
+
+# user-callable umfpack_*.[ch] files (int/UF_long and real/complex):
+UMFPACK = umfpack_col_to_triplet umfpack_defaults umfpack_free_numeric \
+	umfpack_free_symbolic umfpack_get_numeric umfpack_get_lunz \
+	umfpack_get_symbolic umfpack_get_determinant umfpack_numeric \
+	umfpack_qsymbolic umfpack_report_control umfpack_report_info \
+	umfpack_report_matrix umfpack_report_numeric umfpack_report_perm \
+	umfpack_report_status umfpack_report_symbolic umfpack_report_triplet \
+	umfpack_report_vector umfpack_solve umfpack_symbolic \
+	umfpack_transpose umfpack_triplet_to_col umfpack_scale \
+	umfpack_load_numeric umfpack_save_numeric \
+	umfpack_load_symbolic umfpack_save_symbolic
+
+# user-callable, created from umfpack_solve.c (umfpack_wsolve.h exists, though):
+# with int/UF_long and real/complex versions:
+UMFPACKW = umfpack_wsolve
+
+USER = $(UMFPACKW) $(UMFPACK)
+
+# user-callable, only one version for int/UF_long, real/complex, *.[ch] files:
+GENERIC = umfpack_timer umfpack_tictoc umfpack_global
+
+#-------------------------------------------------------------------------------
+# include files:
+#-------------------------------------------------------------------------------
+
+INC = ../Include/umfpack.h ../../UFconfig/UFconfig.h \
+	umf_config.h umf_version.h umf_internal.h umf_triplet.h \
+	$(addsuffix .h,$(UMFCH)) \
+	$(addsuffix .h,$(UMFINT)) \
+	$(addprefix ../Include/, $(addsuffix .h,$(USER))) \
+	$(addprefix ../Include/, $(addsuffix .h,$(GENERIC))) \
+	../../AMD/Include/amd_internal.h ../../AMD/Include/amd.h
+
+#-------------------------------------------------------------------------------
+# object files for each version
+#-------------------------------------------------------------------------------
+
+DI = $(addsuffix .o, $(subst umf_,umf_di_,$(UMF)) $(subst umfpack_,umfpack_di_,$(USER)))
+DL = $(addsuffix .o, $(subst umf_,umf_dl_,$(UMF)) $(subst umfpack_,umfpack_dl_,$(USER)))
+ZI = $(addsuffix .o, $(subst umf_,umf_zi_,$(UMF)) $(subst umfpack_,umfpack_zi_,$(USER)))
+ZL = $(addsuffix .o, $(subst umf_,umf_zl_,$(UMF)) $(subst umfpack_,umfpack_zl_,$(USER)))
+II = $(addsuffix .o, $(subst umf_,umf_i_,$(UMFINT)))
+LL = $(addsuffix .o, $(subst umf_,umf_l_,$(UMFINT)))
+GN = $(addsuffix .o, $(subst umfpack_,umfpack_gn_,$(GENERIC)))
+
+#-------------------------------------------------------------------------------
+# compile each int and UF_long routine (with no real/complex version)
+#-------------------------------------------------------------------------------
+
+umf_i_%.o: umf_%.c $(INC)
+	$(C) -DDINT -c $< -o $@
+
+umf_l_%.o: umf_%.c $(INC)
+	$(C) -DDLONG -c $< -o $@
+
+#-------------------------------------------------------------------------------
+# compile each routine in the DI version
+#-------------------------------------------------------------------------------
+
+umf_di_%.o: umf_%.c $(INC)
+	$(C) -DDINT -c $< -o $@
+
+umf_di_%hsolve.o: umf_%tsolve.c $(INC)
+	$(C) -DDINT -DCONJUGATE_SOLVE -c $< -o $@
+
+umf_di_triplet_map_x.o: umf_triplet.c $(INC)
+	$(C) -DDINT -DDO_MAP -DDO_VALUES -c $< -o $@
+
+umf_di_triplet_map_nox.o: umf_triplet.c $(INC)
+	$(C) -DDINT -DDO_MAP -c $< -o $@
+
+umf_di_triplet_nomap_x.o: umf_triplet.c $(INC)
+	$(C) -DDINT -DDO_VALUES -c $< -o $@
+
+umf_di_triplet_nomap_nox.o: umf_triplet.c $(INC)
+	$(C) -DDINT -c $< -o $@
+
+umf_di_assemble_fixq.o: umf_assemble.c $(INC)
+	$(C) -DDINT -DFIXQ -c $< -o $@
+
+umf_di_store_lu_drop.o: umf_store_lu.c $(INC)
+	$(C) -DDINT -DDROP -c $< -o $@
+
+umfpack_di_wsolve.o: umfpack_solve.c $(INC)
+	$(C) -DDINT -DWSOLVE -c $< -o $@
+
+umfpack_di_%.o: umfpack_%.c $(INC)
+	$(C) -DDINT -c $< -o $@
+
+#-------------------------------------------------------------------------------
+# compile each routine in the DL version
+#-------------------------------------------------------------------------------
+
+umf_dl_%.o: umf_%.c $(INC)
+	$(C) -DDLONG -c $< -o $@
+
+umf_dl_%hsolve.o: umf_%tsolve.c $(INC)
+	$(C) -DDLONG -DCONJUGATE_SOLVE -c $< -o $@
+
+umf_dl_triplet_map_x.o: umf_triplet.c $(INC)
+	$(C) -DDLONG -DDO_MAP -DDO_VALUES -c $< -o $@
+
+umf_dl_triplet_map_nox.o: umf_triplet.c $(INC)
+	$(C) -DDLONG -DDO_MAP -c $< -o $@
+
+umf_dl_triplet_nomap_x.o: umf_triplet.c $(INC)
+	$(C) -DDLONG -DDO_VALUES -c $< -o $@
+
+umf_dl_triplet_nomap_nox.o: umf_triplet.c $(INC)
+	$(C) -DDLONG -c $< -o $@
+
+umf_dl_assemble_fixq.o: umf_assemble.c $(INC)
+	$(C) -DDLONG -DFIXQ -c $< -o $@
+
+umf_dl_store_lu_drop.o: umf_store_lu.c $(INC)
+	$(C) -DDLONG -DDROP -c $< -o $@
+
+umfpack_dl_wsolve.o: umfpack_solve.c $(INC)
+	$(C) -DDLONG -DWSOLVE -c $< -o $@
+
+umfpack_dl_%.o: umfpack_%.c $(INC)
+	$(C) -DDLONG -c $< -o $@
+
+#-------------------------------------------------------------------------------
+# compile each routine in the ZI version
+#-------------------------------------------------------------------------------
+
+umf_zi_%.o: umf_%.c $(INC)
+	$(C) -DZINT -c $< -o $@
+
+umf_zi_%hsolve.o: umf_%tsolve.c $(INC)
+	$(C) -DZINT -DCONJUGATE_SOLVE -c $< -o $@
+
+umf_zi_triplet_map_x.o: umf_triplet.c $(INC)
+	$(C) -DZINT -DDO_MAP -DDO_VALUES -c $< -o $@
+
+umf_zi_triplet_map_nox.o: umf_triplet.c $(INC)
+	$(C) -DZINT -DDO_MAP -c $< -o $@
+
+umf_zi_triplet_nomap_x.o: umf_triplet.c $(INC)
+	$(C) -DZINT -DDO_VALUES -c $< -o $@
+
+umf_zi_triplet_nomap_nox.o: umf_triplet.c $(INC)
+	$(C) -DZINT -c $< -o $@
+
+umf_zi_assemble_fixq.o: umf_assemble.c $(INC)
+	$(C) -DZINT -DFIXQ -c $< -o $@
+
+umf_zi_store_lu_drop.o: umf_store_lu.c $(INC)
+	$(C) -DZINT -DDROP -c $< -o $@
+
+umfpack_zi_wsolve.o: umfpack_solve.c $(INC)
+	$(C) -DZINT -DWSOLVE -c $< -o $@
+
+umfpack_zi_%.o: umfpack_%.c $(INC)
+	$(C) -DZINT -c $< -o $@
+
+#-------------------------------------------------------------------------------
+# compile each routine in the ZL version
+#-------------------------------------------------------------------------------
+
+umf_zl_%.o: umf_%.c $(INC)
+	$(C) -DZLONG -c $< -o $@
+
+umf_zl_%hsolve.o: umf_%tsolve.c $(INC)
+	$(C) -DZLONG -DCONJUGATE_SOLVE -c $< -o $@
+
+umf_zl_triplet_map_x.o: umf_triplet.c $(INC)
+	$(C) -DZLONG -DDO_MAP -DDO_VALUES -c $< -o $@
+
+umf_zl_triplet_map_nox.o: umf_triplet.c $(INC)
+	$(C) -DZLONG -DDO_MAP -c $< -o $@
+
+umf_zl_triplet_nomap_x.o: umf_triplet.c $(INC)
+	$(C) -DZLONG -DDO_VALUES -c $< -o $@
+
+umf_zl_triplet_nomap_nox.o: umf_triplet.c $(INC)
+	$(C) -DZLONG -c $< -o $@
+
+umf_zl_assemble_fixq.o: umf_assemble.c $(INC)
+	$(C) -DZLONG -DFIXQ -c $< -o $@
+
+umf_zl_store_lu_drop.o: umf_store_lu.c $(INC)
+	$(C) -DZLONG -DDROP -c $< -o $@
+
+umfpack_zl_wsolve.o: umfpack_solve.c $(INC)
+	$(C) -DZLONG -DWSOLVE -c $< -o $@
+
+umfpack_zl_%.o: umfpack_%.c $(INC)
+	$(C) -DZLONG -c $< -o $@
+
+#-------------------------------------------------------------------------------
+# Create the generic routines (GN) using a generic rule
+#-------------------------------------------------------------------------------
+
+umfpack_gn_%.o: umfpack_%.c $(INC)
+	$(C) -c $< -o $@
+
+#-------------------------------------------------------------------------------
+# Create the libumfpack.a library
+#-------------------------------------------------------------------------------
+
+../Lib/libumfpack.a: $(II) $(LL) $(GN) $(DI) $(DL) $(ZI) $(ZL)
+	$(AR) ../Lib/libumfpack.a $^
+	- $(RANLIB) ../Lib/libumfpack.a
+
+#-------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#-------------------------------------------------------------------------------
+
+purge: clean
+	- $(RM) ../Lib/libumfpack.a
+
+clean:
+	- $(RM) $(CLEAN)
diff --git a/src/C/SuiteSparse/UMFPACK/Source/Makefile b/src/C/SuiteSparse/UMFPACK/Source/Makefile
new file mode 100644
index 0000000..56ab48b
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/Makefile
@@ -0,0 +1,482 @@
+#-------------------------------------------------------------------------------
+# UMFPACK Makefile for compiling on Unix systems (for original make only)
+#-------------------------------------------------------------------------------
+
+# This is a very ugly Makefile, and is only provided for those who do not
+# have GNU make.  Note that it is not used if you have GNU make.  It ignores
+# dependency checking and just compiles everything.
+
+default: everything
+
+include ../../UFconfig/UFconfig.mk
+
+C = $(CC) $(CFLAGS) $(UMFPACK_CONFIG) -I../Include -I../../AMD/Include
+
+everything:
+	$(C) -c umfpack_global.c -o umfpack_gn_global.o
+	$(C) -DDINT -c umf_analyze.c -o umf_i_analyze.o
+	$(C) -DDINT -c umf_apply_order.c -o umf_i_apply_order.o
+	$(C) -DDINT -c umf_colamd.c -o umf_i_colamd.o
+	$(C) -DDINT -c umf_free.c -o umf_i_free.o
+	$(C) -DDINT -c umf_fsize.c -o umf_i_fsize.o
+	$(C) -DDINT -c umf_is_permutation.c -o umf_i_is_permutation.o
+	$(C) -DDINT -c umf_malloc.c -o umf_i_malloc.o
+	$(C) -DDINT -c umf_realloc.c -o umf_i_realloc.o
+	$(C) -DDINT -c umf_report_perm.c -o umf_i_report_perm.o
+	$(C) -DDINT -c umf_singletons.c -o umf_i_singletons.o
+	$(C) -DDLONG -c umf_analyze.c -o umf_l_analyze.o
+	$(C) -DDLONG -c umf_apply_order.c -o umf_l_apply_order.o
+	$(C) -DDLONG -c umf_colamd.c -o umf_l_colamd.o
+	$(C) -DDLONG -c umf_free.c -o umf_l_free.o
+	$(C) -DDLONG -c umf_fsize.c -o umf_l_fsize.o
+	$(C) -DDLONG -c umf_is_permutation.c -o umf_l_is_permutation.o
+	$(C) -DDLONG -c umf_malloc.c -o umf_l_malloc.o
+	$(C) -DDLONG -c umf_realloc.c -o umf_l_realloc.o
+	$(C) -DDLONG -c umf_report_perm.c -o umf_l_report_perm.o
+	$(C) -DDLONG -c umf_singletons.c -o umf_l_singletons.o
+	$(C) -c umfpack_timer.c -o umfpack_gn_timer.o
+	$(C) -c umfpack_tictoc.c -o umfpack_gn_tictoc.o
+	$(C) -DDINT -DCONJUGATE_SOLVE -c umf_ltsolve.c -o umf_di_lhsolve.o
+	$(C) -DDINT -DCONJUGATE_SOLVE -c umf_utsolve.c -o umf_di_uhsolve.o
+	$(C) -DDINT -DDO_MAP -c umf_triplet.c -o umf_di_triplet_map_nox.o
+	$(C) -DDINT -DDO_VALUES -c umf_triplet.c -o umf_di_triplet_nomap_x.o
+	$(C) -DDINT -c umf_triplet.c -o umf_di_triplet_nomap_nox.o
+	$(C) -DDINT -DDO_MAP -DDO_VALUES -c umf_triplet.c -o umf_di_triplet_map_x.o
+	$(C) -DDINT -DFIXQ -c umf_assemble.c -o umf_di_assemble_fixq.o
+	$(C) -DDINT -DDROP -c umf_store_lu.c -o umf_di_store_lu_drop.o
+	$(C) -DDINT -c umf_assemble.c -o umf_di_assemble.o
+	$(C) -DDINT -c umf_blas3_update.c -o umf_di_blas3_update.o
+	$(C) -DDINT -c umf_build_tuples.c -o umf_di_build_tuples.o
+	$(C) -DDINT -c umf_create_element.c -o umf_di_create_element.o
+	$(C) -DDINT -c umf_dump.c -o umf_di_dump.o
+	$(C) -DDINT -c umf_extend_front.c -o umf_di_extend_front.o
+	$(C) -DDINT -c umf_garbage_collection.c -o umf_di_garbage_collection.o
+	$(C) -DDINT -c umf_get_memory.c -o umf_di_get_memory.o
+	$(C) -DDINT -c umf_init_front.c -o umf_di_init_front.o
+	$(C) -DDINT -c umf_kernel.c -o umf_di_kernel.o
+	$(C) -DDINT -c umf_kernel_init.c -o umf_di_kernel_init.o
+	$(C) -DDINT -c umf_kernel_wrapup.c -o umf_di_kernel_wrapup.o
+	$(C) -DDINT -c umf_local_search.c -o umf_di_local_search.o
+	$(C) -DDINT -c umf_lsolve.c -o umf_di_lsolve.o
+	$(C) -DDINT -c umf_ltsolve.c -o umf_di_ltsolve.o
+	$(C) -DDINT -c umf_mem_alloc_element.c -o umf_di_mem_alloc_element.o
+	$(C) -DDINT -c umf_mem_alloc_head_block.c -o umf_di_mem_alloc_head_block.o
+	$(C) -DDINT -c umf_mem_alloc_tail_block.c -o umf_di_mem_alloc_tail_block.o
+	$(C) -DDINT -c umf_mem_free_tail_block.c -o umf_di_mem_free_tail_block.o
+	$(C) -DDINT -c umf_mem_init_memoryspace.c -o umf_di_mem_init_memoryspace.o
+	$(C) -DDINT -c umf_report_vector.c -o umf_di_report_vector.o
+	$(C) -DDINT -c umf_row_search.c -o umf_di_row_search.o
+	$(C) -DDINT -c umf_scale_column.c -o umf_di_scale_column.o
+	$(C) -DDINT -c umf_set_stats.c -o umf_di_set_stats.o
+	$(C) -DDINT -c umf_solve.c -o umf_di_solve.o
+	$(C) -DDINT -c umf_symbolic_usage.c -o umf_di_symbolic_usage.o
+	$(C) -DDINT -c umf_transpose.c -o umf_di_transpose.o
+	$(C) -DDINT -c umf_tuple_lengths.c -o umf_di_tuple_lengths.o
+	$(C) -DDINT -c umf_usolve.c -o umf_di_usolve.o
+	$(C) -DDINT -c umf_utsolve.c -o umf_di_utsolve.o
+	$(C) -DDINT -c umf_valid_numeric.c -o umf_di_valid_numeric.o
+	$(C) -DDINT -c umf_valid_symbolic.c -o umf_di_valid_symbolic.o
+	$(C) -DDINT -c umf_grow_front.c -o umf_di_grow_front.o
+	$(C) -DDINT -c umf_start_front.c -o umf_di_start_front.o
+	$(C) -DDINT -c umf_2by2.c -o umf_di_2by2.o
+	$(C) -DDINT -c umf_store_lu.c -o umf_di_store_lu.o
+	$(C) -DDINT -c umf_scale.c -o umf_di_scale.o
+	$(C) -DDINT -DWSOLVE -c umfpack_solve.c -o umfpack_di_wsolve.o
+	$(C) -DDINT -c umfpack_col_to_triplet.c -o umfpack_di_col_to_triplet.o
+	$(C) -DDINT -c umfpack_defaults.c -o umfpack_di_defaults.o
+	$(C) -DDINT -c umfpack_free_numeric.c -o umfpack_di_free_numeric.o
+	$(C) -DDINT -c umfpack_free_symbolic.c -o umfpack_di_free_symbolic.o
+	$(C) -DDINT -c umfpack_get_numeric.c -o umfpack_di_get_numeric.o
+	$(C) -DDINT -c umfpack_get_lunz.c -o umfpack_di_get_lunz.o
+	$(C) -DDINT -c umfpack_get_symbolic.c -o umfpack_di_get_symbolic.o
+	$(C) -DDINT -c umfpack_get_determinant.c -o umfpack_di_get_determinant.o
+	$(C) -DDINT -c umfpack_numeric.c -o umfpack_di_numeric.o
+	$(C) -DDINT -c umfpack_qsymbolic.c -o umfpack_di_qsymbolic.o
+	$(C) -DDINT -c umfpack_report_control.c -o umfpack_di_report_control.o
+	$(C) -DDINT -c umfpack_report_info.c -o umfpack_di_report_info.o
+	$(C) -DDINT -c umfpack_report_matrix.c -o umfpack_di_report_matrix.o
+	$(C) -DDINT -c umfpack_report_numeric.c -o umfpack_di_report_numeric.o
+	$(C) -DDINT -c umfpack_report_perm.c -o umfpack_di_report_perm.o
+	$(C) -DDINT -c umfpack_report_status.c -o umfpack_di_report_status.o
+	$(C) -DDINT -c umfpack_report_symbolic.c -o umfpack_di_report_symbolic.o
+	$(C) -DDINT -c umfpack_report_triplet.c -o umfpack_di_report_triplet.o
+	$(C) -DDINT -c umfpack_report_vector.c -o umfpack_di_report_vector.o
+	$(C) -DDINT -c umfpack_solve.c -o umfpack_di_solve.o
+	$(C) -DDINT -c umfpack_symbolic.c -o umfpack_di_symbolic.o
+	$(C) -DDINT -c umfpack_transpose.c -o umfpack_di_transpose.o
+	$(C) -DDINT -c umfpack_triplet_to_col.c -o umfpack_di_triplet_to_col.o
+	$(C) -DDINT -c umfpack_scale.c -o umfpack_di_scale.o
+	$(C) -DDINT -c umfpack_load_numeric.c -o umfpack_di_load_numeric.o
+	$(C) -DDINT -c umfpack_save_numeric.c -o umfpack_di_save_numeric.o
+	$(C) -DDINT -c umfpack_load_symbolic.c -o umfpack_di_load_symbolic.o
+	$(C) -DDINT -c umfpack_save_symbolic.c -o umfpack_di_save_symbolic.o
+	$(C) -DDLONG -DCONJUGATE_SOLVE -c umf_ltsolve.c -o umf_dl_lhsolve.o
+	$(C) -DDLONG -DCONJUGATE_SOLVE -c umf_utsolve.c -o umf_dl_uhsolve.o
+	$(C) -DDLONG -DDO_MAP -c umf_triplet.c -o umf_dl_triplet_map_nox.o
+	$(C) -DDLONG -DDO_VALUES -c umf_triplet.c -o umf_dl_triplet_nomap_x.o
+	$(C) -DDLONG -c umf_triplet.c -o umf_dl_triplet_nomap_nox.o
+	$(C) -DDLONG -DDO_MAP -DDO_VALUES -c umf_triplet.c -o umf_dl_triplet_map_x.o
+	$(C) -DDLONG -DFIXQ -c umf_assemble.c -o umf_dl_assemble_fixq.o
+	$(C) -DDLONG -DDROP -c umf_store_lu.c -o umf_dl_store_lu_drop.o
+	$(C) -DDLONG -c umf_assemble.c -o umf_dl_assemble.o
+	$(C) -DDLONG -c umf_blas3_update.c -o umf_dl_blas3_update.o
+	$(C) -DDLONG -c umf_build_tuples.c -o umf_dl_build_tuples.o
+	$(C) -DDLONG -c umf_create_element.c -o umf_dl_create_element.o
+	$(C) -DDLONG -c umf_dump.c -o umf_dl_dump.o
+	$(C) -DDLONG -c umf_extend_front.c -o umf_dl_extend_front.o
+	$(C) -DDLONG -c umf_garbage_collection.c -o umf_dl_garbage_collection.o
+	$(C) -DDLONG -c umf_get_memory.c -o umf_dl_get_memory.o
+	$(C) -DDLONG -c umf_init_front.c -o umf_dl_init_front.o
+	$(C) -DDLONG -c umf_kernel.c -o umf_dl_kernel.o
+	$(C) -DDLONG -c umf_kernel_init.c -o umf_dl_kernel_init.o
+	$(C) -DDLONG -c umf_kernel_wrapup.c -o umf_dl_kernel_wrapup.o
+	$(C) -DDLONG -c umf_local_search.c -o umf_dl_local_search.o
+	$(C) -DDLONG -c umf_lsolve.c -o umf_dl_lsolve.o
+	$(C) -DDLONG -c umf_ltsolve.c -o umf_dl_ltsolve.o
+	$(C) -DDLONG -c umf_mem_alloc_element.c -o umf_dl_mem_alloc_element.o
+	$(C) -DDLONG -c umf_mem_alloc_head_block.c -o umf_dl_mem_alloc_head_block.o
+	$(C) -DDLONG -c umf_mem_alloc_tail_block.c -o umf_dl_mem_alloc_tail_block.o
+	$(C) -DDLONG -c umf_mem_free_tail_block.c -o umf_dl_mem_free_tail_block.o
+	$(C) -DDLONG -c umf_mem_init_memoryspace.c -o umf_dl_mem_init_memoryspace.o
+	$(C) -DDLONG -c umf_report_vector.c -o umf_dl_report_vector.o
+	$(C) -DDLONG -c umf_row_search.c -o umf_dl_row_search.o
+	$(C) -DDLONG -c umf_scale_column.c -o umf_dl_scale_column.o
+	$(C) -DDLONG -c umf_set_stats.c -o umf_dl_set_stats.o
+	$(C) -DDLONG -c umf_solve.c -o umf_dl_solve.o
+	$(C) -DDLONG -c umf_symbolic_usage.c -o umf_dl_symbolic_usage.o
+	$(C) -DDLONG -c umf_transpose.c -o umf_dl_transpose.o
+	$(C) -DDLONG -c umf_tuple_lengths.c -o umf_dl_tuple_lengths.o
+	$(C) -DDLONG -c umf_usolve.c -o umf_dl_usolve.o
+	$(C) -DDLONG -c umf_utsolve.c -o umf_dl_utsolve.o
+	$(C) -DDLONG -c umf_valid_numeric.c -o umf_dl_valid_numeric.o
+	$(C) -DDLONG -c umf_valid_symbolic.c -o umf_dl_valid_symbolic.o
+	$(C) -DDLONG -c umf_grow_front.c -o umf_dl_grow_front.o
+	$(C) -DDLONG -c umf_start_front.c -o umf_dl_start_front.o
+	$(C) -DDLONG -c umf_2by2.c -o umf_dl_2by2.o
+	$(C) -DDLONG -c umf_store_lu.c -o umf_dl_store_lu.o
+	$(C) -DDLONG -c umf_scale.c -o umf_dl_scale.o
+	$(C) -DDLONG -DWSOLVE -c umfpack_solve.c -o umfpack_dl_wsolve.o
+	$(C) -DDLONG -c umfpack_col_to_triplet.c -o umfpack_dl_col_to_triplet.o
+	$(C) -DDLONG -c umfpack_defaults.c -o umfpack_dl_defaults.o
+	$(C) -DDLONG -c umfpack_free_numeric.c -o umfpack_dl_free_numeric.o
+	$(C) -DDLONG -c umfpack_free_symbolic.c -o umfpack_dl_free_symbolic.o
+	$(C) -DDLONG -c umfpack_get_numeric.c -o umfpack_dl_get_numeric.o
+	$(C) -DDLONG -c umfpack_get_lunz.c -o umfpack_dl_get_lunz.o
+	$(C) -DDLONG -c umfpack_get_symbolic.c -o umfpack_dl_get_symbolic.o
+	$(C) -DDLONG -c umfpack_get_determinant.c -o umfpack_dl_get_determinant.o
+	$(C) -DDLONG -c umfpack_numeric.c -o umfpack_dl_numeric.o
+	$(C) -DDLONG -c umfpack_qsymbolic.c -o umfpack_dl_qsymbolic.o
+	$(C) -DDLONG -c umfpack_report_control.c -o umfpack_dl_report_control.o
+	$(C) -DDLONG -c umfpack_report_info.c -o umfpack_dl_report_info.o
+	$(C) -DDLONG -c umfpack_report_matrix.c -o umfpack_dl_report_matrix.o
+	$(C) -DDLONG -c umfpack_report_numeric.c -o umfpack_dl_report_numeric.o
+	$(C) -DDLONG -c umfpack_report_perm.c -o umfpack_dl_report_perm.o
+	$(C) -DDLONG -c umfpack_report_status.c -o umfpack_dl_report_status.o
+	$(C) -DDLONG -c umfpack_report_symbolic.c -o umfpack_dl_report_symbolic.o
+	$(C) -DDLONG -c umfpack_report_triplet.c -o umfpack_dl_report_triplet.o
+	$(C) -DDLONG -c umfpack_report_vector.c -o umfpack_dl_report_vector.o
+	$(C) -DDLONG -c umfpack_solve.c -o umfpack_dl_solve.o
+	$(C) -DDLONG -c umfpack_symbolic.c -o umfpack_dl_symbolic.o
+	$(C) -DDLONG -c umfpack_transpose.c -o umfpack_dl_transpose.o
+	$(C) -DDLONG -c umfpack_triplet_to_col.c -o umfpack_dl_triplet_to_col.o
+	$(C) -DDLONG -c umfpack_scale.c -o umfpack_dl_scale.o
+	$(C) -DDLONG -c umfpack_load_numeric.c -o umfpack_dl_load_numeric.o
+	$(C) -DDLONG -c umfpack_save_numeric.c -o umfpack_dl_save_numeric.o
+	$(C) -DDLONG -c umfpack_load_symbolic.c -o umfpack_dl_load_symbolic.o
+	$(C) -DDLONG -c umfpack_save_symbolic.c -o umfpack_dl_save_symbolic.o
+	$(C) -DZINT -DCONJUGATE_SOLVE -c umf_ltsolve.c -o umf_zi_lhsolve.o
+	$(C) -DZINT -DCONJUGATE_SOLVE -c umf_utsolve.c -o umf_zi_uhsolve.o
+	$(C) -DZINT -DDO_MAP -c umf_triplet.c -o umf_zi_triplet_map_nox.o
+	$(C) -DZINT -DDO_VALUES -c umf_triplet.c -o umf_zi_triplet_nomap_x.o
+	$(C) -DZINT -c umf_triplet.c -o umf_zi_triplet_nomap_nox.o
+	$(C) -DZINT -DDO_MAP -DDO_VALUES -c umf_triplet.c -o umf_zi_triplet_map_x.o
+	$(C) -DZINT -DFIXQ -c umf_assemble.c -o umf_zi_assemble_fixq.o
+	$(C) -DZINT -DDROP -c umf_store_lu.c -o umf_zi_store_lu_drop.o
+	$(C) -DZINT -c umf_assemble.c -o umf_zi_assemble.o
+	$(C) -DZINT -c umf_blas3_update.c -o umf_zi_blas3_update.o
+	$(C) -DZINT -c umf_build_tuples.c -o umf_zi_build_tuples.o
+	$(C) -DZINT -c umf_create_element.c -o umf_zi_create_element.o
+	$(C) -DZINT -c umf_dump.c -o umf_zi_dump.o
+	$(C) -DZINT -c umf_extend_front.c -o umf_zi_extend_front.o
+	$(C) -DZINT -c umf_garbage_collection.c -o umf_zi_garbage_collection.o
+	$(C) -DZINT -c umf_get_memory.c -o umf_zi_get_memory.o
+	$(C) -DZINT -c umf_init_front.c -o umf_zi_init_front.o
+	$(C) -DZINT -c umf_kernel.c -o umf_zi_kernel.o
+	$(C) -DZINT -c umf_kernel_init.c -o umf_zi_kernel_init.o
+	$(C) -DZINT -c umf_kernel_wrapup.c -o umf_zi_kernel_wrapup.o
+	$(C) -DZINT -c umf_local_search.c -o umf_zi_local_search.o
+	$(C) -DZINT -c umf_lsolve.c -o umf_zi_lsolve.o
+	$(C) -DZINT -c umf_ltsolve.c -o umf_zi_ltsolve.o
+	$(C) -DZINT -c umf_mem_alloc_element.c -o umf_zi_mem_alloc_element.o
+	$(C) -DZINT -c umf_mem_alloc_head_block.c -o umf_zi_mem_alloc_head_block.o
+	$(C) -DZINT -c umf_mem_alloc_tail_block.c -o umf_zi_mem_alloc_tail_block.o
+	$(C) -DZINT -c umf_mem_free_tail_block.c -o umf_zi_mem_free_tail_block.o
+	$(C) -DZINT -c umf_mem_init_memoryspace.c -o umf_zi_mem_init_memoryspace.o
+	$(C) -DZINT -c umf_report_vector.c -o umf_zi_report_vector.o
+	$(C) -DZINT -c umf_row_search.c -o umf_zi_row_search.o
+	$(C) -DZINT -c umf_scale_column.c -o umf_zi_scale_column.o
+	$(C) -DZINT -c umf_set_stats.c -o umf_zi_set_stats.o
+	$(C) -DZINT -c umf_solve.c -o umf_zi_solve.o
+	$(C) -DZINT -c umf_symbolic_usage.c -o umf_zi_symbolic_usage.o
+	$(C) -DZINT -c umf_transpose.c -o umf_zi_transpose.o
+	$(C) -DZINT -c umf_tuple_lengths.c -o umf_zi_tuple_lengths.o
+	$(C) -DZINT -c umf_usolve.c -o umf_zi_usolve.o
+	$(C) -DZINT -c umf_utsolve.c -o umf_zi_utsolve.o
+	$(C) -DZINT -c umf_valid_numeric.c -o umf_zi_valid_numeric.o
+	$(C) -DZINT -c umf_valid_symbolic.c -o umf_zi_valid_symbolic.o
+	$(C) -DZINT -c umf_grow_front.c -o umf_zi_grow_front.o
+	$(C) -DZINT -c umf_start_front.c -o umf_zi_start_front.o
+	$(C) -DZINT -c umf_2by2.c -o umf_zi_2by2.o
+	$(C) -DZINT -c umf_store_lu.c -o umf_zi_store_lu.o
+	$(C) -DZINT -c umf_scale.c -o umf_zi_scale.o
+	$(C) -DZINT -DWSOLVE -c umfpack_solve.c -o umfpack_zi_wsolve.o
+	$(C) -DZINT -c umfpack_col_to_triplet.c -o umfpack_zi_col_to_triplet.o
+	$(C) -DZINT -c umfpack_defaults.c -o umfpack_zi_defaults.o
+	$(C) -DZINT -c umfpack_free_numeric.c -o umfpack_zi_free_numeric.o
+	$(C) -DZINT -c umfpack_free_symbolic.c -o umfpack_zi_free_symbolic.o
+	$(C) -DZINT -c umfpack_get_numeric.c -o umfpack_zi_get_numeric.o
+	$(C) -DZINT -c umfpack_get_lunz.c -o umfpack_zi_get_lunz.o
+	$(C) -DZINT -c umfpack_get_symbolic.c -o umfpack_zi_get_symbolic.o
+	$(C) -DZINT -c umfpack_get_determinant.c -o umfpack_zi_get_determinant.o
+	$(C) -DZINT -c umfpack_numeric.c -o umfpack_zi_numeric.o
+	$(C) -DZINT -c umfpack_qsymbolic.c -o umfpack_zi_qsymbolic.o
+	$(C) -DZINT -c umfpack_report_control.c -o umfpack_zi_report_control.o
+	$(C) -DZINT -c umfpack_report_info.c -o umfpack_zi_report_info.o
+	$(C) -DZINT -c umfpack_report_matrix.c -o umfpack_zi_report_matrix.o
+	$(C) -DZINT -c umfpack_report_numeric.c -o umfpack_zi_report_numeric.o
+	$(C) -DZINT -c umfpack_report_perm.c -o umfpack_zi_report_perm.o
+	$(C) -DZINT -c umfpack_report_status.c -o umfpack_zi_report_status.o
+	$(C) -DZINT -c umfpack_report_symbolic.c -o umfpack_zi_report_symbolic.o
+	$(C) -DZINT -c umfpack_report_triplet.c -o umfpack_zi_report_triplet.o
+	$(C) -DZINT -c umfpack_report_vector.c -o umfpack_zi_report_vector.o
+	$(C) -DZINT -c umfpack_solve.c -o umfpack_zi_solve.o
+	$(C) -DZINT -c umfpack_symbolic.c -o umfpack_zi_symbolic.o
+	$(C) -DZINT -c umfpack_transpose.c -o umfpack_zi_transpose.o
+	$(C) -DZINT -c umfpack_triplet_to_col.c -o umfpack_zi_triplet_to_col.o
+	$(C) -DZINT -c umfpack_scale.c -o umfpack_zi_scale.o
+	$(C) -DZINT -c umfpack_load_numeric.c -o umfpack_zi_load_numeric.o
+	$(C) -DZINT -c umfpack_save_numeric.c -o umfpack_zi_save_numeric.o
+	$(C) -DZINT -c umfpack_load_symbolic.c -o umfpack_zi_load_symbolic.o
+	$(C) -DZINT -c umfpack_save_symbolic.c -o umfpack_zi_save_symbolic.o
+	$(C) -DZLONG -DCONJUGATE_SOLVE -c umf_ltsolve.c -o umf_zl_lhsolve.o
+	$(C) -DZLONG -DCONJUGATE_SOLVE -c umf_utsolve.c -o umf_zl_uhsolve.o
+	$(C) -DZLONG -DDO_MAP -c umf_triplet.c -o umf_zl_triplet_map_nox.o
+	$(C) -DZLONG -DDO_VALUES -c umf_triplet.c -o umf_zl_triplet_nomap_x.o
+	$(C) -DZLONG -c umf_triplet.c -o umf_zl_triplet_nomap_nox.o
+	$(C) -DZLONG -DDO_MAP -DDO_VALUES -c umf_triplet.c -o umf_zl_triplet_map_x.o
+	$(C) -DZLONG -DFIXQ -c umf_assemble.c -o umf_zl_assemble_fixq.o
+	$(C) -DZLONG -DDROP -c umf_store_lu.c -o umf_zl_store_lu_drop.o
+	$(C) -DZLONG -c umf_assemble.c -o umf_zl_assemble.o
+	$(C) -DZLONG -c umf_blas3_update.c -o umf_zl_blas3_update.o
+	$(C) -DZLONG -c umf_build_tuples.c -o umf_zl_build_tuples.o
+	$(C) -DZLONG -c umf_create_element.c -o umf_zl_create_element.o
+	$(C) -DZLONG -c umf_dump.c -o umf_zl_dump.o
+	$(C) -DZLONG -c umf_extend_front.c -o umf_zl_extend_front.o
+	$(C) -DZLONG -c umf_garbage_collection.c -o umf_zl_garbage_collection.o
+	$(C) -DZLONG -c umf_get_memory.c -o umf_zl_get_memory.o
+	$(C) -DZLONG -c umf_init_front.c -o umf_zl_init_front.o
+	$(C) -DZLONG -c umf_kernel.c -o umf_zl_kernel.o
+	$(C) -DZLONG -c umf_kernel_init.c -o umf_zl_kernel_init.o
+	$(C) -DZLONG -c umf_kernel_wrapup.c -o umf_zl_kernel_wrapup.o
+	$(C) -DZLONG -c umf_local_search.c -o umf_zl_local_search.o
+	$(C) -DZLONG -c umf_lsolve.c -o umf_zl_lsolve.o
+	$(C) -DZLONG -c umf_ltsolve.c -o umf_zl_ltsolve.o
+	$(C) -DZLONG -c umf_mem_alloc_element.c -o umf_zl_mem_alloc_element.o
+	$(C) -DZLONG -c umf_mem_alloc_head_block.c -o umf_zl_mem_alloc_head_block.o
+	$(C) -DZLONG -c umf_mem_alloc_tail_block.c -o umf_zl_mem_alloc_tail_block.o
+	$(C) -DZLONG -c umf_mem_free_tail_block.c -o umf_zl_mem_free_tail_block.o
+	$(C) -DZLONG -c umf_mem_init_memoryspace.c -o umf_zl_mem_init_memoryspace.o
+	$(C) -DZLONG -c umf_report_vector.c -o umf_zl_report_vector.o
+	$(C) -DZLONG -c umf_row_search.c -o umf_zl_row_search.o
+	$(C) -DZLONG -c umf_scale_column.c -o umf_zl_scale_column.o
+	$(C) -DZLONG -c umf_set_stats.c -o umf_zl_set_stats.o
+	$(C) -DZLONG -c umf_solve.c -o umf_zl_solve.o
+	$(C) -DZLONG -c umf_symbolic_usage.c -o umf_zl_symbolic_usage.o
+	$(C) -DZLONG -c umf_transpose.c -o umf_zl_transpose.o
+	$(C) -DZLONG -c umf_tuple_lengths.c -o umf_zl_tuple_lengths.o
+	$(C) -DZLONG -c umf_usolve.c -o umf_zl_usolve.o
+	$(C) -DZLONG -c umf_utsolve.c -o umf_zl_utsolve.o
+	$(C) -DZLONG -c umf_valid_numeric.c -o umf_zl_valid_numeric.o
+	$(C) -DZLONG -c umf_valid_symbolic.c -o umf_zl_valid_symbolic.o
+	$(C) -DZLONG -c umf_grow_front.c -o umf_zl_grow_front.o
+	$(C) -DZLONG -c umf_start_front.c -o umf_zl_start_front.o
+	$(C) -DZLONG -c umf_2by2.c -o umf_zl_2by2.o
+	$(C) -DZLONG -c umf_store_lu.c -o umf_zl_store_lu.o
+	$(C) -DZLONG -c umf_scale.c -o umf_zl_scale.o
+	$(C) -DZLONG -DWSOLVE -c umfpack_solve.c -o umfpack_zl_wsolve.o
+	$(C) -DZLONG -c umfpack_col_to_triplet.c -o umfpack_zl_col_to_triplet.o
+	$(C) -DZLONG -c umfpack_defaults.c -o umfpack_zl_defaults.o
+	$(C) -DZLONG -c umfpack_free_numeric.c -o umfpack_zl_free_numeric.o
+	$(C) -DZLONG -c umfpack_free_symbolic.c -o umfpack_zl_free_symbolic.o
+	$(C) -DZLONG -c umfpack_get_numeric.c -o umfpack_zl_get_numeric.o
+	$(C) -DZLONG -c umfpack_get_lunz.c -o umfpack_zl_get_lunz.o
+	$(C) -DZLONG -c umfpack_get_symbolic.c -o umfpack_zl_get_symbolic.o
+	$(C) -DZLONG -c umfpack_get_determinant.c -o umfpack_zl_get_determinant.o
+	$(C) -DZLONG -c umfpack_numeric.c -o umfpack_zl_numeric.o
+	$(C) -DZLONG -c umfpack_qsymbolic.c -o umfpack_zl_qsymbolic.o
+	$(C) -DZLONG -c umfpack_report_control.c -o umfpack_zl_report_control.o
+	$(C) -DZLONG -c umfpack_report_info.c -o umfpack_zl_report_info.o
+	$(C) -DZLONG -c umfpack_report_matrix.c -o umfpack_zl_report_matrix.o
+	$(C) -DZLONG -c umfpack_report_numeric.c -o umfpack_zl_report_numeric.o
+	$(C) -DZLONG -c umfpack_report_perm.c -o umfpack_zl_report_perm.o
+	$(C) -DZLONG -c umfpack_report_status.c -o umfpack_zl_report_status.o
+	$(C) -DZLONG -c umfpack_report_symbolic.c -o umfpack_zl_report_symbolic.o
+	$(C) -DZLONG -c umfpack_report_triplet.c -o umfpack_zl_report_triplet.o
+	$(C) -DZLONG -c umfpack_report_vector.c -o umfpack_zl_report_vector.o
+	$(C) -DZLONG -c umfpack_solve.c -o umfpack_zl_solve.o
+	$(C) -DZLONG -c umfpack_symbolic.c -o umfpack_zl_symbolic.o
+	$(C) -DZLONG -c umfpack_transpose.c -o umfpack_zl_transpose.o
+	$(C) -DZLONG -c umfpack_triplet_to_col.c -o umfpack_zl_triplet_to_col.o
+	$(C) -DZLONG -c umfpack_scale.c -o umfpack_zl_scale.o
+	$(C) -DZLONG -c umfpack_load_numeric.c -o umfpack_zl_load_numeric.o
+	$(C) -DZLONG -c umfpack_save_numeric.c -o umfpack_zl_save_numeric.o
+	$(C) -DZLONG -c umfpack_load_symbolic.c -o umfpack_zl_load_symbolic.o
+	$(C) -DZLONG -c umfpack_save_symbolic.c -o umfpack_zl_save_symbolic.o
+	$(AR) ../Lib/libumfpack.a \
+	    umfpack_gn_global.o \
+	    umf_i_analyze.o umf_i_apply_order.o umf_i_colamd.o umf_i_free.o \
+	    umf_i_fsize.o umf_i_is_permutation.o umf_i_malloc.o umf_i_realloc.o \
+	    umf_i_report_perm.o umf_i_singletons.o \
+	    umf_l_analyze.o umf_l_apply_order.o umf_l_colamd.o umf_l_free.o \
+	    umf_l_fsize.o umf_l_is_permutation.o umf_l_malloc.o umf_l_realloc.o \
+	    umf_l_report_perm.o umf_l_singletons.o \
+	    umfpack_gn_timer.o umfpack_gn_tictoc.o \
+	    umf_di_lhsolve.o \
+	    umf_di_uhsolve.o umf_di_triplet_map_nox.o umf_di_triplet_nomap_x.o \
+	    umf_di_triplet_nomap_nox.o umf_di_triplet_map_x.o \
+	    umf_di_assemble_fixq.o umf_di_store_lu_drop.o umf_di_assemble.o \
+	    umf_di_blas3_update.o umf_di_build_tuples.o \
+	    umf_di_create_element.o umf_di_dump.o umf_di_extend_front.o \
+	    umf_di_garbage_collection.o umf_di_get_memory.o \
+	    umf_di_init_front.o umf_di_kernel.o umf_di_kernel_init.o \
+	    umf_di_kernel_wrapup.o umf_di_local_search.o umf_di_lsolve.o \
+	    umf_di_ltsolve.o umf_di_mem_alloc_element.o \
+	    umf_di_mem_alloc_head_block.o umf_di_mem_alloc_tail_block.o \
+	    umf_di_mem_free_tail_block.o umf_di_mem_init_memoryspace.o \
+	    umf_di_report_vector.o umf_di_row_search.o umf_di_scale_column.o \
+	    umf_di_set_stats.o umf_di_solve.o umf_di_symbolic_usage.o \
+	    umf_di_transpose.o umf_di_tuple_lengths.o umf_di_usolve.o \
+	    umf_di_utsolve.o umf_di_valid_numeric.o umf_di_valid_symbolic.o \
+	    umf_di_grow_front.o umf_di_start_front.o umf_di_2by2.o \
+	    umf_di_store_lu.o umf_di_scale.o umfpack_di_wsolve.o \
+	    umfpack_di_col_to_triplet.o umfpack_di_defaults.o \
+	    umfpack_di_free_numeric.o umfpack_di_free_symbolic.o \
+	    umfpack_di_get_numeric.o umfpack_di_get_lunz.o \
+	    umfpack_di_get_symbolic.o umfpack_di_get_determinant.o \
+	    umfpack_di_numeric.o \
+	    umfpack_di_qsymbolic.o umfpack_di_report_control.o \
+	    umfpack_di_report_info.o umfpack_di_report_matrix.o \
+	    umfpack_di_report_numeric.o umfpack_di_report_perm.o \
+	    umfpack_di_report_status.o umfpack_di_report_symbolic.o \
+	    umfpack_di_report_triplet.o umfpack_di_report_vector.o \
+	    umfpack_di_solve.o umfpack_di_symbolic.o umfpack_di_transpose.o \
+	    umfpack_di_triplet_to_col.o umfpack_di_scale.o \
+	    umfpack_di_load_numeric.o umfpack_di_save_numeric.o \
+	    umfpack_di_load_symbolic.o umfpack_di_save_symbolic.o \
+	    umf_dl_lhsolve.o \
+	    umf_dl_uhsolve.o umf_dl_triplet_map_nox.o umf_dl_triplet_nomap_x.o \
+	    umf_dl_triplet_nomap_nox.o umf_dl_triplet_map_x.o \
+	    umf_dl_assemble_fixq.o umf_dl_store_lu_drop.o umf_dl_assemble.o \
+	    umf_dl_blas3_update.o umf_dl_build_tuples.o \
+	    umf_dl_create_element.o umf_dl_dump.o umf_dl_extend_front.o \
+	    umf_dl_garbage_collection.o umf_dl_get_memory.o \
+	    umf_dl_init_front.o umf_dl_kernel.o umf_dl_kernel_init.o \
+	    umf_dl_kernel_wrapup.o umf_dl_local_search.o umf_dl_lsolve.o \
+	    umf_dl_ltsolve.o umf_dl_mem_alloc_element.o \
+	    umf_dl_mem_alloc_head_block.o umf_dl_mem_alloc_tail_block.o \
+	    umf_dl_mem_free_tail_block.o umf_dl_mem_init_memoryspace.o \
+	    umf_dl_report_vector.o umf_dl_row_search.o umf_dl_scale_column.o \
+	    umf_dl_set_stats.o umf_dl_solve.o umf_dl_symbolic_usage.o \
+	    umf_dl_transpose.o umf_dl_tuple_lengths.o umf_dl_usolve.o \
+	    umf_dl_utsolve.o umf_dl_valid_numeric.o umf_dl_valid_symbolic.o \
+	    umf_dl_grow_front.o umf_dl_start_front.o umf_dl_2by2.o \
+	    umf_dl_store_lu.o umf_dl_scale.o umfpack_dl_wsolve.o \
+	    umfpack_dl_col_to_triplet.o umfpack_dl_defaults.o \
+	    umfpack_dl_free_numeric.o umfpack_dl_free_symbolic.o \
+	    umfpack_dl_get_numeric.o umfpack_dl_get_lunz.o \
+	    umfpack_dl_get_symbolic.o umfpack_dl_get_determinant.o \
+	    umfpack_dl_numeric.o \
+	    umfpack_dl_qsymbolic.o umfpack_dl_report_control.o \
+	    umfpack_dl_report_info.o umfpack_dl_report_matrix.o \
+	    umfpack_dl_report_numeric.o umfpack_dl_report_perm.o \
+	    umfpack_dl_report_status.o umfpack_dl_report_symbolic.o \
+	    umfpack_dl_report_triplet.o umfpack_dl_report_vector.o \
+	    umfpack_dl_solve.o umfpack_dl_symbolic.o umfpack_dl_transpose.o \
+	    umfpack_dl_triplet_to_col.o umfpack_dl_scale.o \
+	    umfpack_dl_load_numeric.o umfpack_dl_save_numeric.o \
+	    umfpack_dl_load_symbolic.o umfpack_dl_save_symbolic.o \
+	    umf_zi_lhsolve.o \
+	    umf_zi_uhsolve.o umf_zi_triplet_map_nox.o umf_zi_triplet_nomap_x.o \
+	    umf_zi_triplet_nomap_nox.o umf_zi_triplet_map_x.o \
+	    umf_zi_assemble_fixq.o umf_zi_store_lu_drop.o umf_zi_assemble.o \
+	    umf_zi_blas3_update.o umf_zi_build_tuples.o \
+	    umf_zi_create_element.o umf_zi_dump.o umf_zi_extend_front.o \
+	    umf_zi_garbage_collection.o umf_zi_get_memory.o \
+	    umf_zi_init_front.o umf_zi_kernel.o umf_zi_kernel_init.o \
+	    umf_zi_kernel_wrapup.o umf_zi_local_search.o umf_zi_lsolve.o \
+	    umf_zi_ltsolve.o umf_zi_mem_alloc_element.o \
+	    umf_zi_mem_alloc_head_block.o umf_zi_mem_alloc_tail_block.o \
+	    umf_zi_mem_free_tail_block.o umf_zi_mem_init_memoryspace.o \
+	    umf_zi_report_vector.o umf_zi_row_search.o umf_zi_scale_column.o \
+	    umf_zi_set_stats.o umf_zi_solve.o umf_zi_symbolic_usage.o \
+	    umf_zi_transpose.o umf_zi_tuple_lengths.o umf_zi_usolve.o \
+	    umf_zi_utsolve.o umf_zi_valid_numeric.o umf_zi_valid_symbolic.o \
+	    umf_zi_grow_front.o umf_zi_start_front.o umf_zi_2by2.o \
+	    umf_zi_store_lu.o umf_zi_scale.o umfpack_zi_wsolve.o \
+	    umfpack_zi_col_to_triplet.o umfpack_zi_defaults.o \
+	    umfpack_zi_free_numeric.o umfpack_zi_free_symbolic.o \
+	    umfpack_zi_get_numeric.o umfpack_zi_get_lunz.o \
+	    umfpack_zi_get_symbolic.o umfpack_zi_get_determinant.o \
+	    umfpack_zi_numeric.o \
+	    umfpack_zi_qsymbolic.o umfpack_zi_report_control.o \
+	    umfpack_zi_report_info.o umfpack_zi_report_matrix.o \
+	    umfpack_zi_report_numeric.o umfpack_zi_report_perm.o \
+	    umfpack_zi_report_status.o umfpack_zi_report_symbolic.o \
+	    umfpack_zi_report_triplet.o umfpack_zi_report_vector.o \
+	    umfpack_zi_solve.o umfpack_zi_symbolic.o umfpack_zi_transpose.o \
+	    umfpack_zi_triplet_to_col.o umfpack_zi_scale.o \
+	    umfpack_zi_load_numeric.o umfpack_zi_save_numeric.o \
+	    umfpack_zi_load_symbolic.o umfpack_zi_save_symbolic.o \
+	    umf_zl_lhsolve.o \
+	    umf_zl_uhsolve.o umf_zl_triplet_map_nox.o umf_zl_triplet_nomap_x.o \
+	    umf_zl_triplet_nomap_nox.o umf_zl_triplet_map_x.o \
+	    umf_zl_assemble_fixq.o umf_zl_store_lu_drop.o umf_zl_assemble.o \
+	    umf_zl_blas3_update.o umf_zl_build_tuples.o \
+	    umf_zl_create_element.o umf_zl_dump.o umf_zl_extend_front.o \
+	    umf_zl_garbage_collection.o umf_zl_get_memory.o \
+	    umf_zl_init_front.o umf_zl_kernel.o umf_zl_kernel_init.o \
+	    umf_zl_kernel_wrapup.o umf_zl_local_search.o umf_zl_lsolve.o \
+	    umf_zl_ltsolve.o umf_zl_mem_alloc_element.o \
+	    umf_zl_mem_alloc_head_block.o umf_zl_mem_alloc_tail_block.o \
+	    umf_zl_mem_free_tail_block.o umf_zl_mem_init_memoryspace.o \
+	    umf_zl_report_vector.o umf_zl_row_search.o umf_zl_scale_column.o \
+	    umf_zl_set_stats.o umf_zl_solve.o umf_zl_symbolic_usage.o \
+	    umf_zl_transpose.o umf_zl_tuple_lengths.o umf_zl_usolve.o \
+	    umf_zl_utsolve.o umf_zl_valid_numeric.o umf_zl_valid_symbolic.o \
+	    umf_zl_grow_front.o umf_zl_start_front.o umf_zl_2by2.o \
+	    umf_zl_store_lu.o umf_zl_scale.o umfpack_zl_wsolve.o \
+	    umfpack_zl_col_to_triplet.o umfpack_zl_defaults.o \
+	    umfpack_zl_free_numeric.o umfpack_zl_free_symbolic.o \
+	    umfpack_zl_get_numeric.o umfpack_zl_get_lunz.o \
+	    umfpack_zl_get_symbolic.o umfpack_zl_get_determinant.o \
+	    umfpack_zl_numeric.o \
+	    umfpack_zl_qsymbolic.o umfpack_zl_report_control.o \
+	    umfpack_zl_report_info.o umfpack_zl_report_matrix.o \
+	    umfpack_zl_report_numeric.o umfpack_zl_report_perm.o \
+	    umfpack_zl_report_status.o umfpack_zl_report_symbolic.o \
+	    umfpack_zl_report_triplet.o umfpack_zl_report_vector.o \
+	    umfpack_zl_solve.o umfpack_zl_symbolic.o umfpack_zl_transpose.o \
+	    umfpack_zl_triplet_to_col.o umfpack_zl_scale.o \
+	    umfpack_zl_load_numeric.o umfpack_zl_save_numeric.o \
+	    umfpack_zl_load_symbolic.o umfpack_zl_save_symbolic.o
+	- $(RANLIB) ../Lib/libumfpack.a
+
+#-------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#-------------------------------------------------------------------------------
+
+purge: clean
+	- $(RM) ../Lib/libumfpack.a
+
+clean:
+	- $(RM) $(CLEAN)
diff --git a/src/C/SuiteSparse/UMFPACK/Source/cholmod_blas.h b/src/C/SuiteSparse/UMFPACK/Source/cholmod_blas.h
new file mode 100644
index 0000000..9619804
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/cholmod_blas.h
@@ -0,0 +1,451 @@
+/* ========================================================================== */
+/* === Include/cholmod_blas.h =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_blas.h.  Version 1.2.
+ * Copyright (C) 2005-2006, Univ. of Florida.  Author: Timothy A. Davis
+ * CHOLMOD/Include/cholmod_blas.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* This does not need to be included in the user's program. */
+
+#ifndef CHOLMOD_BLAS_H
+#define CHOLMOD_BLAS_H
+
+/* ========================================================================== */
+/* === Architecture ========================================================= */
+/* ========================================================================== */
+
+#if defined (__sun) || defined (MSOL2) || defined (ARCH_SOL2)
+#define CHOLMOD_SOL2
+#define CHOLMOD_ARCHITECTURE "Sun Solaris"
+
+#elif defined (__sgi) || defined (MSGI) || defined (ARCH_SGI)
+#define CHOLMOD_SGI
+#define CHOLMOD_ARCHITECTURE "SGI Irix"
+
+#elif defined (__linux) || defined (MGLNX86) || defined (ARCH_GLNX86)
+#define CHOLMOD_LINUX
+#define CHOLMOD_ARCHITECTURE "Linux"
+
+#elif defined (_AIX) || defined (MIBM_RS) || defined (ARCH_IBM_RS)
+#define CHOLMOD_AIX
+#define CHOLMOD_ARCHITECTURE "IBM AIX"
+#define BLAS_NO_UNDERSCORE
+
+#elif defined (__alpha) || defined (MALPHA) || defined (ARCH_ALPHA)
+#define CHOLMOD_ALPHA
+#define CHOLMOD_ARCHITECTURE "Compaq Alpha"
+
+#elif defined (_WIN32) || defined (WIN32) || defined (_WIN64) || defined (WIN64)
+#if defined (__MINGW32__) || defined (__MINGW32__)
+#define CHOLMOD_MINGW
+#elif defined (__CYGWIN32__) || defined (__CYGWIN32__)
+#define CHOLMOD_CYGWIN
+#else
+#define CHOLMOD_WINDOWS
+#define BLAS_NO_UNDERSCORE
+#endif
+#define CHOLMOD_ARCHITECTURE "Microsoft Windows"
+
+#elif defined (__hppa) || defined (__hpux) || defined (MHPUX) || defined (ARCH_HPUX)
+#define CHOLMOD_HP
+#define CHOLMOD_ARCHITECTURE "HP Unix"
+#define BLAS_NO_UNDERSCORE
+
+#elif defined (__hp700) || defined (MHP700) || defined (ARCH_HP700)
+#define CHOLMOD_HP
+#define CHOLMOD_ARCHITECTURE "HP 700 Unix"
+#define BLAS_NO_UNDERSCORE
+
+#else
+/* If the architecture is unknown, and you call the BLAS, you may need to */
+/* define BLAS_BY_VALUE, BLAS_NO_UNDERSCORE, and/or BLAS_CHAR_ARG yourself. */
+#define CHOLMOD_ARCHITECTURE "unknown"
+#endif
+
+
+/* ========================================================================== */
+/* === BLAS and LAPACK names ================================================ */
+/* ========================================================================== */
+
+/* Prototypes for the various versions of the BLAS.  */
+
+/* Determine if the 64-bit Sun Performance BLAS is to be used */
+#if defined(CHOLMOD_SOL2) && !defined(NSUNPERF) && defined(LONG) && defined(LONGBLAS)
+#define SUN64
+#endif
+
+#ifdef SUN64
+
+#define BLAS_DTRSV dtrsv_64_
+#define BLAS_DGEMV dgemv_64_
+#define BLAS_DTRSM dtrsm_64_
+#define BLAS_DGEMM dgemm_64_
+#define BLAS_DSYRK dsyrk_64_
+#define BLAS_DGER  dger_64_
+#define BLAS_DSCAL dscal_64_
+#define LAPACK_DPOTRF dpotrf_64_
+
+#define BLAS_ZTRSV ztrsv_64_
+#define BLAS_ZGEMV zgemv_64_
+#define BLAS_ZTRSM ztrsm_64_
+#define BLAS_ZGEMM zgemm_64_
+#define BLAS_ZHERK zherk_64_
+#define BLAS_ZGER  zgeru_64_
+#define BLAS_ZSCAL zscal_64_
+#define LAPACK_ZPOTRF zpotrf_64_
+
+#elif defined (BLAS_NO_UNDERSCORE)
+
+#define BLAS_DTRSV dtrsv
+#define BLAS_DGEMV dgemv
+#define BLAS_DTRSM dtrsm
+#define BLAS_DGEMM dgemm
+#define BLAS_DSYRK dsyrk
+#define BLAS_DGER  dger
+#define BLAS_DSCAL dscal
+#define LAPACK_DPOTRF dpotrf
+
+#define BLAS_ZTRSV ztrsv
+#define BLAS_ZGEMV zgemv
+#define BLAS_ZTRSM ztrsm
+#define BLAS_ZGEMM zgemm
+#define BLAS_ZHERK zherk
+#define BLAS_ZGER  zgeru
+#define BLAS_ZSCAL zscal
+#define LAPACK_ZPOTRF zpotrf
+
+#else
+
+#define BLAS_DTRSV dtrsv_
+#define BLAS_DGEMV dgemv_
+#define BLAS_DTRSM dtrsm_
+#define BLAS_DGEMM dgemm_
+#define BLAS_DSYRK dsyrk_
+#define BLAS_DGER  dger_
+#define BLAS_DSCAL dscal_
+#define LAPACK_DPOTRF dpotrf_
+
+#define BLAS_ZTRSV ztrsv_
+#define BLAS_ZGEMV zgemv_
+#define BLAS_ZTRSM ztrsm_
+#define BLAS_ZGEMM zgemm_
+#define BLAS_ZHERK zherk_
+#define BLAS_ZGER  zgeru_
+#define BLAS_ZSCAL zscal_
+#define LAPACK_ZPOTRF zpotrf_
+
+#endif
+
+/* ========================================================================== */
+/* === BLAS and LAPACK integer arguments ==================================== */
+/* ========================================================================== */
+
+/* CHOLMOD can be compiled with -D'LONGBLAS=long' for the Sun Performance
+ * Library, or -D'LONGBLAS=long long' for SGI's SCSL BLAS.  This defines the
+ * integer used in the BLAS for the cholmod_l_* routines.
+ *
+ * The "int" version of CHOLMOD always uses the "int" version of the BLAS.
+ */
+
+#if defined (LONGBLAS) && defined (LONG)
+#define BLAS_INT LONGBLAS
+#else
+#define BLAS_INT int
+#endif
+
+/* If the BLAS integer is smaller than the basic CHOLMOD integer, then we need
+ * to check for integer overflow when converting from one to the other.  If
+ * any integer overflows, the externally-defined blas_ok variable is set to
+ * FALSE.  blas_ok should be set to TRUE before calling any BLAS_* macro.
+ */
+
+#define CHECK_BLAS_INT (sizeof (BLAS_INT) < sizeof (Int))
+#define EQ(K,k) (((BLAS_INT) K) == ((Int) k))
+
+/* ========================================================================== */
+/* === BLAS and LAPACK prototypes and macros ================================ */
+/* ========================================================================== */
+
+void BLAS_DGEMV (char *trans, BLAS_INT *m, BLAS_INT *n, double *alpha,
+	double *A, BLAS_INT *lda, double *X, BLAS_INT *incx, double *beta,
+	double *Y, BLAS_INT *incy) ;
+
+#define BLAS_dgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) \
+		&& EQ (INCY,incy) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_DGEMV (trans, &M, &N, alpha, A, &LDA, X, &INCX, beta, Y, &INCY) ; \
+    } \
+}
+
+void BLAS_ZGEMV (char *trans, BLAS_INT *m, BLAS_INT *n, double *alpha,
+	double *A, BLAS_INT *lda, double *X, BLAS_INT *incx, double *beta,
+	double *Y, BLAS_INT *incy) ;
+
+#define BLAS_zgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) \
+		&& EQ (INCY,incy) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_ZGEMV (trans, &M, &N, alpha, A, &LDA, X, &INCX, beta, Y, &INCY) ; \
+    } \
+}
+
+void BLAS_DTRSV (char *uplo, char *trans, char *diag, BLAS_INT *n, double *A,
+	BLAS_INT *lda, double *X, BLAS_INT *incx) ;
+
+#define BLAS_dtrsv(uplo,trans,diag,n,A,lda,X,incx) \
+{ \
+    BLAS_INT N = n, LDA = lda, INCX = incx ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_DTRSV (uplo, trans, diag, &N, A, &LDA, X, &INCX) ; \
+    } \
+}
+
+void BLAS_ZTRSV (char *uplo, char *trans, char *diag, BLAS_INT *n, double *A,
+	BLAS_INT *lda, double *X, BLAS_INT *incx) ;
+
+#define BLAS_ztrsv(uplo,trans,diag,n,A,lda,X,incx) \
+{ \
+    BLAS_INT N = n, LDA = lda, INCX = incx ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_ZTRSV (uplo, trans, diag, &N, A, &LDA, X, &INCX) ; \
+    } \
+}
+
+void BLAS_DTRSM (char *side, char *uplo, char *transa, char *diag, BLAS_INT *m,
+	BLAS_INT *n, double *alpha, double *A, BLAS_INT *lda, double *B,
+	BLAS_INT *ldb) ;
+
+#define BLAS_dtrsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, LDB = ldb ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (LDB,ldb) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_DTRSM (side, uplo, transa, diag, &M, &N, alpha, A, &LDA, B, &LDB);\
+    } \
+}
+
+void BLAS_ZTRSM (char *side, char *uplo, char *transa, char *diag, BLAS_INT *m,
+	BLAS_INT *n, double *alpha, double *A, BLAS_INT *lda, double *B,
+	BLAS_INT *ldb) ;
+
+#define BLAS_ztrsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, LDB = ldb ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (LDB,ldb) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_ZTRSM (side, uplo, transa, diag, &M, &N, alpha, A, &LDA, B, &LDB);\
+    } \
+}
+
+void BLAS_DGEMM (char *transa, char *transb, BLAS_INT *m, BLAS_INT *n,
+	BLAS_INT *k, double *alpha, double *A, BLAS_INT *lda, double *B,
+	BLAS_INT *ldb, double *beta, double *C, BLAS_INT *ldc) ;
+
+#define BLAS_dgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta,C,ldc) \
+{ \
+    BLAS_INT M = m, N = n, K = k, LDA = lda, LDB = ldb, LDC = ldc ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (M,m) && EQ (N,n) && EQ (K,k) && EQ (LDA,lda) \
+		&& EQ (LDB,ldb) && EQ (LDC,ldc) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_DGEMM (transa, transb, &M, &N, &K, alpha, A, &LDA, B, &LDB, beta, \
+	    C, &LDC) ; \
+    } \
+}
+
+void BLAS_ZGEMM (char *transa, char *transb, BLAS_INT *m, BLAS_INT *n,
+	BLAS_INT *k, double *alpha, double *A, BLAS_INT *lda, double *B,
+	BLAS_INT *ldb, double *beta, double *C, BLAS_INT *ldc) ;
+
+#define BLAS_zgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta,C,ldc) \
+{ \
+    BLAS_INT M = m, N = n, K = k, LDA = lda, LDB = ldb, LDC = ldc ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (M,m) && EQ (N,n) && EQ (K,k) && EQ (LDA,lda) \
+		&& EQ (LDB,ldb) && EQ (LDC,ldc) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_ZGEMM (transa, transb, &M, &N, &K, alpha, A, &LDA, B, &LDB, beta, \
+	    C, &LDC) ; \
+    } \
+}
+
+void BLAS_DSYRK (char *uplo, char *trans, BLAS_INT *n, BLAS_INT *k,
+	double *alpha, double *A, BLAS_INT *lda, double *beta, double *C,
+	BLAS_INT *ldc) ;
+
+#define BLAS_dsyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc) \
+{ \
+    BLAS_INT N = n, K = k, LDA = lda, LDC = ldc ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (N,n) && EQ (K,k) && EQ (LDA,lda) && EQ (LDC,ldc) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_DSYRK (uplo, trans, &N, &K, alpha, A, &LDA, beta, C, &LDC) ; \
+    } \
+} \
+
+void BLAS_ZHERK (char *uplo, char *trans, BLAS_INT *n, BLAS_INT *k,
+	double *alpha, double *A, BLAS_INT *lda, double *beta, double *C,
+	BLAS_INT *ldc) ;
+
+#define BLAS_zherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc) \
+{ \
+    BLAS_INT N = n, K = k, LDA = lda, LDC = ldc ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (N,n) && EQ (K,k) && EQ (LDA,lda) && EQ (LDC,ldc) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_ZHERK (uplo, trans, &N, &K, alpha, A, &LDA, beta, C, &LDC) ; \
+    } \
+} \
+
+void LAPACK_DPOTRF (char *uplo, BLAS_INT *n, double *A, BLAS_INT *lda,
+	BLAS_INT *info) ;
+
+#define LAPACK_dpotrf(uplo,n,A,lda,info) \
+{ \
+    BLAS_INT N = n, LDA = lda, INFO = 1 ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (N,n) && EQ (LDA,lda) ; \
+    } \
+    if (blas_ok) \
+    { \
+	LAPACK_DPOTRF (uplo, &N, A, &LDA, &INFO) ; \
+    } \
+    info = INFO ; \
+}
+
+void LAPACK_ZPOTRF (char *uplo, BLAS_INT *n, double *A, BLAS_INT *lda,
+	BLAS_INT *info) ;
+
+#define LAPACK_zpotrf(uplo,n,A,lda,info) \
+{ \
+    BLAS_INT N = n, LDA = lda, INFO = 1 ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (N,n) && EQ (LDA,lda) ; \
+    } \
+    if (blas_ok) \
+    { \
+	LAPACK_ZPOTRF (uplo, &N, A, &LDA, &INFO) ; \
+    } \
+    info = INFO ; \
+}
+
+/* ========================================================================== */
+
+void BLAS_DSCAL (BLAS_INT *n, double *alpha, double *Y, BLAS_INT *incy) ;
+
+#define BLAS_dscal(n,alpha,Y,incy) \
+{ \
+    BLAS_INT N = n, INCY = incy ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (N,n) && EQ (INCY,incy) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_DSCAL (&N, alpha, Y, &INCY) ; \
+    } \
+}
+
+void BLAS_ZSCAL (BLAS_INT *n, double *alpha, double *Y, BLAS_INT *incy) ;
+
+#define BLAS_zscal(n,alpha,Y,incy) \
+{ \
+    BLAS_INT N = n, INCY = incy ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (N,n) && EQ (INCY,incy) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_ZSCAL (&N, alpha, Y, &INCY) ; \
+    } \
+}
+
+void BLAS_DGER (BLAS_INT *m, BLAS_INT *n, double *alpha,
+	double *X, BLAS_INT *incx, double *Y, BLAS_INT *incy,
+	double *A, BLAS_INT *lda) ;
+
+#define BLAS_dger(m,n,alpha,X,incx,Y,incy,A,lda) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) \
+		&& EQ (INCY,incy) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_DGER (&M, &N, alpha, X, &INCX, Y, &INCY, A, &LDA) ; \
+    } \
+}
+
+void BLAS_ZGERU (BLAS_INT *m, BLAS_INT *n, double *alpha,
+	double *X, BLAS_INT *incx, double *Y, BLAS_INT *incy,
+	double *A, BLAS_INT *lda) ;
+
+#define BLAS_zgeru(m,n,alpha,X,incx,Y,incy,A,lda) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \
+    if (CHECK_BLAS_INT) \
+    { \
+	blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) \
+		&& EQ (INCY,incy) ; \
+    } \
+    if (blas_ok) \
+    { \
+	BLAS_ZGER (&M, &N, alpha, X, &INCX, Y, &INCY, A, &LDA) ; \
+    } \
+}
+
+#endif
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_2by2.c b/src/C/SuiteSparse/UMFPACK/Source/umf_2by2.c
new file mode 100644
index 0000000..7a4e3e1
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_2by2.c
@@ -0,0 +1,859 @@
+/* ========================================================================== */
+/* === UMF_2by2 ============================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*  Not user-callable.  Computes a 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) == AMD_OK) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* for each weak diagonal, find a pair of strong off-diagonal entries */
+    /* ---------------------------------------------------------------------- */
+
+    for (row = 0 ; row < n2 ; row++)
+    {
+	P [row] = EMPTY ;
+    }
+
+    unmatched = 0 ;
+    best = EMPTY ;
+    jdiff = EMPTY ;
+    jdeg = EMPTY ;
+
+    for (deg = mindeg ; deg <= maxdeg ; deg++)
+    {
+	/* find the next weak diagonal of lowest degree */
+	DEBUGm2 (("---------------------------------- Deg: "ID"\n", deg)) ;
+	for (k = Head [deg] ; k != EMPTY ; k = Next [k])
+	{
+	    DEBUGm2 (("k: "ID"\n", k)) ;
+	    if (P [k] == EMPTY)
+	    {
+		/* C (k,k) is a weak diagonal entry.  Find an index j != k such
+		 * that C (j,k) and C (k,j) are both strong, and also such
+		 * that Degree [j] is minimized.  In case of a tie, pick
+		 * the smallest index j.  C and R contain the pattern of
+		 * strong entries only.
+		 *
+		 * Note that row k of R and column k of C are both sorted. */
+
+		DEBUGm4 (("===== Weak diagonal k = "ID"\n", k)) ;
+		DEBUG1 (("Column k of C:\n")) ;
+		for (p = Cp [k] ; p < Cp [k+1] ; p++)
+		{
+		    DEBUG1 (("    "ID": deg "ID"\n", Ci [p], Degree [Ci [p]]));
+		}
+		DEBUG1 (("Row k of R (strong entries only):\n")) ;
+		for (p = Rp [k] ; p < Rp [k+1] ; p++)
+		{
+		    DEBUG1 (("    "ID": deg "ID"\n", Ri [p], Degree [Ri [p]]));
+		}
+
+		/* no (C (k,j), C (j,k)) pair exists yet */
+		j_best = EMPTY ;
+		jdiff_best = Int_MAX ;
+		jdeg_best = Int_MAX ;
+
+		/* pointers into column k (including values) */
+		cp1 = Cp [k] ;
+		cp2 = Cp [k+1] ;
+		cp = cp1 ;
+
+		/* pointers into row k (strong entries only, no values) */
+		rp1 = Rp [k] ;
+		rp2 = Rp [k+1] ;
+		rp = rp1 ;
+
+		/* while entries searched in column k and row k */
+		while (TRUE)
+		{
+
+		    if (cp >= cp2)
+		    {
+			/* no more entries in this column */
+			break ;
+		    }
+
+		    /* get C (j,k), which is strong */
+		    j = Ci [cp] ;
+
+		    if (rp >= rp2)
+		    {
+			/* no more entries in this column */
+			break ;
+		    }
+
+		    /* get R (k,j2), which is strong */
+		    j2 = Ri [rp] ;
+
+		    if (j < j2)
+		    {
+			/* C (j,k) is strong, but R (k,j) is not strong */
+			cp++ ;
+			continue ;
+		    }
+
+		    if (j2 < j)
+		    {
+			/* C (k,j2) is strong, but R (j2,k) is not strong */
+			rp++ ;
+			continue ;
+		    }
+
+		    /* j == j2: C (j,k) is strong and R (k,j) is strong */
+
+		    best = FALSE ;
+
+		    if (P [j] == EMPTY)
+		    {
+			/* j has not yet been matched */
+			jdeg = Degree [j] ;
+			jdiff = SCALAR_ABS (k-j) ;
+
+			DEBUG1 (("Try candidate j "ID" deg "ID" diff "ID
+				    "\n", j, jdeg, jdiff)) ;
+
+			if (j_best == EMPTY)
+			{
+			    /* this is the first candidate seen */
+			    DEBUG1 (("   first\n")) ;
+			    best = TRUE ;
+			}
+			else
+			{
+			    if (jdeg < jdeg_best)
+			    {
+				/* the degree of j is best seen so far. */
+				DEBUG1 (("   least degree\n")) ;
+				best = TRUE ;
+			    }
+			    else if (jdeg == jdeg_best)
+			    {
+				/* degree of j and j_best are the same */
+				/* tie break by nearest node number */
+				if (jdiff < jdiff_best)
+				{
+				    DEBUG1 (("   tie degree, closer\n")) ;
+				    best = TRUE ;
+				}
+				else if (jdiff == jdiff_best)
+				{
+				    /* |j-k| = |j_best-k|.  For any given k
+				     * and j_best there is only one other j
+				     * than can be just as close as j_best.
+				     * Tie break by picking the smaller of
+				     * j and j_best */
+				    DEBUG1 (("   tie degree, as close\n"));
+				    best = j < j_best ;
+				}
+			    }
+			    else
+			    {
+				/* j has higher degree than best so far */
+				best = FALSE ;
+			    }
+			}
+		    }
+
+		    if (best)
+		    {
+			/* j is best match for k */
+			/* found a strong pair, A (j,k) and A (k,j) */
+			DEBUG1 ((" --- Found pair k: "ID" j: " ID
+			    " jdeg: "ID" jdiff: "ID"\n",
+			    k, j, jdeg, jdiff)) ;
+			ASSERT (jdiff != EMPTY) ;
+			ASSERT (jdeg != EMPTY) ;
+			j_best = j ;
+			jdeg_best = jdeg ;
+			jdiff_best = jdiff ;
+		    }
+
+		    /* get the next entries in column k and row k */
+		    cp++ ;
+		    rp++ ;
+		}
+
+		/* save the pair (j,k), if we found one */
+		if (j_best != EMPTY)
+		{
+		    j = j_best ;
+		    DEBUGm4 ((" --- best pair j: "ID" for k: "ID"\n", j, k)) ;
+		    P [k] = j ;
+		    P [j] = k ;
+		}
+		else
+		{
+		    /* no match was found for k */
+		    unmatched++ ;
+		}
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* finalize the row permutation, P */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < n2 ; k++)
+    {
+	if (P [k] == EMPTY)
+	{
+	    P [k] = k ;
+	}
+    }
+    ASSERT (UMF_is_permutation (P, Rp, n2, n2)) ;
+
+    return (unmatched) ;
+}
+
+
+/* ========================================================================== */
+/* === UMF_2by2 ============================================================= */
+/* ========================================================================== */
+
+GLOBAL void UMF_2by2
+(
+    /* input, not modified: */
+    Int n,		    /* A is n-by-n */
+    const Int Ap [ ],	    /* size n+1 */
+    const Int Ai [ ],	    /* size nz = Ap [n] */
+    const double Ax [ ],    /* size nz if present */
+#ifdef COMPLEX
+    const double Az [ ],    /* size nz if present */
+#endif
+    double tol,		/* tolerance for determining whether or not an
+			 * entry is numerically acceptable.  If tol <= 0
+			 * then all numerical values ignored. */
+    Int scale,		/* scaling to perform (none, sum, or max) */
+    Int Cperm1 [ ],	/* singleton permutations */
+#ifndef NDEBUG
+    Int Rperm1 [ ],	/* not needed, since Rperm1 = Cperm1 for submatrix S */
+#endif
+    Int InvRperm1 [ ],	/* inverse of Rperm1 */
+    Int n1,		/* number of singletons */
+    Int nempty,		/* number of empty rows/cols */
+
+    /* input, contents undefined on output: */
+    Int Degree [ ],	/* Degree [j] is the number of off-diagonal
+			 * entries in row/column j of S+S', where
+			 * where S = A (Cperm1 [n1..], Rperm1 [n1..]).
+			 * Note that S is not used, nor formed. */
+
+    /* output: */
+    Int P [ ],		/* P [k] = i means original row i is kth row in S(P,:)
+			 * where S = A (Cperm1 [n1..], Rperm1 [n1..]) */
+    Int *p_nweak,
+    Int *p_unmatched,
+
+    /* workspace (not defined on input or output): */
+    Int Ri [ ],		/* of size >= max (nz, n) */
+    Int Rp [ ],		/* of size n+1 */
+    double Rs [ ],	/* of size n if present.  Rs = sum (abs (A),2) or
+			 * max (abs (A),2), the sum or max of each row.  Unused
+			 * if scale is equal to UMFPACK_SCALE_NONE. */
+    Int Head [ ],	/* of size n.  Head pointers for bucket sort */
+    Int Next [ ],	/* of size n.  Next pointers for bucket sort */
+    Int Ci [ ],		/* size nz */
+    Int Cp [ ]		/* size n+1 */
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Entry aij ;
+    double cmax, value, rs, ctol, dvalue ;
+    Int k, p, row, col, do_values, do_sum, do_max, do_scale, nweak, weak,
+	p1, p2, dfound, unmatched, n2, oldrow, newrow, oldcol, newcol, pp ;
+#ifdef COMPLEX
+    Int split = SPLIT (Az) ;
+#endif
+#ifndef NRECIPROCAL
+    Int do_recip = FALSE ;
+#endif
+
+#ifndef NDEBUG
+    /* UMF_debug += 99 ; */
+    DEBUGm3 (("\n ==================================UMF_2by2: tol %g\n", tol)) ;
+    ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
+    for (k = n1 ; k < n - nempty ; k++)
+    {
+	ASSERT (Cperm1 [k] == Rperm1 [k]) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* determine scaling options */
+    /* ---------------------------------------------------------------------- */
+
+    /* use the values, but only if they are present */
+    /* ignore the values if tol <= 0 */
+    do_values = (tol > 0) && (Ax != (double *) NULL) ;
+    if (do_values && (Rs != (double *) NULL))
+    {
+	do_sum = (scale == UMFPACK_SCALE_SUM) ;
+	do_max = (scale == UMFPACK_SCALE_MAX) ;
+    }
+    else
+    {
+	/* no scaling */
+	do_sum = FALSE ;
+	do_max = FALSE ;
+    }
+    do_scale = do_max || do_sum ;
+    DEBUGm3 (("do_values "ID" do_sum "ID" do_max "ID" do_scale "ID"\n",
+	do_values, do_sum, do_max, do_scale)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the row scaling, if requested */
+    /* ---------------------------------------------------------------------- */
+
+    /* see also umf_kernel_init */
+
+    if (do_scale)
+    {
+#ifndef NRECIPROCAL
+	double rsmin ;
+#endif
+	for (row = 0 ; row < n ; row++)
+	{
+	    Rs [row] = 0.0 ;
+	}
+	for (col = 0 ; col < n ; col++)
+	{
+	    p2 = Ap [col+1] ;
+	    for (p = Ap [col] ; p < p2 ; p++)
+	    {
+		row = Ai [p] ;
+		ASSIGN (aij, Ax, Az, p, split) ;
+		APPROX_ABS (value, aij) ;
+		rs = Rs [row] ;
+		if (!SCALAR_IS_NAN (rs))
+		{
+		    if (SCALAR_IS_NAN (value))
+		    {
+			/* if any entry in a row is NaN, then the scale factor
+			 * for the row is NaN.  It will be set to 1 later. */
+			Rs [row] = value ;
+		    }
+		    else if (do_max)
+		    {
+			Rs [row] = MAX (rs, value) ;
+		    }
+		    else
+		    {
+			Rs [row] += value ;
+		    }
+		}
+	    }
+	}
+#ifndef NRECIPROCAL
+	rsmin = Rs [0] ;
+	if (SCALAR_IS_ZERO (rsmin) || SCALAR_IS_NAN (rsmin))
+	{
+	    rsmin = 1.0 ;
+	}
+#endif
+	for (row = 0 ; row < n ; row++)
+	{
+	    /* do not scale an empty row, or a row with a NaN */
+	    rs = Rs [row] ;
+	    if (SCALAR_IS_ZERO (rs) || SCALAR_IS_NAN (rs))
+	    {
+		Rs [row] = 1.0 ;
+	    }
+#ifndef NRECIPROCAL
+	    rsmin = MIN (rsmin, Rs [row]) ;
+#endif
+	}
+
+#ifndef NRECIPROCAL
+	/* multiply by the reciprocal if Rs is not too small */
+	do_recip = (rsmin >= RECIPROCAL_TOLERANCE) ;
+	if (do_recip)
+	{
+	    /* invert the scale factors */
+	    for (row = 0 ; row < n ; row++)
+	    {
+		Rs [row] = 1.0 / Rs [row] ;
+	    }
+	}
+#endif
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the max in each column and find diagonal */
+    /* ---------------------------------------------------------------------- */
+
+    nweak = 0 ;
+
+#ifndef NDEBUG
+    for (k = 0 ; k < n ; k++)
+    {
+	ASSERT (Rperm1 [k] >= 0 && Rperm1 [k] < n) ;
+	ASSERT (InvRperm1 [Rperm1 [k]] == k) ;
+    }
+#endif
+
+    n2 = n - n1 - nempty ;
+
+    /* use Ri to count the number of strong entries in each row */
+    for (row = 0 ; row < n2 ; row++)
+    {
+	Ri [row] = 0 ;
+    }
+
+    pp = 0 ;
+    ctol = 0 ;
+    dvalue = 1 ;
+
+    /* construct C = pruned submatrix, strong values only, column form */
+
+    for (k = n1 ; k < n - nempty ; k++)
+    {
+	oldcol = Cperm1 [k] ;
+	newcol = k - n1 ;
+	Next [newcol] = EMPTY ;
+	DEBUGm1 (("Column "ID" newcol "ID" oldcol "ID"\n", k, newcol, oldcol)) ;
+
+	Cp [newcol] = pp ;
+
+	dfound = FALSE ;
+	p1 = Ap [oldcol] ;
+	p2 = Ap [oldcol+1] ;
+	if (do_values)
+	{
+	    cmax = 0 ;
+	    dvalue = 0 ;
+
+	    if (!do_scale)
+	    {
+		/* no scaling */
+		for (p = p1 ; p < p2 ; p++)
+		{
+		    oldrow = Ai [p] ;
+		    ASSERT (oldrow >= 0 && oldrow < n) ;
+		    newrow = InvRperm1 [oldrow] - n1 ;
+		    ASSERT (newrow >= -n1 && newrow < n2) ;
+		    if (newrow < 0) continue ;
+		    ASSIGN (aij, Ax, Az, p, split) ;
+		    APPROX_ABS (value, aij) ;
+		    /* if either cmax or value is NaN, define cmax as NaN */
+		    if (!SCALAR_IS_NAN (cmax))
+		    {
+			if (SCALAR_IS_NAN (value))
+			{
+			    cmax = value ;
+			}
+			else
+			{
+			    cmax = MAX (cmax, value) ;
+			}
+		    }
+		    if (oldrow == oldcol)
+		    {
+			/* we found the diagonal entry in this column */
+			dvalue = value ;
+			dfound = TRUE ;
+			ASSERT (newrow == newcol) ;
+		    }
+		}
+	    }
+#ifndef NRECIPROCAL
+	    else if (do_recip)
+	    {
+		/* multiply by the reciprocal */
+		for (p = p1 ; p < p2 ; p++)
+		{
+		    oldrow = Ai [p] ;
+		    ASSERT (oldrow >= 0 && oldrow < n) ;
+		    newrow = InvRperm1 [oldrow] - n1 ;
+		    ASSERT (newrow >= -n1 && newrow < n2) ;
+		    if (newrow < 0) continue ;
+		    ASSIGN (aij, Ax, Az, p, split) ;
+		    APPROX_ABS (value, aij) ;
+		    value *= Rs [oldrow] ;
+		    /* if either cmax or value is NaN, define cmax as NaN */
+		    if (!SCALAR_IS_NAN (cmax))
+		    {
+			if (SCALAR_IS_NAN (value))
+			{
+			    cmax = value ;
+			}
+			else
+			{
+			    cmax = MAX (cmax, value) ;
+			}
+		    }
+		    if (oldrow == oldcol)
+		    {
+			/* we found the diagonal entry in this column */
+			dvalue = value ;
+			dfound = TRUE ;
+			ASSERT (newrow == newcol) ;
+		    }
+		}
+	    }
+#endif
+	    else
+	    {
+		/* divide instead */
+		for (p = p1 ; p < p2 ; p++)
+		{
+		    oldrow = Ai [p] ;
+		    ASSERT (oldrow >= 0 && oldrow < n) ;
+		    newrow = InvRperm1 [oldrow] - n1 ;
+		    ASSERT (newrow >= -n1 && newrow < n2) ;
+		    if (newrow < 0) continue ;
+		    ASSIGN (aij, Ax, Az, p, split) ;
+		    APPROX_ABS (value, aij) ;
+		    value /= Rs [oldrow] ;
+		    /* if either cmax or value is NaN, define cmax as NaN */
+		    if (!SCALAR_IS_NAN (cmax))
+		    {
+			if (SCALAR_IS_NAN (value))
+			{
+			    cmax = value ;
+			}
+			else
+			{
+			    cmax = MAX (cmax, value) ;
+			}
+		    }
+		    if (oldrow == oldcol)
+		    {
+			/* we found the diagonal entry in this column */
+			dvalue = value ;
+			dfound = TRUE ;
+			ASSERT (newrow == newcol) ;
+		    }
+		}
+	    }
+
+	    ctol = tol * cmax ;
+	    DEBUGm1 (("    cmax col "ID" %g  ctol %g\n", oldcol, cmax, ctol)) ;
+	}
+	else
+	{
+	    for (p = p1 ; p < p2 ; p++)
+	    {
+		oldrow = Ai [p] ;
+		ASSERT (oldrow >= 0 && oldrow < n) ;
+		newrow = InvRperm1 [oldrow] - n1 ;
+		ASSERT (newrow >= -n1 && newrow < n2) ;
+		if (newrow < 0) continue ;
+		Ci [pp++] = newrow ;
+		if (oldrow == oldcol)
+		{
+		    /* we found the diagonal entry in this column */
+		    ASSERT (newrow == newcol) ;
+		    dfound = TRUE ;
+		}
+		/* count the entries in each column */
+		Ri [newrow]++ ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* flag the weak diagonals */
+	/* ------------------------------------------------------------------ */
+
+	if (!dfound)
+	{
+	    /* no diagonal entry present */
+	    weak = TRUE ;
+	}
+	else
+	{
+	    /* diagonal entry is present, check its value */
+	    weak = (do_values) ?  WEAK (dvalue, ctol) : FALSE ;
+	}
+	if (weak)
+	{
+	    /* flag this column as weak */
+	    DEBUG0 (("Weak!\n")) ;
+	    Next [newcol] = IS_WEAK ;
+	    nweak++ ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* count entries in each row that are not numerically weak */
+	/* ------------------------------------------------------------------ */
+
+	if (do_values)
+	{
+	    if (!do_scale)
+	    {
+		/* no scaling */
+		for (p = p1 ; p < p2 ; p++)
+		{
+		    oldrow = Ai [p] ;
+		    newrow = InvRperm1 [oldrow] - n1 ;
+		    if (newrow < 0) continue ;
+		    ASSIGN (aij, Ax, Az, p, split) ;
+		    APPROX_ABS (value, aij) ;
+		    weak = WEAK (value, ctol) ;
+		    if (!weak)
+		    {
+			DEBUG0 (("    strong: row "ID": %g\n", oldrow, value)) ;
+			Ci [pp++] = newrow ;
+			Ri [newrow]++ ;
+		    }
+		}
+	    }
+#ifndef NRECIPROCAL
+	    else if (do_recip)
+	    {
+		/* multiply by the reciprocal */
+		for (p = p1 ; p < p2 ; p++)
+		{
+		    oldrow = Ai [p] ;
+		    newrow = InvRperm1 [oldrow] - n1 ;
+		    if (newrow < 0) continue ;
+		    ASSIGN (aij, Ax, Az, p, split) ;
+		    APPROX_ABS (value, aij) ;
+		    value *= Rs [oldrow] ;
+		    weak = WEAK (value, ctol) ;
+		    if (!weak)
+		    {
+			DEBUG0 (("    strong: row "ID": %g\n", oldrow, value)) ;
+			Ci [pp++] = newrow ;
+			Ri [newrow]++ ;
+		    }
+		}
+	    }
+#endif
+	    else
+	    {
+		/* divide instead */
+		for (p = p1 ; p < p2 ; p++)
+		{
+		    oldrow = Ai [p] ;
+		    newrow = InvRperm1 [oldrow] - n1 ;
+		    if (newrow < 0) continue ;
+		    ASSIGN (aij, Ax, Az, p, split) ;
+		    APPROX_ABS (value, aij) ;
+		    value /= Rs [oldrow] ;
+		    weak = WEAK (value, ctol) ;
+		    if (!weak)
+		    {
+			DEBUG0 (("    strong: row "ID": %g\n", oldrow, value)) ;
+			Ci [pp++] = newrow ;
+			Ri [newrow]++ ;
+		    }
+		}
+	    }
+	}
+    }
+    Cp [n2] = pp ;
+    ASSERT (AMD_valid (n2, n2, Cp, Ci) == AMD_OK) ;
+
+    if (nweak == 0)
+    {
+	/* nothing to do, quick return */
+	DEBUGm2 (("\n =============================UMF_2by2: quick return\n")) ;
+	for (k = 0 ; k < n ; k++)
+	{
+	    P [k] = k ;
+	}
+	*p_nweak = 0 ;
+	*p_unmatched = 0 ;
+	return ;
+    }
+
+#ifndef NDEBUG
+    for (k = 0 ; k < n2 ; k++)
+    {
+	P [k] = EMPTY ;
+    }
+    for (k = 0 ; k < n2 ; k++)
+    {
+	ASSERT (Degree [k] >= 0 && Degree [k] < n2) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* find the 2-by-2 permutation */
+    /* ---------------------------------------------------------------------- */
+
+    /* The matrix S is now mapped to the index range 0 to n2-1.  We have
+     * S = A (Rperm [n1 .. n-nempty-1], Cperm [n1 .. n-nempty-1]), and then
+     * C = pattern of strong entries in S.  A weak diagonal k in S is marked
+     * with Next [k] = IS_WEAK. */
+
+    unmatched = two_by_two (n2, Cp, Ci, Degree, Next, Ri, P, Rp, Head) ;
+
+    /* ---------------------------------------------------------------------- */
+
+    *p_nweak = nweak ;
+    *p_unmatched = unmatched ;
+
+#ifndef NDEBUG
+    DEBUGm4 (("UMF_2by2: weak "ID"  unmatched "ID"\n", nweak, unmatched)) ;
+    for (row = 0 ; row < n ; row++)
+    {
+	DEBUGm2 (("P ["ID"] = "ID"\n", row, P [row])) ;
+    }
+    DEBUGm2 (("\n =============================UMF_2by2: done\n\n")) ;
+#endif
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_2by2.h b/src/C/SuiteSparse/UMFPACK/Source/umf_2by2.h
new file mode 100644
index 0000000..078625e
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_2by2.h
@@ -0,0 +1,36 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_2by2
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    double tol,
+    Int scale,
+    Int Cperm1 [ ],
+#ifndef NDEBUG
+    Int Rperm1 [ ],
+#endif
+    Int InvRperm [ ],
+    Int n1,
+    Int nempty,
+    Int Degree [ ],
+    Int P [ ],
+    Int *p_nweak,
+    Int *p_nmatched,
+    Int Ri [ ],
+    Int Rp [ ],
+    double Rs [ ],
+    Int Head [ ],
+    Int Next [ ],
+    Int Si [ ],
+    Int Sp [ ]
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_analyze.c b/src/C/SuiteSparse/UMFPACK/Source/umf_analyze.c
new file mode 100644
index 0000000..fa8aecd
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_analyze.c
@@ -0,0 +1,704 @@
+/* ========================================================================== */
+/* === UMF_analyze ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Symbolic LL' factorization of A'*A, to get upper bounds on the size of
+    L and U for LU = PAQ, and to determine the frontal matrices and
+    (supernodal) column elimination tree.  No fill-reducing column pre-ordering
+    is used.
+
+    Returns TRUE if successful, FALSE if out of memory.  UMF_analyze can only
+    run out of memory if anzmax (which is Ap [n_row]) is too small.
+
+    Uses workspace of size O(nonzeros in A).  On input, the matrix A is
+    stored in row-form at the tail end of Ai.  It is destroyed on output.
+    The rows of A must be sorted by increasing first column index.
+    The matrix is assumed to be valid.
+
+    Empty rows and columns have already been removed.
+
+*/
+
+#include "umf_internal.h"
+#include "umf_apply_order.h"
+#include "umf_fsize.h"
+
+/* ========================================================================== */
+
+GLOBAL Int UMF_analyze
+(
+    Int n_row,		/* A is n_row-by-n_col */
+    Int n_col,
+    Int Ai [ ],		/* Ai [Ap [0]..Ap[n_row]-1]: column indices */
+			/* destroyed on output.  Note that this is NOT the */
+			/* user's Ai that was passed to UMFPACK_*symbolic */
+			/* size of Ai, Ap [n_row] = anzmax >= anz + n_col */
+			/* Ap [0] must be => n_col.  The space to the */
+			/* front of Ai is used as workspace. */
+
+    Int Ap [ ],		/* of size MAX (n_row, n_col) + 1 */
+			/* Ap [0..n_row]: row pointers */
+			/* Row i is in Ai [Ap [i] ... Ap [i+1]-1] */
+
+			/* rows must have smallest col index first, or be */
+			/* in sorted form.  Used as workspace of size n_col */
+			/* and destroyed. */
+
+			/* Note that this is NOT the */
+			/* user's Ap that was passed to UMFPACK_*symbolic */
+
+    Int Up [ ],		/* workspace of size n_col, and output column perm.
+			 * for column etree postorder. */
+
+    Int fixQ,
+
+    /* temporary workspaces: */
+    Int W [ ],		/* W [0..n_col-1] */
+    Int Link [ ],	/* Link [0..n_col-1] */
+
+    /* output: information about each frontal matrix: */
+    Int Front_ncols [ ],	/* size n_col */
+    Int Front_nrows [ ],	/* of size n_col */
+    Int Front_npivcol [ ],	/* of size n_col */
+    Int Front_parent [ ],	/* of size n_col */
+    Int *nfr_out,
+
+    Int *p_ncompactions		/* number of compactions in UMF_analyze */
+)
+{
+    /* ====================================================================== */
+    /* ==== local variables ================================================= */
+    /* ====================================================================== */
+
+    Int j, j3, col, k, row, parent, j2, pdest, p, p2, thickness, npivots, nfr,
+	i, *Winv, kk, npiv, jnext, krow, knext, pfirst, jlast, ncompactions,
+	*Front_stack, *Front_order, *Front_child, *Front_sibling,
+	Wflag, npivcol, fallrows, fallcols, fpiv, frows, fcols, *Front_size ;
+
+    nfr = 0 ;
+    DEBUG0 (("UMF_analyze: anzmax "ID" anrow "ID" ancol "ID"\n",
+	Ap [n_row], n_row, n_col)) ;
+
+    /* ====================================================================== */
+    /* ==== initializations ================================================= */
+    /* ====================================================================== */
+
+#pragma ivdep
+    for (j = 0 ; j < n_col ; j++)
+    {
+	Link [j] = EMPTY ;
+	W [j] = EMPTY ;
+	Up [j] = EMPTY ;
+
+	/* Frontal matrix data structure: */
+	Front_npivcol [j] = 0 ;		/* number of pivot columns */
+	Front_nrows [j] = 0 ;		/* number of rows, incl. pivot rows */
+	Front_ncols [j] = 0 ;		/* number of cols, incl. pivot cols */
+	Front_parent [j] = EMPTY ;	/* parent front */
+	/* Note that only non-pivotal columns are stored in a front (a "row" */
+	/* of U) during elimination. */
+    }
+
+    /* the rows must be sorted by increasing min col */
+    krow = 0 ;
+    pfirst = Ap [0] ;
+    jlast = EMPTY ;
+    jnext = EMPTY ;
+    Wflag = 0 ;
+
+    /* this test requires the size of Ai to be >= n_col + nz */
+    ASSERT (pfirst >= n_col) ;	/* Ai must be large enough */
+
+    /* pdest points to the first free space in Ai */
+    pdest = 0 ;
+    ncompactions = 0 ;
+
+    /* ====================================================================== */
+    /* === compute symbolic LL' factorization (unsorted) ==================== */
+    /* ====================================================================== */
+
+    for (j = 0 ; j < n_col ; j = jnext)
+    {
+	DEBUG1 (("\n\n============Front "ID" starting. nfr = "ID"\n", j, nfr)) ;
+
+	/* ================================================================== */
+	/* === garbage collection =========================================== */
+	/* ================================================================== */
+
+	if (pdest + (n_col-j) > pfirst)
+	{
+	    /* we might run out ... compact the rows of U */
+
+#ifndef NDEBUG
+	    DEBUG0 (("UMF_analyze COMPACTION, j="ID" pfirst="ID"\n",
+		j, pfirst)) ;
+	    for (row = 0 ; row < j ; row++)
+	    {
+		if (Up [row] != EMPTY)
+		{
+		    /* this is a live row of U */
+		    DEBUG1 (("Live row: "ID" cols: ", row)) ;
+		    p = Up [row] ;
+		    ASSERT (Front_ncols [row] > Front_npivcol [row]) ;
+		    p2 = p + (Front_ncols [row] - Front_npivcol [row]) ;
+		    for ( ; p < p2 ; p++)
+		    {
+			DEBUG1 ((ID, Ai [p])) ;
+			ASSERT (p < pfirst) ;
+			ASSERT (Ai [p] > row && Ai [p] < n_col) ;
+		    }
+		    DEBUG1 (("\n")) ;
+		}
+	    }
+	    DEBUG1 (("\nStarting to compact:\n")) ;
+#endif
+
+	    pdest = 0 ;
+	    ncompactions++ ;
+	    for (row = 0 ; row < j ; row++)
+	    {
+		if (Up [row] != EMPTY)
+		{
+		    /* this is a live row of U */
+		    DEBUG1 (("Live row: "ID" cols: ", row)) ;
+		    ASSERT (row < n_col) ;
+		    p = Up [row] ;
+		    ASSERT (Front_ncols [row] > Front_npivcol [row]) ;
+		    p2 = p + (Front_ncols [row] - Front_npivcol [row]) ;
+		    Up [row] = pdest ;
+		    for ( ; p < p2 ; p++)
+		    {
+			DEBUG1 ((ID, Ai [p])) ;
+			ASSERT (p < pfirst) ;
+			ASSERT (Ai [p] > row && Ai [p] < n_col) ;
+			Ai [pdest++] = Ai [p] ;
+			ASSERT (pdest <= pfirst) ;
+		    }
+		    DEBUG1 (("\n")) ;
+		}
+	    }
+
+#ifndef NDEBUG
+	    DEBUG1 (("\nAFTER COMPACTION, j="ID" pfirst="ID"\n", j, pfirst)) ;
+	    for (row = 0 ; row < j ; row++)
+	    {
+		if (Up [row] != EMPTY)
+		{
+		    /* this is a live row of U */
+		    DEBUG1 (("Live row: "ID" cols: ", row)) ;
+		    p = Up [row] ;
+		    ASSERT (Front_ncols [row] > Front_npivcol [row]) ;
+		    p2 = p + (Front_ncols [row] - Front_npivcol [row]) ;
+		    for ( ; p < p2 ; p++)
+		    {
+			DEBUG1 ((ID, Ai [p])) ;
+			ASSERT (p < pfirst) ;
+			ASSERT (Ai [p] > row && Ai [p] < n_col) ;
+		    }
+		    DEBUG1 (("\n")) ;
+		}
+	    }
+#endif
+
+	}
+
+	if (pdest + (n_col-j) > pfirst)
+	{
+	    /* :: out of memory in umf_analyze :: */
+	    /* it can't happen, if pfirst >= n_col */
+	    return (FALSE) ;	/* internal error! */
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* is the last front a child of this one? */
+	/* ------------------------------------------------------------------ */
+
+	if (jlast != EMPTY && Link [j] == jlast)
+	{
+	    /* yes - create row j by appending to jlast */
+	    DEBUG1 (("GOT:last front is child of this one: j "ID" jlast "ID"\n",
+		j, jlast)) ;
+	    ASSERT (jlast >= 0 && jlast < j) ;
+
+	    Up [j] = Up [jlast] ;
+	    Up [jlast] = EMPTY ;
+
+	    /* find the parent, delete column j, and update W */
+	    parent = n_col ;
+	    for (p = Up [j] ; p < pdest ; )
+	    {
+		j3 = Ai [p] ;
+		DEBUG1 (("Initial row of U: col "ID" ", j3)) ;
+		ASSERT (j3 >= 0 && j3 < n_col) ;
+		DEBUG1 (("W: "ID" \n", W [j3])) ;
+		ASSERT (W [j3] == Wflag) ;
+		if (j == j3)
+		{
+		    DEBUG1 (("Found column j at p = "ID"\n", p)) ;
+		    Ai [p] = Ai [--pdest] ;
+		}
+		else
+		{
+		    if (j3 < parent)
+		    {
+			parent = j3 ;
+		    }
+		    p++ ;
+		}
+	    }
+
+	    /* delete jlast from the link list of j */
+	    Link [j] = Link [jlast] ;
+
+	    ASSERT (Front_nrows [jlast] > Front_npivcol [jlast]) ;
+	    thickness = (Front_nrows [jlast] - Front_npivcol [jlast]) ;
+	    DEBUG1 (("initial thickness: "ID"\n", thickness)) ;
+
+	}
+	else
+	{
+	    Up [j] = pdest ;
+	    parent = n_col ;
+	    /* thickness: number of (nonpivotal) rows in frontal matrix j */
+	    thickness = 0 ;
+	    Wflag = j ;
+	}
+
+	/* ================================================================== */
+	/* === compute row j of A*A' ======================================== */
+	/* ================================================================== */
+
+	/* ------------------------------------------------------------------ */
+	/* flag the diagonal entry in row U, but do not add to pattern */
+	/* ------------------------------------------------------------------ */
+
+	ASSERT (pdest <= pfirst) ;
+	W [j] = Wflag ;
+
+	DEBUG1 (("\nComputing row "ID" of A'*A\n", j)) ;
+	DEBUG2 (("	col: "ID" (diagonal)\n", j)) ;
+
+	/* ------------------------------------------------------------------ */
+	/* find the rows the contribute to this column j */
+	/* ------------------------------------------------------------------ */
+
+	jnext = n_col ;
+	for (knext = krow ; knext < n_row ; knext++)
+	{
+	    ASSERT (Ap [knext] < Ap [knext+1]) ;
+	    ASSERT (Ap [knext] >= pfirst && Ap [knext] <= Ap [n_row]) ;
+	    jnext = Ai [Ap [knext]] ;
+	    ASSERT (jnext >= j) ;
+	    if (jnext != j)
+	    {
+		break ;
+	    }
+	}
+
+	/* rows krow ... knext-1 all have first column index of j */
+	/* (or are empty) */
+
+	/* row knext has first column index of jnext */
+	/* if knext = n_row, then jnext is n_col */
+	if (knext == n_row)
+	{
+	    jnext = n_col ;
+	}
+
+	ASSERT (jnext > j) ;
+	ASSERT (jnext <= n_col) ;
+
+	/* ------------------------------------------------------------------ */
+	/* for each nonzero A (k,j) in column j of A do: */
+	/* ------------------------------------------------------------------ */
+
+	for (k = krow ; k < knext ; k++)
+	{
+	    p = Ap [k] ;
+	    p2 = Ap [k+1] ;
+	    ASSERT (p < p2) ;
+
+	    /* merge row k of A into W */
+	    DEBUG2 (("	---- A row "ID" ", k)) ;
+	    ASSERT (k >= 0 && k < n_row) ;
+	    ASSERT (Ai [p] == j) ;
+	    DEBUG2 (("  p "ID" p2 "ID"\n        cols:", p, p2)) ;
+	    ASSERT (p  >= pfirst && p  < Ap [n_row]) ;
+	    ASSERT (p2 >  pfirst && p2 <= Ap [n_row]) ;
+	    for ( ; p < p2 ; p++)
+	    {
+		/* add to pattern if seen for the first time */
+		col = Ai [p] ;
+		ASSERT (col >= j && col < n_col) ;
+		DEBUG3 ((" "ID, col)) ;
+		if (W [col] != Wflag)
+		{
+		    Ai [pdest++] = col ;
+		    ASSERT (pdest <= pfirst) ;
+		    /* flag this column has having been seen for row j */
+		    W [col] = Wflag ;
+		    if (col < parent)
+		    {
+			parent = col ;
+		    }
+		}
+	    }
+	    DEBUG2 (("\n")) ;
+	    thickness++ ;
+	}
+
+#ifndef NDEBUG
+	DEBUG3 (("\nRow "ID" of A'A:\n", j)) ;
+	for (p = Up [j] ; p < pdest ; p++)
+	{
+	    DEBUG3 ((" "ID, Ai [p])) ;
+	}
+	DEBUG3 (("\n")) ;
+#endif
+
+	/* ------------------------------------------------------------------ */
+	/* delete rows up to but not including knext */
+	/* ------------------------------------------------------------------ */
+
+	krow = knext ;
+	pfirst = Ap [knext] ;
+
+	/* we can now use Ai [0..pfirst-1] as workspace for rows of U */
+
+	/* ================================================================== */
+	/* === compute jth row of U ========================================= */
+	/* ================================================================== */
+
+	/* for each nonzero U (k,j) in column j of U (1:j-1,:) do */
+	for (k = Link [j] ; k != EMPTY ; k = Link [k])
+	{
+	    /* merge row k of U into W */
+	    DEBUG2 (("	---- U row "ID, k)) ;
+	    ASSERT (k >= 0 && k < n_col) ;
+	    ASSERT (Up [k] != EMPTY) ;
+	    p = Up [k] ;
+	    ASSERT (Front_ncols [k] > Front_npivcol [k]) ;
+	    p2 = p + (Front_ncols [k] - Front_npivcol [k]) ;
+	    DEBUG2 (("  p "ID" p2 "ID"\n        cols:", p, p2)) ;
+	    ASSERT (p <= pfirst) ;
+	    ASSERT (p2 <= pfirst) ;
+	    for ( ; p < p2 ; p++)
+	    {
+		/* add to pattern if seen for the first time */
+		col = Ai [p] ;
+		ASSERT (col >= j && col < n_col) ;
+		DEBUG3 ((" "ID, col)) ;
+		if (W [col] != Wflag)
+		{
+		    Ai [pdest++] = col ;
+		    ASSERT (pdest <= pfirst) ;
+		    /* flag this col has having been seen for row j */
+		    W [col] = Wflag ;
+		    if (col < parent)
+		    {
+			parent = col ;
+		    }
+		}
+	    }
+	    DEBUG2 (("\n")) ;
+
+	    /* mark the row k as deleted */
+	    Up [k] = EMPTY ;
+
+	    ASSERT (Front_nrows [k] > Front_npivcol [k]) ;
+	    thickness += (Front_nrows [k] - Front_npivcol [k]) ;
+	    ASSERT (Front_parent [k] == j) ;
+	}
+
+#ifndef NDEBUG
+	DEBUG3 (("\nRow "ID" of U prior to supercolumn detection:\n", j));
+	for (p = Up [j] ; p < pdest ; p++)
+	{
+	    DEBUG3 ((" "ID, Ai [p])) ;
+	}
+	DEBUG3 (("\n")) ;
+	DEBUG1 (("thickness, prior to supercol detect: "ID"\n", thickness)) ;
+#endif
+
+	/* ================================================================== */
+	/* === quicky mass elimination ====================================== */
+	/* ================================================================== */
+
+	/* this code detects some supernodes, but it might miss */
+	/* some because the elimination tree (created on the fly) */
+	/* is not yet post-ordered, and because the pattern of A'*A */
+	/* is also computed on the fly. */
+
+	/* j2 is incremented because the pivot columns are not stored */
+
+	for (j2 = j+1 ; j2 < jnext ; j2++)
+	{
+	    ASSERT (j2 >= 0 && j2 < n_col) ;
+	    if (W [j2] != Wflag || Link [j2] != EMPTY)
+	    {
+		break ;
+	    }
+	}
+
+	/* the loop above terminated with j2 at the first non-supernode */
+	DEBUG1 (("jnext = "ID"\n", jnext)) ;
+	ASSERT (j2 <= jnext) ;
+	jnext = j2 ;
+	j2-- ;
+	DEBUG1 (("j2 = "ID"\n", j2)) ;
+	ASSERT (j2 < n_col) ;
+
+	npivots = j2-j+1 ;
+	DEBUG1 (("Number of pivot columns: "ID"\n", npivots)) ;
+
+	/* rows j:j2 have the same nonzero pattern, except for columns j:j2-1 */
+
+	if (j2 > j)
+	{
+	    /* supernode detected, prune the pattern of new row j */
+	    ASSERT (parent == j+1) ;
+	    ASSERT (j2 < n_col) ;
+	    DEBUG1 (("Supernode detected, j "ID" to j2 "ID"\n", j, j2)) ;
+
+	    parent = n_col ;
+	    p2 = pdest ;
+	    pdest = Up [j] ;
+	    for (p = Up [j] ; p < p2 ; p++)
+	    {
+		col = Ai [p] ;
+		ASSERT (col >= 0 && col < n_col) ;
+		ASSERT (W [col] == Wflag) ;
+		if (col > j2)
+		{
+		    /* keep this col in the pattern of the new row j */
+		    Ai [pdest++] = col ;
+		    if (col < parent)
+		    {
+			parent = col ;
+		    }
+		}
+	    }
+	}
+
+	DEBUG1 (("Parent ["ID"] = "ID"\n", j, parent)) ;
+	ASSERT (parent > j2) ;
+
+	if (parent == n_col)
+	{
+	    /* this front has no parent - it is the root of a subtree */
+	    parent = EMPTY ;
+	}
+
+#ifndef NDEBUG
+	DEBUG3 (("\nFinal row "ID" of U after supercolumn detection:\n", j)) ;
+	for (p = Up [j] ; p < pdest ; p++)
+	{
+	    ASSERT (Ai [p] >= 0 && Ai [p] < n_col) ;
+	    DEBUG3 ((" "ID" ("ID")", Ai [p], W [Ai [p]])) ;
+	    ASSERT (W [Ai [p]] == Wflag) ;
+	}
+	DEBUG3 (("\n")) ;
+#endif
+
+	/* ================================================================== */
+	/* === frontal matrix =============================================== */
+	/* ================================================================== */
+
+	/* front has Front_npivcol [j] pivot columns */
+	/* entire front is Front_nrows [j] -by- Front_ncols [j] */
+	/* j is first column in the front */
+
+	npivcol = npivots ;
+	fallrows = thickness ;
+	fallcols = npivots + pdest - Up [j] ;
+
+	/* number of pivots in the front (rows and columns) */
+	fpiv = MIN (npivcol, fallrows) ;
+
+	/* size of contribution block */
+	frows = fallrows - fpiv ;
+	fcols = fallcols - fpiv ;
+
+	if (frows == 0 || fcols == 0)
+	{
+	    /* front has no contribution block and thus needs no parent */
+	    DEBUG1 (("Frontal matrix evaporation\n")) ;
+	    Up [j] = EMPTY ;
+	    parent = EMPTY ;
+	}
+
+	Front_npivcol [j] = npivots ;
+	Front_nrows [j] = fallrows ;
+	Front_ncols [j] = fallcols ;
+	Front_parent [j] = parent ;
+	ASSERT (npivots > 0) ;
+
+	/* Front_parent [j] is the first column of the parent frontal matrix */
+
+	DEBUG1 (("\n\n==== Front "ID", nfr "ID" pivot columns "ID":"ID
+	    " all front: "ID"-by-"ID" Parent: "ID"\n", j, nfr, j,j+npivots-1,
+	    Front_nrows [j], Front_ncols [j], Front_parent [j])) ;
+	nfr++ ;
+
+	/* ================================================================== */
+	/* === prepare this row for its parent ============================== */
+	/* ================================================================== */
+
+	if (parent != EMPTY)
+	{
+	    Link [j] = Link [parent] ;
+	    Link [parent] = j ;
+	}
+
+	ASSERT (jnext > j) ;
+
+	jlast = j ;
+    }
+
+    /* ====================================================================== */
+    /* === postorder the fronts ============================================= */
+    /* ====================================================================== */
+
+    *nfr_out = nfr ;
+
+    Front_order = W ;	/* use W for Front_order [ */
+
+    if (fixQ)
+    {
+	/* do not postorder the fronts if Q is fixed */
+	DEBUG1 (("\nNo postorder (Q is fixed)\n")) ;
+	k = 0 ;
+	/* Pragma added May 14, 2003.  The Intel compiler icl 6.0 (an old
+	 * version) incorrectly vectorizes this loop. */
+#pragma novector
+	for (j = 0 ; j < n_col ; j++)
+	{
+	    if (Front_npivcol [j] > 0)
+	    {
+		Front_order [j] = k++ ;
+		DEBUG1 (("Front order of j: "ID" is:"ID"\n", j,
+		    Front_order [j])) ;
+	    }
+	    else
+	    {
+		Front_order [j] = EMPTY ;
+	    }
+	}
+    }
+    else
+    {
+
+	/* use Ap for Front_child and use Link for Front_sibling [ */
+	Front_child = Ap ;
+	Front_sibling = Link ;
+
+	/* use Ai for Front_stack, size of Ai is >= 2*n_col */
+	Front_stack = Ai ;
+	Front_size = Front_stack + n_col ;
+
+	UMF_fsize (n_col, Front_size, Front_nrows, Front_ncols,
+	    Front_parent, Front_npivcol) ;
+
+	AMD_postorder (n_col, Front_parent, Front_npivcol, Front_size,
+	    Front_order, Front_child, Front_sibling, Front_stack) ;
+
+	/* done with Front_child, Front_sibling, Front_size, and Front_stack ]*/
+
+	/* ------------------------------------------------------------------ */
+	/* construct the column permutation (return in Up) */
+	/* ------------------------------------------------------------------ */
+
+	/* Front_order [i] = k means that front i is kth front in the new order.
+	 * i is in the range 0 to n_col-1, and k is in the range 0 to nfr-1 */
+
+	/* Use Ai as workspace for Winv [ */
+	Winv = Ai ;
+	for (k = 0 ; k < nfr ; k++)
+	{
+	    Winv [k] = EMPTY ;
+	}
+
+	/* compute the inverse of Front_order, so that Winv [k] = i */
+	/* if Front_order [i] = k */
+
+	DEBUG1 (("\n\nComputing output column permutation:\n")) ;
+	for (i = 0 ; i < n_col ; i++)
+	{
+	    k = Front_order [i] ;
+	    if (k != EMPTY)
+	    {
+		DEBUG1 (("Front "ID" new order: "ID"\n", i, k)) ;
+		ASSERT (k >= 0 && k < nfr) ;
+		ASSERT (Winv [k] == EMPTY) ;
+		Winv [k] = i ;
+	    }
+	}
+
+	/* Use Up as output permutation */
+	kk = 0 ;
+	for (k = 0 ; k < nfr ; k++)
+	{
+	    i = Winv [k] ;
+	    DEBUG1 (("Old Front "ID" New Front "ID" npivots "ID" nrows "ID
+		" ncols "ID"\n",
+		i, k, Front_npivcol [i], Front_nrows [i], Front_ncols [i])) ;
+	    ASSERT (i >= 0 && i < n_col) ;
+	    ASSERT (Front_npivcol [i] > 0) ;
+	    for (npiv = 0 ; npiv < Front_npivcol [i] ; npiv++)
+	    {
+		Up [kk] = i + npiv ;
+		DEBUG1 (("    Cperm ["ID"] = "ID"\n", kk, Up [kk])) ;
+		kk++ ;
+	    }
+	}
+	ASSERT (kk == n_col) ;
+
+	/* Winv no longer needed ] */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* apply the postorder traversal to renumber the frontal matrices */
+    /* (or pack them in same order, if fixQ) */
+    /* ---------------------------------------------------------------------- */
+
+    /* use Ai as workspace */
+
+    UMF_apply_order (Front_npivcol, Front_order, Ai, n_col, nfr) ;
+    UMF_apply_order (Front_nrows,   Front_order, Ai, n_col, nfr) ;
+    UMF_apply_order (Front_ncols,   Front_order, Ai, n_col, nfr) ;
+    UMF_apply_order (Front_parent,  Front_order, Ai, n_col, nfr) ;
+
+    /* fix the parent to refer to the new numbering */
+    for (i = 0 ; i < nfr ; i++)
+    {
+	parent = Front_parent [i] ;
+	if (parent != EMPTY)
+	{
+	    ASSERT (parent >= 0 && parent < n_col) ;
+	    ASSERT (Front_order [parent] >= 0 && Front_order [parent] < nfr) ;
+	    Front_parent [i] = Front_order [parent] ;
+	}
+    }
+
+    /* Front_order longer needed ] */
+
+#ifndef NDEBUG
+    DEBUG1 (("\nFinal frontal matrices:\n")) ;
+    for (i = 0 ; i < nfr ; i++)
+    {
+	DEBUG1 (("Final front "ID": npiv "ID" nrows "ID" ncols "ID" parent "
+	    ID"\n", i, Front_npivcol [i], Front_nrows [i],
+	    Front_ncols [i], Front_parent [i])) ;
+    }
+#endif
+
+    *p_ncompactions = ncompactions ;
+    return (TRUE) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_analyze.h b/src/C/SuiteSparse/UMFPACK/Source/umf_analyze.h
new file mode 100644
index 0000000..c0592a6
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_analyze.h
@@ -0,0 +1,23 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_analyze
+(
+    Int n_row,
+    Int n_col,
+    Int Ai [ ],
+    Int Ap [ ],
+    Int Up [ ],
+    Int fixQ,
+    Int Front_ncols [ ],
+    Int W [ ],
+    Int Link [ ],
+    Int Front_nrows [ ],
+    Int Front_npivcol [ ],
+    Int Front_parent [ ],
+    Int *nfr_out,
+    Int *p_ncompactions
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_apply_order.c b/src/C/SuiteSparse/UMFPACK/Source/umf_apply_order.c
new file mode 100644
index 0000000..996f2e3
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_apply_order.c
@@ -0,0 +1,43 @@
+/* ========================================================================== */
+/* === UMF_apply_order ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Apply post-ordering of supernodal elimination tree.
+*/
+
+#include "umf_internal.h"
+
+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] ;
+    }
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_apply_order.h b/src/C/SuiteSparse/UMFPACK/Source/umf_apply_order.h
new file mode 100644
index 0000000..8363a96
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_apply_order.h
@@ -0,0 +1,14 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_apply_order
+(
+    Int Front [ ],
+    const Int Order [ ],
+    Int Temp [ ],
+    Int n_col,
+    Int nfr
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_assemble.c b/src/C/SuiteSparse/UMFPACK/Source/umf_assemble.c
new file mode 100644
index 0000000..0bc175f
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_assemble.c
@@ -0,0 +1,1215 @@
+/* ========================================================================== */
+/* === UMF_assemble ========================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*  Degree update and numerical assembly.  This is compiled twice (with and
+ *  without FIXQ) for each real/complex int/UF_long version, for a total of 8
+ *  versions.*/
+
+#include "umf_internal.h"
+#include "umf_mem_free_tail_block.h"
+
+/* ========================================================================== */
+/* === row_assemble ========================================================= */
+/* ========================================================================== */
+
+PRIVATE void row_assemble
+(
+    Int row,
+    NumericType *Numeric,
+    WorkType *Work
+)
+{
+
+    Entry *S, *Fcblock, *Frow ;
+    Int tpi, e, *E, *Fcpos, *Frpos, *Row_degree, *Row_tuples, *Row_tlen, rdeg0,
+	f, nrows, ncols, *Rows, *Cols, col, ncolsleft, j ;
+    Tuple *tp, *tp1, *tp2, *tpend ;
+    Unit *Memory, *p ;
+    Element *ep ;
+
+#ifndef FIXQ
+    Int *Col_degree ;
+    Col_degree = Numeric->Cperm ;
+#endif
+
+    Row_tuples = Numeric->Uip ;
+    tpi = Row_tuples [row] ;
+    if (!tpi) return ;
+
+    Memory = Numeric->Memory ;
+    E = Work->E ;
+    Fcpos = Work->Fcpos ;
+    Frpos = Work->Frpos ;
+    Row_degree = Numeric->Rperm ;
+    Row_tlen   = Numeric->Uilen ;
+    E = Work->E ;
+    Memory = Numeric->Memory ;
+    rdeg0 = Work->rdeg0 ;
+    Fcblock = Work->Fcblock ;
+
+#ifndef NDEBUG
+    DEBUG6 (("SCAN2-row: "ID"\n", row)) ;
+    UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ;
+#endif
+
+    ASSERT (NON_PIVOTAL_ROW (row)) ;
+
+    tp = (Tuple *) (Memory + tpi) ;
+    tp1 = tp ;
+    tp2 = tp ;
+    tpend = tp + Row_tlen [row] ;
+    for ( ; tp < tpend ; tp++)
+    {
+	e = tp->e ;
+	ASSERT (e > 0 && e <= Work->nel) ;
+	if (!E [e]) continue ;	/* element already deallocated */
+	f = tp->f ;
+	p = Memory + E [e] ;
+	ep = (Element *) p ;
+	p += UNITS (Element, 1) ;
+	Cols = (Int *) p ;
+	Rows = Cols + ep->ncols ;
+	if (Rows [f] == EMPTY) continue ;   /* row already assembled */
+	ASSERT (row == Rows [f] && row >= 0 && row < Work->n_row) ;
+
+	if (ep->rdeg == rdeg0)
+	{
+	    /* ------------------------------------------------------ */
+	    /* this is an old Lson - assemble just one row */
+	    /* ------------------------------------------------------ */
+
+	    /* flag the row as assembled from the Lson */
+	    Rows [f] = EMPTY ;
+
+	    nrows = ep->nrows ;
+	    ncols = ep->ncols ;
+
+	    p += UNITS (Int, ncols + nrows) ;
+	    S = ((Entry *) p) + f ;
+
+	    DEBUG6 (("Old LSON: "ID"\n", e)) ;
+#ifndef NDEBUG
+	    UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+
+	    ncolsleft = ep->ncolsleft ;
+
+	    Frow = Fcblock + Frpos [row] ;
+	    DEBUG6 (("LSON found (in scan2-row): "ID"\n", e)) ;
+
+	    Row_degree [row] -= ncolsleft ;
+
+	    if (ncols == ncolsleft)
+	    {
+		/* -------------------------------------------------- */
+		/* no columns assembled out this Lson yet */
+		/* -------------------------------------------------- */
+
+#pragma ivdep
+		for (j = 0 ; j < ncols ; j++)
+		{
+		    col = Cols [j] ;
+		    ASSERT (col >= 0 && col < Work->n_col) ;
+#ifndef FIXQ
+		    Col_degree [col] -- ;
+#endif
+		    /* Frow [Fcpos [col]] += *S ; */
+		    ASSEMBLE (Frow [Fcpos [col]], *S) ;
+		    S += nrows ;
+		}
+
+	    }
+	    else
+	    {
+		/* -------------------------------------------------- */
+		/* some columns have been assembled out of this Lson */
+		/* -------------------------------------------------- */
+
+#pragma ivdep
+		for (j = 0 ; j < ncols ; j++)
+		{
+		    col = Cols [j] ;
+		    if (col >= 0)
+		    {
+			ASSERT (col < Work->n_col) ;
+#ifndef FIXQ
+			Col_degree [col] -- ;
+#endif
+			/* Frow [Fcpos [col]] += *S ; */
+			ASSEMBLE (Frow [Fcpos [col]], *S) ;
+		    }
+		    S += nrows ;
+		}
+
+	    }
+	    ep->nrowsleft-- ;
+	    ASSERT (ep->nrowsleft > 0) ;
+	}
+	else
+	{
+	    *tp2++ = *tp ;	/* leave the tuple in the list */
+	}
+    }
+    Row_tlen [row] = tp2 - tp1 ;
+
+#ifndef NDEBUG
+    DEBUG7 (("row assembled in scan2-row: "ID"\n", row)) ;
+    UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ;
+    DEBUG7 (("Current frontal matrix: (scan 1b)\n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+}
+
+/* ========================================================================== */
+/* === col_assemble ========================================================= */
+/* ========================================================================== */
+
+PRIVATE void col_assemble
+(
+    Int col,
+    NumericType *Numeric,
+    WorkType *Work
+)
+{
+
+    Entry *S, *Fcblock, *Fcol ;
+    Int tpi, e, *E, *Fcpos, *Frpos, *Row_degree, *Col_tuples, *Col_tlen, cdeg0,
+	f, nrows, ncols, *Rows, *Cols, row, nrowsleft, i ;
+    Tuple *tp, *tp1, *tp2, *tpend ;
+    Unit *Memory, *p ;
+    Element *ep ;
+
+#if !defined (FIXQ) || !defined (NDEBUG)
+    Int *Col_degree ;
+    Col_degree = Numeric->Cperm ;
+#endif
+
+    Col_tuples = Numeric->Lip ;
+    tpi = Col_tuples [col] ;
+    if (!tpi) return ;
+
+    Memory = Numeric->Memory ;
+    E = Work->E ;
+    Fcpos = Work->Fcpos ;
+    Frpos = Work->Frpos ;
+    Row_degree = Numeric->Rperm ;
+    Col_tlen   = Numeric->Lilen ;
+    E = Work->E ;
+    Memory = Numeric->Memory ;
+    cdeg0 = Work->cdeg0 ;
+    Fcblock = Work->Fcblock ;
+
+    DEBUG6 (("SCAN2-col: "ID"\n", col)) ;
+#ifndef NDEBUG
+    UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+#endif
+
+    ASSERT (NON_PIVOTAL_COL (col)) ;
+    tp = (Tuple *) (Memory + tpi) ;
+    tp1 = tp ;
+    tp2 = tp ;
+    tpend = tp + Col_tlen [col] ;
+    for ( ; tp < tpend ; tp++)
+    {
+	e = tp->e ;
+	ASSERT (e > 0 && e <= Work->nel) ;
+	if (!E [e]) continue ;	/* element already deallocated */
+	f = tp->f ;
+	p = Memory + E [e] ;
+	ep = (Element *) p ;
+	p += UNITS (Element, 1) ;
+	Cols = (Int *) p ;
+
+	if (Cols [f] == EMPTY) continue ;   /* col already assembled */
+	ASSERT (col == Cols [f] && col >= 0 && col < Work->n_col) ;
+
+	if (ep->cdeg == cdeg0)
+	{
+	    /* ------------------------------------------------------ */
+	    /* this is an old Uson - assemble just one col */
+	    /* ------------------------------------------------------ */
+
+	    /* flag the col as assembled from the Uson */
+	    Cols [f] = EMPTY ;
+
+	    nrows = ep->nrows ;
+	    ncols = ep->ncols ;
+	    Rows = Cols + ncols ;
+	    p += UNITS (Int, ncols + nrows) ;
+	    S = ((Entry *) p) + f * nrows ;
+
+	    DEBUG6 (("Old USON: "ID"\n", e)) ;
+#ifndef NDEBUG
+	    UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+
+	    nrowsleft = ep->nrowsleft ;
+
+	    Fcol = Fcblock + Fcpos [col] ;
+	    DEBUG6 (("USON found (in scan2-col): "ID"\n", e)) ;
+#ifndef FIXQ
+	    Col_degree [col] -= nrowsleft ;
+#endif
+	    if (nrows == nrowsleft)
+	    {
+		/* -------------------------------------------------- */
+		/* no rows assembled out of this Uson yet */
+		/* -------------------------------------------------- */
+
+#pragma ivdep
+		for (i = 0 ; i < nrows ; i++)
+		{
+		    row = Rows [i] ;
+		    ASSERT (row >= 0 && row < Work->n_row) ;
+		    Row_degree [row]-- ;
+		    /* Fcol [Frpos [row]] += S [i] ; */
+		    ASSEMBLE (Fcol [Frpos [row]], S [i]) ;
+		}
+	    }
+	    else
+	    {
+		/* -------------------------------------------------- */
+		/* some rows have been assembled out of this Uson */
+		/* -------------------------------------------------- */
+
+#pragma ivdep
+		for (i = 0 ; i < nrows ; i++)
+		{
+		    row = Rows [i] ;
+		    if (row >= 0)
+		    {
+			ASSERT (row < Work->n_row) ;
+			Row_degree [row]-- ;
+			/* Fcol [Frpos [row]] += S [i] ; */
+			ASSEMBLE (Fcol [Frpos [row]], S [i]) ;
+		    }
+		}
+	    }
+	    ep->ncolsleft-- ;
+	    ASSERT (ep->ncolsleft > 0) ;
+	}
+	else
+	{
+	    *tp2++ = *tp ;	/* leave the tuple in the list */
+	}
+    }
+    Col_tlen [col] = tp2 - tp1 ;
+
+#ifndef NDEBUG
+    DEBUG7 (("Column assembled in scan2-col: "ID"\n", col)) ;
+    UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+    DEBUG7 (("Current frontal matrix: after scan2-col\n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+}
+
+
+/* ========================================================================== */
+/* === UMF_assemble / UMF_assemble_fixq ===================================== */
+/* ========================================================================== */
+
+#ifndef FIXQ
+GLOBAL void UMF_assemble
+#else
+GLOBAL void UMF_assemble_fixq
+#endif
+(
+    NumericType *Numeric,
+    WorkType *Work
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int e, i, row, col, i2, nrows, ncols, f, tpi, extcdeg, extrdeg, rdeg0,
+	cdeg0, son_list, next, nrows_to_assemble,
+	ncols_to_assemble, ngetrows, j, j2,
+	nrowsleft,	/* number of rows remaining in S */
+	ncolsleft,	/* number of columns remaining in S */
+	prior_Lson, prior_Uson, *E, *Cols, *Rows, *Wm, *Woo,
+	*Row_tuples, *Row_degree, *Row_tlen,
+	*Col_tuples, *Col_tlen ;
+    Unit *Memory, *p ;
+    Element *ep ;
+    Tuple *tp, *tp1, *tp2, *tpend ;
+    Entry
+	*S,		/* a pointer into the contribution block of a son */
+	*Fcblock,	/* current contribution block */
+	*Fcol ;		/* a column of FC */
+    Int *Frpos,
+	*Fcpos,
+	fnrows,		/* number of rows in contribution block in F */
+	fncols ;	/* number of columns in contribution block in F */
+
+#if !defined (FIXQ) || !defined (NDEBUG)
+    Int *Col_degree ;
+#endif
+
+#ifndef NDEBUG
+    Int n_row, n_col ;
+    n_row = Work->n_row ;
+    n_col = Work->n_col ;
+    DEBUG3 (("::Assemble SCANS 1-4\n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+#if !defined (FIXQ) || !defined (NDEBUG)
+    Col_degree = Numeric->Cperm ;   /* not updated if FIXQ is true */
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    fncols = Work->fncols ;
+    fnrows = Work->fnrows ;
+    Fcpos = Work->Fcpos ;
+    Frpos = Work->Frpos ;
+    Row_degree = Numeric->Rperm ;
+    Row_tuples = Numeric->Uip ;
+    Row_tlen   = Numeric->Uilen ;
+    Col_tuples = Numeric->Lip ;
+    Col_tlen   = Numeric->Lilen ;
+    E = Work->E ;
+    Memory = Numeric->Memory ;
+    Wm = Work->Wm ;
+    Woo = Work->Woo ;
+    rdeg0 = Work->rdeg0 ;
+    cdeg0 = Work->cdeg0 ;
+
+#ifndef NDEBUG
+    DEBUG6 (("============================================\n")) ;
+    DEBUG6 (("Degree update, assembly.\n")) ;
+    DEBUG6 (("pivot row pattern:  fncols="ID"\n", fncols)) ;
+    for (j = 0 ; j < fncols ; j++)
+    {
+	col = Work->Fcols [j] ;
+	DEBUG6 ((ID" ", col)) ;
+	ASSERT (Fcpos [col] == j * Work->fnr_curr) ;
+	ASSERT (NON_PIVOTAL_COL (col)) ;
+    }
+    ASSERT (Fcpos [Work->pivcol] >= 0) ;
+    DEBUG6 (("pivcol: "ID" pos "ID" fnr_curr "ID" fncols "ID"\n",
+	Work->pivcol, Fcpos [Work->pivcol], Work->fnr_curr, fncols)) ;
+    ASSERT (Fcpos [Work->pivcol] <  fncols * Work->fnr_curr) ;
+    DEBUG6 (("\npivot col pattern:  fnrows="ID"\n", fnrows)) ;
+    for (i = 0 ; i < fnrows ; i++)
+    {
+	row = Work->Frows [i] ;
+	DEBUG6 ((ID" ", row)) ;
+	ASSERT (Frpos [row] == i) ;
+	ASSERT (NON_PIVOTAL_ROW (row)) ;
+    }
+    DEBUG6 (("\n")) ;
+    ASSERT (Frpos [Work->pivrow] >= 0) ;
+    ASSERT (Frpos [Work->pivrow] < fnrows) ;
+    ASSERT (Work->Flublock == (Entry *) (Numeric->Memory + E [0])) ;
+    ASSERT (Work->Fcblock == Work->Flublock + Work->nb *
+	(Work->nb + Work->fnr_curr + Work->fnc_curr)) ;
+#endif
+
+    Fcblock = Work->Fcblock ;
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the largest actual frontal matrix size (for Info only) */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (fnrows == Work->fnrows_new + 1) ;
+    ASSERT (fncols == Work->fncols_new + 1) ;
+
+    Numeric->maxnrows = MAX (Numeric->maxnrows, fnrows) ;
+    Numeric->maxncols = MAX (Numeric->maxncols, fncols) ;
+
+    /* this is safe from integer overflow, since the current frontal matrix
+     * is already allocated. */
+    Numeric->maxfrsize = MAX (Numeric->maxfrsize, fnrows * fncols) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* assemble from prior elements into the current frontal matrix */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG2 (("New assemble start [prior_element:"ID"\n", Work->prior_element)) ;
+
+    /* Currently no rows or columns are marked.  No elements are scanned, */
+    /* that is, (ep->next == EMPTY) is true for all elements */
+
+    son_list = 0 ;	/* start creating son_list [ */
+
+    /* ---------------------------------------------------------------------- */
+    /* determine if most recent element is Lson or Uson of current front */
+    /* ---------------------------------------------------------------------- */
+
+    if (!Work->do_extend)
+    {
+	prior_Uson = ( Work->pivcol_in_front && !Work->pivrow_in_front) ;
+	prior_Lson = (!Work->pivcol_in_front &&  Work->pivrow_in_front) ;
+	if (prior_Uson || prior_Lson)
+	{
+	    e = Work->prior_element ;
+	    if (e != EMPTY)
+	    {
+		ASSERT (E [e]) ;
+		p = Memory + E [e] ;
+		ep = (Element *) p ;
+		ep->next = son_list ;
+		son_list = e ;
+#ifndef NDEBUG
+		DEBUG2 (("e "ID" is Prior son "ID" "ID"\n",
+		    e, prior_Uson, prior_Lson)) ;
+		UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+		ASSERT (E [e]) ;
+	    }
+	}
+    }
+    Work->prior_element = EMPTY ;
+
+    /* ---------------------------------------------------------------------- */
+    /* SCAN1-row:  scan the element lists of each new row in the pivot col */
+    /* and compute the external column degree for each frontal */
+    /* ---------------------------------------------------------------------- */
+
+    for (i2 = Work->fscan_row ; i2 < fnrows ; i2++)
+    {
+	/* Get a row */
+	row = Work->NewRows [i2] ;
+	if (row < 0) row = FLIP (row) ;
+	ASSERT (row >= 0 && row < n_row) ;
+
+	DEBUG6 (("SCAN1-row: "ID"\n", row)) ;
+#ifndef NDEBUG
+	UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ;
+#endif
+
+	ASSERT (NON_PIVOTAL_ROW (row)) ;
+	tpi = Row_tuples [row] ;
+	if (!tpi) continue ;
+	tp = (Tuple *) (Memory + tpi) ;
+	tp1 = tp ;
+	tp2 = tp ;
+	tpend = tp + Row_tlen [row] ;
+	for ( ; tp < tpend ; tp++)
+	{
+	    e = tp->e ;
+	    ASSERT (e > 0 && e <= Work->nel) ;
+	    if (!E [e]) continue ;	/* element already deallocated */
+	    f = tp->f ;
+	    p = Memory + E [e] ;
+	    ep = (Element *) p ;
+	    p += UNITS (Element, 1) ;
+	    Rows = ((Int *) p) + ep->ncols ;
+	    if (Rows [f] == EMPTY) continue ;	/* row already assembled */
+	    ASSERT (row == Rows [f]) ;
+
+	    if (ep->cdeg < cdeg0)
+	    {
+		/* first time seen in scan1-row */
+		ep->cdeg = ep->nrowsleft + cdeg0 ;
+		DEBUG6 (("e "ID" First seen: cdeg: "ID" ", e, ep->cdeg-cdeg0)) ;
+		ASSERT (ep->ncolsleft > 0 && ep->nrowsleft > 0) ;
+	    }
+
+	    ep->cdeg-- ;	/* decrement external column degree */
+	    DEBUG6 (("e "ID" New ext col deg: "ID"\n", e, ep->cdeg - cdeg0)) ;
+
+	    /* this element is not yet in the new son list */
+	    if (ep->cdeg == cdeg0 && ep->next == EMPTY)
+	    {
+		/* A new LUson or Uson has been found */
+		ep->next = son_list ;
+		son_list = e ;
+	    }
+
+	    ASSERT (ep->cdeg >= cdeg0) ;
+	    *tp2++ = *tp ;	/* leave the tuple in the list */
+	}
+	Row_tlen [row] = tp2 - tp1 ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* SCAN1-col:  scan the element lists of each new col in the pivot row */
+    /*	 and compute the external row degree for each frontal */
+    /* ---------------------------------------------------------------------- */
+
+    for (j2 = Work->fscan_col ; j2 < fncols ; j2++)
+    {
+	/* Get a column */
+	col = Work->NewCols [j2] ;
+	if (col < 0) col = FLIP (col) ;
+	ASSERT (col >= 0 && col < n_col) ;
+
+	DEBUG6 (("SCAN 1-col: "ID"\n", col)) ;
+#ifndef NDEBUG
+	UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+#endif
+
+	ASSERT (NON_PIVOTAL_COL (col)) ;
+	tpi = Col_tuples [col] ;
+	if (!tpi) continue ;
+	tp = (Tuple *) (Memory + tpi) ;
+	tp1 = tp ;
+	tp2 = tp ;
+	tpend = tp + Col_tlen [col] ;
+	for ( ; tp < tpend ; tp++)
+	{
+	    e = tp->e ;
+	    ASSERT (e > 0 && e <= Work->nel) ;
+	    if (!E [e]) continue ;	/* element already deallocated */
+	    f = tp->f ;
+	    p = Memory + E [e] ;
+	    ep = (Element *) p ;
+	    p += UNITS (Element, 1) ;
+	    Cols = (Int *) p ;
+	    if (Cols [f] == EMPTY) continue ;	/* column already assembled */
+	    ASSERT (col == Cols [f]) ;
+
+	    if (ep->rdeg < rdeg0)
+	    {
+		/* first time seen in scan1-col */
+		ep->rdeg = ep->ncolsleft + rdeg0 ;
+		DEBUG6 (("e "ID" First seen: rdeg: "ID" ", e, ep->rdeg-rdeg0)) ;
+		ASSERT (ep->ncolsleft > 0 && ep->nrowsleft > 0) ;
+	    }
+
+	    ep->rdeg-- ;	/* decrement external row degree */
+	    DEBUG6 (("e "ID" New ext row degree: "ID"\n", e, ep->rdeg-rdeg0)) ;
+
+	    if (ep->rdeg == rdeg0 && ep->next == EMPTY)
+	    {
+		/* A new LUson or Lson has been found */
+		ep->next = son_list ;
+		son_list = e ;
+	    }
+
+	    ASSERT (ep->rdeg >= rdeg0) ;
+	    *tp2++ = *tp ;	/* leave the tuple in the list */
+	}
+	Col_tlen [col] = tp2 - tp1 ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* assemble new sons via full scans */
+    /* ---------------------------------------------------------------------- */
+
+    next = EMPTY ;
+
+    for (e = son_list ; e > 0 ; e = next)
+    {
+	ASSERT (e > 0 && e <= Work->nel && E [e]) ;
+	p = Memory + E [e] ;
+	DEBUG2 (("New son: "ID"\n", e)) ;
+#ifndef NDEBUG
+	UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+	GET_ELEMENT (ep, p, Cols, Rows, ncols, nrows, S) ;
+	nrowsleft = ep->nrowsleft ;
+	ncolsleft = ep->ncolsleft ;
+	next = ep->next ;
+	ep->next = EMPTY ;
+
+	extrdeg = (ep->rdeg < rdeg0) ? ncolsleft : (ep->rdeg - rdeg0) ;
+	extcdeg = (ep->cdeg < cdeg0) ? nrowsleft : (ep->cdeg - cdeg0) ;
+	ncols_to_assemble = ncolsleft - extrdeg ;
+	nrows_to_assemble = nrowsleft - extcdeg ;
+	DEBUG2 (("extrdeg "ID" extcdeg "ID"\n", extrdeg, extcdeg)) ;
+
+	if (extrdeg == 0 && extcdeg == 0)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* this is an LUson - assemble an entire contribution block */
+	    /* -------------------------------------------------------------- */
+
+	    DEBUG6 (("LUson found: "ID"\n", e)) ;
+
+	    if (nrows == nrowsleft)
+	    {
+		/* ---------------------------------------------------------- */
+		/* no rows assembled out of this LUson yet */
+		/* ---------------------------------------------------------- */
+
+		/* compute the compressed column offset vector*/
+		/* [ use Wm [0..nrows-1] for offsets */
+#pragma ivdep
+		for (i = 0 ; i < nrows ; i++)
+		{
+		    row = Rows [i] ;
+		    Row_degree [row] -= ncolsleft ;
+		    Wm [i] = Frpos [row] ;
+		}
+
+		if (ncols == ncolsleft)
+		{
+		    /* ------------------------------------------------------ */
+		    /* no rows or cols assembled out of LUson yet */
+		    /* ------------------------------------------------------ */
+
+		    for (j = 0 ; j < ncols ; j++)
+		    {
+			col = Cols [j] ;
+#ifndef FIXQ
+			Col_degree [col] -= nrowsleft ;
+#endif
+			Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+			for (i = 0 ; i < nrows ; i++)
+			{
+			    /* Fcol [Wm [i]] += S [i] ; */
+			    ASSEMBLE (Fcol [Wm [i]], S [i]) ;
+			}
+			S += nrows ;
+		    }
+
+
+		}
+		else
+		{
+		    /* ------------------------------------------------------ */
+		    /* only cols have been assembled out of LUson */
+		    /* ------------------------------------------------------ */
+
+		    for (j = 0 ; j < ncols ; j++)
+		    {
+			col = Cols [j] ;
+			if (col >= 0)
+			{
+#ifndef FIXQ
+			    Col_degree [col] -= nrowsleft ;
+#endif
+			    Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+			    for (i = 0 ; i < nrows ; i++)
+			    {
+				/* Fcol [Wm [i]] += S [i] ; */
+				ASSEMBLE (Fcol [Wm [i]], S [i]) ;
+			    }
+			}
+			S += nrows ;
+		    }
+
+		}
+		/* ] done using Wm [0..nrows-1] for offsets */
+	    }
+	    else
+	    {
+		/* ---------------------------------------------------------- */
+		/* some rows have been assembled out of this LUson */
+		/* ---------------------------------------------------------- */
+
+		/* compute the compressed column offset vector*/
+		/* [ use Woo,Wm [0..nrowsleft-1] for offsets */
+		ngetrows = 0 ;
+		for (i = 0 ; i < nrows ; i++)
+		{
+		    row = Rows [i] ;
+		    if (row >= 0)
+		    {
+			Row_degree [row] -= ncolsleft ;
+			Woo [ngetrows] = i ;
+			Wm [ngetrows++] = Frpos [row] ;
+		    }
+		}
+		ASSERT (ngetrows == nrowsleft) ;
+
+		if (ncols == ncolsleft)
+		{
+		    /* ------------------------------------------------------ */
+		    /* only rows have been assembled out of this LUson */
+		    /* ------------------------------------------------------ */
+
+		    for (j = 0 ; j < ncols ; j++)
+		    {
+			col = Cols [j] ;
+#ifndef FIXQ
+			Col_degree [col] -= nrowsleft ;
+#endif
+			Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+			for (i = 0 ; i < nrowsleft ; i++)
+			{
+			    /* Fcol [Wm [i]] += S [Woo [i]] ; */
+			    ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
+			}
+			S += nrows ;
+		    }
+
+		}
+		else
+		{
+		    /* ------------------------------------------------------ */
+		    /* both rows and columns have been assembled out of LUson */
+		    /* ------------------------------------------------------ */
+
+		    for (j = 0 ; j < ncols ; j++)
+		    {
+			col = Cols [j] ;
+			if (col >= 0)
+			{
+#ifndef FIXQ
+			    Col_degree [col] -= nrowsleft ;
+#endif
+			    Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+			    for (i = 0 ; i < nrowsleft ; i++)
+			    {
+				/* Fcol [Wm [i]] += S [Woo [i]] ; */
+				ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
+			    }
+			}
+			S += nrows ;
+		    }
+
+		}
+		/* ] done using Woo,Wm [0..nrowsleft-1] */
+	    }
+
+	    /* deallocate the element: remove from ordered list */
+	    UMF_mem_free_tail_block (Numeric, E [e]) ;
+	    E [e] = 0 ;
+
+	}
+	else if (extcdeg == 0)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* this is a Uson - assemble all possible columns */
+	    /* -------------------------------------------------------------- */
+
+	    DEBUG6 (("New USON: "ID"\n", e)) ;
+	    ASSERT (extrdeg > 0) ;
+
+	    DEBUG6 (("New uson "ID" cols to do "ID"\n", e, ncols_to_assemble)) ;
+
+	    if (ncols_to_assemble > 0)
+	    {
+
+		Int skip = FALSE ;
+		if (ncols_to_assemble * 16 < ncols && nrows == 1)
+		{
+		    /* this is a tall and thin frontal matrix consisting of
+		     * only one column (most likely an original column). Do
+		     * not assemble it.   It cannot be the pivot column, since
+		     * the pivot column element would be an LU son, not an Lson,
+		     * of the current frontal matrix. */
+		    ASSERT (nrowsleft == 1) ;
+		    ASSERT (Rows [0] >= 0 && Rows [0] < Work->n_row) ;
+		    skip = TRUE ;
+		    Work->any_skip = TRUE ;
+		}
+
+		if (!skip)
+		{
+
+		    if (nrows == nrowsleft)
+		    {
+			/* -------------------------------------------------- */
+			/* no rows have been assembled out of this Uson yet */
+			/* -------------------------------------------------- */
+
+			/* compute the compressed column offset vector */
+			/* [ use Wm [0..nrows-1] for offsets */
+#pragma ivdep
+			for (i = 0 ; i < nrows ; i++)
+			{
+			    row = Rows [i] ;
+			    ASSERT (row >= 0 && row < n_row) ;
+			    Row_degree [row] -= ncols_to_assemble ;
+			    Wm [i] = Frpos [row] ;
+			}
+
+			for (j = 0 ; j < ncols ; j++)
+			{
+			    col = Cols [j] ;
+			    if ((col >= 0) && (Fcpos [col] >= 0))
+			    {
+#ifndef FIXQ
+				Col_degree [col] -= nrowsleft ;
+#endif
+				Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+				for (i = 0 ; i < nrows ; i++)
+				{
+				    /* Fcol [Wm [i]] += S [i] ; */
+				    ASSEMBLE (Fcol [Wm [i]], S [i]) ;
+				}
+				/* flag the column as assembled from Uson */
+				Cols [j] = EMPTY ;
+			    }
+			    S += nrows ;
+			}
+
+
+			/* ] done using Wm [0..nrows-1] for offsets */
+		    }
+		    else
+		    {
+			/* -------------------------------------------------- */
+			/* some rows have been assembled out of this Uson */
+			/* -------------------------------------------------- */
+
+			/* compute the compressed column offset vector*/
+			/* [ use Woo,Wm [0..nrows-1] for offsets */
+			ngetrows = 0 ;
+			for (i = 0 ; i < nrows ; i++)
+			{
+			    row = Rows [i] ;
+			    if (row >= 0)
+			    {
+				Row_degree [row] -= ncols_to_assemble ;
+				ASSERT (row < n_row && Frpos [row] >= 0) ;
+				Woo [ngetrows] = i ;
+				Wm [ngetrows++] = Frpos [row] ;
+			    }
+			}
+			ASSERT (ngetrows == nrowsleft) ;
+
+			for (j = 0 ; j < ncols ; j++)
+			{
+			    col = Cols [j] ;
+			    if ((col >= 0) && (Fcpos [col] >= 0))
+			    {
+#ifndef FIXQ
+				Col_degree [col] -= nrowsleft ;
+#endif
+				Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+				for (i = 0 ; i < nrowsleft ; i++)
+				{
+				    /* Fcol [Wm [i]] += S [Woo [i]] ; */
+				    ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
+				}
+				/* flag the column as assembled from Uson */
+				Cols [j] = EMPTY ;
+			    }
+			    S += nrows ;
+			}
+
+			/* ] done using Woo,Wm */
+		    }
+		    ep->ncolsleft = extrdeg ;
+		}
+	    }
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* this is an Lson - assemble all possible rows */
+	    /* -------------------------------------------------------------- */
+
+	    DEBUG6 (("New LSON: "ID"\n", e)) ;
+	    ASSERT (extrdeg == 0 && extcdeg > 0) ;
+
+	    DEBUG6 (("New lson "ID" rows to do "ID"\n", e, nrows_to_assemble)) ;
+
+	    if (nrows_to_assemble > 0)
+	    {
+
+		Int skip = FALSE ;
+		if (nrows_to_assemble * 16 < nrows && ncols == 1)
+		{
+		    /* this is a tall and thin frontal matrix consisting of
+		     * only one column (most likely an original column). Do
+		     * not assemble it.   It cannot be the pivot column, since
+		     * the pivot column element would be an LU son, not an Lson,
+		     * of the current frontal matrix. */
+		    ASSERT (ncolsleft == 1) ;
+		    ASSERT (Cols [0] >= 0 && Cols [0] < Work->n_col) ;
+		    Work->any_skip = TRUE ;
+		    skip = TRUE ;
+		}
+
+		if (!skip)
+		{
+
+		    /* compute the compressed column offset vector */
+		    /* [ use Woo,Wm [0..nrows-1] for offsets */
+		    ngetrows = 0 ;
+		    for (i = 0 ; i < nrows ; i++)
+		    {
+			row = Rows [i] ;
+			if ((row >= 0) && (Frpos [row] >= 0))
+			{
+			    ASSERT (row < n_row) ;
+			    Row_degree [row] -= ncolsleft ;
+			    Woo [ngetrows] = i ;
+			    Wm [ngetrows++] = Frpos [row] ;
+			    /* flag the row as assembled from the Lson */
+			    Rows [i] = EMPTY ;
+			}
+		    }
+		    ASSERT (nrowsleft - ngetrows == extcdeg) ;
+		    ASSERT (ngetrows == nrows_to_assemble) ;
+
+		    if (ncols == ncolsleft)
+		    {
+			/* -------------------------------------------------- */
+			/* no columns assembled out this Lson yet */
+			/* -------------------------------------------------- */
+
+			for (j = 0 ; j < ncols ; j++)
+			{
+			    col = Cols [j] ;
+			    ASSERT (col >= 0 && col < n_col) ;
+#ifndef FIXQ
+			    Col_degree [col] -= nrows_to_assemble ;
+#endif
+			    Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+			    for (i = 0 ; i < nrows_to_assemble ; i++)
+			    {
+				/* Fcol [Wm [i]] += S [Woo [i]] ; */
+				ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
+			    }
+			    S += nrows ;
+			}
+
+
+		    }
+		    else
+		    {
+			/* -------------------------------------------------- */
+			/* some columns have been assembled out of this Lson */
+			/* -------------------------------------------------- */
+
+			for (j = 0 ; j < ncols ; j++)
+			{
+			    col = Cols [j] ;
+			    ASSERT (col < n_col) ;
+			    if (col >= 0)
+			    {
+#ifndef FIXQ
+				Col_degree [col] -= nrows_to_assemble ;
+#endif
+				Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+				for (i = 0 ; i < nrows_to_assemble ; i++)
+				{
+				    /* Fcol [Wm [i]] += S [Woo [i]] ; */
+				    ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
+				}
+			    }
+			    S += nrows ;
+			}
+
+		    }
+
+		    /* ] done using Woo,Wm */
+
+		    ep->nrowsleft = extcdeg ;
+		}
+	    }
+	}
+    }
+
+    /* Note that garbage collection, and build tuples */
+    /* both destroy the son list. */
+
+    /* ] son_list now empty */
+
+    /* ---------------------------------------------------------------------- */
+    /* If frontal matrix extended, assemble old L/Usons from new rows/cols */
+    /* ---------------------------------------------------------------------- */
+
+    /* ---------------------------------------------------------------------- */
+    /* SCAN2-row:  assemble rows of old Lsons from the new rows */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    DEBUG7 (("Current frontal matrix: (prior to scan2-row)\n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+    /* rescan the pivot row */
+    if (Work->any_skip)
+    {
+	row_assemble (Work->pivrow, Numeric, Work) ;
+    }
+
+    if (Work->do_scan2row)
+    {
+	for (i2 = Work->fscan_row ; i2 < fnrows ; i2++)
+	{
+	    /* Get a row */
+	    row = Work->NewRows [i2] ;
+	    if (row < 0) row = FLIP (row) ;
+	    ASSERT (row >= 0 && row < n_row) ;
+	    if (!(row == Work->pivrow && Work->any_skip))
+	    {
+		/* assemble it */
+		row_assemble (row, Numeric, Work) ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* SCAN2-col:  assemble columns of old Usons from the new columns */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    DEBUG7 (("Current frontal matrix: (prior to scan2-col)\n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+    /* rescan the pivot col */
+    if (Work->any_skip)
+    {
+	col_assemble (Work->pivcol, Numeric, Work) ;
+    }
+
+    if (Work->do_scan2col)
+    {
+
+	for (j2 = Work->fscan_col ; j2 < fncols ; j2++)
+	{
+	    /* Get a column */
+	    col = Work->NewCols [j2] ;
+	    if (col < 0) col = FLIP (col) ;
+	    ASSERT (col >= 0 && col < n_col) ;
+	    if (!(col == Work->pivcol && Work->any_skip))
+	    {
+		/* assemble it */
+		col_assemble (col, Numeric, Work) ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* done.  the remainder of this routine is used only when in debug mode */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+
+    /* ---------------------------------------------------------------------- */
+    /* when debugging: make sure the assembly did everything that it could */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG3 (("::Assemble done\n")) ;
+
+    for (i2 = 0 ; i2 < fnrows ; i2++)
+    {
+	/* Get a row */
+	row = Work->Frows [i2] ;
+	ASSERT (row >= 0 && row < n_row) ;
+
+	DEBUG6 (("DEBUG SCAN 1: "ID"\n", row)) ;
+	UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ;
+
+	ASSERT (NON_PIVOTAL_ROW (row)) ;
+	tpi = Row_tuples [row] ;
+	if (!tpi) continue ;
+	tp = (Tuple *) (Memory + tpi) ;
+	tpend = tp + Row_tlen [row] ;
+	for ( ; tp < tpend ; tp++)
+	{
+	    e = tp->e ;
+	    ASSERT (e > 0 && e <= Work->nel) ;
+	    if (!E [e]) continue ;	/* element already deallocated */
+	    f = tp->f ;
+	    p = Memory + E [e] ;
+	    ep = (Element *) p ;
+	    p += UNITS (Element, 1) ;
+	    Cols = (Int *) p ;
+	    Rows = ((Int *) p) + ep->ncols ;
+	    if (Rows [f] == EMPTY) continue ;	/* row already assembled */
+	    ASSERT (row == Rows [f]) ;
+	    extrdeg = (ep->rdeg < rdeg0) ? ep->ncolsleft : (ep->rdeg - rdeg0) ;
+	    extcdeg = (ep->cdeg < cdeg0) ? ep->nrowsleft : (ep->cdeg - cdeg0) ;
+	    DEBUG6 ((
+		"e "ID" After assembly ext row deg: "ID" ext col degree "ID"\n",
+		e, extrdeg, extcdeg)) ;
+
+	    if (Work->any_skip)
+	    {
+		/* no Lsons in any row, except for very tall and thin ones */
+		ASSERT (extrdeg >= 0) ;
+		if (extrdeg == 0)
+		{
+		    /* this is an unassemble Lson */
+		    ASSERT (ep->ncols == 1) ;
+		    ASSERT (ep->ncolsleft == 1) ;
+		    col = Cols [0] ;
+		    ASSERT (col != Work->pivcol) ;
+		}
+	    }
+	    else
+	    {
+		/* no Lsons in any row */
+		ASSERT (extrdeg > 0) ;
+		/* Uson external row degree is = number of cols left */
+		ASSERT (IMPLIES (extcdeg == 0, extrdeg == ep->ncolsleft)) ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+
+    for (j2 = 0 ; j2 < fncols ; j2++)
+    {
+	/* Get a column */
+	col = Work->Fcols [j2] ;
+	ASSERT (col >= 0 && col < n_col) ;
+
+	DEBUG6 (("DEBUG SCAN 2: "ID"\n", col)) ;
+#ifndef FIXQ
+	UMF_dump_rowcol (1, Numeric, Work, col, TRUE) ;
+#else
+	UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+#endif
+
+	ASSERT (NON_PIVOTAL_COL (col)) ;
+	tpi = Col_tuples [col] ;
+	if (!tpi) continue ;
+	tp = (Tuple *) (Memory + tpi) ;
+	tpend = tp + Col_tlen [col] ;
+	for ( ; tp < tpend ; tp++)
+	{
+	    e = tp->e ;
+	    ASSERT (e > 0 && e <= Work->nel) ;
+	    if (!E [e]) continue ;	/* element already deallocated */
+	    f = tp->f ;
+	    p = Memory + E [e] ;
+	    ep = (Element *) p ;
+	    p += UNITS (Element, 1) ;
+	    Cols = (Int *) p ;
+	    Rows = ((Int *) p) + ep->ncols ;
+	    if (Cols [f] == EMPTY) continue ;	/* column already assembled */
+	    ASSERT (col == Cols [f]) ;
+	    extrdeg = (ep->rdeg < rdeg0) ? ep->ncolsleft : (ep->rdeg - rdeg0) ;
+	    extcdeg = (ep->cdeg < cdeg0) ? ep->nrowsleft : (ep->cdeg - cdeg0) ;
+	    DEBUG6 (("e "ID" After assembly ext col deg: "ID"\n", e, extcdeg)) ;
+
+	    if (Work->any_skip)
+	    {
+		/* no Usons in any column, except for very tall and thin ones */
+		ASSERT (extcdeg >= 0) ;
+		if (extcdeg == 0)
+		{
+		    /* this is an unassemble Uson */
+		    ASSERT (ep->nrows == 1) ;
+		    ASSERT (ep->nrowsleft == 1) ;
+		    row = Rows [0] ;
+		    ASSERT (row != Work->pivrow) ;
+		}
+	    }
+	    else
+	    {
+		/* no Usons in any column */
+		ASSERT (extcdeg > 0) ;
+		/* Lson external column degree is = number of rows left */
+		ASSERT (IMPLIES (extrdeg == 0, extcdeg == ep->nrowsleft)) ;
+	    }
+	}
+    }
+#endif /* NDEBUG */
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_assemble.h b/src/C/SuiteSparse/UMFPACK/Source/umf_assemble.h
new file mode 100644
index 0000000..d219e2c
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_assemble.h
@@ -0,0 +1,17 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_assemble
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
+
+GLOBAL void UMF_assemble_fixq
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_blas3_update.c b/src/C/SuiteSparse/UMFPACK/Source/umf_blas3_update.c
new file mode 100644
index 0000000..f11fb7b
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_blas3_update.c
@@ -0,0 +1,175 @@
+/* ========================================================================== */
+/* === UMF_blas3_update ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_blas3_update
+(
+    WorkType *Work
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Entry *L, *U, *C, *LU ;
+    Int i, j, s, k, m, n, d, nb, dc ;
+    
+#ifndef NBLAS
+    Int blas_ok = TRUE ;
+#else
+#define blas_ok FALSE
+#endif
+
+    DEBUG5 (("In UMF_blas3_update "ID" "ID" "ID"\n",
+	Work->fnpiv, Work->fnrows, Work->fncols)) ;
+
+    k = Work->fnpiv ;
+    if (k == 0)
+    {
+	/* no work to do */
+	return ;
+    }
+
+    m = Work->fnrows ;
+    n = Work->fncols ;
+
+    d = Work->fnr_curr ;
+    dc = Work->fnc_curr ;
+    nb = Work->nb ;
+    ASSERT (d >= 0 && (d % 2) == 1) ;
+    C = Work->Fcblock ;	    /* ldc is fnr_curr */
+    L =	Work->Flblock ;	    /* ldl is fnr_curr */
+    U = Work->Fublock ;	    /* ldu is fnc_curr, stored by rows */
+    LU = Work->Flublock ;   /* nb-by-nb */
+
+#ifndef NDEBUG
+    DEBUG5 (("DO RANK-NB UPDATE of frontal:\n")) ;
+    DEBUG5 (("DGEMM : "ID" "ID" "ID"\n", k, m, n)) ;
+    DEBUG7 (("C  block: ")) ; UMF_dump_dense (C,  d, m, n) ;
+    DEBUG7 (("A  block: ")) ; UMF_dump_dense (L,  d, m, k) ;
+    DEBUG7 (("B' block: ")) ; UMF_dump_dense (U, dc, n, k) ;
+    DEBUG7 (("LU block: ")) ; UMF_dump_dense (LU, nb, k, k) ;
+#endif
+
+    if (k == 1)
+    {
+
+#ifndef NBLAS
+	BLAS_GER (m, n, L, U, C, d) ;
+#endif
+
+	if (!blas_ok)
+	{
+	    /* rank-1 outer product to update the C block */
+	    for (j = 0 ; j < n ; j++)
+	    {
+		Entry u_j = U [j] ;
+		if (IS_NONZERO (u_j))
+		{
+		    Entry *c_ij, *l_is ;
+		    c_ij = & C [j*d] ;
+		    l_is = & L [0] ;
+#pragma ivdep
+		    for (i = 0 ; i < m ; i++)
+		    {
+			/* C [i+j*d]-= L [i] * U [j] */
+			MULT_SUB (*c_ij, *l_is, u_j) ;
+			c_ij++ ;
+			l_is++ ;
+		    }
+		}
+	    }
+	}
+
+    }
+    else
+    {
+
+	/* triangular solve to update the U block */
+
+#ifndef NBLAS
+	BLAS_TRSM_RIGHT (n, k, LU, nb, U, dc) ;
+#endif
+
+	if (!blas_ok)
+	{
+	    /* use plain C code if no BLAS at compile time, or if integer
+	     * overflow has occurred */
+	    for (s = 0 ; s < k ; s++)
+	    {
+		for (i = s+1 ; i < k ; i++)
+		{
+		    Entry l_is = LU [i+s*nb] ;
+		    if (IS_NONZERO (l_is))
+		    {
+			Entry *u_ij, *u_sj ;
+			u_ij = & U [i*dc] ;
+			u_sj = & U [s*dc] ;
+#pragma ivdep
+			for (j = 0 ; j < n ; j++)
+			{
+			    /* U [i*dc+j] -= LU [i+s*nb] * U [s*dc+j] ; */
+			    MULT_SUB (*u_ij, l_is, *u_sj) ;
+			    u_ij++ ;
+			    u_sj++ ;
+			}
+		    }
+		}
+	    }
+	}
+
+	/* rank-k outer product to update the C block */
+	/* C = C - L*U' (U is stored by rows, not columns) */
+
+#ifndef NBLAS
+	BLAS_GEMM (m, n, k, L, U, dc, C, d) ;
+#endif
+
+	if (!blas_ok)
+	{
+	    /* use plain C code if no BLAS at compile time, or if integer
+	     * overflow has occurred */
+
+	    for (s = 0 ; s < k ; s++)
+	    {
+		for (j = 0 ; j < n ; j++)
+		{
+		    Entry u_sj = U [j+s*dc] ;
+		    if (IS_NONZERO (u_sj))
+		    {
+			Entry *c_ij, *l_is ;
+			c_ij = & C [j*d] ;
+			l_is = & L [s*d] ;
+#pragma ivdep
+			for (i = 0 ; i < m ; i++)
+			{
+			    /* C [i+j*d]-= L [i+s*d] * U [s*dc+j] */
+			    MULT_SUB (*c_ij, *l_is, u_sj) ;
+			    c_ij++ ;
+			    l_is++ ;
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+#ifndef NDEBUG
+    DEBUG5 (("RANK-NB UPDATE of frontal done:\n")) ;
+    DEBUG5 (("DGEMM : "ID" "ID" "ID"\n", k, m, n)) ;
+    DEBUG7 (("C  block: ")) ; UMF_dump_dense (C,  d, m, n) ;
+    DEBUG7 (("A  block: ")) ; UMF_dump_dense (L,  d, m, k) ;
+    DEBUG7 (("B' block: ")) ; UMF_dump_dense (U, dc, n, k) ;
+    DEBUG7 (("LU block: ")) ; UMF_dump_dense (LU, nb, k, k) ;
+#endif
+
+    DEBUG2 (("blas3 "ID" "ID" "ID"\n", k, Work->fnrows, Work->fncols)) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_blas3_update.h b/src/C/SuiteSparse/UMFPACK/Source/umf_blas3_update.h
new file mode 100644
index 0000000..62cea48
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_blas3_update.h
@@ -0,0 +1,10 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_blas3_update
+(
+    WorkType *Work
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_build_tuples.c b/src/C/SuiteSparse/UMFPACK/Source/umf_build_tuples.c
new file mode 100644
index 0000000..4895089
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_build_tuples.c
@@ -0,0 +1,159 @@
+/* ========================================================================== */
+/* === UMF_build_tuples ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Construct the tuple lists from a set of packed elements (no holes in
+    elements, no internal or external fragmentation, and a packed (0..Work->nel)
+    element name space).  Assume no tuple lists are currently allocated, but
+    that the tuple lengths have been initialized by UMF_tuple_lengths.
+
+    Returns TRUE if successful, FALSE if not enough memory.
+*/
+
+#include "umf_internal.h"
+#include "umf_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) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_build_tuples.h b/src/C/SuiteSparse/UMFPACK/Source/umf_build_tuples.h
new file mode 100644
index 0000000..8ee8052
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_build_tuples.h
@@ -0,0 +1,11 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_build_tuples
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_colamd.c b/src/C/SuiteSparse/UMFPACK/Source/umf_colamd.c
new file mode 100644
index 0000000..edbbad0
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_colamd.c
@@ -0,0 +1,3139 @@
+/* ========================================================================== */
+/* === UMF_colamd =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+UMF_colamd:  an approximate minimum degree column ordering algorithm,
+    used as a preordering for UMFPACK.
+
+NOTE: if this routine is used outside of UMFPACK, for a sparse Cholesky
+factorization of (AQ)'*(AQ) or a QR factorization of A, then one line should
+be removed (the "&& pivot_row_thickness > 0" expression).  See the comment
+regarding the Cholesky factorization, below.
+
+Purpose:
+
+    Colamd computes a permutation Q such that the Cholesky factorization of
+    (AQ)'(AQ) has less fill-in and requires fewer floating point operations
+    than A'A.  This also provides a good ordering for sparse partial
+    pivoting methods, P(AQ) = LU, where Q is computed prior to numerical
+    factorization, and P is computed during numerical factorization via
+    conventional partial pivoting with row interchanges.  Colamd is the
+    column ordering method used in SuperLU, part of the ScaLAPACK library.
+    It is also available as built-in function in MATLAB Version 6,
+    available from MathWorks, Inc. (http://www.mathworks.com).  This
+    routine can be used in place of colmmd in MATLAB.  By default, the \
+    and / operators in MATLAB perform a column ordering (using colmmd
+    or colamd) prior to LU factorization using sparse partial pivoting,
+    in the built-in MATLAB lu(A) routine.
+
+    This code is derived from Colamd Version 2.0.
+
+Authors:
+
+    The authors of the COLAMD code itself are Stefan I. Larimore and Timothy A.
+    Davis, University of Florida.  The algorithm was developed in collaboration
+    with John Gilbert, Xerox PARC, and Esmond Ng, Oak Ridge National Laboratory.
+    The AMD metric on which this is based is by Patrick Amestoy, T. Davis,
+    and Iain Duff.
+
+Date:
+
+    UMFPACK Version: see above.
+    COLAMD Version 2.0 was released on January 31, 2000.
+
+Acknowledgements:
+
+    This work was supported by the National Science Foundation, under
+    grants DMS-9504974, DMS-9803599, and CCR-0203270.
+
+UMFPACK:  Copyright (c) 2003 by Timothy A. Davis.  All Rights Reserved.
+
+See the UMFPACK README file for the License for your use of this code.
+
+Availability:
+
+    Both UMFPACK and the original unmodified colamd/symamd library are
+    available at http://www.cise.ufl.edu/research/sparse.
+
+Changes for inclusion in UMFPACK:
+
+    * symamd, symamd_report, and colamd_report removed
+
+    * additional terms added to RowInfo, ColInfo, and stats
+
+    * Frontal matrix information computed for UMFPACK
+
+    * routines renamed
+
+    * column elimination tree post-ordering incorporated.  In the original
+	version 2.0, this was performed in colamd.m.
+
+For more information, see:
+
+	Amestoy, P. R. and Davis, T. A. and Duff, I. S.,
+	An approximate minimum degree ordering algorithm,
+	SIAM J. Matrix Analysis and Applic, vol 17, no 4., pp 886-905, 1996.
+
+	Davis, T. A. and Gilbert, J. R. and Larimore, S. I. and Ng, E. G.,
+	A column approximate minimum degree ordering algorithm,
+	Univ. of Florida, CISE Dept., TR-00-005, Gainesville, FL
+	Oct. 2000.  Submitted to ACM Trans. Math. Softw.
+
+*/
+
+/* ========================================================================== */
+/* === Description of user-callable routines ================================ */
+/* ========================================================================== */
+
+/*
+    ----------------------------------------------------------------------------
+    colamd_recommended: removed for UMFPACK
+    ----------------------------------------------------------------------------
+
+    ----------------------------------------------------------------------------
+    colamd_set_defaults:
+    ----------------------------------------------------------------------------
+
+	C syntax:
+
+	    #include "colamd.h"
+	    colamd_set_defaults (double knobs [COLAMD_KNOBS]) ;
+
+	Purpose:
+
+	    Sets the default parameters.  The use of this routine is optional.
+
+	Arguments:
+
+	    double knobs [COLAMD_KNOBS] ;	Output only.
+
+		Let c = knobs [COLAMD_DENSE_COL], r = knobs [COLAMD_DENSE_ROW].
+		Colamd: rows with more than max (16, r*16*sqrt(n_col))
+		entries are removed prior to ordering.  Columns with more than
+		max (16, c*16*sqrt(n_row)) entries are removed prior to
+		ordering, and placed last in the output column ordering.
+
+		Symamd: removed for UMFPACK.
+
+		COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1,
+		respectively, in colamd.h.  Default values of these two knobs
+		are both 0.5.  Currently, only knobs [0] and knobs [1] are
+		used, but future versions may use more knobs.  If so, they will
+		be properly set to their defaults by the future version of
+		colamd_set_defaults, so that the code that calls colamd will
+		not need to change, assuming that you either use
+		colamd_set_defaults, or pass a (double *) NULL pointer as the
+		knobs array to colamd or symamd.
+
+		knobs [COLAMD_AGGRESSIVE]: if nonzero, then perform aggressive
+		absorption.  Otherwise, do not.  This version does aggressive
+		absorption by default.  COLAMD v2.1 (in MATLAB) always
+		does aggressive absorption (it doesn't have an option to turn
+		it off).
+
+    ----------------------------------------------------------------------------
+    colamd:
+    ----------------------------------------------------------------------------
+
+	C syntax:
+
+	    #include "colamd.h"
+	    Int UMF_colamd (Int n_row, Int n_col, Int Alen, Int *A, Int *p,
+		double knobs [COLAMD_KNOBS], Int stats [COLAMD_STATS]) ;
+
+	Purpose:
+
+	    Computes a column ordering (Q) of A such that P(AQ)=LU or
+	    (AQ)'AQ=LL' have less fill-in and require fewer floating point
+	    operations than factorizing the unpermuted matrix A or A'A,
+	    respectively.
+
+	Returns:
+
+	    TRUE (1) if successful, FALSE (0) otherwise.
+
+	Arguments:
+
+	    Int n_row ;		Input argument.
+
+		Number of rows in the matrix A.
+		Restriction:  n_row >= 0.
+		Colamd returns FALSE if n_row is negative.
+
+	    Int n_col ;		Input argument.
+
+		Number of columns in the matrix A.
+		Restriction:  n_col >= 0.
+		Colamd returns FALSE if n_col is negative.
+
+	    Int Alen ;		Input argument.
+
+		Restriction (see note):
+		Alen >= 2*nnz + 8*(n_col+1) + 6*(n_row+1) + n_col
+		Colamd returns FALSE if these conditions are not met.
+
+		Note:  this restriction makes an modest assumption regarding
+		the size of the two typedef's structures in colamd.h.
+		We do, however, guarantee that
+
+			Alen >= UMF_COLAMD_RECOMMENDED (nnz, n_row, n_col)
+
+		will be sufficient.
+
+	    Int A [Alen] ;	Input and output argument.
+
+		A is an integer array of size Alen.  Alen must be at least as
+		large as the bare minimum value given above, but this is very
+		low, and can result in excessive run time.  For best
+		performance, we recommend that Alen be greater than or equal to
+		UMF_COLAMD_RECOMMENDED (nnz, n_row, n_col), which adds
+		nnz/5 to the bare minimum value given above.
+
+		On input, the row indices of the entries in column c of the
+		matrix are held in A [(p [c]) ... (p [c+1]-1)].  The row indices
+		in a given column c need not be in ascending order, and
+		duplicate row indices may be be present.  However, colamd will
+		work a little faster if both of these conditions are met
+		(Colamd puts the matrix into this format, if it finds that the
+		the conditions are not met).
+
+		The matrix is 0-based.  That is, rows are in the range 0 to
+		n_row-1, and columns are in the range 0 to n_col-1.  Colamd
+		returns FALSE if any row index is out of range.
+
+		A holds the inverse permutation on output.
+
+	    Int p [n_col+1] ;	Both input and output argument.
+
+		p is an integer array of size n_col+1.  On input, it holds the
+		"pointers" for the column form of the matrix A.  Column c of
+		the matrix A is held in A [(p [c]) ... (p [c+1]-1)].  The first
+		entry, p [0], must be zero, and p [c] <= p [c+1] must hold
+		for all c in the range 0 to n_col-1.  The value p [n_col] is
+		thus the total number of entries in the pattern of the matrix A.
+		Colamd returns FALSE if these conditions are not met.
+
+		On output, if colamd returns TRUE, the array p holds the column
+		permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is
+		the first column index in the new ordering, and p [n_col-1] is
+		the last.  That is, p [k] = j means that column j of A is the
+		kth pivot column, in AQ, where k is in the range 0 to n_col-1
+		(p [0] = j means that column j of A is the first column in AQ).
+
+		If colamd returns FALSE, then no permutation is returned, and
+		p is undefined on output.
+
+	    double knobs [COLAMD_KNOBS] ;	Input argument.
+
+		See colamd_set_defaults for a description.
+		The behavior is undefined if knobs contains NaN's.
+		(UMFPACK does not call umf_colamd with NaN-valued knobs).
+
+	    Int stats [COLAMD_STATS] ;		Output argument.
+
+		Statistics on the ordering, and error status.
+		See colamd.h for related definitions.
+		Colamd returns FALSE if stats is not present.
+
+		stats [0]:  number of dense or empty rows ignored.
+
+		stats [1]:  number of dense or empty columns ignored (and
+				ordered last in the output permutation p)
+				Note that a row can become "empty" if it
+				contains only "dense" and/or "empty" columns,
+				and similarly a column can become "empty" if it
+				only contains "dense" and/or "empty" rows.
+
+		stats [2]:  number of garbage collections performed.
+				This can be excessively high if Alen is close
+				to the minimum required value.
+
+		stats [3]:  status code.  < 0 is an error code.
+			    > 1 is a warning or notice.
+
+			0	OK.  Each column of the input matrix contained
+				row indices in increasing order, with no
+				duplicates.
+
+			-11	Columns of input matrix jumbled
+				(unsorted columns or duplicate entries).
+
+					stats [4]: the bad column index
+					stats [5]: the bad row index
+
+			-1	A is a null pointer
+
+			-2	p is a null pointer
+
+			-3	n_row is negative
+
+					stats [4]: n_row
+
+			-4	n_col is negative
+
+					stats [4]: n_col
+
+			-5	number of nonzeros in matrix is negative
+
+					stats [4]: number of nonzeros, p [n_col]
+
+			-6	p [0] is nonzero
+
+					stats [4]: p [0]
+
+			-7	A is too small
+
+					stats [4]: required size
+					stats [5]: actual size (Alen)
+
+			-8	a column has a zero or negative number of
+				entries (changed for UMFPACK)
+
+					stats [4]: column with <= 0 entries
+					stats [5]: number of entries in col
+
+			-9	a row index is out of bounds
+
+					stats [4]: column with bad row index
+					stats [5]: bad row index
+					stats [6]: n_row, # of rows of matrx
+
+			-10	unused
+
+			-999	(unused; see symamd.c)
+
+		Future versions may return more statistics in the stats array.
+
+	Example:
+
+	    See http://www.cise.ufl.edu/~davis/colamd/example.c
+	    for a complete example.
+
+	    To order the columns of a 5-by-4 matrix with 11 nonzero entries in
+	    the following nonzero pattern
+
+		x 0 x 0
+		x 0 x x
+		0 x x 0
+		0 0 x x
+		x x 0 0
+
+	    with default knobs and no output statistics, do the following:
+
+		#include "colamd.h"
+		#define ALEN UMF_COLAMD_RECOMMENDED (11, 5, 4)
+		Int A [ALEN] = {1, 2, 5, 3, 5, 1, 2, 3, 4, 2, 4} ;
+		Int p [ ] = {0, 3, 5, 9, 11} ;
+		Int stats [COLAMD_STATS] ;
+		UMF_colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ;
+
+	    The permutation is returned in the array p, and A is destroyed.
+
+
+    ----------------------------------------------------------------------------
+    symamd:  does not appear in this version for UMFPACK
+    ----------------------------------------------------------------------------
+
+    ----------------------------------------------------------------------------
+    colamd_report: does not appear in this version for UMFPACK
+    ----------------------------------------------------------------------------
+
+    ----------------------------------------------------------------------------
+    symamd_report: does not appear in this version for UMFPACK
+    ----------------------------------------------------------------------------
+
+*/
+
+/* ========================================================================== */
+/* === Scaffolding code definitions  ======================================== */
+/* ========================================================================== */
+
+/* UMFPACK debugging control moved to amd_internal.h */
+
+/*
+   Our "scaffolding code" philosophy:  In our opinion, well-written library
+   code should keep its "debugging" code, and just normally have it turned off
+   by the compiler so as not to interfere with performance.  This serves
+   several purposes:
+
+   (1) assertions act as comments to the reader, telling you what the code
+	expects at that point.  All assertions will always be true (unless
+	there really is a bug, of course).
+
+   (2) leaving in the scaffolding code assists anyone who would like to modify
+	the code, or understand the algorithm (by reading the debugging output,
+	one can get a glimpse into what the code is doing).
+
+   (3) (gasp!) for actually finding bugs.  This code has been heavily tested
+	and "should" be fully functional and bug-free ... but you never know...
+
+    To enable debugging, comment out the "#define NDEBUG" above.  For a MATLAB
+    mexFunction, you will also need to modify mexopts.sh to remove the -DNDEBUG
+    definition.  The code will become outrageously slow when debugging is
+    enabled.  To control the level of debugging output, set an environment
+    variable D to 0 (little), 1 (some), 2, 3, or 4 (lots).  When debugging,
+    you should see the following message on the standard output:
+
+	colamd: debug version, D = 1 (THIS WILL BE SLOW!)
+
+    or a similar message for symamd.  If you don't, then debugging has not
+    been enabled.
+
+*/
+
+/* ========================================================================== */
+/* === Include files ======================================================== */
+/* ========================================================================== */
+
+/* ------------------ */
+/* modified for UMFPACK: */
+#include "umf_internal.h"
+#include "umf_colamd.h"
+#include "umf_apply_order.h"
+#include "umf_fsize.h"
+/* ------------------ */
+
+/* ========================================================================== */
+/* === Definitions ========================================================== */
+/* ========================================================================== */
+
+/* ------------------ */
+/* UMFPACK: duplicate definitions moved to umf_internal.h */
+/* ------------------ */
+
+/* Row and column status */
+#define ALIVE	(0)
+#define DEAD	(-1)
+
+/* Column status */
+#define DEAD_PRINCIPAL		(-1)
+#define DEAD_NON_PRINCIPAL	(-2)
+
+/* Macros for row and column status update and checking. */
+#define ROW_IS_DEAD(r)			ROW_IS_MARKED_DEAD (Row[r].shared2.mark)
+#define ROW_IS_MARKED_DEAD(row_mark)	(row_mark < ALIVE)
+#define ROW_IS_ALIVE(r)			(Row [r].shared2.mark >= ALIVE)
+#define COL_IS_DEAD(c)			(Col [c].start < ALIVE)
+#define COL_IS_ALIVE(c)			(Col [c].start >= ALIVE)
+#define COL_IS_DEAD_PRINCIPAL(c)	(Col [c].start == DEAD_PRINCIPAL)
+#define KILL_ROW(r)			{ Row [r].shared2.mark = DEAD ; }
+#define KILL_PRINCIPAL_COL(c)		{ Col [c].start = DEAD_PRINCIPAL ; }
+#define KILL_NON_PRINCIPAL_COL(c)	{ Col [c].start = DEAD_NON_PRINCIPAL ; }
+
+/* ------------------ */
+/* UMFPACK: Colamd reporting mechanism moved to umf_internal.h */
+/* ------------------ */
+
+/* ========================================================================== */
+/* === Prototypes of PRIVATE routines ======================================= */
+/* ========================================================================== */
+
+PRIVATE Int init_rows_cols
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int p []
+    /* Int stats [COLAMD_STATS] */
+) ;
+
+PRIVATE void init_scoring
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int head [],
+    double knobs [COLAMD_KNOBS],
+    Int *p_n_row2,
+    Int *p_n_col2,
+    Int *p_max_deg
+    /* ------------------ */
+    /* added for UMFPACK */
+    , Int *p_ndense_row		/* number of dense rows */
+    , Int *p_nempty_row		/* number of original empty rows */
+    , Int *p_nnewlyempty_row	/* number of newly empty rows */
+    , Int *p_ndense_col		/* number of dense cols (excl "empty" cols) */
+    , Int *p_nempty_col		/* number of original empty cols */
+    , Int *p_nnewlyempty_col	/* number of newly empty cols */
+) ;
+
+PRIVATE Int find_ordering
+(
+    Int n_row,
+    Int n_col,
+    Int Alen,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int head [],
+    Int n_col2,
+    Int max_deg,
+    Int pfree
+    /* ------------------ */
+    /* added for UMFPACK: */
+    , Int Front_npivcol [ ]
+    , Int Front_nrows [ ]
+    , Int Front_ncols [ ]
+    , Int Front_parent [ ]
+    , Int Front_cols [ ]
+    , Int *p_nfr
+    , Int aggressive
+    , Int InFront [ ]
+    /* ------------------ */
+) ;
+
+/* ------------------ */
+/* order_children deleted for UMFPACK: */
+/* ------------------ */
+
+PRIVATE void detect_super_cols
+(
+
+#ifndef NDEBUG
+    Int n_col,
+    Colamd_Row Row [],
+#endif /* NDEBUG */
+
+    Colamd_Col Col [],
+    Int A [],
+    Int head [],
+    Int row_start,
+    Int row_length
+) ;
+
+PRIVATE Int garbage_collection
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int *pfree
+) ;
+
+PRIVATE Int clear_mark
+(
+    Int n_row,
+    Colamd_Row Row []
+) ;
+
+/* ------------------ */
+/* print_report deleted for UMFPACK */
+/* ------------------ */
+
+/* ========================================================================== */
+/* === Debugging prototypes and definitions ================================= */
+/* ========================================================================== */
+
+#ifndef NDEBUG
+
+/* ------------------ */
+/* debugging macros moved for UMFPACK */
+/* ------------------ */
+
+PRIVATE void debug_deg_lists
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int head [],
+    Int min_score,
+    Int should,
+    Int max_deg
+) ;
+
+PRIVATE void debug_mark
+(
+    Int n_row,
+    Colamd_Row Row [],
+    Int tag_mark,
+    Int max_mark
+) ;
+
+PRIVATE void debug_matrix
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A []
+) ;
+
+PRIVATE void debug_structures
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int n_col2
+) ;
+
+/* ------------------ */
+/* dump_super added for UMFPACK: */
+PRIVATE void dump_super
+(
+    Int super_c,
+    Colamd_Col Col [],
+    Int n_col
+) ;
+/* ------------------ */
+
+#endif /* NDEBUG */
+
+/* ========================================================================== */
+
+
+
+/* ========================================================================== */
+/* === USER-CALLABLE ROUTINES: ============================================== */
+/* ========================================================================== */
+
+
+/* ========================================================================== */
+/* === colamd_set_defaults ================================================== */
+/* ========================================================================== */
+
+/*
+    The colamd_set_defaults routine sets the default values of the user-
+    controllable parameters for colamd:
+
+	knobs [0]	rows with knobs[0]*n_col entries or more are removed
+			prior to ordering in colamd.  Rows and columns with
+			knobs[0]*n_col entries or more are removed prior to
+			ordering in symamd and placed last in the output
+			ordering.
+
+	knobs [1]	columns with knobs[1]*n_row entries or more are removed
+			prior to ordering in colamd, and placed last in the
+			column permutation.  Symamd ignores this knob.
+
+	knobs [2]	if nonzero, then perform aggressive absorption.
+
+	knobs [3..19]	unused, but future versions might use this
+*/
+
+GLOBAL void UMF_colamd_set_defaults
+(
+    /* === Parameters ======================================================= */
+
+    double knobs [COLAMD_KNOBS]		/* knob array */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;
+
+#if 0
+    if (!knobs)
+    {
+	return ;			/* UMFPACK always passes knobs array */
+    }
+#endif
+    for (i = 0 ; i < COLAMD_KNOBS ; i++)
+    {
+	knobs [i] = 0 ;
+    }
+    knobs [COLAMD_DENSE_ROW] = 0.2 ;	/* default changed for UMFPACK */
+    knobs [COLAMD_DENSE_COL] = 0.2 ;	/* default changed for UMFPACK */
+    knobs [COLAMD_AGGRESSIVE] = TRUE ;	/* default is to do aggressive
+					 * absorption */
+}
+
+
+/* ========================================================================== */
+/* === symamd removed for UMFPACK =========================================== */
+/* ========================================================================== */
+
+
+
+/* ========================================================================== */
+/* === colamd =============================================================== */
+/* ========================================================================== */
+
+/*
+    The colamd routine computes a column ordering Q of a sparse matrix
+    A such that the LU factorization P(AQ) = LU remains sparse, where P is
+    selected via partial pivoting.   The routine can also be viewed as
+    providing a permutation Q such that the Cholesky factorization
+    (AQ)'(AQ) = LL' remains sparse.
+*/
+
+/* For UMFPACK: colamd always returns TRUE */
+
+GLOBAL Int UMF_colamd		/* returns TRUE if successful, FALSE otherwise*/
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,			/* number of rows in A */
+    Int n_col,			/* number of columns in A */
+    Int Alen,			/* length of A */
+    Int A [],			/* row indices of A */
+    Int p [],			/* pointers to columns in A */
+    double knobs [COLAMD_KNOBS],/* parameters (uses defaults if NULL) */
+    Int stats [COLAMD_STATS]	/* output statistics and error codes */
+
+    /* ------------------ */
+    /* added for UMFPACK: each Front_ array is of size n_col+1 */
+    , Int Front_npivcol [ ]	/* # pivot cols in each front */
+    , Int Front_nrows [ ]	/* # of rows in each front (incl. pivot rows) */
+    , Int Front_ncols [ ]	/* # of cols in each front (incl. pivot cols) */
+    , Int Front_parent [ ]	/* parent of each front */
+    , Int Front_cols [ ]	/* link list of pivot columns for each front */
+    , Int *p_nfr		/* total number of frontal matrices */
+    , Int InFront [ ]		/* InFront [row] = f if the original row was
+				 * absorbed into front f.  EMPTY if the row was
+				 * empty, dense, or not absorbed.  This array
+				 * has size n_row+1 */
+    /* ------------------ */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int row ;			/* row index */
+    Int i ;			/* loop index */
+    Int nnz ;			/* nonzeros in A */
+    Int Row_size ;		/* size of Row [], in integers */
+    Int Col_size ;		/* size of Col [], in integers */
+#if 0
+    Int need ;			/* minimum required length of A */
+#endif
+    Colamd_Row *Row ;		/* pointer into A of Row [0..n_row] array */
+    Colamd_Col *Col ;		/* pointer into A of Col [0..n_col] array */
+    Int n_col2 ;		/* number of non-dense, non-empty columns */
+    Int n_row2 ;		/* number of non-dense, non-empty rows */
+    Int ngarbage ;		/* number of garbage collections performed */
+    Int max_deg ;		/* maximum row degree */
+    Int aggressive ;		/* TRUE if doing aggressive absorption */
+#if 0
+    double default_knobs [COLAMD_KNOBS] ;	/* default knobs array */
+#endif
+
+    /* ------------------ */
+    /* debugging initializations moved for UMFPACK */
+    /* ------------------ */
+
+    /* ------------------ */
+    /* added for UMFPACK: */
+    Int ndense_row, nempty_row, parent, ndense_col,
+	nempty_col, k, col, nfr, *Front_child, *Front_sibling, *Front_stack,
+	*Front_order, *Front_size ;
+    Int nnewlyempty_col, nnewlyempty_row ;
+    /* ------------------ */
+
+    /* === Check the input arguments ======================================== */
+
+#if 0
+    if (!stats)
+    {
+	DEBUG0 (("colamd: stats not present\n")) ;
+	return (FALSE) ;	/* UMFPACK:  always passes stats [ ] */
+    }
+#endif
+
+    ASSERT (stats != (Int *) NULL) ;
+
+    for (i = 0 ; i < COLAMD_STATS ; i++)
+    {
+	stats [i] = 0 ;
+    }
+    stats [COLAMD_STATUS] = COLAMD_OK ;
+    stats [COLAMD_INFO1] = -1 ;
+    stats [COLAMD_INFO2] = -1 ;
+
+#if 0
+    if (!A)		/* A is not present */
+    {
+	/* UMFPACK:  always passes A [ ] */
+	DEBUG0 (("colamd: A not present\n")) ;
+	stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
+	return (FALSE) ;
+    }
+
+    if (!p)		/* p is not present */
+    {
+	/* UMFPACK:  always passes p [ ] */
+	DEBUG0 (("colamd: p not present\n")) ;
+	stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
+	return (FALSE) ;
+    }
+
+    if (n_row < 0)	/* n_row must be >= 0 */
+    {
+	/* UMFPACK:  does not call UMF_colamd if n <= 0 */
+	DEBUG0 (("colamd: nrow negative "ID"\n", n_row)) ;
+	stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ;
+	stats [COLAMD_INFO1] = n_row ;
+	return (FALSE) ;
+    }
+
+    if (n_col < 0)	/* n_col must be >= 0 */
+    {
+	/* UMFPACK:  does not call UMF_colamd if n <= 0 */
+	DEBUG0 (("colamd: ncol negative "ID"\n", n_col)) ;
+	stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
+	stats [COLAMD_INFO1] = n_col ;
+	return (FALSE) ;
+    }
+#endif
+
+    ASSERT (A != (Int *) NULL) ;
+    ASSERT (p != (Int *) NULL) ;
+    ASSERT (n_row >= 0) ;
+    ASSERT (n_col >= 0) ;
+
+    nnz = p [n_col] ;
+
+#if 0
+    if (nnz < 0)	/* nnz must be >= 0 */
+    {
+	/* UMFPACK:  does not call UMF_colamd if nnz < 0 */
+	DEBUG0 (("colamd: number of entries negative "ID"\n", nnz)) ;
+	stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
+	stats [COLAMD_INFO1] = nnz ;
+	return (FALSE) ;
+    }
+
+    if (p [0] != 0)	/* p [0] must be exactly zero */
+    {
+	DEBUG0 (("colamd: p[0] not zero "ID"\n", p [0])) ;
+	stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero	;
+	stats [COLAMD_INFO1] = p [0] ;
+	return (FALSE) ;
+    }
+#endif
+
+    ASSERT (nnz >= 0) ;
+    ASSERT (p [0] == 0) ;
+
+    /* === If no knobs, set default knobs =================================== */
+
+#if 0
+    if (!knobs)
+    {
+	/* UMFPACK:  always passes the knobs */
+	UMF_colamd_set_defaults (default_knobs) ;
+	knobs = default_knobs ;
+    }
+#endif
+
+    ASSERT (knobs != (double *) NULL) ;
+
+    /* --------------------- */
+    /* added for UMFPACK v4.1: */
+    aggressive = (knobs [COLAMD_AGGRESSIVE] != 0) ;
+    /* --------------------- */
+
+    /* === Allocate the Row and Col arrays from array A ===================== */
+
+    Col_size = UMF_COLAMD_C (n_col) ;
+    Row_size = UMF_COLAMD_R (n_row) ;
+
+#if 0
+    need = MAX (2*nnz, 4*n_col) + n_col + Col_size + Row_size ;
+    if (need > Alen)
+    {
+	/* UMFPACK: always passes enough space */
+	/* not enough space in array A to perform the ordering */
+	DEBUG0 (("colamd: Need Alen >= "ID", given only Alen = "ID"\n",
+	    need, Alen)) ;
+	stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ;
+	stats [COLAMD_INFO1] = need ;
+	stats [COLAMD_INFO2] = Alen ;
+	return (FALSE) ;
+    }
+#endif
+
+    Alen -= Col_size + Row_size ;
+    Col = (Colamd_Col *) &A [Alen] ;
+    Row = (Colamd_Row *) &A [Alen + Col_size] ;
+
+    /* Size of A is now Alen >= MAX (2*nnz, 4*n_col) + n_col.  The ordering
+     * requires Alen >= 2*nnz + n_col, and the postorder requires
+     * Alen >= 5*n_col. */
+
+    /* === Construct the row and column data structures ===================== */
+
+    i = init_rows_cols (n_row, n_col, Row, Col, A, p) ;
+
+#if 0
+    if (!i)
+    {
+	/* input matrix is invalid */
+	DEBUG0 (("colamd: Matrix invalid\n")) ;
+	return (FALSE) ;
+    }
+#endif
+
+    ASSERT (i) ;
+
+    /* === UMFPACK: Initialize front info =================================== */
+
+    for (col = 0 ; col < n_col ; col++)
+    {
+	Front_npivcol [col] = 0 ;
+	Front_nrows [col] = 0 ;
+	Front_ncols [col] = 0 ;
+	Front_parent [col] = EMPTY ;
+	Front_cols [col] = EMPTY ;
+    }
+
+    /* === Initialize scores, kill dense rows/columns ======================= */
+
+    init_scoring (n_row, n_col, Row, Col, A, p, knobs,
+	&n_row2, &n_col2, &max_deg
+	/* ------------------ */
+	/* added for UMFPACK: */
+	, &ndense_row, &nempty_row, &nnewlyempty_row
+	, &ndense_col, &nempty_col, &nnewlyempty_col
+	/* ------------------ */
+	) ;
+    ASSERT (n_row2 == n_row - nempty_row - nnewlyempty_row - ndense_row) ;
+    ASSERT (n_col2 == n_col - nempty_col - nnewlyempty_col - ndense_col) ;
+
+    /* === Order the supercolumns =========================================== */
+
+    ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p,
+	n_col2, max_deg, 2*nnz
+	/* ------------------ */
+	/* added for UMFPACK: */
+	, Front_npivcol, Front_nrows, Front_ncols, Front_parent, Front_cols
+	, &nfr, aggressive, InFront
+	/* ------------------ */
+	) ;
+
+    /* ------------------ */
+    /* changed for UMFPACK: */
+
+    /* A is no longer needed, so use A [0..5*nfr-1] as workspace [ [ */
+    /* This step requires Alen >= 5*n_col */
+    Front_child   = A ;
+    Front_sibling = Front_child + nfr ;
+    Front_stack   = Front_sibling + nfr ;
+    Front_order   = Front_stack + nfr ;
+    Front_size    = Front_order + nfr ;
+
+    UMF_fsize (nfr, Front_size, Front_nrows, Front_ncols,
+	    Front_parent, Front_npivcol) ;
+
+    AMD_postorder (nfr, Front_parent, Front_npivcol, Front_size,
+	Front_order, Front_child, Front_sibling, Front_stack) ;
+
+    /* Front_size, Front_stack, Front_child, Front_sibling no longer needed ] */
+
+    /* use A [0..nfr-1] as workspace */
+    UMF_apply_order (Front_npivcol, Front_order, A, nfr, nfr) ;
+    UMF_apply_order (Front_nrows,   Front_order, A, nfr, nfr) ;
+    UMF_apply_order (Front_ncols,   Front_order, A, nfr, nfr) ;
+    UMF_apply_order (Front_parent,  Front_order, A, nfr, nfr) ;
+    UMF_apply_order (Front_cols,    Front_order, A, nfr, nfr) ;
+
+    /* fix the parent to refer to the new numbering */
+    for (i = 0 ; i < nfr ; i++)
+    {
+	parent = Front_parent [i] ;
+	if (parent != EMPTY)
+	{
+	    Front_parent [i] = Front_order [parent] ;
+	}
+    }
+
+    /* fix InFront to refer to the new numbering */
+    for (row = 0 ; row < n_row ; row++)
+    {
+	i = InFront [row] ;
+	ASSERT (i >= EMPTY && i < nfr) ;
+	if (i != EMPTY)
+	{
+	    InFront [row] = Front_order [i] ;
+	}
+    }
+
+    /* Front_order longer needed ] */
+
+    /* === Order the columns in the fronts ================================== */
+
+    /* use A [0..n_col-1] as inverse permutation */
+    for (i = 0 ; i < n_col ; i++)
+    {
+	A [i] = EMPTY ;
+    }
+    k = 0 ;
+    for (i = 0 ; i < nfr ; i++)
+    {
+	ASSERT (Front_npivcol [i] > 0) ;
+	for (col = Front_cols [i] ; col != EMPTY ; col = Col [col].nextcol)
+	{
+	    ASSERT (col >= 0 && col < n_col) ;
+	    DEBUG1 (("Colamd output ordering: k "ID" col "ID"\n", k, col)) ;
+	    p [k] = col ;
+	    ASSERT (A [col] == EMPTY) ;
+	    A [col] = k ;
+	    k++ ;
+	}
+    }
+
+    /* === Order the "dense" and null columns =============================== */
+
+    ASSERT (k == n_col2) ;
+    if (n_col2 < n_col)
+    {
+	for (col = 0 ; col < n_col ; col++)
+	{
+	    if (A [col] == EMPTY)
+	    {
+		k = Col [col].shared2.order ;
+		ASSERT (k >= n_col2 && k < n_col) ;
+		DEBUG1 (("Colamd output ordering: k "ID" col "ID
+		    " (dense or null col)\n", k, col)) ;
+		p [k] = col ;
+		A [col] = k ;
+	    }
+	}
+    }
+
+    /* ------------------ */
+
+    /* === Return statistics in stats ======================================= */
+
+    /* ------------------ */
+    /* modified for UMFPACK */
+    stats [COLAMD_DENSE_ROW] = ndense_row ;
+    stats [COLAMD_EMPTY_ROW] = nempty_row ;
+    stats [COLAMD_NEWLY_EMPTY_ROW] = nnewlyempty_row ;
+    stats [COLAMD_DENSE_COL] = ndense_col ;
+    stats [COLAMD_EMPTY_COL] = nempty_col ;
+    stats [COLAMD_NEWLY_EMPTY_COL] = nnewlyempty_col ;
+    ASSERT (ndense_col + nempty_col + nnewlyempty_col == n_col - n_col2) ;
+    /* ------------------ */
+    stats [COLAMD_DEFRAG_COUNT] = ngarbage ;
+    *p_nfr = nfr ;
+    DEBUG1 (("colamd: done.\n")) ;
+    return (TRUE) ;
+}
+
+
+
+
+/* ========================================================================== */
+/* === colamd_report removed for UMFPACK ==================================== */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* === symamd_report removed for UMFPACK ==================================== */
+/* ========================================================================== */
+
+
+
+/* ========================================================================== */
+/* === NON-USER-CALLABLE ROUTINES: ========================================== */
+/* ========================================================================== */
+
+/* There are no user-callable routines beyond this point in the file */
+
+
+/* ========================================================================== */
+/* === init_rows_cols ======================================================= */
+/* ========================================================================== */
+
+/*
+    Takes the column form of the matrix in A and creates the row form of the
+    matrix.  Also, row and column attributes are stored in the Col and Row
+    structs.  If the columns are un-sorted or contain duplicate row indices,
+    this routine will also sort and remove duplicate row indices from the
+    column form of the matrix.  Returns FALSE if the matrix is invalid,
+    TRUE otherwise.  Not user-callable.
+*/
+
+/* For UMFPACK, this always returns TRUE */
+
+PRIVATE Int init_rows_cols	/* returns TRUE if OK, or FALSE otherwise */
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,			/* number of rows of A */
+    Int n_col,			/* number of columns of A */
+    Colamd_Row Row [],		/* of size n_row+1 */
+    Colamd_Col Col [],		/* of size n_col+1 */
+    Int A [],			/* row indices of A, of size Alen */
+    Int p []			/* pointers to columns in A, of size n_col+1 */
+/*
+    Int stats [COLAMD_STATS]	colamd statistics, removed for UMFPACK
+*/
+)
+{
+    /* === Local variables ================================================== */
+
+    Int col ;			/* a column index */
+    Int row ;			/* a row index */
+    Int *cp ;			/* a column pointer */
+    Int *cp_end ;		/* a pointer to the end of a column */
+
+    /* === Initialize columns, and check column pointers ==================== */
+
+    for (col = 0 ; col < n_col ; col++)
+    {
+	Col [col].start = p [col] ;
+	Col [col].length = p [col+1] - p [col] ;
+
+#if 0
+	if (Col [col].length < 0)
+	{
+	    /* column pointers must be non-decreasing */
+	    stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
+	    stats [COLAMD_INFO1] = col ;
+	    stats [COLAMD_INFO2] = Col [col].length ;
+	    DEBUG0 (("colamd: col "ID" length "ID" <= 0\n",
+		col, Col [col].length));
+	    return (FALSE) ;
+	}
+#endif
+
+	ASSERT (Col [col].length >= 0) ;
+
+	/* added for UMFPACK v4.1 */
+	ASSERT (Col [col].length > 0) ;
+
+	Col [col].shared1.thickness = 1 ;
+	Col [col].shared2.score = 0 ;
+	Col [col].shared3.prev = EMPTY ;
+	Col [col].shared4.degree_next = EMPTY ;
+
+	/* ------------------ */
+	/* added for UMFPACK: */
+	Col [col].nextcol = EMPTY ;
+	Col [col].lastcol = col ;
+	/* ------------------ */
+    }
+
+    /* p [0..n_col] no longer needed, used as "head" in subsequent routines */
+
+    /* === Scan columns, compute row degrees, and check row indices ========= */
+
+    /* ------------------ */
+    /* stats [COLAMD_INFO3] = 0 ; */
+    /* number of duplicate or unsorted row indices - not computed in UMFPACK */
+    /* ------------------ */
+
+    for (row = 0 ; row < n_row ; row++)
+    {
+	Row [row].length = 0 ;
+	/* ------------------ */
+	/* removed for UMFPACK */
+	/* Row [row].shared2.mark = -1 ; */
+	/* ------------------ */
+	/* ------------------ */
+	/* added for UMFPACK: */
+	Row [row].thickness = 1 ;
+	Row [row].front = EMPTY ;
+	/* ------------------ */
+    }
+
+    for (col = 0 ; col < n_col ; col++)
+    {
+#ifndef NDEBUG
+	Int last_row = -1 ;
+#endif
+
+	cp = &A [p [col]] ;
+	cp_end = &A [p [col+1]] ;
+
+	while (cp < cp_end)
+	{
+	    row = *cp++ ;
+
+#if 0
+	    /* make sure row indices within range */
+	    if (row < 0 || row >= n_row)
+	    {
+		stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
+		stats [COLAMD_INFO1] = col ;
+		stats [COLAMD_INFO2] = row ;
+		/* ------------------ */
+		/* not needed in UMFPACK: */
+		/* stats [COLAMD_INFO3] = n_row ; */
+		/* ------------------ */
+		DEBUG0 (("colamd: row "ID" col "ID" out of bounds\n", row,col));
+		return (FALSE) ;
+	    }
+#endif
+
+	    ASSERT (row >= 0 && row < n_row) ;
+
+#if 0
+	    /* ------------------ */
+	    /* changed for UMFPACK */
+	    if (row <= last_row)
+	    {
+		/* row index are unsorted or repeated (or both), thus col */
+		/* is jumbled.  This is an error condition for UMFPACK */
+		stats [COLAMD_STATUS] = COLAMD_ERROR_jumbled_matrix ;
+		stats [COLAMD_INFO1] = col ;
+		stats [COLAMD_INFO2] = row ;
+		DEBUG1 (("colamd: row "ID" col "ID" unsorted/duplicate\n",
+		    row, col)) ;
+		return (FALSE) ;
+	    }
+	    /* ------------------ */
+#endif
+
+	    ASSERT (row > last_row) ;
+
+	    /* ------------------ */
+	    /* changed for UMFPACK - jumbled columns not tolerated */
+	    Row [row].length++ ;
+	    /* ------------------ */
+
+#ifndef NDEBUG
+	    last_row = row ;
+#endif
+	}
+    }
+
+    /* === Compute row pointers ============================================= */
+
+    /* row form of the matrix starts directly after the column */
+    /* form of matrix in A */
+    Row [0].start = p [n_col] ;
+    Row [0].shared1.p = Row [0].start ;
+    /* ------------------ */
+    /* removed for UMFPACK */
+    /* Row [0].shared2.mark = -1 ; */
+    /* ------------------ */
+    for (row = 1 ; row < n_row ; row++)
+    {
+	Row [row].start = Row [row-1].start + Row [row-1].length ;
+	Row [row].shared1.p = Row [row].start ;
+	/* ------------------ */
+	/* removed for UMFPACK */
+	/* Row [row].shared2.mark = -1 ; */
+	/* ------------------ */
+    }
+
+    /* === Create row form ================================================== */
+
+    /* ------------------ */
+    /* jumbled matrix case removed for UMFPACK */
+    /* ------------------ */
+
+	for (col = 0 ; col < n_col ; col++)
+	{
+	    cp = &A [p [col]] ;
+	    cp_end = &A [p [col+1]] ;
+	    while (cp < cp_end)
+	    {
+		A [(Row [*cp++].shared1.p)++] = col ;
+	    }
+	}
+
+    /* === Clear the row marks and set row degrees ========================== */
+
+    for (row = 0 ; row < n_row ; row++)
+    {
+	Row [row].shared2.mark = 0 ;
+	Row [row].shared1.degree = Row [row].length ;
+    }
+
+    /* ------------------ */
+    /* recreate columns for jumbled matrix case removed for UMFPACK */
+    /* ------------------ */
+
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === init_scoring ========================================================= */
+/* ========================================================================== */
+
+/*
+    Kills dense or empty columns and rows, calculates an initial score for
+    each column, and places all columns in the degree lists.  Not user-callable.
+*/
+
+PRIVATE void init_scoring
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,			/* number of rows of A */
+    Int n_col,			/* number of columns of A */
+    Colamd_Row Row [],		/* of size n_row+1 */
+    Colamd_Col Col [],		/* of size n_col+1 */
+    Int A [],			/* column form and row form of A */
+    Int head [],		/* of size n_col+1 */
+    double knobs [COLAMD_KNOBS],/* parameters */
+    Int *p_n_row2,		/* number of non-dense, non-empty rows */
+    Int *p_n_col2,		/* number of non-dense, non-empty columns */
+    Int *p_max_deg		/* maximum row degree */
+    /* ------------------ */
+    /* added for UMFPACK */
+    , Int *p_ndense_row		/* number of dense rows */
+    , Int *p_nempty_row		/* number of original empty rows */
+    , Int *p_nnewlyempty_row	/* number of newly empty rows */
+    , Int *p_ndense_col		/* number of dense cols (excl "empty" cols) */
+    , Int *p_nempty_col		/* number of original empty cols */
+    , Int *p_nnewlyempty_col	/* number of newly empty cols */
+    /* ------------------ */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int c ;			/* a column index */
+    Int r, row ;		/* a row index */
+    Int *cp ;			/* a column pointer */
+    Int deg ;			/* degree of a row or column */
+    Int *cp_end ;		/* a pointer to the end of a column */
+    Int *new_cp ;		/* new column pointer */
+    Int col_length ;		/* length of pruned column */
+    Int score ;			/* current column score */
+    Int n_col2 ;		/* number of non-dense, non-empty columns */
+    Int n_row2 ;		/* number of non-dense, non-empty rows */
+    Int dense_row_count ;	/* remove rows with more entries than this */
+    Int dense_col_count ;	/* remove cols with more entries than this */
+    Int min_score ;		/* smallest column score */
+    Int max_deg ;		/* maximum row degree */
+    Int next_col ;		/* Used to add to degree list.*/
+
+    /* ------------------ */
+    /* added for UMFPACK */
+    Int ndense_row ;		/* number of dense rows */
+    Int nempty_row ;		/* number of empty rows */
+    Int nnewlyempty_row ;	/* number of newly empty rows */
+    Int ndense_col ;		/* number of dense cols (excl "empty" cols) */
+    Int nempty_col ;		/* number of original empty cols */
+    Int nnewlyempty_col ;	/* number of newly empty cols */
+    Int ne ;
+    /* ------------------ */
+
+#ifndef NDEBUG
+    Int debug_count ;		/* debug only. */
+#endif /* NDEBUG */
+
+    /* === Extract knobs ==================================================== */
+
+    /* --------------------- */
+    /* old dense row/column knobs:
+    dense_row_count = MAX (0, MIN (knobs [COLAMD_DENSE_ROW] * n_col, n_col)) ;
+    dense_col_count = MAX (0, MIN (knobs [COLAMD_DENSE_COL] * n_row, n_row)) ;
+    */
+    /* new, for UMFPACK: */
+    /* Note: if knobs contains a NaN, this is undefined: */
+    dense_row_count =
+	UMFPACK_DENSE_DEGREE_THRESHOLD (knobs [COLAMD_DENSE_ROW], n_col) ;
+    dense_col_count =
+	UMFPACK_DENSE_DEGREE_THRESHOLD (knobs [COLAMD_DENSE_COL], n_row) ;
+    /* Make sure dense_*_count is between 0 and n: */
+    dense_row_count = MAX (0, MIN (dense_row_count, n_col)) ;
+    dense_col_count = MAX (0, MIN (dense_col_count, n_row)) ;
+    /* --------------------- */
+
+    DEBUG1 (("colamd: densecount: "ID" "ID"\n",
+	dense_row_count, dense_col_count)) ;
+    max_deg = 0 ;
+    n_col2 = n_col ;
+    n_row2 = n_row ;
+
+    /* --------------------- */
+    /* added for UMFPACK */
+    ndense_col = 0 ;
+    nempty_col = 0 ;
+    nnewlyempty_col = 0 ;
+    ndense_row = 0 ;
+    nempty_row = 0 ;
+    nnewlyempty_row = 0 ;
+    /* --------------------- */
+
+    /* === Kill empty columns =============================================== */
+
+    /* removed for UMFPACK v4.1.  prune_singletons has already removed empty
+     * columns and empty rows */
+
+#if 0
+    /* Put the empty columns at the end in their natural order, so that LU */
+    /* factorization can proceed as far as possible. */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+	deg = Col [c].length ;
+	if (deg == 0)
+	{
+	    /* this is a empty column, kill and order it last */
+	    Col [c].shared2.order = --n_col2 ;
+	    KILL_PRINCIPAL_COL (c) ;
+	    /* --------------------- */
+	    /* added for UMFPACK */
+	    nempty_col++ ;
+	    /* --------------------- */
+	}
+    }
+    DEBUG1 (("colamd: null columns killed: "ID"\n", n_col - n_col2)) ;
+#endif
+
+#ifndef NDEBUG
+    for (c = 0 ; c < n_col ; c++)
+    {
+	ASSERT (Col [c].length > 0) ;
+    }
+#endif
+
+    /* === Count null rows ================================================== */
+
+#if 0
+    for (r = 0 ; r < n_row ; r++)
+    {
+	deg = Row [r].shared1.degree ;
+	if (deg == 0)
+	{
+	    /* this is an original empty row */
+	    nempty_row++ ;
+	}
+    }
+#endif
+
+#ifndef NDEBUG
+    for (r = 0 ; r < n_row ; r++)
+    {
+	ASSERT (Row [r].shared1.degree > 0) ;
+	ASSERT (Row [r].length > 0) ;
+    }
+#endif
+
+    /* === Kill dense columns =============================================== */
+
+    /* Put the dense columns at the end, in their natural order */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+
+	/* ----------------------------------------------------------------- */
+#if 0
+	/* removed for UMFPACK v4.1: no empty columns */
+	/* skip any dead columns */
+	if (COL_IS_DEAD (c))
+	{
+	    continue ;
+	}
+#endif
+	ASSERT (COL_IS_ALIVE (c)) ;
+	ASSERT (Col [c].length > 0) ;
+	/* ----------------------------------------------------------------- */
+
+	deg = Col [c].length ;
+	if (deg > dense_col_count)
+	{
+	    /* this is a dense column, kill and order it last */
+	    Col [c].shared2.order = --n_col2 ;
+	    /* --------------------- */
+	    /* added for UMFPACK */
+	    ndense_col++ ;
+	    /* --------------------- */
+	    /* decrement the row degrees */
+	    cp = &A [Col [c].start] ;
+	    cp_end = cp + Col [c].length ;
+	    while (cp < cp_end)
+	    {
+		Row [*cp++].shared1.degree-- ;
+	    }
+	    KILL_PRINCIPAL_COL (c) ;
+	}
+    }
+    DEBUG1 (("colamd: Dense and null columns killed: "ID"\n", n_col - n_col2)) ;
+
+    /* === Kill dense and empty rows ======================================== */
+
+    /* Note that there can now be empty rows, since dense columns have
+     * been deleted.  These are "newly" empty rows. */
+
+    ne = 0 ;
+    for (r = 0 ; r < n_row ; r++)
+    {
+	deg = Row [r].shared1.degree ;
+	ASSERT (deg >= 0 && deg <= n_col) ;
+	/* --------------------- */
+	/* added for UMFPACK */
+	if (deg > dense_row_count)
+	{
+	    /* There is at least one dense row.  Continue ordering, but */
+	    /* symbolic factorization will be redone after UMF_colamd is done.*/
+	    ndense_row++ ;
+	}
+	if (deg == 0)
+	{
+	    /* this is a newly empty row, or original empty row */
+	    ne++ ;
+	}
+	/* --------------------- */
+	if (deg > dense_row_count || deg == 0)
+	{
+	    /* kill a dense or empty row */
+	    KILL_ROW (r) ;
+	    /* --------------------- */
+	    /* added for UMFPACK */
+	    Row [r].thickness = 0 ;
+	    /* --------------------- */
+	    --n_row2 ;
+	}
+	else
+	{
+	    /* keep track of max degree of remaining rows */
+	    max_deg = MAX (max_deg, deg) ;
+	}
+    }
+    nnewlyempty_row = ne - nempty_row ;
+    DEBUG1 (("colamd: Dense rows killed: "ID"\n", ndense_row)) ;
+    DEBUG1 (("colamd: Dense and null rows killed: "ID"\n", n_row - n_row2)) ;
+
+    /* === Compute initial column scores ==================================== */
+
+    /* At this point the row degrees are accurate.  They reflect the number */
+    /* of "live" (non-dense) columns in each row.  No empty rows exist. */
+    /* Some "live" columns may contain only dead rows, however.  These are */
+    /* pruned in the code below. */
+
+    /* now find the initial matlab score for each column */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+	/* skip dead column */
+	if (COL_IS_DEAD (c))
+	{
+	    continue ;
+	}
+	score = 0 ;
+	cp = &A [Col [c].start] ;
+	new_cp = cp ;
+	cp_end = cp + Col [c].length ;
+	while (cp < cp_end)
+	{
+	    /* get a row */
+	    row = *cp++ ;
+	    /* skip if dead */
+	    if (ROW_IS_DEAD (row))
+	    {
+		continue ;
+	    }
+	    /* compact the column */
+	    *new_cp++ = row ;
+	    /* add row's external degree */
+	    score += Row [row].shared1.degree - 1 ;
+	    /* guard against integer overflow */
+	    score = MIN (score, n_col) ;
+	}
+	/* determine pruned column length */
+	col_length = (Int) (new_cp - &A [Col [c].start]) ;
+	if (col_length == 0)
+	{
+	    /* a newly-made null column (all rows in this col are "dense" */
+	    /* and have already been killed) */
+	    DEBUG2 (("Newly null killed: "ID"\n", c)) ;
+	    Col [c].shared2.order = --n_col2 ;
+	    KILL_PRINCIPAL_COL (c) ;
+	    /* --------------------- */
+	    /* added for UMFPACK */
+	    nnewlyempty_col++ ;
+	    /* --------------------- */
+	}
+	else
+	{
+	    /* set column length and set score */
+	    ASSERT (score >= 0) ;
+	    ASSERT (score <= n_col) ;
+	    Col [c].length = col_length ;
+	    Col [c].shared2.score = score ;
+	}
+    }
+    DEBUG1 (("colamd: Dense, null, and newly-null columns killed: "ID"\n",
+	n_col-n_col2)) ;
+
+    /* At this point, all empty rows and columns are dead.  All live columns */
+    /* are "clean" (containing no dead rows) and simplicial (no supercolumns */
+    /* yet).  Rows may contain dead columns, but all live rows contain at */
+    /* least one live column. */
+
+#ifndef NDEBUG
+    debug_structures (n_row, n_col, Row, Col, A, n_col2) ;
+#endif /* NDEBUG */
+
+    /* === Initialize degree lists ========================================== */
+
+#ifndef NDEBUG
+    debug_count = 0 ;
+#endif /* NDEBUG */
+
+    /* clear the hash buckets */
+    for (c = 0 ; c <= n_col ; c++)
+    {
+	head [c] = EMPTY ;
+    }
+    min_score = n_col ;
+    /* place in reverse order, so low column indices are at the front */
+    /* of the lists.  This is to encourage natural tie-breaking */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+	/* only add principal columns to degree lists */
+	if (COL_IS_ALIVE (c))
+	{
+	    DEBUG4 (("place "ID" score "ID" minscore "ID" ncol "ID"\n",
+		c, Col [c].shared2.score, min_score, n_col)) ;
+
+	    /* === Add columns score to DList =============================== */
+
+	    score = Col [c].shared2.score ;
+
+	    ASSERT (min_score >= 0) ;
+	    ASSERT (min_score <= n_col) ;
+	    ASSERT (score >= 0) ;
+	    ASSERT (score <= n_col) ;
+	    ASSERT (head [score] >= EMPTY) ;
+
+	    /* now add this column to dList at proper score location */
+	    next_col = head [score] ;
+	    Col [c].shared3.prev = EMPTY ;
+	    Col [c].shared4.degree_next = next_col ;
+
+	    /* if there already was a column with the same score, set its */
+	    /* previous pointer to this new column */
+	    if (next_col != EMPTY)
+	    {
+		Col [next_col].shared3.prev = c ;
+	    }
+	    head [score] = c ;
+
+	    /* see if this score is less than current min */
+	    min_score = MIN (min_score, score) ;
+
+#ifndef NDEBUG
+	    debug_count++ ;
+#endif /* NDEBUG */
+
+	}
+    }
+
+#ifndef NDEBUG
+    DEBUG1 (("colamd: Live cols "ID" out of "ID", non-princ: "ID"\n",
+	debug_count, n_col, n_col-debug_count)) ;
+    ASSERT (debug_count == n_col2) ;
+    debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ;
+#endif /* NDEBUG */
+
+    /* === Return number of remaining columns, and max row degree =========== */
+
+    *p_n_col2 = n_col2 ;
+    *p_n_row2 = n_row2 ;
+    *p_max_deg = max_deg ;
+
+    /* --------------------- */
+    /* added for UMFPACK */
+    *p_ndense_row = ndense_row ;
+    *p_nempty_row = nempty_row ;	/* original empty rows */
+    *p_nnewlyempty_row = nnewlyempty_row ;
+    *p_ndense_col = ndense_col ;
+    *p_nempty_col = nempty_col ;	/* original empty cols */
+    *p_nnewlyempty_col = nnewlyempty_col ;
+    /* --------------------- */
+}
+
+
+/* ========================================================================== */
+/* === find_ordering ======================================================== */
+/* ========================================================================== */
+
+/*
+    Order the principal columns of the supercolumn form of the matrix
+    (no supercolumns on input).  Uses a minimum approximate column minimum
+    degree ordering method.  Not user-callable.
+*/
+
+PRIVATE Int find_ordering	/* return the number of garbage collections */
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,			/* number of rows of A */
+    Int n_col,			/* number of columns of A */
+    Int Alen,			/* size of A, 2*nnz + n_col or larger */
+    Colamd_Row Row [],		/* of size n_row+1 */
+    Colamd_Col Col [],		/* of size n_col+1 */
+    Int A [],			/* column form and row form of A */
+    Int head [],		/* of size n_col+1 */
+    Int n_col2,			/* Remaining columns to order */
+    Int max_deg,		/* Maximum row degree */
+    Int pfree			/* index of first free slot (2*nnz on entry) */
+    /* ------------------ */
+    /* added for UMFPACK: */
+    , Int Front_npivcol [ ]
+    , Int Front_nrows [ ]
+    , Int Front_ncols [ ]
+    , Int Front_parent [ ]
+    , Int Front_cols [ ]
+    , Int *p_nfr		/* number of fronts */
+    , Int aggressive
+    , Int InFront [ ]
+    /* ------------------ */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int k ;			/* current pivot ordering step */
+    Int pivot_col ;		/* current pivot column */
+    Int *cp ;			/* a column pointer */
+    Int *rp ;			/* a row pointer */
+    Int pivot_row ;		/* current pivot row */
+    Int *new_cp ;		/* modified column pointer */
+    Int *new_rp ;		/* modified row pointer */
+    Int pivot_row_start ;	/* pointer to start of pivot row */
+    Int pivot_row_degree ;	/* number of columns in pivot row */
+    Int pivot_row_length ;	/* number of supercolumns in pivot row */
+    Int pivot_col_score ;	/* score of pivot column */
+    Int needed_memory ;		/* free space needed for pivot row */
+    Int *cp_end ;		/* pointer to the end of a column */
+    Int *rp_end ;		/* pointer to the end of a row */
+    Int row ;			/* a row index */
+    Int col ;			/* a column index */
+    Int max_score ;		/* maximum possible score */
+    Int cur_score ;		/* score of current column */
+    unsigned Int hash ;		/* hash value for supernode detection */
+    Int head_column ;		/* head of hash bucket */
+    Int first_col ;		/* first column in hash bucket */
+    Int tag_mark ;		/* marker value for mark array */
+    Int row_mark ;		/* Row [row].shared2.mark */
+    Int set_difference ;	/* set difference size of row with pivot row */
+    Int min_score ;		/* smallest column score */
+    Int col_thickness ;		/* "thickness" (no. of columns in a supercol) */
+    Int max_mark ;		/* maximum value of tag_mark */
+    Int pivot_col_thickness ;	/* number of columns represented by pivot col */
+    Int prev_col ;		/* Used by Dlist operations. */
+    Int next_col ;		/* Used by Dlist operations. */
+    Int ngarbage ;		/* number of garbage collections performed */
+
+#ifndef NDEBUG
+    Int debug_d ;		/* debug loop counter */
+    Int debug_step = 0 ;	/* debug loop counter */
+#endif /* NDEBUG */
+
+    /* ------------------ */
+    /* added for UMFPACK: */
+    Int pivot_row_thickness ;	/* number of rows represented by pivot row */
+    Int nfr = 0 ;		/* number of fronts */
+    Int child ;
+    /* ------------------ */
+
+    /* === Initialization and clear mark ==================================== */
+
+    max_mark = MAX_MARK (n_col) ;	/* defined in umfpack.h */
+    tag_mark = clear_mark (n_row, Row) ;
+    min_score = 0 ;
+    ngarbage = 0 ;
+    DEBUG1 (("colamd: Ordering, n_col2="ID"\n", n_col2)) ;
+
+    for (row = 0 ; row < n_row ; row++)
+    {
+	InFront [row] = EMPTY ;
+    }
+
+    /* === Order the columns ================================================ */
+
+    for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */)
+    {
+
+#ifndef NDEBUG
+	if (debug_step % 100 == 0)
+	{
+	    DEBUG2 (("\n...  Step k: "ID" out of n_col2: "ID"\n", k, n_col2)) ;
+	}
+	else
+	{
+	    DEBUG3 (("\n-----Step k: "ID" out of n_col2: "ID"\n", k, n_col2)) ;
+	}
+	debug_step++ ;
+	debug_deg_lists (n_row, n_col, Row, Col, head,
+		min_score, n_col2-k, max_deg) ;
+	debug_matrix (n_row, n_col, Row, Col, A) ;
+#endif /* NDEBUG */
+
+	/* === Select pivot column, and order it ============================ */
+
+	/* make sure degree list isn't empty */
+	ASSERT (min_score >= 0) ;
+	ASSERT (min_score <= n_col) ;
+	ASSERT (head [min_score] >= EMPTY) ;
+
+#ifndef NDEBUG
+	for (debug_d = 0 ; debug_d < min_score ; debug_d++)
+	{
+	    ASSERT (head [debug_d] == EMPTY) ;
+	}
+#endif /* NDEBUG */
+
+	/* get pivot column from head of minimum degree list */
+	while (head [min_score] == EMPTY && min_score < n_col)
+	{
+	    min_score++ ;
+	}
+	pivot_col = head [min_score] ;
+	ASSERT (pivot_col >= 0 && pivot_col <= n_col) ;
+	next_col = Col [pivot_col].shared4.degree_next ;
+	head [min_score] = next_col ;
+	if (next_col != EMPTY)
+	{
+	    Col [next_col].shared3.prev = EMPTY ;
+	}
+
+	ASSERT (COL_IS_ALIVE (pivot_col)) ;
+	DEBUG3 (("Pivot col: "ID"\n", pivot_col)) ;
+
+	/* remember score for defrag check */
+	pivot_col_score = Col [pivot_col].shared2.score ;
+
+	/* the pivot column is the kth column in the pivot order */
+	Col [pivot_col].shared2.order = k ;
+
+	/* increment order count by column thickness */
+	pivot_col_thickness = Col [pivot_col].shared1.thickness ;
+	/* ------------------ */
+	/* changed for UMFPACK: */
+	k += pivot_col_thickness ;
+	/* ------------------ */
+	ASSERT (pivot_col_thickness > 0) ;
+
+	/* === Garbage_collection, if necessary ============================= */
+
+	needed_memory = MIN (pivot_col_score, n_col - k) ;
+	if (pfree + needed_memory >= Alen)
+	{
+	    pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ;
+	    ngarbage++ ;
+	    /* after garbage collection we will have enough */
+	    ASSERT (pfree + needed_memory < Alen) ;
+	    /* garbage collection has wiped out the Row[].shared2.mark array */
+	    tag_mark = clear_mark (n_row, Row) ;
+
+#ifndef NDEBUG
+	    debug_matrix (n_row, n_col, Row, Col, A) ;
+#endif /* NDEBUG */
+	}
+
+	/* === Compute pivot row pattern ==================================== */
+
+	/* get starting location for this new merged row */
+	pivot_row_start = pfree ;
+
+	/* initialize new row counts to zero */
+	pivot_row_degree = 0 ;
+
+	/* ------------------ */
+	/* added for UMFPACK: */
+	pivot_row_thickness = 0 ;
+	/* ------------------ */
+
+	/* [ tag pivot column as having been visited so it isn't included */
+	/* in merged pivot row */
+	Col [pivot_col].shared1.thickness = -pivot_col_thickness ;
+
+	/* pivot row is the union of all rows in the pivot column pattern */
+	cp = &A [Col [pivot_col].start] ;
+	cp_end = cp + Col [pivot_col].length ;
+	while (cp < cp_end)
+	{
+	    /* get a row */
+	    row = *cp++ ;
+	    DEBUG4 (("Pivot col pattern %d "ID"\n", ROW_IS_ALIVE(row), row)) ;
+	    /* skip if row is dead */
+	    if (ROW_IS_DEAD (row))
+	    {
+		continue ;
+	    }
+
+	    /* ------------------ */
+	    /* added for UMFPACK: */
+	    /* sum the thicknesses of all the rows */
+	    /* ASSERT (Row [row].thickness > 0) ; */
+	    pivot_row_thickness += Row [row].thickness ;
+	    /* ------------------ */
+
+	    rp = &A [Row [row].start] ;
+	    rp_end = rp + Row [row].length ;
+	    while (rp < rp_end)
+	    {
+		/* get a column */
+		col = *rp++ ;
+		/* add the column, if alive and untagged */
+		col_thickness = Col [col].shared1.thickness ;
+		if (col_thickness > 0 && COL_IS_ALIVE (col))
+		{
+		    /* tag column in pivot row */
+		    Col [col].shared1.thickness = -col_thickness ;
+		    ASSERT (pfree < Alen) ;
+		    /* place column in pivot row */
+		    A [pfree++] = col ;
+		    pivot_row_degree += col_thickness ;
+		    /* ------------------ */
+		    /* added for UMFPACK: */
+		    DEBUG4 (("\t\t\tNew live column in pivot row: "ID"\n",col));
+		    /* ------------------ */
+		}
+		/* ------------------ */
+		/* added for UMFPACK */
+#ifndef NDEBUG
+		if (col_thickness < 0 && COL_IS_ALIVE (col))
+		{
+		    DEBUG4 (("\t\t\tOld live column in pivot row: "ID"\n",col));
+		}
+#endif
+		/* ------------------ */
+	    }
+	}
+
+	/* ------------------ */
+	/* added for UMFPACK: */
+	/* pivot_row_thickness is the number of rows in frontal matrix */
+	/* both pivotal rows and nonpivotal rows */
+	/* ------------------ */
+
+	/* clear tag on pivot column */
+	Col [pivot_col].shared1.thickness = pivot_col_thickness ;	/* ] */
+	max_deg = MAX (max_deg, pivot_row_degree) ;
+
+#ifndef NDEBUG
+	DEBUG3 (("check2\n")) ;
+	debug_mark (n_row, Row, tag_mark, max_mark) ;
+#endif /* NDEBUG */
+
+	/* === Kill all rows used to construct pivot row ==================== */
+
+	/* also kill pivot row, temporarily */
+	cp = &A [Col [pivot_col].start] ;
+	cp_end = cp + Col [pivot_col].length ;
+	while (cp < cp_end)
+	{
+	    /* may be killing an already dead row */
+	    row = *cp++ ;
+
+	    DEBUG2 (("Kill row in pivot col: "ID" alive? %d, front "ID"\n",
+		row, ROW_IS_ALIVE (row), Row [row].front)) ;
+
+	    /* added for UMFPACK: */
+	    if (ROW_IS_ALIVE (row))
+	    {
+		if (Row [row].front != EMPTY)
+		{
+		    /* This row represents a frontal matrix. */
+		    /* Row [row].front is a child of current front */
+		    child = Row [row].front ;
+		    Front_parent [child] = nfr ;
+		    DEBUG1 (("Front "ID" => front "ID", normal\n", child, nfr));
+		}
+		else
+		{
+		    /* This is an original row.  Keep track of which front
+		     * is its parent in the row-merge tree. */
+		    InFront [row] = nfr ;
+		    DEBUG1 (("Row "ID" => front "ID", normal\n", row, nfr)) ;
+		}
+	    }
+
+	    KILL_ROW (row) ;
+
+	    /* ------------------ */
+	    /* added for UMFPACK: */
+	    Row [row].thickness = 0 ;
+	    /* ------------------ */
+	}
+
+	/* === Select a row index to use as the new pivot row =============== */
+
+	pivot_row_length = pfree - pivot_row_start ;
+	if (pivot_row_length > 0)
+	{
+	    /* pick the "pivot" row arbitrarily (first row in col) */
+	    pivot_row = A [Col [pivot_col].start] ;
+	    DEBUG3 (("Pivotal row is "ID"\n", pivot_row)) ;
+	}
+	else
+	{
+	    /* there is no pivot row, since it is of zero length */
+	    pivot_row = EMPTY ;
+	    ASSERT (pivot_row_length == 0) ;
+	}
+	ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ;
+
+	/* === Approximate degree computation =============================== */
+
+	/* Here begins the computation of the approximate degree.  The column */
+	/* score is the sum of the pivot row "length", plus the size of the */
+	/* set differences of each row in the column minus the pattern of the */
+	/* pivot row itself.  The column ("thickness") itself is also */
+	/* excluded from the column score (we thus use an approximate */
+	/* external degree). */
+
+	/* The time taken by the following code (compute set differences, and */
+	/* add them up) is proportional to the size of the data structure */
+	/* being scanned - that is, the sum of the sizes of each column in */
+	/* the pivot row.  Thus, the amortized time to compute a column score */
+	/* is proportional to the size of that column (where size, in this */
+	/* context, is the column "length", or the number of row indices */
+	/* in that column).  The number of row indices in a column is */
+	/* monotonically non-decreasing, from the length of the original */
+	/* column on input to colamd. */
+
+	/* === Compute set differences ====================================== */
+
+	DEBUG3 (("** Computing set differences phase. **\n")) ;
+
+	/* pivot row is currently dead - it will be revived later. */
+
+	DEBUG3 (("Pivot row: \n")) ;
+	/* for each column in pivot row */
+	rp = &A [pivot_row_start] ;
+	rp_end = rp + pivot_row_length ;
+	while (rp < rp_end)
+	{
+	    col = *rp++ ;
+	    ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
+	    DEBUG3 (("    Col: "ID"\n", col)) ;
+
+	    /* clear tags used to construct pivot row pattern */
+	    col_thickness = -Col [col].shared1.thickness ;
+	    ASSERT (col_thickness > 0) ;
+	    Col [col].shared1.thickness = col_thickness ;
+
+	    /* === Remove column from degree list =========================== */
+
+	    cur_score = Col [col].shared2.score ;
+	    prev_col = Col [col].shared3.prev ;
+	    next_col = Col [col].shared4.degree_next ;
+	    ASSERT (cur_score >= 0) ;
+	    ASSERT (cur_score <= n_col) ;
+	    ASSERT (cur_score >= EMPTY) ;
+	    if (prev_col == EMPTY)
+	    {
+		head [cur_score] = next_col ;
+	    }
+	    else
+	    {
+		Col [prev_col].shared4.degree_next = next_col ;
+	    }
+	    if (next_col != EMPTY)
+	    {
+		Col [next_col].shared3.prev = prev_col ;
+	    }
+
+	    /* === Scan the column ========================================== */
+
+	    cp = &A [Col [col].start] ;
+	    cp_end = cp + Col [col].length ;
+	    while (cp < cp_end)
+	    {
+		/* get a row */
+		row = *cp++ ;
+		row_mark = Row [row].shared2.mark ;
+		/* skip if dead */
+		if (ROW_IS_MARKED_DEAD (row_mark))
+		{
+		    continue ;
+		}
+		ASSERT (row != pivot_row) ;
+		set_difference = row_mark - tag_mark ;
+		/* check if the row has been seen yet */
+		if (set_difference < 0)
+		{
+		    ASSERT (Row [row].shared1.degree <= max_deg) ;
+		    set_difference = Row [row].shared1.degree ;
+		}
+		/* subtract column thickness from this row's set difference */
+		set_difference -= col_thickness ;
+		ASSERT (set_difference >= 0) ;
+		ASSERT (ROW_IS_ALIVE (row)) ;
+
+		/* absorb this row if the set difference becomes zero */
+		if (set_difference == 0 && aggressive)
+		{
+		    /* v4.1: do aggressive absorption */
+		    DEBUG3 (("aggressive absorption. Row: "ID"\n", row)) ;
+
+		    if (Row [row].front != EMPTY)
+		    {
+			/* Row [row].front is a child of current front. */
+			child = Row [row].front ;
+			Front_parent [child] = nfr ;
+			DEBUG1 (("Front "ID" => front "ID", aggressive\n",
+				    child, nfr)) ;
+		    }
+		    else
+		    {
+			/* this is an original row.  Keep track of which front
+			 * assembles it, for the row-merge tree */
+			InFront [row] = nfr ;
+			DEBUG1 (("Row "ID" => front "ID", aggressive\n",
+				    row, nfr)) ;
+		    }
+
+		    KILL_ROW (row) ;
+
+		    /* sum the thicknesses of all the rows */
+		    /* ASSERT (Row [row].thickness > 0) ; */
+		    pivot_row_thickness += Row [row].thickness ;
+		    Row [row].thickness = 0 ;
+
+		}
+		else
+		{
+		    /* save the new mark */
+		    Row [row].shared2.mark = set_difference + tag_mark ;
+		}
+	    }
+	}
+
+#ifndef NDEBUG
+	debug_deg_lists (n_row, n_col, Row, Col, head,
+		min_score, n_col2-k-pivot_row_degree, max_deg) ;
+#endif /* NDEBUG */
+
+	/* === Add up set differences for each column ======================= */
+
+	DEBUG3 (("** Adding set differences phase. **\n")) ;
+
+	/* for each column in pivot row */
+	rp = &A [pivot_row_start] ;
+	rp_end = rp + pivot_row_length ;
+	while (rp < rp_end)
+	{
+	    /* get a column */
+	    col = *rp++ ;
+	    ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
+	    hash = 0 ;
+	    cur_score = 0 ;
+	    cp = &A [Col [col].start] ;
+	    /* compact the column */
+	    new_cp = cp ;
+	    cp_end = cp + Col [col].length ;
+
+	    DEBUG4 (("Adding set diffs for Col: "ID".\n", col)) ;
+
+	    while (cp < cp_end)
+	    {
+		/* get a row */
+		row = *cp++ ;
+		ASSERT(row >= 0 && row < n_row) ;
+		row_mark = Row [row].shared2.mark ;
+		/* skip if dead */
+		if (ROW_IS_MARKED_DEAD (row_mark))
+		{
+		    /* ------------------ */
+		    /* changed for UMFPACK: */
+		    DEBUG4 ((" Row "ID", dead\n", row)) ;
+		    /* ------------------ */
+		    continue ;
+		}
+		/* ------------------ */
+		/* changed for UMFPACK: */
+		/* ASSERT (row_mark > tag_mark) ; */
+		DEBUG4 ((" Row "ID", set diff "ID"\n", row, row_mark-tag_mark));
+		ASSERT (row_mark >= tag_mark) ;
+		/* ------------------ */
+		/* compact the column */
+		*new_cp++ = row ;
+		/* compute hash function */
+		hash += row ;
+		/* add set difference */
+		cur_score += row_mark - tag_mark ;
+		/* integer overflow... */
+		cur_score = MIN (cur_score, n_col) ;
+	    }
+
+	    /* recompute the column's length */
+	    Col [col].length = (Int) (new_cp - &A [Col [col].start]) ;
+
+	    /* === Further mass elimination ================================= */
+
+	    if (Col [col].length == 0)
+	    {
+		DEBUG4 (("further mass elimination. Col: "ID"\n", col)) ;
+		/* nothing left but the pivot row in this column */
+		KILL_PRINCIPAL_COL (col) ;
+		pivot_row_degree -= Col [col].shared1.thickness ;
+		ASSERT (pivot_row_degree >= 0) ;
+		/* order it */
+		Col [col].shared2.order = k ;
+		/* increment order count by column thickness */
+		k += Col [col].shared1.thickness ;
+
+		/* ------------------ */
+		/* added for UMFPACK: */
+		pivot_col_thickness += Col [col].shared1.thickness ;
+
+		/* add to column list of front ... */
+#ifndef NDEBUG
+		DEBUG1 (("Mass")) ;
+		dump_super (col, Col, n_col) ;
+#endif
+		Col [Col [col].lastcol].nextcol = Front_cols [nfr] ;
+		Front_cols [nfr] = col ;
+		/* ------------------ */
+
+	    }
+	    else
+	    {
+		/* === Prepare for supercolumn detection ==================== */
+
+		DEBUG4 (("Preparing supercol detection for Col: "ID".\n", col));
+
+		/* save score so far */
+		Col [col].shared2.score = cur_score ;
+
+		/* add column to hash table, for supercolumn detection */
+		/* NOTE: hash is an unsigned Int to avoid a problem in ANSI C.
+		 * The sign of the expression a % b is not defined when a and/or
+		 * b are negative.  Since hash is unsigned and n_col >= 0,
+		 * this problem is avoided. */
+		hash %= n_col + 1 ;
+
+		DEBUG4 ((" Hash = "ID", n_col = "ID".\n", (Int) hash, n_col)) ;
+		ASSERT (((Int) hash) <= n_col) ;
+
+		head_column = head [hash] ;
+		if (head_column > EMPTY)
+		{
+		    /* degree list "hash" is non-empty, use prev (shared3) of */
+		    /* first column in degree list as head of hash bucket */
+		    first_col = Col [head_column].shared3.headhash ;
+		    Col [head_column].shared3.headhash = col ;
+		}
+		else
+		{
+		    /* degree list "hash" is empty, use head as hash bucket */
+		    first_col = - (head_column + 2) ;
+		    head [hash] = - (col + 2) ;
+		}
+		Col [col].shared4.hash_next = first_col ;
+
+		/* save hash function in Col [col].shared3.hash */
+		Col [col].shared3.hash = (Int) hash ;
+		ASSERT (COL_IS_ALIVE (col)) ;
+	    }
+	}
+
+	/* The approximate external column degree is now computed.  */
+
+	/* === Supercolumn detection ======================================== */
+
+	DEBUG3 (("** Supercolumn detection phase. **\n")) ;
+
+	detect_super_cols (
+
+#ifndef NDEBUG
+		n_col, Row,
+#endif /* NDEBUG */
+
+		Col, A, head, pivot_row_start, pivot_row_length) ;
+
+	/* === Kill the pivotal column ====================================== */
+
+	KILL_PRINCIPAL_COL (pivot_col) ;
+
+	/* ------------------ */
+	/* added for UMFPACK: */
+	/* add columns to column list of front */
+#ifndef NDEBUG
+	DEBUG1 (("Pivot")) ;
+	dump_super (pivot_col, Col, n_col) ;
+#endif
+	Col [Col [pivot_col].lastcol].nextcol = Front_cols [nfr] ;
+	Front_cols [nfr] = pivot_col ;
+	/* ------------------ */
+
+	/* === Clear mark =================================================== */
+
+	tag_mark += (max_deg + 1) ;
+	if (tag_mark >= max_mark)
+	{
+	    DEBUG2 (("clearing tag_mark\n")) ;
+	    tag_mark = clear_mark (n_row, Row) ;
+	}
+
+#ifndef NDEBUG
+	DEBUG3 (("check3\n")) ;
+	debug_mark (n_row, Row, tag_mark, max_mark) ;
+#endif /* NDEBUG */
+
+	/* === Finalize the new pivot row, and column scores ================ */
+
+	DEBUG3 (("** Finalize scores phase. **\n")) ;
+	DEBUG3 (("pivot_row_degree "ID"\n", pivot_row_degree)) ;
+
+	/* for each column in pivot row */
+	rp = &A [pivot_row_start] ;
+	/* compact the pivot row */
+	new_rp = rp ;
+	rp_end = rp + pivot_row_length ;
+	while (rp < rp_end)
+	{
+	    col = *rp++ ;
+	    DEBUG3 (("Col "ID" \n", col)) ;
+	    /* skip dead columns */
+	    if (COL_IS_DEAD (col))
+	    {
+		DEBUG3 (("dead\n")) ;
+		continue ;
+	    }
+	    *new_rp++ = col ;
+	    /* add new pivot row to column */
+	    A [Col [col].start + (Col [col].length++)] = pivot_row ;
+
+	    /* retrieve score so far and add on pivot row's degree. */
+	    /* (we wait until here for this in case the pivot */
+	    /* row's degree was reduced due to mass elimination). */
+	    cur_score = Col [col].shared2.score + pivot_row_degree ;
+	    DEBUG3 ((" cur_score "ID" ", cur_score)) ;
+
+	    /* calculate the max possible score as the number of */
+	    /* external columns minus the 'k' value minus the */
+	    /* columns thickness */
+	    max_score = n_col - k - Col [col].shared1.thickness ;
+	    DEBUG3 ((" max_score "ID" ", max_score)) ;
+
+	    /* make the score the external degree of the union-of-rows */
+	    cur_score -= Col [col].shared1.thickness ;
+	    DEBUG3 ((" cur_score "ID" ", cur_score)) ;
+
+	    /* make sure score is less or equal than the max score */
+	    cur_score = MIN (cur_score, max_score) ;
+	    ASSERT (cur_score >= 0) ;
+
+	    /* store updated score */
+	    Col [col].shared2.score = cur_score ;
+	    DEBUG3 ((" "ID"\n", cur_score)) ;
+
+	    /* === Place column back in degree list ========================= */
+
+	    ASSERT (min_score >= 0) ;
+	    ASSERT (min_score <= n_col) ;
+	    ASSERT (cur_score >= 0) ;
+	    ASSERT (cur_score <= n_col) ;
+	    ASSERT (head [cur_score] >= EMPTY) ;
+	    next_col = head [cur_score] ;
+	    Col [col].shared4.degree_next = next_col ;
+	    Col [col].shared3.prev = EMPTY ;
+	    if (next_col != EMPTY)
+	    {
+		Col [next_col].shared3.prev = col ;
+	    }
+	    head [cur_score] = col ;
+
+	    /* see if this score is less than current min */
+	    min_score = MIN (min_score, cur_score) ;
+
+	}
+
+#ifndef NDEBUG
+	debug_deg_lists (n_row, n_col, Row, Col, head,
+		min_score, n_col2-k, max_deg) ;
+#endif /* NDEBUG */
+
+	/* ------------------ */
+	/* added for UMFPACK: */
+	/* frontal matrix can have more pivot cols than pivot rows for */
+	/* singular matrices. */
+
+	/* number of candidate pivot columns */
+	Front_npivcol [nfr] = pivot_col_thickness ;
+
+	/* all rows (not just size of contrib. block) */
+	Front_nrows [nfr] = pivot_row_thickness ;
+
+	/* all cols */
+	Front_ncols [nfr] = pivot_col_thickness + pivot_row_degree ;
+
+	Front_parent [nfr] = EMPTY ;
+
+	pivot_row_thickness -= pivot_col_thickness ;
+	DEBUG1 (("Front "ID" Pivot_row_thickness after pivot cols elim: "ID"\n",
+	    nfr, pivot_row_thickness)) ;
+	pivot_row_thickness = MAX (0, pivot_row_thickness) ;
+	/* ------------------ */
+
+	/* === Resurrect the new pivot row ================================== */
+
+	if (pivot_row_degree > 0
+	/* ------------------ */
+	/* added for UMFPACK.  Note that this part of the expression should be
+	 * removed if this routine is used outside of UMFPACK, for a Cholesky
+	 * factorization of (AQ)'(AQ) */
+	&& pivot_row_thickness > 0
+	/* ------------------ */
+	)
+	{
+	    /* update pivot row length to reflect any cols that were killed */
+	    /* during super-col detection and mass elimination */
+	    Row [pivot_row].start  = pivot_row_start ;
+	    Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ;
+	    ASSERT (Row [pivot_row].length > 0) ;
+	    Row [pivot_row].shared1.degree = pivot_row_degree ;
+	    Row [pivot_row].shared2.mark = 0 ;
+	    /* ------------------ */
+	    /* added for UMFPACK: */
+	    Row [pivot_row].thickness = pivot_row_thickness ;
+	    Row [pivot_row].front = nfr ;
+	    /* ------------------ */
+	    /* pivot row is no longer dead */
+	}
+
+	/* ------------------ */
+	/* added for UMFPACK: */
+
+#ifndef NDEBUG
+	DEBUG1 (("Front "ID" : "ID" "ID" "ID" ", nfr,
+		Front_npivcol [nfr], Front_nrows [nfr], Front_ncols [nfr])) ;
+	DEBUG1 ((" cols:[ ")) ;
+	debug_d = 0 ;
+	for (col = Front_cols [nfr] ; col != EMPTY ; col = Col [col].nextcol)
+	{
+	    DEBUG1 ((" "ID, col)) ;
+	    ASSERT (col >= 0 && col < n_col) ;
+	    ASSERT (COL_IS_DEAD (col)) ;
+	    debug_d++ ;
+	    ASSERT (debug_d <= pivot_col_thickness) ;
+	}
+	ASSERT (debug_d == pivot_col_thickness) ;
+	DEBUG1 ((" ]\n ")) ;
+#endif
+	nfr++ ; /* one more front */
+	/* ------------------ */
+
+    }
+
+    /* === All principal columns have now been ordered ====================== */
+
+    /* ------------------ */
+    /* added for UMFPACK: */
+    *p_nfr = nfr ;
+    /* ------------------ */
+
+    return (ngarbage) ;
+}
+
+
+/* ========================================================================== */
+/* === order_children deleted for UMFPACK =================================== */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* === detect_super_cols ==================================================== */
+/* ========================================================================== */
+
+/*
+    Detects supercolumns by finding matches between columns in the hash buckets.
+    Check amongst columns in the set A [row_start ... row_start + row_length-1].
+    The columns under consideration are currently *not* in the degree lists,
+    and have already been placed in the hash buckets.
+
+    The hash bucket for columns whose hash function is equal to h is stored
+    as follows:
+
+	if head [h] is >= 0, then head [h] contains a degree list, so:
+
+		head [h] is the first column in degree bucket h.
+		Col [head [h]].headhash gives the first column in hash bucket h.
+
+	otherwise, the degree list is empty, and:
+
+		-(head [h] + 2) is the first column in hash bucket h.
+
+    For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous
+    column" pointer.  Col [c].shared3.hash is used instead as the hash number
+    for that column.  The value of Col [c].shared4.hash_next is the next column
+    in the same hash bucket.
+
+    Assuming no, or "few" hash collisions, the time taken by this routine is
+    linear in the sum of the sizes (lengths) of each column whose score has
+    just been computed in the approximate degree computation.
+    Not user-callable.
+*/
+
+PRIVATE void detect_super_cols
+(
+    /* === Parameters ======================================================= */
+
+#ifndef NDEBUG
+    /* these two parameters are only needed when debugging is enabled: */
+    Int n_col,			/* number of columns of A */
+    Colamd_Row Row [],		/* of size n_row+1 */
+#endif /* NDEBUG */
+
+    Colamd_Col Col [],		/* of size n_col+1 */
+    Int A [],			/* row indices of A */
+    Int head [],		/* head of degree lists and hash buckets */
+    Int row_start,		/* pointer to set of columns to check */
+    Int row_length		/* number of columns to check */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int hash ;			/* hash value for a column */
+    Int *rp ;			/* pointer to a row */
+    Int c ;			/* a column index */
+    Int super_c ;		/* column index of the column to absorb into */
+    Int *cp1 ;			/* column pointer for column super_c */
+    Int *cp2 ;			/* column pointer for column c */
+    Int length ;		/* length of column super_c */
+    Int prev_c ;		/* column preceding c in hash bucket */
+    Int i ;			/* loop counter */
+    Int *rp_end ;		/* pointer to the end of the row */
+    Int col ;			/* a column index in the row to check */
+    Int head_column ;		/* first column in hash bucket or degree list */
+    Int first_col ;		/* first column in hash bucket */
+
+    /* === Consider each column in the row ================================== */
+
+    rp = &A [row_start] ;
+    rp_end = rp + row_length ;
+    while (rp < rp_end)
+    {
+	col = *rp++ ;
+	if (COL_IS_DEAD (col))
+	{
+	    continue ;
+	}
+
+	/* get hash number for this column */
+	hash = Col [col].shared3.hash ;
+	ASSERT (hash <= n_col) ;
+
+	/* === Get the first column in this hash bucket ===================== */
+
+	head_column = head [hash] ;
+	if (head_column > EMPTY)
+	{
+	    first_col = Col [head_column].shared3.headhash ;
+	}
+	else
+	{
+	    first_col = - (head_column + 2) ;
+	}
+
+	/* === Consider each column in the hash bucket ====================== */
+
+	for (super_c = first_col ; super_c != EMPTY ;
+	    super_c = Col [super_c].shared4.hash_next)
+	{
+	    ASSERT (COL_IS_ALIVE (super_c)) ;
+	    ASSERT (Col [super_c].shared3.hash == hash) ;
+	    length = Col [super_c].length ;
+
+	    /* prev_c is the column preceding column c in the hash bucket */
+	    prev_c = super_c ;
+
+	    /* === Compare super_c with all columns after it ================ */
+
+	    for (c = Col [super_c].shared4.hash_next ;
+		c != EMPTY ; c = Col [c].shared4.hash_next)
+	    {
+		ASSERT (c != super_c) ;
+		ASSERT (COL_IS_ALIVE (c)) ;
+		ASSERT (Col [c].shared3.hash == hash) ;
+
+		/* not identical if lengths or scores are different */
+		if (Col [c].length != length ||
+		    Col [c].shared2.score != Col [super_c].shared2.score)
+		{
+		    prev_c = c ;
+		    continue ;
+		}
+
+		/* compare the two columns */
+		cp1 = &A [Col [super_c].start] ;
+		cp2 = &A [Col [c].start] ;
+
+		for (i = 0 ; i < length ; i++)
+		{
+		    /* the columns are "clean" (no dead rows) */
+		    ASSERT (ROW_IS_ALIVE (*cp1))  ;
+		    ASSERT (ROW_IS_ALIVE (*cp2))  ;
+		    /* row indices will same order for both supercols, */
+		    /* no gather scatter nessasary */
+		    if (*cp1++ != *cp2++)
+		    {
+			break ;
+		    }
+		}
+
+		/* the two columns are different if the for-loop "broke" */
+		if (i != length)
+		{
+		    prev_c = c ;
+		    continue ;
+		}
+
+		/* === Got it!  two columns are identical =================== */
+
+		ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ;
+
+		Col [super_c].shared1.thickness += Col [c].shared1.thickness ;
+		Col [c].shared1.parent = super_c ;
+		KILL_NON_PRINCIPAL_COL (c) ;
+
+		Col [c].shared2.order = EMPTY ;
+		/* remove c from hash bucket */
+		Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ;
+
+		/* ------------------ */
+		/* added for UMFPACK: */
+		/* add c to end of list of super_c */
+		ASSERT (Col [super_c].lastcol >= 0) ;
+		ASSERT (Col [super_c].lastcol < n_col) ;
+		Col [Col [super_c].lastcol].nextcol = c ;
+		Col [super_c].lastcol = Col [c].lastcol ;
+#ifndef NDEBUG
+		/* dump the supercolumn */
+		DEBUG1 (("Super")) ;
+		dump_super (super_c, Col, n_col) ;
+#endif
+		/* ------------------ */
+
+	    }
+	}
+
+	/* === Empty this hash bucket ======================================= */
+
+	if (head_column > EMPTY)
+	{
+	    /* corresponding degree list "hash" is not empty */
+	    Col [head_column].shared3.headhash = EMPTY ;
+	}
+	else
+	{
+	    /* corresponding degree list "hash" is empty */
+	    head [hash] = EMPTY ;
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === garbage_collection =================================================== */
+/* ========================================================================== */
+
+/*
+    Defragments and compacts columns and rows in the workspace A.  Used when
+    all avaliable memory has been used while performing row merging.  Returns
+    the index of the first free position in A, after garbage collection.  The
+    time taken by this routine is linear is the size of the array A, which is
+    itself linear in the number of nonzeros in the input matrix.
+    Not user-callable.
+*/
+
+PRIVATE Int garbage_collection  /* returns the new value of pfree */
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,			/* number of rows */
+    Int n_col,			/* number of columns */
+    Colamd_Row Row [],		/* row info */
+    Colamd_Col Col [],		/* column info */
+    Int A [],			/* A [0 ... Alen-1] holds the matrix */
+    Int *pfree			/* &A [0] ... pfree is in use */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int *psrc ;			/* source pointer */
+    Int *pdest ;		/* destination pointer */
+    Int j ;			/* counter */
+    Int r ;			/* a row index */
+    Int c ;			/* a column index */
+    Int length ;		/* length of a row or column */
+
+#ifndef NDEBUG
+    Int debug_rows ;
+    DEBUG2 (("Defrag..\n")) ;
+    for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ;
+    debug_rows = 0 ;
+#endif /* NDEBUG */
+
+    /* === Defragment the columns =========================================== */
+
+    pdest = &A[0] ;
+    for (c = 0 ; c < n_col ; c++)
+    {
+	if (COL_IS_ALIVE (c))
+	{
+	    psrc = &A [Col [c].start] ;
+
+	    /* move and compact the column */
+	    ASSERT (pdest <= psrc) ;
+	    Col [c].start = (Int) (pdest - &A [0]) ;
+	    length = Col [c].length ;
+	    for (j = 0 ; j < length ; j++)
+	    {
+		r = *psrc++ ;
+		if (ROW_IS_ALIVE (r))
+		{
+		    *pdest++ = r ;
+		}
+	    }
+	    Col [c].length = (Int) (pdest - &A [Col [c].start]) ;
+	}
+    }
+
+    /* === Prepare to defragment the rows =================================== */
+
+    for (r = 0 ; r < n_row ; r++)
+    {
+	if (ROW_IS_ALIVE (r))
+	{
+	    if (Row [r].length == 0)
+	    {
+		/* :: defrag row kill :: */
+		/* This row is of zero length.  cannot compact it, so kill it.
+		 * NOTE: in the current version, there are no zero-length live
+		 * rows when garbage_collection is called.  So this code will
+		 * never trigger.  However, if the code is modified, or if
+		 * garbage_collection is called at a different place, then rows
+		 * can be of zero length.  So this test is kept, just in case.
+		 */
+		DEBUGm4 (("Defrag row kill\n")) ;
+		KILL_ROW (r) ;
+	    }
+	    else
+	    {
+		/* save first column index in Row [r].shared2.first_column */
+		psrc = &A [Row [r].start] ;
+		Row [r].shared2.first_column = *psrc ;
+		ASSERT (ROW_IS_ALIVE (r)) ;
+		/* flag the start of the row with the one's complement of row */
+		*psrc = ONES_COMPLEMENT (r) ;
+#ifndef NDEBUG
+		debug_rows++ ;
+#endif /* NDEBUG */
+	    }
+	}
+    }
+
+    /* === Defragment the rows ============================================== */
+
+    psrc = pdest ;
+    while (psrc < pfree)
+    {
+	/* find a negative number ... the start of a row */
+	if (*psrc++ < 0)
+	{
+	    psrc-- ;
+	    /* get the row index */
+	    r = ONES_COMPLEMENT (*psrc) ;
+	    ASSERT (r >= 0 && r < n_row) ;
+	    /* restore first column index */
+	    *psrc = Row [r].shared2.first_column ;
+	    ASSERT (ROW_IS_ALIVE (r)) ;
+
+	    /* move and compact the row */
+	    ASSERT (pdest <= psrc) ;
+	    Row [r].start = (Int) (pdest - &A [0]) ;
+	    length = Row [r].length ;
+	    for (j = 0 ; j < length ; j++)
+	    {
+		c = *psrc++ ;
+		if (COL_IS_ALIVE (c))
+		{
+		    *pdest++ = c ;
+		}
+	    }
+	    Row [r].length = (Int) (pdest - &A [Row [r].start]) ;
+
+#ifndef NDEBUG
+	    debug_rows-- ;
+#endif /* NDEBUG */
+
+	}
+    }
+    /* ensure we found all the rows */
+    ASSERT (debug_rows == 0) ;
+
+    /* === Return the new value of pfree ==================================== */
+
+    return ((Int) (pdest - &A [0])) ;
+}
+
+
+/* ========================================================================== */
+/* === clear_mark =========================================================== */
+/* ========================================================================== */
+
+/*
+    Clears the Row [].shared2.mark array, and returns the new tag_mark.
+    Return value is the new tag_mark.  Not user-callable.
+*/
+
+PRIVATE Int clear_mark	/* return the new value for tag_mark */
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,		/* number of rows in A */
+    Colamd_Row Row []	/* Row [0 ... n-1].shared2.mark is set to zero */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int r ;
+
+    for (r = 0 ; r < n_row ; r++)
+    {
+	if (ROW_IS_ALIVE (r))
+	{
+	    Row [r].shared2.mark = 0 ;
+	}
+    }
+
+    /* ------------------ */
+    return (1) ;
+    /* ------------------ */
+
+}
+
+
+/* ========================================================================== */
+/* === print_report removed for UMFPACK ===================================== */
+/* ========================================================================== */
+
+
+
+/* ========================================================================== */
+/* === colamd debugging routines ============================================ */
+/* ========================================================================== */
+
+/* When debugging is disabled, the remainder of this file is ignored. */
+
+#ifndef NDEBUG
+
+
+/* ========================================================================== */
+/* === debug_structures ===================================================== */
+/* ========================================================================== */
+
+/*
+    At this point, all empty rows and columns are dead.  All live columns
+    are "clean" (containing no dead rows) and simplicial (no supercolumns
+    yet).  Rows may contain dead columns, but all live rows contain at
+    least one live column.
+*/
+
+PRIVATE void debug_structures
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int n_col2
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;
+    Int c ;
+    Int *cp ;
+    Int *cp_end ;
+    Int len ;
+    Int score ;
+    Int r ;
+    Int *rp ;
+    Int *rp_end ;
+    Int deg ;
+
+    /* === Check A, Row, and Col ============================================ */
+
+    for (c = 0 ; c < n_col ; c++)
+    {
+	if (COL_IS_ALIVE (c))
+	{
+	    len = Col [c].length ;
+	    score = Col [c].shared2.score ;
+	    DEBUG4 (("initial live col "ID" "ID" "ID"\n", c, len, score)) ;
+	    ASSERT (len > 0) ;
+	    ASSERT (score >= 0) ;
+	    ASSERT (Col [c].shared1.thickness == 1) ;
+	    cp = &A [Col [c].start] ;
+	    cp_end = cp + len ;
+	    while (cp < cp_end)
+	    {
+		r = *cp++ ;
+		ASSERT (ROW_IS_ALIVE (r)) ;
+	    }
+	}
+	else
+	{
+	    i = Col [c].shared2.order ;
+	    ASSERT (i >= n_col2 && i < n_col) ;
+	}
+    }
+
+    for (r = 0 ; r < n_row ; r++)
+    {
+	if (ROW_IS_ALIVE (r))
+	{
+	    i = 0 ;
+	    len = Row [r].length ;
+	    deg = Row [r].shared1.degree ;
+	    ASSERT (len > 0) ;
+	    ASSERT (deg > 0) ;
+	    rp = &A [Row [r].start] ;
+	    rp_end = rp + len ;
+	    while (rp < rp_end)
+	    {
+		c = *rp++ ;
+		if (COL_IS_ALIVE (c))
+		{
+		    i++ ;
+		}
+	    }
+	    ASSERT (i > 0) ;
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === debug_deg_lists ====================================================== */
+/* ========================================================================== */
+
+/*
+    Prints the contents of the degree lists.  Counts the number of columns
+    in the degree list and compares it to the total it should have.  Also
+    checks the row degrees.
+*/
+
+PRIVATE void debug_deg_lists
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int head [],
+    Int min_score,
+    Int should,
+    Int max_deg
+)
+{
+    /* === Local variables ================================================== */
+
+    Int deg ;
+    Int col ;
+    Int have ;
+    Int row ;
+
+    /* === Check the degree lists =========================================== */
+
+    if (n_col > 10000 && UMF_debug <= 0)
+    {
+	return ;
+    }
+    have = 0 ;
+    DEBUG4 (("Degree lists: "ID"\n", min_score)) ;
+    for (deg = 0 ; deg <= n_col ; deg++)
+    {
+	col = head [deg] ;
+	if (col == EMPTY)
+	{
+	    continue ;
+	}
+	DEBUG4 ((ID":", deg)) ;
+	while (col != EMPTY)
+	{
+	    DEBUG4 ((" "ID, col)) ;
+	    have += Col [col].shared1.thickness ;
+	    ASSERT (COL_IS_ALIVE (col)) ;
+	    col = Col [col].shared4.degree_next ;
+	}
+	DEBUG4 (("\n")) ;
+    }
+    DEBUG4 (("should "ID" have "ID"\n", should, have)) ;
+    ASSERT (should == have) ;
+
+    /* === Check the row degrees ============================================ */
+
+    if (n_row > 10000 && UMF_debug <= 0)
+    {
+	return ;
+    }
+    for (row = 0 ; row < n_row ; row++)
+    {
+	if (ROW_IS_ALIVE (row))
+	{
+	    ASSERT (Row [row].shared1.degree <= max_deg) ;
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === debug_mark =========================================================== */
+/* ========================================================================== */
+
+/*
+    Ensures that the tag_mark is less that the maximum and also ensures that
+    each entry in the mark array is less than the tag mark.
+*/
+
+PRIVATE void debug_mark
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Colamd_Row Row [],
+    Int tag_mark,
+    Int max_mark
+)
+{
+    /* === Local variables ================================================== */
+
+    Int r ;
+
+    /* === Check the Row marks ============================================== */
+
+    ASSERT (tag_mark > 0 && tag_mark <= max_mark) ;
+    if (n_row > 10000 && UMF_debug <= 0)
+    {
+	return ;
+    }
+    for (r = 0 ; r < n_row ; r++)
+    {
+	ASSERT (Row [r].shared2.mark < tag_mark) ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === debug_matrix ========================================================= */
+/* ========================================================================== */
+
+/*
+    Prints out the contents of the columns and the rows.
+*/
+
+PRIVATE void debug_matrix
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A []
+)
+{
+    /* === Local variables ================================================== */
+
+    Int r ;
+    Int c ;
+    Int *rp ;
+    Int *rp_end ;
+    Int *cp ;
+    Int *cp_end ;
+
+    /* === Dump the rows and columns of the matrix ========================== */
+
+    if (UMF_debug < 3)
+    {
+	return ;
+    }
+    DEBUG3 (("DUMP MATRIX:\n")) ;
+    for (r = 0 ; r < n_row ; r++)
+    {
+	DEBUG3 (("Row "ID" alive? %d\n", r, ROW_IS_ALIVE (r))) ;
+	if (ROW_IS_DEAD (r))
+	{
+	    continue ;
+	}
+
+	/* ------------------ */
+	/* changed for UMFPACK: */
+	DEBUG3 (("start "ID" length "ID" degree "ID" thickness "ID"\n",
+		Row [r].start, Row [r].length, Row [r].shared1.degree,
+		Row [r].thickness)) ;
+	/* ------------------ */
+
+	rp = &A [Row [r].start] ;
+	rp_end = rp + Row [r].length ;
+	while (rp < rp_end)
+	{
+	    c = *rp++ ;
+	    DEBUG4 (("	%d col "ID"\n", COL_IS_ALIVE (c), c)) ;
+	}
+    }
+
+    for (c = 0 ; c < n_col ; c++)
+    {
+	DEBUG3 (("Col "ID" alive? %d\n", c, COL_IS_ALIVE (c))) ;
+	if (COL_IS_DEAD (c))
+	{
+	    continue ;
+	}
+	/* ------------------ */
+	/* changed for UMFPACK: */
+	DEBUG3 (("start "ID" length "ID" shared1[thickness,parent] "ID
+		" shared2 [order,score] "ID"\n", Col [c].start, Col [c].length,
+		Col [c].shared1.thickness, Col [c].shared2.score));
+	/* ------------------ */
+	cp = &A [Col [c].start] ;
+	cp_end = cp + Col [c].length ;
+	while (cp < cp_end)
+	{
+	    r = *cp++ ;
+	    DEBUG4 (("	%d row "ID"\n", ROW_IS_ALIVE (r), r)) ;
+	}
+
+	/* ------------------ */
+	/* added for UMFPACK: */
+	DEBUG1 (("Col")) ;
+	dump_super (c, Col, n_col) ;
+	/* ------------------ */
+
+    }
+}
+
+/* ------------------ */
+/* dump_super added for UMFPACK: */
+PRIVATE void dump_super
+(
+    Int super_c,
+    Colamd_Col Col [],
+    Int n_col
+)
+{
+    Int col, ncols ;
+
+    DEBUG1 ((" =[ ")) ;
+    ncols = 0 ;
+    for (col = super_c ; col != EMPTY ; col = Col [col].nextcol)
+    {
+	DEBUG1 ((" "ID, col)) ;
+	ASSERT (col >= 0 && col < n_col) ;
+	if (col != super_c)
+	{
+	    ASSERT (COL_IS_DEAD (col)) ;
+	}
+	if (Col [col].nextcol == EMPTY)
+	{
+	    ASSERT (col == Col [super_c].lastcol) ;
+	}
+	ncols++ ;
+	ASSERT (ncols <= Col [super_c].shared1.thickness) ;
+    }
+    ASSERT (ncols == Col [super_c].shared1.thickness) ;
+    DEBUG1 (("]\n")) ;
+}
+/* ------------------ */
+
+
+#endif /* NDEBUG */
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_colamd.h b/src/C/SuiteSparse/UMFPACK/Source/umf_colamd.h
new file mode 100644
index 0000000..c7d9167
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_colamd.h
@@ -0,0 +1,255 @@
+/* ========================================================================== */
+/* === umf_colamd.h ========================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+
+Authors:
+
+    The authors of the COLAMD code itself are Stefan I. Larimore and Timothy A.
+    Davis, University of Florida.  The algorithm was developed in collaboration
+    with John Gilbert, Xerox PARC, and Esmond Ng, Oak Ridge National Laboratory.
+
+Date:
+
+    UMFPACK Version: see above.
+    COLAMD Version 2.0 was released on January 31, 2000.
+
+Acknowledgements:
+
+    This work was supported by the National Science Foundation, under
+    grants DMS-9504974, DMS-9803599, and CCR-0203270.
+
+UMFPACK:  Copyright (c) 2003 by Timothy A. Davis.  All Rights Reserved.
+
+See the UMFPACK README file for the License for your use of this code.
+
+Availability:
+
+    Both UMFPACK and the original unmodified colamd/symamd library are
+    available at http://www.cise.ufl.edu/research/sparse.
+
+*/
+
+#ifndef COLAMD_H
+#define COLAMD_H
+
+/* ========================================================================== */
+/* === Include files ======================================================== */
+/* ========================================================================== */
+
+#include <stdlib.h>
+
+/* ========================================================================== */
+/* === 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 */
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_config.h b/src/C/SuiteSparse/UMFPACK/Source/umf_config.h
new file mode 100644
index 0000000..224cf52
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_config.h
@@ -0,0 +1,324 @@
+/* ========================================================================== */
+/* === umf_config.h ========================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    This file controls the compile-time configuration of UMFPACK.  Modify the
+    UFconfig/UFconfig.mk file and this file if necessary, to control these
+    options.  The following flags may be given as options to your C compiler
+    (as in "cc -DNSUNPERF", for example).  These flags are normally placed in
+    your UMFPACK_CONFIG string, defined in the UFconfig/UFconfig.mk file.
+
+    All of these options, except for the timer, are for accessing the BLAS.
+
+	-DNSUNPERF
+
+	    Applies only to Sun Solaris.  If -DNSUNPERF is set, then the Sun
+	    Performance Library BLAS will not be used.
+
+	    The Sun Performance Library BLAS is used by default when compiling
+	    the C-callable libumfpack.a library on Sun Solaris.
+
+	-DLONGBLAS
+
+	-DNPOSIX
+
+	    If -DNPOSIX is set, then your Unix operating system is not POSIX-
+	    compliant, and the POSIX routines sysconf ( ) and times ( )
+	    routines are not used.  These routines provide CPU time and
+	    wallclock time information.  If -DNPOSIX is set, then the ANSI
+	    C clock ( ) routine is used.  If -DNPOSIX is not set, then
+	    sysconf ( ) and times ( ) are used in umfpack_tic and umfpack_toc.
+	    See umfpack_tictoc.c for more information.
+	    The default is to use the POSIX routines, except for Windows,
+	    which is not POSIX-compliant.
+
+	-DGETRUSAGE
+
+	    If -DGETRUSAGE is set, then your system's getrusage ( ) routine
+	    will be used for getting the process CPU time.  Otherwise the ANSI
+	    C clock ( ) routine will be used.  The default is to use getrusage
+	    ( ) on Unix systems, and to use clock on all other architectures.
+
+	-DNO_TIMER
+
+	    If -DNO_TIMER is set, then no timing routines are used at all.
+
+	-DNRECIPROCAL
+
+	    This option controls a tradeoff between speed and accuracy.  Using
+	    -DNRECIPROCAL can lead to more accurate results, but with perhaps
+	    some cost in performance, particularly if floating-point division
+	    is much more costly than floating-point multiplication.
+
+	    This option determines the method used to scale the pivot column.
+	    If set, or if the absolute value of the pivot is < 1e-12 (or is a
+	    NaN), then the pivot column is divided by the pivot value.
+	    Otherwise, the reciprocal of the pivot value is computed, and the
+	    pivot column is multiplied by (1/pivot).  Multiplying by the
+	    reciprocal can be slightly less accurate than dividing by the
+	    pivot, but it is often faster.  See umf_scale.c.
+
+	    This has a small effect on the performance of UMFPACK, at least on
+	    a Pentium 4M.  It may have a larger effect on other architectures
+	    where floating-point division is much more costly than floating-
+	    point multiplication.  The RS 6000 is one such example.
+
+	    By default, the method chosen is to multiply by the reciprocal
+	    (sacrificing accuracy for speed), except when compiling UMFPACK
+	    as a built-in routine in MATLAB, or when gcc is being used.
+
+	    When MATHWORKS is defined, -DNRECIPROCAL is forced on, and the pivot
+	    column is divided by the pivot value.  The only way of using the
+	    other method in this case is to edit this file.
+
+	    If -DNRECIPROCAL is enabled, then the row scaling factors are always
+	    applied by dividing each row by the scale factor, rather than
+	    multiplying by the reciprocal.  If -DNRECIPROCAL is not enabled
+	    (the default case), then the scale factors are normally applied by
+	    multiplying by the reciprocal.  If, however, the smallest scale
+	    factor is tiny, then the scale factors are applied via division.
+
+	-DNO_DIVIDE_BY_ZERO
+
+	    If the pivot is zero, and this flag is set, then no divide-by-zero
+	    occurs.
+
+    The following options are controlled by amd_internal.h:
+
+	-DMATLAB_MEX_FILE
+
+	    This flag is turned on when compiling the umfpack mexFunction for
+	    use in MATLAB.  The -DNRECIPROCAL flag is forced on (more accurate,
+	    slightly slower).  The umfpack mexFunction always returns
+	    L*U = P*(R\A)*Q.
+
+	-DMATHWORKS
+
+	    This flag is turned on when compiling umfpack as a built-in routine
+	    in MATLAB.  The -DNRECIPROCAL flag is forced on.
+
+	-DNDEBUG
+
+	    Debugging mode (if NDEBUG is not defined).  The default, of course,
+	    is no debugging.  Turning on debugging takes some work (see below).
+	    If you do not edit this file, then debugging is turned off anyway,
+	    regardless of whether or not -DNDEBUG is specified in your compiler
+	    options.
+*/
+
+/* ========================================================================== */
+/* === AMD configuration ==================================================== */
+/* ========================================================================== */
+
+/* NDEBUG, PRINTF defined in amd_internal.h */
+
+/* ========================================================================== */
+/* === reciprocal option ==================================================== */
+/* ========================================================================== */
+
+/* Force the definition NRECIPROCAL when MATHWORKS or MATLAB_MEX_FILE
+ * are defined.  Do not multiply by the reciprocal in those cases. */
+
+#ifndef NRECIPROCAL
+#if defined (MATHWORKS) || defined (MATLAB_MEX_FILE)
+#define NRECIPROCAL
+#endif
+#endif
+
+/* ========================================================================== */
+/* === Microsoft Windows configuration ====================================== */
+/* ========================================================================== */
+
+#if defined (UMF_WINDOWS) || defined (UMF_MINGW)
+/* Windows isn't Unix.  Profound. */
+#define NPOSIX
+#endif
+
+/* ========================================================================== */
+/* === 0-based or 1-based printing ========================================== */
+/* ========================================================================== */
+
+#if defined (MATLAB_MEX_FILE) && defined (NDEBUG)
+/* In MATLAB, matrices are 1-based to the user, but 0-based internally. */
+/* One is added to all row and column indices when printing matrices */
+/* for the MATLAB user.  The +1 shift is turned off when debugging. */
+#define INDEX(i) ((i)+1)
+#else
+/* In ANSI C, matrices are 0-based and indices are reported as such. */
+/* This mode is also used for debug mode, and if MATHWORKS is defined rather */
+/* than MATLAB_MEX_FILE. */
+#define INDEX(i) (i)
+#endif
+
+/* ========================================================================== */
+/* === Timer ================================================================ */
+/* ========================================================================== */
+
+/*
+    If you have the getrusage routine (all Unix systems I've test do), then use
+    that.  Otherwise, use the ANSI C clock function.   Note that on many
+    systems, the ANSI clock function wraps around after only 2147 seconds, or
+    about 36 minutes.  BE CAREFUL:  if you compare the run time of UMFPACK with
+    other sparse matrix packages, be sure to use the same timer.  See
+    umfpack_tictoc.c for the timer used internally by UMFPACK.  See also
+    umfpack_timer.c for the timer used in an earlier version of UMFPACK.
+    That timer is still available as a user-callable routine, but it is no
+    longer used internally by UMFPACK.
+*/
+
+/* Sun Solaris, SGI Irix, Linux, Compaq Alpha, and IBM RS 6000 all have */
+/* getrusage.  It's in BSD unix, so perhaps all unix systems have it. */
+#if defined (UMF_SOL2) || defined (UMF_SGI) || defined (UMF_LINUX) \
+|| defined (UMF_ALPHA) || defined (UMF_AIX) || defined (UMF_CYGWIN)
+#define GETRUSAGE
+#endif
+
+
+/* ========================================================================== */
+/* === BLAS ================================================================= */
+/* ========================================================================== */
+
+#include "cholmod_blas.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* DGEMM */
+/* -------------------------------------------------------------------------- */
+
+/* C = C - A*B', where:
+ * A is m-by-k with leading dimension ldac
+ * B is k-by-n with leading dimension ldb
+ * C is m-by-n with leading dimension ldac */
+#ifdef COMPLEX
+#define BLAS_GEMM(m,n,k,A,B,ldb,C,ldac) \
+{ \
+    double alpha [2] = {-1,0}, beta [2] = {1,0} ; \
+    BLAS_zgemm ("N", "T", m, n, k, alpha, (double *) A, ldac, \
+	(double *) B, ldb, beta, (double *) C, ldac) ; \
+}
+#else
+#define BLAS_GEMM(m,n,k,A,B,ldb,C,ldac) \
+{ \
+    double alpha = -1, beta = 1 ; \
+    BLAS_dgemm ("N", "T", m, n, k, &alpha, A, ldac, B, ldb, &beta, C, ldac) ; \
+}
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* GER */
+/* -------------------------------------------------------------------------- */
+
+/* A = A - x*y', where:
+ * A is m-by-n with leading dimension d
+   x is a column vector with stride 1
+   y is a column vector with stride 1 */
+#ifdef COMPLEX
+#define BLAS_GER(m,n,x,y,A,d) \
+{ \
+    double alpha [2] = {-1,0} ; \
+    BLAS_zgeru (m, n, alpha, (double *) x, 1, (double *) y, 1, \
+	(double *) A, d) ; \
+}
+#else
+#define BLAS_GER(m,n,x,y,A,d) \
+{ \
+    double alpha = -1 ; \
+    BLAS_dger (m, n, &alpha, x, 1, y, 1, A, d) ; \
+}
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* GEMV */
+/* -------------------------------------------------------------------------- */
+
+/* y = y - A*x, where A is m-by-n with leading dimension d,
+   x is a column vector with stride 1
+   y is a column vector with stride 1 */
+#ifdef COMPLEX
+#define BLAS_GEMV(m,n,A,x,y,d) \
+{ \
+    double alpha [2] = {-1,0}, beta [2] = {1,0} ; \
+    BLAS_zgemv ("N", m, n, alpha, (double *) A, d, (double *) x, 1, beta, \
+	(double *) y, 1) ; \
+}
+#else
+#define BLAS_GEMV(m,n,A,x,y,d) \
+{ \
+    double alpha = -1, beta = 1 ; \
+    BLAS_dgemv ("N", m, n, &alpha, A, d, x, 1, &beta, y, 1) ; \
+}
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* TRSV */
+/* -------------------------------------------------------------------------- */
+
+/* solve Lx=b, where:
+ * B is a column vector (m-by-1) with leading dimension d
+ * A is m-by-m with leading dimension d */
+#ifdef COMPLEX
+#define BLAS_TRSV(m,A,b,d) \
+{ \
+    BLAS_ztrsv ("L", "N", "U", m, (double *) A, d, (double *) b, 1) ; \
+}
+#else
+#define BLAS_TRSV(m,A,b,d) \
+{ \
+    BLAS_dtrsv ("L", "N", "U", m, A, d, b, 1) ; \
+}
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* TRSM */
+/* -------------------------------------------------------------------------- */
+
+/* solve XL'=B where:
+ * B is m-by-n with leading dimension ldb
+ * A is n-by-n with leading dimension lda */
+#ifdef COMPLEX
+#define BLAS_TRSM_RIGHT(m,n,A,lda,B,ldb) \
+{ \
+    double alpha [2] = {1,0} ; \
+    BLAS_ztrsm ("R", "L", "T", "U", m, n, alpha, (double *) A, lda, \
+	(double *) B, ldb) ; \
+}
+#else
+#define BLAS_TRSM_RIGHT(m,n,A,lda,B,ldb) \
+{ \
+    double alpha = 1 ; \
+    BLAS_dtrsm ("R", "L", "T", "U", m, n, &alpha, A, lda, B, ldb) ; \
+}
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* SCAL */
+/* -------------------------------------------------------------------------- */
+
+/* x = s*x, where x is a stride-1 vector of length n */
+#ifdef COMPLEX
+#define BLAS_SCAL(n,s,x) \
+{ \
+    double alpha [2] ; \
+    alpha [0] = REAL_COMPONENT (s) ; \
+    alpha [1] = IMAG_COMPONENT (s) ; \
+    BLAS_zscal (n, alpha, (double *) x, 1) ; \
+}
+#else
+#define BLAS_SCAL(n,s,x) \
+{ \
+    double alpha = REAL_COMPONENT (s) ; \
+    BLAS_dscal (n, &alpha, (double *) x, 1) ; \
+}
+#endif
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_create_element.c b/src/C/SuiteSparse/UMFPACK/Source/umf_create_element.c
new file mode 100644
index 0000000..2588a64
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_create_element.c
@@ -0,0 +1,592 @@
+/* ========================================================================== */
+/* === UMF_create_element =================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Factorization of a frontal matrix is complete.  Create a new element for
+    later assembly into a subsequent frontal matrix.  Returns TRUE if
+    successful, FALSE if out of memory.
+*/
+
+#include "umf_internal.h"
+#include "umf_mem_alloc_element.h"
+#include "umf_mem_alloc_tail_block.h"
+#include "umf_mem_free_tail_block.h"
+#include "umf_get_memory.h"
+
+/* ========================================================================== */
+/* === copy_column ========================================================== */
+/* ========================================================================== */
+
+PRIVATE void copy_column (Int len, Entry *X, Entry *Y)
+{
+    Int i ;
+#pragma ivdep
+    for (i = 0 ; i < len ; i++)
+    {
+	Y [i] = X [i] ;
+    }
+}
+
+/* ========================================================================== */
+/* === UMF_create_element =================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMF_create_element
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int j, col, row, *Fcols, *Frows, fnrows, fncols, *Cols, len, needunits, t1,
+	t2, size, e, i, *E, *Fcpos, *Frpos, *Rows, eloc, fnr_curr, f,
+	got_memory, *Row_tuples, *Row_degree, *Row_tlen, *Col_tuples, max_mark,
+	*Col_degree, *Col_tlen, nn, n_row, n_col, r2, c2, do_Fcpos ;
+    Entry *C, *Fcol ;
+    Element *ep ;
+    Unit *p, *Memory ;
+    Tuple *tp, *tp1, *tp2, tuple, *tpend ;
+#ifndef NDEBUG
+    DEBUG2 (("FRONTAL WRAPUP\n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (Work->fnpiv == 0) ;
+    ASSERT (Work->fnzeros == 0) ;
+    Row_degree = Numeric->Rperm ;
+    Row_tuples = Numeric->Uip ;
+    Row_tlen   = Numeric->Uilen ;
+    Col_degree = Numeric->Cperm ;
+    Col_tuples = Numeric->Lip ;
+    Col_tlen   = Numeric->Lilen ;
+    n_row = Work->n_row ;
+    n_col = Work->n_col ;
+    nn = MAX (n_row, n_col) ;
+    Fcols = Work->Fcols ;
+    Frows = Work->Frows ;
+    Fcpos = Work->Fcpos ;
+    Frpos = Work->Frpos ;
+    Memory = Numeric->Memory ;
+    fncols = Work->fncols ;
+    fnrows = Work->fnrows ;
+
+    tp = (Tuple *) NULL ;
+    tp1 = (Tuple *) NULL ;
+    tp2 = (Tuple *) NULL ;
+
+    /* ---------------------------------------------------------------------- */
+    /* add the current frontal matrix to the degrees of each column */
+    /* ---------------------------------------------------------------------- */
+
+    if (!Symbolic->fixQ)
+    {
+	/* but only if the column ordering is not fixed */
+#pragma ivdep
+	for (j = 0 ; j < fncols ; j++)
+	{
+	    /* add the current frontal matrix to the degree */
+	    ASSERT (Fcols [j] >= 0 && Fcols [j] < n_col) ;
+	    Col_degree [Fcols [j]] += fnrows ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* add the current frontal matrix to the degrees of each row */
+    /* ---------------------------------------------------------------------- */
+
+#pragma ivdep
+    for (i = 0 ; i < fnrows ; i++)
+    {
+	/* add the current frontal matrix to the degree */
+	ASSERT (Frows [i] >= 0 && Frows [i] < n_row) ;
+	Row_degree [Frows [i]] += fncols ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* Reset the external degree counters */
+    /* ---------------------------------------------------------------------- */
+
+    E = Work->E ;
+    max_mark = MAX_MARK (nn) ;
+
+    if (!Work->pivcol_in_front)
+    {
+	/* clear the external column degrees. no more Usons of current front */
+	Work->cdeg0 += (nn + 1) ;
+	if (Work->cdeg0 >= max_mark)
+	{
+	    /* guard against integer overflow.  This is very rare */
+	    DEBUG1 (("Integer overflow, cdeg\n")) ;
+	    Work->cdeg0 = 1 ;
+#pragma ivdep
+	    for (e = 1 ; e <= Work->nel ; e++)
+	    {
+		if (E [e])
+		{
+		    ep = (Element *) (Memory + E [e]) ;
+		    ep->cdeg = 0 ;
+		}
+	    }
+	}
+    }
+
+    if (!Work->pivrow_in_front)
+    {
+	/* clear the external row degrees.  no more Lsons of current front */
+	Work->rdeg0 += (nn + 1) ;
+	if (Work->rdeg0 >= max_mark)
+	{
+	    /* guard against integer overflow.  This is very rare */
+	    DEBUG1 (("Integer overflow, rdeg\n")) ;
+	    Work->rdeg0 = 1 ;
+#pragma ivdep
+	    for (e = 1 ; e <= Work->nel ; e++)
+	    {
+		if (E [e])
+		{
+		    ep = (Element *) (Memory + E [e]) ;
+		    ep->rdeg = 0 ;
+		}
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* clear row/col offsets */
+    /* ---------------------------------------------------------------------- */
+
+    if (!Work->pivrow_in_front)
+    {
+#pragma ivdep
+	for (j = 0 ; j < fncols ; j++)
+	{
+	    Fcpos [Fcols [j]] = EMPTY ;
+	}
+    }
+
+    if (!Work->pivcol_in_front)
+    {
+#pragma ivdep
+	for (i = 0 ; i < fnrows ; i++)
+	{
+	    Frpos [Frows [i]] = EMPTY ;
+	}
+    }
+
+    if (fncols <= 0 || fnrows <= 0)
+    {
+	/* no element to create */
+	DEBUG2 (("Element evaporation\n")) ;
+	Work->prior_element = EMPTY ;
+	return (TRUE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* create element for later assembly */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    UMF_allocfail = FALSE ;
+    if (UMF_gprob > 0)
+    {
+	double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ;
+	DEBUG4 (("Check random %e %e\n", rrr, UMF_gprob)) ;
+	UMF_allocfail = rrr < UMF_gprob ;
+	if (UMF_allocfail) DEBUGm2 (("Random garbage collection (create)\n"));
+    }
+#endif
+
+    needunits = 0 ;
+    got_memory = FALSE ;
+    eloc = UMF_mem_alloc_element (Numeric, fnrows, fncols, &Rows, &Cols, &C,
+	&needunits, &ep) ;
+
+    /* if UMF_get_memory needs to be called */
+    if (Work->do_grow)
+    {
+	/* full compaction of current frontal matrix, since UMF_grow_front will
+	 * be called next anyway. */
+	r2 = fnrows ;
+	c2 = fncols ;
+	do_Fcpos = FALSE ;
+    }
+    else
+    {
+	/* partial compaction. */
+	r2 = MAX (fnrows, Work->fnrows_new + 1) ;
+	c2 = MAX (fncols, Work->fncols_new + 1) ;
+	/* recompute Fcpos if pivot row is in the front */
+	do_Fcpos = Work->pivrow_in_front ;
+    }
+
+    if (!eloc)
+    {
+	/* Do garbage collection, realloc, and try again. */
+	/* Compact the current front if it needs to grow anyway. */
+	/* Note that there are no pivot rows or columns in the current front */
+	DEBUGm3 (("get_memory from umf_create_element, 1\n")) ;
+	if (!UMF_get_memory (Numeric, Work, needunits, r2, c2, do_Fcpos))
+	{
+	    /* :: out of memory in umf_create_element (1) :: */
+	    DEBUGm4 (("out of memory: create element (1)\n")) ;
+	    return (FALSE) ;	/* out of memory */
+	}
+	got_memory = TRUE ;
+	Memory = Numeric->Memory ;
+	eloc = UMF_mem_alloc_element (Numeric, fnrows, fncols, &Rows, &Cols, &C,
+	    &needunits, &ep) ;
+	ASSERT (eloc >= 0) ;
+	if (!eloc)
+	{
+	    /* :: out of memory in umf_create_element (2) :: */
+	    DEBUGm4 (("out of memory: create element (2)\n")) ;
+	    return (FALSE) ;	/* out of memory */
+	}
+    }
+
+    e = ++(Work->nel) ;	/* get the name of this new frontal matrix */
+    Work->prior_element = e ;
+    DEBUG8 (("wrapup e "ID" nel "ID"\n", e, Work->nel)) ;
+
+    ASSERT (e > 0 && e < Work->elen) ;
+    ASSERT (E [e] == 0) ;
+    E [e] = eloc ;
+
+    if (Work->pivcol_in_front)
+    {
+	/* the new element is a Uson of the next frontal matrix */
+	ep->cdeg = Work->cdeg0 ;
+    }
+
+    if (Work->pivrow_in_front)
+    {
+	/* the new element is an Lson of the next frontal matrix */
+	ep->rdeg = Work->rdeg0 ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* copy frontal matrix into the new element */
+    /* ---------------------------------------------------------------------- */
+
+#pragma ivdep
+    for (i = 0 ; i < fnrows ; i++)
+    {
+	Rows [i] = Frows [i] ;
+    }
+#pragma ivdep
+    for (i = 0 ; i < fncols ; i++)
+    {
+	Cols [i] = Fcols [i] ;
+    }
+    Fcol = Work->Fcblock ;
+    DEBUG0 (("copy front "ID" by "ID"\n", fnrows, fncols)) ;
+    fnr_curr = Work->fnr_curr ;
+    ASSERT (fnr_curr >= 0 && fnr_curr % 2 == 1) ;
+    for (j = 0 ; j < fncols ; j++)
+    {
+	copy_column (fnrows, Fcol, C) ;
+	Fcol += fnr_curr ;
+	C += fnrows ;
+    }
+
+    DEBUG8 (("element copied\n")) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* add tuples for the new element */
+    /* ---------------------------------------------------------------------- */
+
+    tuple.e = e ;
+
+    if (got_memory)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* UMF_get_memory ensures enough space exists for each new tuple */
+	/* ------------------------------------------------------------------ */
+
+	/* place (e,f) in the element list of each column */
+	for (tuple.f = 0 ; tuple.f < fncols ; tuple.f++)
+	{
+	    col = Fcols [tuple.f] ;
+	    ASSERT (col >= 0 && col < n_col) ;
+	    ASSERT (NON_PIVOTAL_COL (col)) ;
+	    ASSERT (Col_tuples [col]) ;
+	    tp = ((Tuple *) (Memory + Col_tuples [col])) + Col_tlen [col]++ ;
+	    *tp = tuple ;
+	}
+
+	/* ------------------------------------------------------------------ */
+
+	/* place (e,f) in the element list of each row */
+	for (tuple.f = 0 ; tuple.f < fnrows ; tuple.f++)
+	{
+	    row = Frows [tuple.f] ;
+	    ASSERT (row >= 0 && row < n_row) ;
+	    ASSERT (NON_PIVOTAL_ROW (row)) ;
+	    ASSERT (Row_tuples [row]) ;
+	    tp = ((Tuple *) (Memory + Row_tuples [row])) + Row_tlen [row]++ ;
+	    *tp = tuple ;
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* place (e,f) in the element list of each column */
+	/* ------------------------------------------------------------------ */
+
+	/* might not have enough space for each tuple */
+
+	for (tuple.f = 0 ; tuple.f < fncols ; tuple.f++)
+	{
+	    col = Fcols [tuple.f] ;
+	    ASSERT (col >= 0 && col < n_col) ;
+	    ASSERT (NON_PIVOTAL_COL (col)) ;
+	    t1 = Col_tuples [col] ;
+	    DEBUG1 (("Placing on col:"ID" , tuples at "ID"\n",
+		col, Col_tuples [col])) ;
+
+	    size = 0 ;
+	    len = 0 ;
+
+	    if (t1)
+	    {
+		p = Memory + t1 ;
+		tp = (Tuple *) p ;
+		size = GET_BLOCK_SIZE (p) ;
+		len = Col_tlen [col] ;
+		tp2 = tp + len ;
+	    }
+
+	    needunits = UNITS (Tuple, len + 1) ;
+	    DEBUG1 (("len: "ID" size: "ID" needunits: "ID"\n",
+		len, size, needunits));
+
+	    if (needunits > size && t1)
+	    {
+		/* prune the tuples */
+		tp1 = tp ;
+		tp2 = tp ;
+		tpend = tp + len ;
+		for ( ; tp < tpend ; tp++)
+		{
+		    e = tp->e ;
+		    ASSERT (e > 0 && e <= Work->nel) ;
+		    if (!E [e]) continue ;   /* element already deallocated */
+		    f = tp->f ;
+		    p = Memory + E [e] ;
+		    ep = (Element *) p ;
+		    p += UNITS (Element, 1) ;
+		    Cols = (Int *) p ;
+		    ;
+		    if (Cols [f] == EMPTY) continue ;	/* already assembled */
+		    ASSERT (col == Cols [f]) ;
+		    *tp2++ = *tp ;	/* leave the tuple in the list */
+		}
+		len = tp2 - tp1 ;
+		Col_tlen [col] = len ;
+		needunits = UNITS (Tuple, len + 1) ;
+	    }
+
+	    if (needunits > size)
+	    {
+		/* no room exists - reallocate elsewhere */
+		DEBUG1 (("REALLOCATE Col: "ID", size "ID" to "ID"\n",
+		    col, size, 2*needunits)) ;
+
+#ifndef NDEBUG
+		UMF_allocfail = FALSE ;
+		if (UMF_gprob > 0)  /* a double relop, but ignore NaN case */
+		{
+		    double rrr = ((double) (rand ( ))) /
+			(((double) RAND_MAX) + 1) ;
+		    DEBUG1 (("Check random %e %e\n", rrr, UMF_gprob)) ;
+		    UMF_allocfail = rrr < UMF_gprob ;
+		    if (UMF_allocfail) DEBUGm2 (("Random gar. (col tuple)\n")) ;
+		}
+#endif
+
+		needunits = MIN (2*needunits, (Int) UNITS (Tuple, nn)) ;
+		t2 = UMF_mem_alloc_tail_block (Numeric, needunits) ;
+		if (!t2)
+		{
+		    /* :: get memory in umf_create_element (1) :: */
+		    /* get memory, reconstruct all tuple lists, and return */
+		    /* Compact the current front if it needs to grow anyway. */
+		    /* Note: no pivot rows or columns in the current front */
+		    DEBUGm4 (("get_memory from umf_create_element, 1\n")) ;
+		    return (UMF_get_memory (Numeric, Work, 0, r2, c2,do_Fcpos));
+		}
+		Col_tuples [col] = t2 ;
+		tp2 = (Tuple *) (Memory + t2) ;
+		if (t1)
+		{
+		    for (i = 0 ; i < len ; i++)
+		    {
+			*tp2++ = *tp1++ ;
+		    }
+		    UMF_mem_free_tail_block (Numeric, t1) ;
+		}
+	    }
+
+	    /* place the new (e,f) tuple in the element list of the column */
+	    Col_tlen [col]++ ;
+	    *tp2 = tuple ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* place (e,f) in the element list of each row */
+	/* ------------------------------------------------------------------ */
+
+	for (tuple.f = 0 ; tuple.f < fnrows ; tuple.f++)
+	{
+	    row = Frows [tuple.f] ;
+	    ASSERT (row >= 0 && row < n_row) ;
+	    ASSERT (NON_PIVOTAL_ROW (row)) ;
+	    t1 = Row_tuples [row] ;
+	    DEBUG1 (("Placing on row:"ID" , tuples at "ID"\n",
+		row, Row_tuples [row])) ;
+
+	    size = 0 ;
+	    len = 0 ;
+	    if (t1)
+	    {
+		p = Memory + t1 ;
+		tp = (Tuple *) p ;
+		size = GET_BLOCK_SIZE (p) ;
+		len = Row_tlen [row] ;
+		tp2 = tp + len ;
+	    }
+
+	    needunits = UNITS (Tuple, len + 1) ;
+	    DEBUG1 (("len: "ID" size: "ID" needunits: "ID"\n",
+		len, size, needunits)) ;
+
+	    if (needunits > size && t1)
+	    {
+		/* prune the tuples */
+		tp1 = tp ;
+		tp2 = tp ;
+		tpend = tp + len ;
+		for ( ; tp < tpend ; tp++)
+		{
+		    e = tp->e ;
+		    ASSERT (e > 0 && e <= Work->nel) ;
+		    if (!E [e])
+		    {
+			continue ;	/* element already deallocated */
+		    }
+		    f = tp->f ;
+		    p = Memory + E [e] ;
+		    ep = (Element *) p ;
+		    p += UNITS (Element, 1) ;
+		    Cols = (Int *) p ;
+		    Rows = Cols + (ep->ncols) ;
+		    if (Rows [f] == EMPTY) continue ;	/* already assembled */
+		    ASSERT (row == Rows [f]) ;
+		    *tp2++ = *tp ;	/* leave the tuple in the list */
+		}
+		len = tp2 - tp1 ;
+		Row_tlen [row] = len ;
+		needunits = UNITS (Tuple, len + 1) ;
+	    }
+
+	    if (needunits > size)
+	    {
+		/* no room exists - reallocate elsewhere */
+		DEBUG1 (("REALLOCATE Row: "ID", size "ID" to "ID"\n",
+		    row, size, 2*needunits)) ;
+
+#ifndef NDEBUG
+		UMF_allocfail = FALSE ;
+		if (UMF_gprob > 0)  /* a double relop, but ignore NaN case */
+		{
+		    double rrr = ((double) (rand ( ))) /
+			(((double) RAND_MAX) + 1) ;
+		    DEBUG1 (("Check random %e %e\n", rrr, UMF_gprob)) ;
+		    UMF_allocfail = rrr < UMF_gprob ;
+		    if (UMF_allocfail) DEBUGm2 (("Random gar. (row tuple)\n")) ;
+		}
+#endif
+
+		needunits = MIN (2*needunits, (Int) UNITS (Tuple, nn)) ;
+		t2 = UMF_mem_alloc_tail_block (Numeric, needunits) ;
+		if (!t2)
+		{
+		    /* :: get memory in umf_create_element (2) :: */
+		    /* get memory, reconstruct all tuple lists, and return */
+		    /* Compact the current front if it needs to grow anyway. */
+		    /* Note: no pivot rows or columns in the current front */
+		    DEBUGm4 (("get_memory from umf_create_element, 2\n")) ;
+		    return (UMF_get_memory (Numeric, Work, 0, r2, c2,do_Fcpos));
+		}
+		Row_tuples [row] = t2 ;
+		tp2 = (Tuple *) (Memory + t2) ;
+		if (t1)
+		{
+		    for (i = 0 ; i < len ; i++)
+		    {
+			*tp2++ = *tp1++ ;
+		    }
+		    UMF_mem_free_tail_block (Numeric, t1) ;
+		}
+	    }
+
+	    /* place the new (e,f) tuple in the element list of the row */
+	    Row_tlen [row]++ ;
+	    *tp2 = tuple ;
+	}
+
+    }
+
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    DEBUG1 (("Done extending\nFINAL: element row pattern: len="ID"\n", fncols));
+    for (j = 0 ; j < fncols ; j++) DEBUG1 ((""ID"\n", Fcols [j])) ;
+    DEBUG1 (("FINAL: element col pattern:  len="ID"\n", fnrows)) ;
+    for (j = 0 ; j < fnrows ; j++) DEBUG1 ((""ID"\n", Frows [j])) ;
+    for (j = 0 ; j < fncols ; j++)
+    {
+	col = Fcols [j] ;
+	ASSERT (col >= 0 && col < n_col) ;
+	UMF_dump_rowcol (1, Numeric, Work, col, !Symbolic->fixQ) ;
+    }
+    for (j = 0 ; j < fnrows ; j++)
+    {
+	row = Frows [j] ;
+	ASSERT (row >= 0 && row < n_row) ;
+	UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ;
+    }
+    if (n_row < 1000 && n_col < 1000)
+    {
+	UMF_dump_memory (Numeric) ;
+    }
+    DEBUG1 (("New element, after filling with stuff: "ID"\n", e)) ;
+    UMF_dump_element (Numeric, Work, e, TRUE) ;
+    if (nn < 1000)
+    {
+	DEBUG4 (("Matrix dump, after New element: "ID"\n", e)) ;
+	UMF_dump_matrix (Numeric, Work, TRUE) ;
+    }
+    DEBUG3 (("FRONTAL WRAPUP DONE\n")) ;
+#endif
+
+    return (TRUE) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_create_element.h b/src/C/SuiteSparse/UMFPACK/Source/umf_create_element.h
new file mode 100644
index 0000000..f2beda6
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_create_element.h
@@ -0,0 +1,12 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_create_element
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_dump.c b/src/C/SuiteSparse/UMFPACK/Source/umf_dump.c
new file mode 100644
index 0000000..962ad9c
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_dump.c
@@ -0,0 +1,1209 @@
+/* ========================================================================== */
+/* === UMF_dump ============================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* These routines, and external variables, are used only when debugging. */
+/* If debugging is disabled (for normal operation) then this entire file */
+/* becomes empty */
+
+#include "umf_internal.h"
+
+#ifndef NDEBUG
+
+/* These global debugging variables and arrays do not exist if debugging */
+/* is disabled at compile time (which is the default). */
+GLOBAL Int UMF_debug = -999 ;
+GLOBAL Int UMF_allocfail = FALSE ;
+GLOBAL double UMF_gprob = -1.0 ;
+
+/* static debugging arrays used only in UMF_dump_rowcol */
+PRIVATE Int UMF_DBflag = 0 ;
+PRIVATE Int UMF_DBpacked [UMF_DBMAX+1] ;
+PRIVATE Int UMF_DBscatter [UMF_DBMAX+1] ;
+
+/* ========================================================================== */
+/* === UMF_DBinit =========================================================== */
+/* ========================================================================== */
+
+/* clear the debugging arrays */
+
+PRIVATE void UMF_DBinit
+(
+    void
+)
+{
+    Int i ;
+
+    /* Int_MAX is defined in umfpack.h */
+    if (UMF_DBflag < 1 || UMF_DBflag == Int_MAX)
+    {
+	/* clear the debugging arrays */
+	UMF_DBflag = 0 ;
+	for (i = 0 ; i <= UMF_DBMAX ; i++)
+	{
+	    UMF_DBscatter [i] = 0 ;
+	    UMF_DBpacked  [i] = 0 ;
+	}
+    }
+
+    UMF_DBflag++ ;
+
+    /* UMF_DBflag > UMF_DBscatter [0...UMF_DBmax] is now true */
+}
+
+/* ========================================================================== */
+/* === UMF_dump_dense ======================================================= */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_dense
+(
+    Entry *C,
+    Int dim,
+    Int m,
+    Int n
+)
+{
+
+    /* dump C [1..m,1..n], with column dimenstion dim */
+    Int i, j;
+
+    if (UMF_debug < 7) return ;
+    if (C == (Entry *) NULL)
+    {
+	DEBUG7 (("No dense matrix allocated\n")) ;
+	return ;
+    }
+    DEBUG8 ((" dimension= "ID" rows= "ID" cols= "ID"\n", dim, m, n)) ;
+
+    for (i = 0 ; i < m ; i++)
+    {
+	DEBUG9 ((ID": ", i)) ;
+	for (j = 0 ; j < n ; j++)
+	{
+	    EDEBUG9 (C [i+j*dim]) ;
+	    if (j % 6 == 5) DEBUG9 (("\n     ")) ;
+	}
+	DEBUG9 (("\n")) ;
+    }
+
+    for (i = 0 ; i < m ; i++)
+    {
+	for (j = 0 ; j < n ; j++)
+	{
+	    if (IS_ZERO (C [i+j*dim]))
+	    {
+		DEBUG8 ((".")) ;
+	    }
+	    else
+	    {
+		DEBUG8 (("X")) ;
+	    }
+	}
+	DEBUG8 (("\n")) ;
+    }
+}
+
+/* ========================================================================== */
+/* === UMF_dump_element ===================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_element
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int e,
+    Int clean
+)
+{
+
+    Int i, j, k, *Rows, *Cols, nrows, ncols, *E, row, col,
+	*Row_degree, *Col_degree ;
+    Entry *C ;
+    Element *ep ;
+    Unit *p ;
+
+    if (UMF_debug < 7) return ;
+
+    if (e == 0)
+    {
+	UMF_dump_current_front (Numeric, Work, FALSE) ;
+	return ;
+    }
+
+    DEBUG7 (("\n====================ELEMENT: "ID" ", e)) ;
+    if (!Numeric || !Work || !Numeric->Memory)
+    {
+	DEBUG7 ((" No Numeric, Work\n")) ;
+	return ;
+    }
+    DEBUG7 ((" nel: "ID" of "ID, e, Work->nel)) ;
+    E = Work->E ;
+    if (!E)
+    {
+	DEBUG7 ((" No elements\n")) ;
+	return ;
+    }
+    if (e < 0 || e > Work->nel)
+    {
+	DEBUG7 (("e out of range!\n")) ;
+	return ;
+    }
+    if (!E [e])
+    {
+	DEBUG7 ((" deallocated\n")) ;
+	return ;
+    }
+    DEBUG7 (("\n")) ;
+    Col_degree = Numeric->Cperm ;
+    Row_degree = Numeric->Rperm ;
+
+    p = Numeric->Memory + E [e] ;
+    DEBUG7 (("ep "ID"\n", (Int) (p-Numeric->Memory))) ;
+    GET_ELEMENT (ep, p, Cols, Rows, ncols, nrows, C) ;
+    DEBUG7 (("nrows "ID" nrowsleft "ID"\n", nrows, ep->nrowsleft)) ;
+    DEBUG7 (("ncols "ID" ncolsleft "ID"\n", ncols, ep->ncolsleft)) ;
+    DEBUG7 (("cdeg-cdeg0 "ID" rdeg-rdeg0 "ID" next "ID"\n",
+    ep->cdeg - Work->cdeg0, ep->rdeg - Work->rdeg0, ep->next)) ;
+
+    DEBUG8 (("rows: ")) ;
+    k = 0 ;
+    for (i = 0 ; i < ep->nrows ; i++)
+    {
+	row = Rows [i] ;
+	if (row >= 0)
+	{
+	    DEBUG8 ((" "ID, row)) ;
+	    ASSERT (row < Work->n_row) ;
+	    if ((k++ % 10) == 9) DEBUG8 (("\n")) ;
+	    ASSERT (IMPLIES (clean, NON_PIVOTAL_ROW (row))) ;
+	}
+    }
+
+    DEBUG8 (("\ncols: ")) ;
+    k = 0 ;
+    for (j = 0 ; j < ep->ncols ; j++)
+    {
+	col = Cols [j] ;
+	if (col >= 0)
+	{
+	    DEBUG8 ((" "ID, col)) ;
+	    ASSERT (col < Work->n_col) ;
+	    if ((k++ % 10) == 9) DEBUG8 (("\n")) ;
+	    ASSERT (IMPLIES (clean, NON_PIVOTAL_COL (col))) ;
+	}
+    }
+
+    DEBUG8 (("\nvalues:\n")) ;
+    if (UMF_debug >= 9)
+    {
+	for (i = 0 ; i < ep->nrows ; i++)
+	{
+	    row = Rows [i] ;
+	    if (row >= 0)
+	    {
+		DEBUG9 ((ID": ", row)) ;
+		k = 0 ;
+		for (j = 0 ; j < ep->ncols ; j++)
+		{
+		    col = Cols [j] ;
+		    if (col >= 0)
+		    {
+			EDEBUG9 (C [i+j*ep->nrows]) ;
+			if (k++ % 6 == 5) DEBUG9 (("\n     ")) ;
+		    }
+		}
+		DEBUG9 (("\n")) ;
+	    }
+	}
+    }
+
+    DEBUG7 (("====================\n")) ;
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_rowcol ====================================================== */
+/* ========================================================================== */
+
+/* dump a row or a column, from one or more memory spaces */
+/* return exact degree */
+
+GLOBAL void UMF_dump_rowcol
+(
+    Int dumpwhich,		/* 0 for row, 1 for column */
+    NumericType *Numeric,
+    WorkType *Work,
+    Int dumpindex,		/* row or column index to dump */
+    Int check_degree	/* true if degree is to be checked */
+)
+{
+    Entry value ;
+    Entry *C ;
+    Int f, nrows, j, jj, len, e, deg, index, n_row, n_col, *Cols, *Rows, nn,
+	dumpdeg, ncols, preve, *E, tpi, *Pattern, approx_deg, not_in_use ;
+    Tuple *tp, *tend ;
+    Element *ep ;
+    Int *Row_tuples, *Row_degree, *Row_tlen ;
+    Int *Col_tuples, *Col_degree, *Col_tlen ;
+    Unit *p ;
+    Int is_there ;
+
+    /* clear the debugging arrays */
+    UMF_DBinit () ;
+
+    if (dumpwhich == 0)
+    {
+	DEBUG7 (("\n====================ROW: "ID, dumpindex)) ;
+    }
+    else
+    {
+	DEBUG7 (("\n====================COL: "ID, dumpindex)) ;
+    }
+
+    if (dumpindex == EMPTY)
+    {
+	DEBUG7 ((" (EMPTY)\n")) ;
+	return ;
+    }
+
+    deg = 0 ;
+    approx_deg = 0 ;
+
+    if (!Numeric || !Work)
+    {
+	DEBUG7 ((" No Numeric, Work\n")) ;
+	return ;
+    }
+
+    n_row = Work->n_row ;
+    n_col = Work->n_col ;
+    nn = MAX (n_row, n_col) ;
+    E = Work->E ;
+
+    Col_degree = Numeric->Cperm ;
+    Row_degree = Numeric->Rperm ;
+
+    Row_tuples = Numeric->Uip ;
+    Row_tlen   = Numeric->Uilen ;
+    Col_tuples = Numeric->Lip ;
+    Col_tlen   = Numeric->Lilen ;
+
+	if (!E
+	|| !Row_tuples || !Row_degree || !Row_tlen
+	|| !Col_tuples || !Col_degree || !Col_tlen)
+	{
+	    DEBUG7 ((" No E, Rows, Cols\n")) ;
+	    return ;
+	}
+
+	if (dumpwhich == 0)
+	{
+	    /* dump a row */
+	    ASSERT (dumpindex >= 0 && dumpindex < n_row) ;
+	    if (!NON_PIVOTAL_ROW (dumpindex))
+	    {
+		DEBUG7 ((" Pivotal\n")) ;
+		return ;
+	    }
+	    len = Row_tlen [dumpindex] ;
+	    dumpdeg = Row_degree [dumpindex] ;
+	    tpi = Row_tuples [dumpindex] ;
+	}
+	else
+	{
+	    /* dump a column */
+	    ASSERT (dumpindex >= 0 && dumpindex < n_col) ;
+	    if (!NON_PIVOTAL_COL (dumpindex))
+	    {
+		DEBUG7 ((" Pivotal\n")) ;
+		return ;
+	    }
+	    len = Col_tlen [dumpindex] ;
+	    dumpdeg = Col_degree [dumpindex] ;
+	    tpi = Col_tuples [dumpindex] ;
+	}
+
+	p = Numeric->Memory + tpi ;
+	tp = (Tuple *) p ;
+	if (!tpi)
+	{
+	    DEBUG7 ((" Nonpivotal, No tuple list tuples "ID" tlen "ID"\n",
+		tpi, len)) ;
+	    return ;
+	}
+	ASSERT (p >= Numeric->Memory + Numeric->itail) ;
+	ASSERT (p <  Numeric->Memory + Numeric->size) ;
+
+	DEBUG7 ((" degree: "ID" len: "ID"\n", dumpdeg, len)) ;
+	not_in_use = (p-1)->header.size - UNITS (Tuple, len) ;
+	DEBUG7 ((" Tuple list: p+1: "ID" size: "ID" units, "ID" not in use\n",
+		(Int) (p-Numeric->Memory), (p-1)->header.size, not_in_use)) ;
+	ASSERT (not_in_use >= 0) ;
+	tend = tp + len ;
+	preve = 0 ;
+	for ( ; tp < tend ; tp++)
+	{
+	    /* row/col of element e, offset is f: */
+	    /* DEBUG8 (("    (tp="ID")\n", tp)) ; */
+	    e = tp->e ;
+	    f = tp->f ;
+	    DEBUG8 (("    (e="ID", f="ID")\n", e, f)) ;
+	    ASSERT (e > 0 && e <= Work->nel) ;
+	    /* dump the pattern and values */
+	    if (E [e])
+	    {
+		p = Numeric->Memory + E [e] ;
+		GET_ELEMENT (ep, p, Cols, Rows, ncols, nrows, C) ;
+		if (dumpwhich == 0)
+		{
+		    Pattern = Cols ;
+		    jj = ep->ncols ;
+		    is_there = Rows [f] >= 0 ;
+		    if (is_there) approx_deg += ep->ncolsleft ;
+		}
+		else
+		{
+		    Pattern = Rows ;
+		    jj = ep->nrows ;
+		    is_there = Cols [f] >= 0 ;
+		    if (is_there) approx_deg += ep->nrowsleft ;
+		}
+		if (!is_there)
+		{
+			DEBUG8 (("\t\tnot present\n")) ;
+		}
+		else
+		{
+		    for (j = 0 ; j < jj ; j++)
+		    {
+			index = Pattern [j] ;
+			value =
+			    C [ (dumpwhich == 0) ? (f+nrows*j) : (j+nrows*f) ] ;
+			if (index >= 0)
+			{
+			    DEBUG8 (("\t\t"ID":", index)) ;
+			    EDEBUG8 (value) ;
+			    DEBUG8 (("\n")) ;
+			    if (dumpwhich == 0)
+			    {
+				/* col must be in the range 0..n_col-1 */
+				ASSERT (index < n_col) ;
+			    }
+			    else
+			    {
+				/* row must be in the range 0..n_row-1 */
+				ASSERT (index < n_row) ;
+			    }
+
+			    if (nn <= UMF_DBMAX)
+			    {
+				if (UMF_DBscatter [index] != UMF_DBflag)
+				{
+				    UMF_DBpacked [deg++] = index ;
+				    UMF_DBscatter [index] = UMF_DBflag ;
+				}
+			    }
+			}
+		    }
+		}
+		/* the (e,f) tuples should be in order of their creation */
+		/* this means that garbage collection will not jumble them */
+		ASSERT (preve < e) ;
+		preve = e ;
+	    }
+	    else
+	    {
+		DEBUG8 (("\t\tdeallocated\n")) ;
+	    }
+	}
+
+    if (nn <= UMF_DBMAX)
+    {
+	if (deg > 0)
+	{
+	    DEBUG7 ((" Assembled, actual deg: "ID" : ", deg)) ;
+	    for (j = 0 ; j < deg ; j++)
+	    {
+		index = UMF_DBpacked [j] ;
+		DEBUG8 ((ID" ", index)) ;
+		if (j % 20 == 19) DEBUG8 (("\n ")) ;
+		ASSERT (UMF_DBscatter [index] == UMF_DBflag) ;
+	    }
+	    DEBUG7 (("\n")) ;
+	}
+    }
+
+    /* Col_degree is not maintained when fixQ is true */
+    if (check_degree)
+    {
+	DEBUG8 (("  approx_deg "ID"  dumpdeg "ID"\n", approx_deg, dumpdeg)) ;
+	ASSERT (approx_deg == dumpdeg) ;
+    }
+
+    DEBUG7 (("====================\n")) ;
+
+    /* deg is now the exact degree */
+    /* if nn <= UMF_DBMAX, then UMF_DBscatter [i] == UMF_DBflag for every i */
+    /* in the row or col, and != UMF_DBflag if not */
+
+    return ;
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_matrix ====================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_matrix
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int check_degree
+)
+{
+
+    Int e, row, col, intfrag, frag, n_row, n_col, *E, fullsize, actualsize ;
+    Element *ep ;
+    Unit *p ;
+
+    DEBUG6 (("=================================================== MATRIX:\n")) ;
+    if (!Numeric || !Work)
+    {
+	DEBUG6 (("No Numeric or Work allocated\n")) ;
+	return ;
+    }
+    if (!Numeric->Memory)
+    {
+	DEBUG6 (("No Numeric->Memory\n")) ;
+	return ;
+    }
+
+	n_row = Work->n_row ;
+	n_col = Work->n_col ;
+	DEBUG6 (("n_row "ID" n_col "ID" nz "ID"\n", n_row, n_col, Work->nz)) ;
+	DEBUG6 (("============================ ELEMENTS: "ID" \n", Work->nel)) ;
+	intfrag = 0 ;
+	E = Work->E ;
+	if (!E)
+	{
+	    DEBUG6 (("No elements allocated\n")) ;
+	}
+	else
+	{
+	    for (e = 0 ; e <= Work->nel ; e++)
+	    {
+		UMF_dump_element (Numeric, Work, e, FALSE) ;
+		if (e > 0 && E [e])
+		{
+		    p = Numeric->Memory + E [e] ;
+		    ep = (Element *) p ;
+		    ASSERT (ep->nrowsleft > 0 || ep->ncolsleft > 0) ;
+		    fullsize = GET_BLOCK_SIZE (p) ;
+		    actualsize = GET_ELEMENT_SIZE (ep->nrowsleft,ep->ncolsleft);
+		    frag =  fullsize - actualsize ;
+		    intfrag += frag ;
+		    DEBUG7 (("dump el: "ID", full "ID" actual "ID" frag: "ID
+			" intfrag: "ID"\n", e, fullsize, actualsize, frag,
+			intfrag)) ;
+		}
+	    }
+	}
+
+	DEBUG6 (("CURRENT INTERNAL FRAG in elements: "ID" \n", intfrag)) ;
+
+
+
+    DEBUG6 (("======================================== ROWS: "ID"\n", n_row)) ;
+    UMF_debug -= 2 ;
+    for (row = 0 ; row < n_row ; row++)
+    {
+	UMF_dump_rowcol (0, Numeric, Work, row, check_degree) ;
+    }
+    UMF_debug += 2 ;
+    DEBUG6 (("======================================== COLS: "ID"\n", n_col)) ;
+    UMF_debug -= 2 ;
+    for (col = 0 ; col < n_col ; col++)
+    {
+	UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+    }
+    UMF_debug += 2 ;
+    DEBUG6 (("============================================= END OF MATRIX:\n"));
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_current_front =============================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_current_front
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int check
+)
+{
+
+    Entry *Flublock, *Flblock, *Fublock, *Fcblock ;
+    Int fnrows_max, fncols_max, fnrows, fncols, fnpiv, *Frows, *Fcols,
+	i, j, *Fcpos, *Frpos, fnr_curr, fnc_curr, *E ;
+    if (!Work) return ;
+    DEBUG7 (("\n\n========CURRENT FRONTAL MATRIX:\n")) ;
+
+    Flublock = Work->Flublock ;
+    Flblock = Work->Flblock ;
+    Fublock = Work->Fublock ;
+    Fcblock = Work->Fcblock ;
+
+    Frows = Work->Frows ;
+    Fcols = Work->Fcols ;
+    Frpos = Work->Frpos ;
+    Fcpos = Work->Fcpos ;
+    fnrows_max = Work->fnrows_max ;
+    fncols_max = Work->fncols_max ;
+    fnr_curr = Work->fnr_curr ;
+    fnc_curr = Work->fnc_curr ;
+    fnrows = Work->fnrows ;
+    fncols = Work->fncols ;
+    fnpiv = Work->fnpiv ;
+    E = Work->E ;
+
+    DEBUG6 (("=== fnpiv= "ID"\n", fnpiv)) ;
+    DEBUG6 (("fnrows_max      fncols_max "ID" "ID"\n",fnrows_max, fncols_max)) ;
+    DEBUG6 (("fnr_curr        fnc_curr   "ID" "ID"\n",fnr_curr,   fnc_curr)) ;
+    DEBUG6 (("fnrows          fncols     "ID" "ID"\n",fnrows,     fncols)) ;
+    ASSERT ((fnr_curr % 2 == 1) || fnr_curr == 0) ;
+    DEBUG6 (("Pivot row pattern:\n")) ;
+    for (j = 0 ; j < fncols ; j++)
+    {
+	DEBUG7 ((ID" "ID" "ID" %d\n", j, Fcols [j], Fcpos [Fcols [j]],
+	    j < fncols)) ;
+	if (check)
+	{
+	    ASSERT (Fcols [j] >= 0 && Fcols [j] < Work->n_col) ;
+	    ASSERT (Fcpos [Fcols [j]] == j * fnr_curr) ;
+	}
+    }
+    DEBUG6 (("Pivot col pattern:\n")) ;
+    for (i = 0 ; i < fnrows ; i++)
+    {
+	DEBUG7 ((ID" "ID" "ID" %d\n", i, Frows [i], Frpos [Frows [i]],
+	    i < fnrows)) ;
+	if (check)
+	{
+	    ASSERT (Frows [i] >= 0 && Frows [i] < Work->n_row) ;
+	    ASSERT (Frpos [Frows [i]] == i) ;
+	}
+    }
+    if (UMF_debug < 7) return ;
+
+    if (!E [0])
+    {
+	DEBUG6 (("current front not allocated\n")) ;
+	ASSERT (!Work->Flublock) ;
+	return ;
+    }
+
+    ASSERT (Work->Flublock == (Entry *) (Numeric->Memory + E [0])) ;
+    DEBUG7 (("C  block: ")) ;
+    UMF_dump_dense (Fcblock,  fnr_curr, fnrows, fncols) ;
+    DEBUG7 (("L  block: ")) ;
+    UMF_dump_dense (Flblock,  fnr_curr, fnrows, fnpiv) ;
+    DEBUG7 (("U' block: ")) ;
+    UMF_dump_dense (Fublock,  fnc_curr, fncols, fnpiv) ;
+    DEBUG7 (("LU block: ")) ;
+    UMF_dump_dense (Flublock, Work->nb, fnpiv, fnpiv) ;
+    if (fnpiv > 0)
+    {
+	DEBUG7 (("Pivot entry: ")) ;
+	EDEBUG7 (Flublock [(fnpiv-1)+(fnpiv-1)*Work->nb]) ;
+	DEBUG7 (("\n")) ;
+    }
+}
+
+/* ========================================================================== */
+/* === UMF_dump_lu ========================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_lu
+(
+    NumericType *Numeric
+)
+{
+    Int i, n_row, n_col, *Cperm, *Rperm ;
+
+    DEBUG6 (("=============================================== LU factors:\n")) ;
+    if (!Numeric)
+    {
+	DEBUG6 (("No LU factors allocated\n")) ;
+	return ;
+    }
+    n_row = Numeric->n_row ;
+    n_col = Numeric->n_col ;
+    DEBUG6 (("n_row: "ID" n_col: "ID"\n", n_row, n_col)) ;
+    DEBUG6 (("nLentries: "ID" nUentries: "ID"\n",
+	Numeric->nLentries, Numeric->nUentries)) ;
+
+    if (Numeric->Cperm)
+    {
+	Cperm = Numeric->Cperm ;
+	DEBUG7 (("Column permutations: (new: old)\n")) ;
+	for (i = 0 ; i < n_col ; i++)
+	{
+	    if (Cperm [i] != EMPTY)
+	    {
+		DEBUG7 ((ID": "ID"\n", i, Cperm [i])) ;
+	    }
+	}
+    }
+    else
+    {
+	DEBUG7 (("No Numeric->Cperm allocatated\n")) ;
+    }
+
+    if (Numeric->Rperm)
+    {
+	Rperm = Numeric->Rperm ;
+	DEBUG7 (("row permutations: (new: old)\n")) ;
+	for (i = 0 ; i < n_row ; i++)
+	{
+	    if (Rperm [i] != EMPTY)
+	    {
+		DEBUG7 ((ID": "ID"\n", i, Rperm [i])) ;
+	    }
+	}
+    }
+    else
+    {
+	DEBUG7 (("No Numeric->Rperm allocatated\n")) ;
+    }
+
+    DEBUG6 (("========================================= END OF LU factors:\n"));
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_memory ====================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_memory
+(
+    NumericType *Numeric
+)
+{
+
+    Unit *p ;
+    Int prevsize, s ;
+    Int found ;
+
+    if (!Numeric)
+    {
+	DEBUG6 (("No memory space S allocated\n")) ;
+	return ;
+    }
+
+    DEBUG6 (("\n ============================================== MEMORY:\n")) ;
+    if (!Numeric || !Numeric->Memory)
+    {
+	DEBUG6 (("No memory space Numeric allocated\n")) ;
+	return ;
+    }
+
+    DEBUG6 (("S: "ID"\n", (Int) Numeric)) ;
+    DEBUG6 (("S->ihead           : "ID"\n", Numeric->ihead)) ;
+    DEBUG6 (("S->itail           : "ID"\n", Numeric->itail)) ;
+    DEBUG6 (("S->size            : "ID"\n", Numeric->size)) ;
+    DEBUG6 (("S->ngarbage        : "ID"\n", Numeric->ngarbage)) ;
+    DEBUG6 (("S->nrealloc        : "ID"\n", Numeric->nrealloc)) ;
+    DEBUG6 (("   in use at head           : "ID"\n", Numeric->ihead)) ;
+    DEBUG6 (("   free space               : "ID"\n",
+	Numeric->itail - Numeric->ihead)) ;
+    DEBUG6 (("   blocks in use at tail    : "ID"\n",
+	Numeric->size - Numeric->itail)) ;
+    DEBUG6 (("   total in use             : "ID"\n",
+	Numeric->size - (Numeric->itail - Numeric->ihead))) ;
+
+    prevsize = 0 ;
+    found = FALSE ;
+
+    ASSERT (0 <= Numeric->ihead) ;
+    ASSERT (Numeric->ihead <= Numeric->itail) ;
+    ASSERT (Numeric->itail <= Numeric->size) ;
+
+    p = Numeric->Memory + Numeric->itail ;
+
+    while (p < Numeric->Memory + Numeric->size)
+    {
+	DEBUG8 (("p: "ID" p+1: "ID" prevsize: "ID" size: "ID,
+	    (Int) (p-Numeric->Memory), (Int) (p+1-Numeric->Memory),
+	    p->header.prevsize, p->header.size)) ;
+	if (p->header.size < 0)
+	{
+	    DEBUG8 ((" free")) ;
+	}
+
+	if (p == Numeric->Memory + Numeric->itail)
+	{
+	    ASSERT (p->header.prevsize == 0) ;
+	}
+	else
+	{
+	    ASSERT (p->header.prevsize > 0) ;
+	}
+
+	ASSERT (p->header.size != 0) ;
+	s = prevsize >= 0 ? prevsize : -prevsize ;
+	ASSERT (p->header.prevsize == s) ;
+	/* no adjacent free blocks */
+	ASSERT (p->header.size > 0 || prevsize > 0) ;
+	if (Numeric->ibig != EMPTY)
+	{
+	    if (p == Numeric->Memory + Numeric->ibig)
+	    {
+		ASSERT (p->header.size < 0) ;
+		DEBUG8 ((" <===== Numeric->ibig")) ;
+		found = TRUE ;
+	    }
+	}
+	s = p->header.size ;
+	prevsize = s ;
+	s = s >= 0 ? s : -s ;
+	p = p + 1 + s ;
+	DEBUG8 (("\n")) ;
+    }
+
+    ASSERT (p == Numeric->Memory + Numeric->size) ;
+    ASSERT (IMPLIES (Numeric->ibig != EMPTY, found)) ;
+    DEBUG6 (("============================================= END OF MEMORY:\n"));
+
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_packed_memory =============================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_packed_memory
+(
+    NumericType *Numeric,
+    WorkType *Work
+)
+{
+    Unit *p, *p3 ;
+    Int prevsize, col, row, *Rows, *Cols, ncols, nrows, k, esize,
+	*Row_tuples, *Row_degree, *Col_tuples, *Col_degree ;
+    Entry *C ;
+    Element *ep ;
+
+    Col_degree = Numeric->Cperm ;	/* for NON_PIVOTAL_COL macro */
+    Row_degree = Numeric->Rperm ;	/* for NON_PIVOTAL_ROW macro */
+    Row_tuples = Numeric->Uip ;
+    Col_tuples = Numeric->Lip ;
+
+    DEBUG6 (("============================================ PACKED MEMORY:\n")) ;
+    if (!Numeric || !Numeric->Memory)
+    {
+	DEBUG6 (("No memory space S allocated\n")) ;
+	return ;
+    }
+    DEBUG6 (("S: "ID"\n", (Int) Numeric)) ;
+    DEBUG6 (("S->ihead           : "ID"\n", Numeric->ihead)) ;
+    DEBUG6 (("S->itail           : "ID"\n", Numeric->itail)) ;
+    DEBUG6 (("S->size            : "ID"\n", Numeric->size)) ;
+    DEBUG6 (("S->ngarbage        : "ID"\n", Numeric->ngarbage)) ;
+    DEBUG6 (("S->nrealloc        : "ID"\n", Numeric->nrealloc)) ;
+    DEBUG6 (("   in use at head           : "ID"\n", Numeric->ihead)) ;
+    DEBUG6 (("   free space               : "ID"\n",
+	Numeric->itail - Numeric->ihead)) ;
+    DEBUG6 (("   blocks in use at tail    : "ID"\n",
+	Numeric->size - Numeric->itail)) ;
+    DEBUG6 (("   total in use             : "ID"\n",
+	Numeric->size - (Numeric->itail - Numeric->ihead))) ;
+
+    ASSERT (0 <= Numeric->ihead) ;
+    ASSERT (Numeric->ihead <= Numeric->itail) ;
+    ASSERT (Numeric->itail <= Numeric->size) ;
+
+    for (row = 0 ; row < Work->n_row ; row++)
+    {
+	ASSERT (IMPLIES (NON_PIVOTAL_ROW (row), !Row_tuples [row])) ;
+    }
+    for (col = 0 ; col < Work->n_col ; col++)
+    {
+	ASSERT (IMPLIES (NON_PIVOTAL_COL (col), !Col_tuples [col])) ;
+    }
+
+    prevsize = 0 ;
+    p = Numeric->Memory + Numeric->itail ;
+    while (p < Numeric->Memory + Numeric->size)
+    {
+	DEBUG9 (("====================\n")) ;
+	DEBUG7 (("p: "ID" p+1: "ID" prevsize: "ID" size: "ID"\n",
+	    (Int) (p-Numeric->Memory), (Int) (p+1-Numeric->Memory),
+	    p->header.prevsize, p->header.size)) ;
+	ASSERT (p->header.size > 0) ;
+
+	if (p == Numeric->Memory + Numeric->itail)
+	{
+	    ASSERT (p->header.prevsize == 0) ;
+	}
+	else
+	{
+	    ASSERT (p->header.prevsize > 0) ;
+	}
+
+	ASSERT (p->header.prevsize == prevsize) ;
+	prevsize = p->header.size ;
+
+	if (p != Numeric->Memory + Numeric->size - 2)
+	{
+
+	    p3 = p + 1 ;
+	    if (p3 == Numeric->Memory + Work->E [0])
+	    {
+		/* this is the current frontal matrix */
+		UMF_dump_current_front (Numeric, Work, FALSE) ;
+	    }
+	    else
+	    {
+
+		/* this is a packed element */
+		GET_ELEMENT (ep, p3, Cols, Rows, ncols, nrows, C) ;
+		DEBUG9 (("ep "ID"\n nrows "ID" ncols "ID"\n",
+		    (Int) ((p+1)-Numeric->Memory), ep->nrows, ep->ncols)) ;
+		DEBUG9 (("rows:")) ;
+		for (k = 0 ; k < ep->nrows; k++)
+		{
+		    row = Rows [k] ;
+		    DEBUG9 ((" "ID, row)) ;
+		    ASSERT (row >= 0 && row <= Work->n_row) ;
+		    if ((k % 10) == 9) DEBUG9 (("\n")) ;
+		}
+		DEBUG9 (("\ncols:")) ;
+		for (k = 0 ; k < ep->ncols; k++)
+		{
+		    col = Cols [k] ;
+		    DEBUG9 ((" "ID, col)) ;
+		    ASSERT (col >= 0 && col <= Work->n_col) ;
+		    if ((k % 10) == 9) DEBUG9 (("\n")) ;
+		}
+		DEBUG9 (("\nvalues: ")) ;
+		if (UMF_debug >= 9)
+		{
+		    UMF_dump_dense (C, ep->nrows, ep->nrows, ep->ncols) ;
+		}
+		esize = GET_ELEMENT_SIZE (ep->nrows, ep->ncols) ;
+		DEBUG9 (("esize: "ID"\n", esize)) ;
+		ASSERT (esize <= p->header.size) ;
+	    }
+
+	}
+	else
+	{
+	    /* this is the final marker block */
+	    ASSERT (p->header.size == 1) ;
+	}
+	p = p + 1 + p->header.size ;
+    }
+
+    ASSERT (Numeric->ibig == EMPTY) ;
+    ASSERT (p == Numeric->Memory + Numeric->size) ;
+    DEBUG6 (("======================================END OF PACKED MEMORY:\n")) ;
+
+}
+
+/* ========================================================================== */
+/* === UMF_dump_col_matrix ================================================== */
+/* ========================================================================== */
+
+/* This code is the same for real or complex matrices. */
+
+GLOBAL void UMF_dump_col_matrix
+(
+    const double Ax [ ],	/* Ax [0..nz-1]: real values, in column order */
+#ifdef COMPLEX
+    const double Az [ ],	/* Az [0..nz-1]: imag values, in column order */
+#endif
+    const Int Ai [ ],		/* Ai [0..nz-1]: row indices, in column order */
+    const Int Ap [ ],		/* Ap [0..n_col]: column pointers */
+    Int n_row,			/* number of rows of A */
+    Int n_col,			/* number of columns of A */
+    Int nz			/* number of entries */
+)
+{
+    Int col, p, p1, p2, row ;
+#ifdef COMPLEX
+    Int split = SPLIT (Az) ;
+#endif
+
+    if (!Ai || !Ap) return ;
+    DEBUG6 (("============================================ COLUMN FORM:\n")) ;
+
+    ASSERT (n_col >= 0) ;
+    nz = Ap [n_col] ;
+    DEBUG2 (("UMF_dump_col:  nz "ID"\n", nz)) ;
+    DEBUG2 (("n_row "ID"  \n", n_row)) ;
+    DEBUG2 (("n_col "ID"  \n", n_col)) ;
+
+    DEBUG6 ((" n_row = "ID", n_col ="ID" nz = "ID" Ap [0] "ID", Ap [n] "ID"\n",
+	n_row, n_col, nz, Ap [0], Ap [n_col])) ;
+    ASSERT (Ap [0] == 0) ;
+    ASSERT (Ap [n_col] == nz) ;
+    for (col = 0 ; col < n_col ; col++)
+    {
+	p1 = Ap [col] ;
+	p2 = Ap [col+1] ;
+	DEBUG6 (("col: "ID", length "ID"\n", col, p2 - p1)) ;
+	ASSERT (p2 >= p1) ;
+	for (p = p1 ; p < p2 ; p++)
+	{
+	    row = Ai [p] ;
+	    ASSERT (row >= 0 && row < n_row) ;
+	    DEBUG6 (("\t"ID" ", row)) ;
+	    if (Ax != (double *) NULL)
+	    {
+#ifdef COMPLEX
+		if (split)
+		{
+		    DEBUG6 ((" (%e+%ei) ", Ax [p], Az [p])) ;
+		}
+		else
+		{
+		    DEBUG6 ((" (%e+%ei) ", Ax [2*p], Ax [2*p+1])) ;
+		}
+#else
+		DEBUG6 ((" %e", Ax [p])) ;
+#endif
+	    }
+	    DEBUG6 (("\n")) ;
+	}
+    }
+    DEBUG6 (("========================================== COLUMN FORM done\n")) ;
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_chain ======================================================= */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_chain
+(
+    Int frontid,
+    Int Front_parent [ ],
+    Int Front_npivcol [ ],
+    Int Front_nrows [ ],
+    Int Front_ncols [ ],
+    Int nfr
+)
+{
+    Int i, len = 0 ;
+
+    /* print a list of contiguous parents */
+    i = frontid ;
+    ASSERT (Front_parent [i] == EMPTY ||
+	(Front_parent [i] > i && Front_parent [i] < nfr)) ;
+
+    len++ ;
+    DEBUG3 (("Chain:\n	"ID" ["ID","ID"]("ID"-by-"ID")\n", i,
+		Front_npivcol [i],
+		MIN (Front_npivcol [i], Front_nrows [i]),
+		Front_nrows [i],
+		Front_ncols [i])) ;
+
+    for (i = frontid ; i < nfr ; i++)
+    {
+	ASSERT (Front_parent [i] == EMPTY ||
+	(Front_parent [i] > i && Front_parent [i] < nfr)) ;
+	if (Front_parent [i] == i+1)
+	{
+	    len++ ;
+	    DEBUG3 (("\t"ID" ["ID","ID"]("ID"-by-"ID")\n", i+1,
+		Front_npivcol [i+1],
+		MIN (Front_npivcol [i+1], Front_nrows [i+1]),
+		Front_nrows [i+1],
+		Front_ncols [i+1])) ;
+	}
+	else
+	{
+	    DEBUG2 (("Length of chain: "ID"\n", len)) ;
+	    return ;
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_start ======================================================= */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_start
+(
+    void
+)
+{
+    FILE *ff ;
+
+    AMD_debug_init ("from umfpack") ;
+
+    /* get the debug print level from the "debug.umf" file, if it exists */
+    UMF_debug = -999 ;
+    ff = fopen ("debug.umf", "r") ;
+    if (ff)
+    {
+	(void) fscanf (ff, ID, &UMF_debug) ;
+	(void) fclose (ff) ;
+    }
+
+    DEBUG0 (("umfpack: debug version (SLOW!) ")) ;
+
+    DEBUG0 ((" MATLAB: ")) ;
+#ifdef MATLAB_MEX_FILE
+    DEBUG0 (("mexFunction.\n")) ;
+#else
+#ifdef MATHWORKS
+    DEBUG0 (("yes.\n")) ;
+#else
+    DEBUG0 (("no.\n")) ;
+#endif
+#endif
+
+    UMF_gprob = -1.0 ;
+    ff = fopen ("gprob.umf", "r") ;
+    if (ff)
+    {
+	(void) fscanf (ff, "%lg", &UMF_gprob) ;
+	(void) fclose (ff) ;
+	srand (1) ;	/* restart the random number generator */
+    }
+
+    if (UMF_gprob > 1.0) UMF_gprob = 1.0 ;
+    DEBUG1 (("factor: UMF_gprob: %e UMF_debug "ID"\n", UMF_gprob, UMF_debug)) ;
+
+    DEBUG2 (("sizeof: (bytes / int / Units) \n")) ;
+    DEBUG2 (("sizeof (Int)           %u %u %u\n",
+    sizeof (Int), sizeof (Int) / sizeof (int), UNITS (Int, 1) )) ;
+    DEBUG2 (("sizeof (int)           %u %u %u\n",
+    sizeof (int), sizeof (int) / sizeof (int), UNITS (int, 1) )) ;
+    DEBUG2 (("sizeof (size_t)        %u %u %u\n",
+    sizeof (size_t), sizeof (size_t) / sizeof (size_t), UNITS (size_t, 1) )) ;
+    DEBUG2 (("sizeof (UF_long)       %u %u %u\n",
+    sizeof (UF_long), sizeof (UF_long) / sizeof (UF_long), UNITS (UF_long, 1)));
+    DEBUG2 (("sizeof (double)        %u %u %u\n",
+    sizeof (double), sizeof (double) / sizeof (int), UNITS (double, 1) )) ;
+    DEBUG2 (("sizeof (Unit)          %u %u %u\n",
+    sizeof (Unit), sizeof (Unit) / sizeof (int), UNITS (Unit, 1) )) ;
+    DEBUG2 (("sizeof (Entry)         %u %u %u\n",
+    sizeof (Entry), sizeof (Entry) / sizeof (int), UNITS (Entry, 1) )) ;
+    DEBUG2 (("sizeof (Tuple)         %u %u %u\n",
+    sizeof (Tuple), sizeof (Tuple) / sizeof (int), UNITS (Tuple, 1) )) ;
+    DEBUG2 (("sizeof (Tuple *)       %u %u %u\n",
+    sizeof (Tuple *), sizeof (Tuple *) / sizeof (int), UNITS (Tuple *, 1) )) ;
+    DEBUG2 (("sizeof (Element)       %u %u %u\n",
+    sizeof (Element), sizeof (Element) / sizeof (int), UNITS (Element, 1) )) ;
+    DEBUG2 (("sizeof (Element *)     %u %u %u\n",
+    sizeof (Element *), sizeof (Element *) / sizeof (int),
+    UNITS (Element *, 1) )) ;
+    DEBUG2 (("sizeof (WorkType)      %u %u %u\n",
+    sizeof (WorkType), sizeof (WorkType) / sizeof (int),
+    UNITS (WorkType, 1) )) ;
+    DEBUG2 (("sizeof (NumericType)   %u %u %u\n",
+    sizeof (NumericType), sizeof (NumericType) / sizeof (int),
+    UNITS (NumericType, 1) )) ;
+    DEBUG2 (("sizeof (SymbolicType)  %u %u %u\n",
+    sizeof (SymbolicType), sizeof (SymbolicType) / sizeof (int),
+    UNITS (SymbolicType, 1) )) ;
+
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_rowmerge ==================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_rowmerge
+(
+    NumericType *Numeric,
+    SymbolicType *Symbolic,
+    WorkType *Work
+)
+{
+    Int *Front_leftmostdesc, *Front_1strow, *Front_new1strow, row1, row2,
+	fleftmost, nfr, n_row, *Row_degree, i, frontid, row ;
+
+    nfr = Symbolic->nfr ;
+    DEBUG3 (("\n================== Row merge sets: nfr "ID"\n", nfr)) ;
+    Front_leftmostdesc = Symbolic->Front_leftmostdesc ;
+    Front_1strow = Symbolic->Front_1strow ;
+    Front_new1strow = Work->Front_new1strow ;
+    n_row = Symbolic->n_row ;
+    Row_degree = Numeric->Rperm ;
+    frontid = Work->frontid ;
+
+    for (i = frontid ; i <= nfr ; i++)
+    {
+	DEBUG3 (("----------------------\n")) ;
+	if (i == nfr) DEBUG3 (("Dummy: ")) ;
+	DEBUG3 (("Front "ID" 1strow "ID" new1strow "ID" leftmostdesc "ID,
+	    i, Front_1strow [i], Front_new1strow [i], Front_leftmostdesc [i])) ;
+	DEBUG3 ((" parent "ID" pivcol "ID"\n", Symbolic->Front_parent [i],
+	    Symbolic->Front_npivcol [i])) ;
+
+	if (i == nfr)
+	{
+	    fleftmost = -1 ;
+	    row1 = Front_new1strow [i] ;
+	    row2 = n_row-1 ;
+	}
+	else
+	{
+	    fleftmost = Front_leftmostdesc [i] ;
+	    row1 = Front_new1strow [fleftmost] ;
+	    row2 = Front_1strow [i+1] - 1 ;
+	}
+	DEBUG3 (("Leftmost: "ID"  Rows ["ID" to "ID"], search ["ID" to "ID"]\n",
+	    fleftmost, Front_1strow [i], row2, row1, row2)) ;
+
+	for (row = row1 ; row <= row2 ; row++)
+	{
+	    ASSERT (row >= 0 && row < n_row) ;
+	    DEBUG3 (("   Row "ID" live: %d\n", row, NON_PIVOTAL_ROW (row))) ;
+	}
+    }
+}
+
+/* ========================================================================== */
+/* === UMF_dump_diagonal_map ================================================ */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_diagonal_map
+(
+    Int Diagonal_map [ ],
+    Int Diagonal_imap [ ],
+    Int 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 */
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_dump.h b/src/C/SuiteSparse/UMFPACK/Source/umf_dump.h
new file mode 100644
index 0000000..2e0e512
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_dump.h
@@ -0,0 +1,191 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* umf_dump.h: debugging definitions. */
+
+#ifndef NDEBUG
+
+GLOBAL void UMF_dump_dense
+(
+    Entry *C,
+    Int dim,
+    Int m,
+    Int n
+) ;
+
+GLOBAL void UMF_dump_element
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int e,
+    Int clean
+) ;
+
+GLOBAL void UMF_dump_rowcol
+(
+    Int dump_which,
+    NumericType *Numeric,
+    WorkType *Work,
+    Int dump_index,
+    Int check_degree
+) ;
+
+GLOBAL void UMF_dump_matrix
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int check_degree
+) ;
+
+GLOBAL void UMF_dump_current_front
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int check
+) ;
+
+GLOBAL void UMF_dump_lu
+(
+    NumericType *Numeric
+) ;
+
+GLOBAL void UMF_dump_memory
+(
+    NumericType *Numeric
+) ;
+
+GLOBAL void UMF_dump_packed_memory
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
+
+GLOBAL void UMF_dump_col_matrix
+(
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    const Int Ai [ ],
+    const Int Ap [ ],
+    Int n_row,
+    Int n_col,
+    Int nz
+) ;
+
+GLOBAL void UMF_dump_chain
+(
+    Int frontid,
+    Int Front_parent [ ],
+    Int Front_npivcol [ ],
+    Int Front_nrows [ ],
+    Int Front_ncols [ ],
+    Int nfr
+) ;
+
+GLOBAL void UMF_dump_rowmerge
+(
+    NumericType *Numeric,
+    SymbolicType *Symbolic,
+    WorkType *Work
+) ;
+
+GLOBAL void UMF_dump_start
+(
+    void
+) ;
+
+
+GLOBAL void UMF_dump_diagonal_map
+(
+    Int Diagonal_map [ ],
+    Int Diagonal_imap [ ],
+    Int n1,
+    Int nn,
+    Int nempty
+) ;
+
+#define UMF_DBMAX 50000
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+GLOBAL EXTERN Int UMF_debug ;
+GLOBAL EXTERN Int UMF_allocfail ;
+GLOBAL EXTERN double UMF_gprob ;
+
+#define DEBUGk(k,params) { if (UMF_debug >= (k)) { PRINTF (params) ; } }
+
+#define DEBUGm4(params) DEBUGk (-4, params)
+#define DEBUGm3(params) DEBUGk (-3, params)
+#define DEBUGm2(params) DEBUGk (-2, params)
+#define DEBUGm1(params) DEBUGk (-1, params)
+#define DEBUG0(params) DEBUGk (0, params)
+#define DEBUG1(params) DEBUGk (1, params)
+#define DEBUG2(params) DEBUGk (2, params)
+#define DEBUG3(params) DEBUGk (3, params)
+#define DEBUG4(params) DEBUGk (4, params)
+#define DEBUG5(params) DEBUGk (5, params)
+#define DEBUG6(params) DEBUGk (6, params)
+#define DEBUG7(params) DEBUGk (7, params)
+#define DEBUG8(params) DEBUGk (8, params)
+#define DEBUG9(params) DEBUGk (9, params)
+
+#define EDEBUGk(k,a) { if (UMF_debug >= (k)) { PRINT_ENTRY (a) ; } }
+
+#define EDEBUG0(a) EDEBUGk (0, a)
+#define EDEBUG1(a) EDEBUGk (1, a)
+#define EDEBUG2(a) EDEBUGk (2, a)
+#define EDEBUG3(a) EDEBUGk (3, a)
+#define EDEBUG4(a) EDEBUGk (4, a)
+#define EDEBUG5(a) EDEBUGk (5, a)
+#define EDEBUG6(a) EDEBUGk (6, a)
+#define EDEBUG7(a) EDEBUGk (7, a)
+#define EDEBUG8(a) EDEBUGk (8, a)
+#define EDEBUG9(a) EDEBUGk (9, a)
+
+/* ASSERT defined in amd_dump.h */
+
+#else
+
+/* ========================================================================== */
+/* === No debugging ========================================================= */
+/* ========================================================================== */
+
+/* turn off all debugging macros */
+
+#define DEBUGk(k,params)
+
+#define DEBUGm4(params)
+#define DEBUGm3(params)
+#define DEBUGm2(params)
+#define DEBUGm1(params)
+#define DEBUG0(params)
+#define DEBUG1(params)
+#define DEBUG2(params)
+#define DEBUG3(params)
+#define DEBUG4(params)
+#define DEBUG5(params)
+#define DEBUG6(params)
+#define DEBUG7(params)
+#define DEBUG8(params)
+#define DEBUG9(params)
+
+#define EDEBUGk(k,a)
+
+#define EDEBUG0(a)
+#define EDEBUG1(a)
+#define EDEBUG2(a)
+#define EDEBUG3(a)
+#define EDEBUG4(a)
+#define EDEBUG5(a)
+#define EDEBUG6(a)
+#define EDEBUG7(a)
+#define EDEBUG8(a)
+#define EDEBUG9(a)
+
+#endif /* NDEBUG */
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_extend_front.c b/src/C/SuiteSparse/UMFPACK/Source/umf_extend_front.c
new file mode 100644
index 0000000..ee17d7f
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_extend_front.c
@@ -0,0 +1,392 @@
+/* ========================================================================== */
+/* === UMF_extend_front ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Called by kernel. */
+
+#include "umf_internal.h"
+#include "umf_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) ;
+
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_extend_front.h b/src/C/SuiteSparse/UMFPACK/Source/umf_extend_front.h
new file mode 100644
index 0000000..cfb284e
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_extend_front.h
@@ -0,0 +1,11 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_extend_front
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_free.c b/src/C/SuiteSparse/UMFPACK/Source/umf_free.c
new file mode 100644
index 0000000..864d3d6
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_free.c
@@ -0,0 +1,45 @@
+/* ========================================================================== */
+/* === UMF_free ============================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Free a block previously allocated by UMF_malloc and return NULL.
+    Usage is p = UMF_free (p), to ensure that we don't free it twice.
+    Also maintains the UMFPACK malloc count.
+*/
+
+#include "umf_internal.h"
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+#include "umf_malloc.h"
+#endif
+
+GLOBAL void *UMF_free
+(
+    void *p
+)
+{
+    DEBUG0 (("UMF_free: "ID"\n", (Int) p)) ;
+    if (p)
+    {
+
+	/* see AMD/Source/amd_global.c for the memory allocator selection */
+	amd_free (p) ;
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+	/* One more object has been free'd.  Keep track of the count. */
+	/* (purely for sanity checks). */
+	UMF_malloc_count-- ;
+	DEBUG0 (("     new malloc count: "ID"\n", UMF_malloc_count)) ;
+#endif
+
+    }
+
+    return ((void *) NULL) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_free.h b/src/C/SuiteSparse/UMFPACK/Source/umf_free.h
new file mode 100644
index 0000000..045e40b
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_free.h
@@ -0,0 +1,10 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void *UMF_free
+(
+    void *p
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_fsize.c b/src/C/SuiteSparse/UMFPACK/Source/umf_fsize.c
new file mode 100644
index 0000000..6411bf9
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_fsize.c
@@ -0,0 +1,69 @@
+/* ========================================================================== */
+/* === UMF_fsize ============================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Determine the largest frontal matrix size for each subtree.   Called by
+ * UMF_colamd and UMF_analyze.  Only required to sort the children of each
+ * node prior to AMD_postorder. */
+
+#include "umf_internal.h"
+
+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]));
+	    }
+	}
+    }
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_fsize.h b/src/C/SuiteSparse/UMFPACK/Source/umf_fsize.h
new file mode 100644
index 0000000..27601be
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_fsize.h
@@ -0,0 +1,15 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_fsize
+(
+    Int nn,
+    Int MaxFsize [ ],
+    Int Fnrows [ ],
+    Int Fncols [ ],
+    Int Parent [ ],
+    Int Npiv [ ]
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_garbage_collection.c b/src/C/SuiteSparse/UMFPACK/Source/umf_garbage_collection.c
new file mode 100644
index 0000000..15e7163
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_garbage_collection.c
@@ -0,0 +1,695 @@
+/* ========================================================================== */
+/* === UMF_garbage_collection =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Compress the elements at the tail of Numeric->Memory, and delete the tuples.
+    Elements are renumbered.  The new numbering space is compressed, and
+    in the order of element creation (original elements of A first, followed
+    by the new elements in the order that they were formed).
+
+    Only called by UMF_get_memory.
+
+    There are 5 ways in which garbage collection can be performed:
+
+	Allocate a new working array for the current frontal matrix.  In this
+	case, there are never any pivot rows/columns in the current frontal
+	matrix (fnpiv = 0), and the old working array for the current frontal
+	matrix can always be fully compacted, to fnrows-by-fncols.
+
+	    UMF_kernel : UMF_extend : UMF_grow_front : UMF_get_memory
+	    UMF_kernel : UMF_init_front : UMF_grow_front : UMF_get_memory
+	    UMF_kernel : UMF_start_front : UMF_grow_front : UMF_get_memory
+
+	Allocate a new element.  In this case, UMF_grow_front may or may not
+	be subsequently called, depending on Work->do_grow.  There are never
+	any pivot rows/columns in the current frontal matrix (fnpiv=0), but one
+	may be added if UMF_init_front is to be called just after
+	UMF_create_element.  If do_grow is true, then the current front can be
+	fully compacted, to fnrows-by-fncols.  Otherwise, it can only be
+	partially compacted, to MAX (fnrows, fnrows_new + 1) -by-
+	MAX (fncols, fncols_new + 1).
+
+	    UMF_kernel : UMF_create_element : UMF_get_memory
+
+	Allocate rows of L and columns of U.  In this case, the current
+	frontal matrix is only partially compacted, to (fnrows_new + 1)-by-
+	(fncols_new + 1).  There are pivots in the frontal matrix (fnpiv > 0).
+
+	    UMF_kernel : UMF_store_lu : UMF_get_memory
+*/
+
+#include "umf_internal.h"
+
+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")) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_garbage_collection.h b/src/C/SuiteSparse/UMFPACK/Source/umf_garbage_collection.h
new file mode 100644
index 0000000..69d25d9
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_garbage_collection.h
@@ -0,0 +1,14 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_garbage_collection
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int drnew,
+    Int dcnew,
+    Int do_Fcpos
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_get_memory.c b/src/C/SuiteSparse/UMFPACK/Source/umf_get_memory.c
new file mode 100644
index 0000000..bbef6be
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_get_memory.c
@@ -0,0 +1,222 @@
+/* ========================================================================== */
+/* === UMF_get_memory ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Reallocate the workspace (Numeric->Memory) and shift elements downwards.
+    needunits: increase in size so that the free space is at least this many
+    Units (to which the tuple lengths is added).
+
+    Return TRUE if successful, FALSE if out of memory.
+*/
+
+#include "umf_internal.h"
+#include "umf_garbage_collection.h"
+#include "umf_tuple_lengths.h"
+#include "umf_build_tuples.h"
+#include "umf_mem_free_tail_block.h"
+#include "umf_realloc.h"
+
+GLOBAL Int UMF_get_memory
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int needunits,
+    Int r2,		/* compact current front to r2-by-c2 */
+    Int c2,
+    Int do_Fcpos
+)
+{
+    double nsize, bsize, tsize ;
+    Int i, minsize, newsize, newmem, costly, row, col, *Row_tlen, *Col_tlen,
+	n_row, n_col, *Row_degree, *Col_degree ;
+    Unit *mnew, *p ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get and check parameters */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    DEBUG1 (("::::GET MEMORY::::\n")) ;
+    UMF_dump_memory (Numeric) ;
+#endif
+
+    n_row = Work->n_row ;
+    n_col = Work->n_col ;
+    Row_degree = Numeric->Rperm ;	/* for NON_PIVOTAL_ROW macro */
+    Col_degree = Numeric->Cperm ;	/* for NON_PIVOTAL_COL macro */
+    Row_tlen   = Numeric->Uilen ;
+    Col_tlen   = Numeric->Lilen ;
+
+    /* ---------------------------------------------------------------------- */
+    /* initialize the tuple list lengths */
+    /* ---------------------------------------------------------------------- */
+
+    for (row = 0 ; row < n_row ; row++)
+    {
+	if (NON_PIVOTAL_ROW (row))
+	{
+	    Row_tlen [row] = 0 ;
+	}
+    }
+    for (col = 0 ; col < n_col ; col++)
+    {
+	if (NON_PIVOTAL_COL (col))
+	{
+	    Col_tlen [col] = 0 ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* determine how much memory is needed for the tuples */
+    /* ---------------------------------------------------------------------- */
+
+    nsize = (double) needunits + 2 ;
+    needunits += UMF_tuple_lengths (Numeric, Work, &tsize) ;
+    nsize += tsize ;
+    needunits += 2 ;	/* add 2, so that newmem >= 2 is true if realloc'd */
+
+    /* note: Col_tlen and Row_tlen are updated, but the tuple lists */
+    /* themselves are not.  Do not attempt to scan the tuple lists. */
+    /* They are now stale, and are about to be destroyed and recreated. */
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the desired new size of memory */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG0 (("UMF_get_memory: needunits: "ID"\n", needunits)) ;
+
+    minsize = Numeric->size + needunits ;
+    nsize += (double) Numeric->size ;
+
+    bsize = ((double) Int_MAX) / sizeof (Unit) - 1 ;
+
+    newsize = (Int) (UMF_REALLOC_INCREASE * ((double) minsize)) ;
+    nsize *= UMF_REALLOC_INCREASE ;
+    nsize += 1 ;
+
+    if (newsize < 0 || nsize > bsize)
+    {
+	/* :: realloc Numeric->Memory int overflow :: */
+	DEBUGm3 (("Realloc hit integer limit\n")) ;
+	newsize = (Int) bsize ;	/* we cannot increase the size beyond bsize */
+    }
+    else
+    {
+	ASSERT (newsize <= nsize) ;
+	newsize = MAX (newsize, minsize) ;
+    }
+    newsize = MAX (newsize, Numeric->size) ;
+
+    DEBUG0 ((
+    "REALLOC MEMORY: needunits "ID" old size: "ID" new size: "ID" Units \n",
+	needunits, Numeric->size, newsize)) ;
+
+    /* Forget where the biggest free block is (we no longer need it) */
+    /* since garbage collection will occur shortly. */
+    Numeric->ibig = EMPTY ;
+
+    DEBUG0 (("Before realloc E [0] "ID"\n", Work->E [0])) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* reallocate the memory, if possible, and make it bigger */
+    /* ---------------------------------------------------------------------- */
+
+    mnew = (Unit *) NULL ;
+    while (!mnew)
+    {
+	mnew = (Unit *) UMF_realloc (Numeric->Memory, newsize, sizeof (Unit)) ;
+	if (!mnew)
+	{
+	    if (newsize == minsize)	/* last realloc attempt failed */
+	    {
+		/* We failed to get the minimum.  Just stick with the */
+		/* current allocation and hope that garbage collection */
+		/* can recover enough space. */
+		mnew = Numeric->Memory ;	/* no new memory available */
+		newsize = Numeric->size ;
+	    }
+	    else
+	    {
+		/* otherwise, reduce the request and keep trying */
+		newsize = (Int) (UMF_REALLOC_REDUCTION * ((double) newsize)) ;
+		newsize = MAX (minsize, newsize) ;
+	    }
+	}
+    }
+    ASSERT (mnew != (Unit *) NULL) ;
+
+    /* see if realloc had to copy, rather than just extend memory */
+    costly = (mnew != Numeric->Memory) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* extend the tail portion of memory downwards */
+    /* ---------------------------------------------------------------------- */
+
+    Numeric->Memory = mnew ;
+    if (Work->E [0])
+    {
+	Int nb, dr, dc ;
+	nb = Work->nb ;
+	dr = Work->fnr_curr ;
+	dc = Work->fnc_curr ;
+	Work->Flublock = (Entry *) (Numeric->Memory + Work->E [0]) ;
+	Work->Flblock  = Work->Flublock + nb * nb ;
+	Work->Fublock  = Work->Flblock  + dr * nb ;
+	Work->Fcblock  = Work->Fublock  + nb * dc ;
+	DEBUG0 (("after realloc E [0] "ID"\n", Work->E [0])) ;
+    }
+    ASSERT (IMPLIES (!(Work->E [0]), Work->Flublock == (Entry *) NULL)) ;
+
+    newmem = newsize - Numeric->size ;
+    ASSERT (newmem == 0 || newmem >= 2) ;
+
+    if (newmem >= 2)
+    {
+	/* reallocation succeeded */
+
+	/* point to the old tail marker block of size 1 + header */
+	p = Numeric->Memory + Numeric->size - 2 ;
+
+	/* create a new block out of the newly extended memory */
+	p->header.size = newmem - 1 ;
+	i = Numeric->size - 1 ;
+	p += newmem ;
+
+	/* create a new tail marker block */
+	p->header.prevsize = newmem - 1 ;
+	p->header.size = 1 ;
+
+	Numeric->size = newsize ;
+
+	/* free the new block */
+	UMF_mem_free_tail_block (Numeric, i) ;
+
+	Numeric->nrealloc++ ;
+
+	if (costly)
+	{
+	    Numeric->ncostly++ ;
+	}
+
+    }
+    DEBUG1 (("Done with realloc memory\n")) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* garbage collection on the tail of Numeric->memory (destroys tuples) */
+    /* ---------------------------------------------------------------------- */
+
+    UMF_garbage_collection (Numeric, Work, r2, c2, do_Fcpos) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* rebuild the tuples */
+    /* ---------------------------------------------------------------------- */
+
+    return (UMF_build_tuples (Numeric, Work)) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_get_memory.h b/src/C/SuiteSparse/UMFPACK/Source/umf_get_memory.h
new file mode 100644
index 0000000..6131478
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_get_memory.h
@@ -0,0 +1,15 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_get_memory
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int needunits,
+    Int r2,
+    Int c2,
+    Int do_Fcpos
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_grow_front.c b/src/C/SuiteSparse/UMFPACK/Source/umf_grow_front.c
new file mode 100644
index 0000000..9afa6d6
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_grow_front.c
@@ -0,0 +1,293 @@
+/* ========================================================================== */
+/* === UMF_grow_front ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Current frontal matrix is too small.  Make it bigger. */
+
+#include "umf_internal.h"
+#include "umf_mem_free_tail_block.h"
+#include "umf_mem_alloc_tail_block.h"
+#include "umf_get_memory.h"
+
+GLOBAL Int UMF_grow_front
+(
+    NumericType *Numeric,
+    Int fnr2,		/* desired size is fnr2-by-fnc2 */
+    Int fnc2,
+    WorkType *Work,
+    Int do_what		/* -1: UMF_start_front
+			 * 0:  UMF_init_front, do not recompute Fcpos
+			 * 1:  UMF_extend_front
+			 * 2:  UMF_init_front, recompute Fcpos */
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    double s ;
+    Entry *Fcold, *Fcnew ;
+    Int j, i, col, *Fcpos, *Fcols, fnrows_max, fncols_max, fnr_curr, nb,
+	fnrows_new, fncols_new, fnr_min, fnc_min, minsize,
+	newsize, fnrows, fncols, *E, eloc ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    if (do_what != -1) UMF_debug++ ;
+    DEBUG0 (("\n\n====================GROW FRONT: do_what: "ID"\n", do_what)) ;
+    if (do_what != -1) UMF_debug-- ;
+    ASSERT (Work->do_grow) ;
+    ASSERT (Work->fnpiv == 0) ;
+#endif
+
+    Fcols = Work->Fcols ;
+    Fcpos = Work->Fcpos ;
+    E = Work->E ;
+
+    /* ---------------------------------------------------------------------- */
+    /* The current front is too small, find the new size */
+    /* ---------------------------------------------------------------------- */
+
+    /* maximum size of frontal matrix for this chain */
+    nb = Work->nb ;
+    fnrows_max = Work->fnrows_max + nb ;
+    fncols_max = Work->fncols_max + nb ;
+    ASSERT (fnrows_max >= 0 && (fnrows_max % 2) == 1) ;
+    DEBUG0 (("Max     size: "ID"-by-"ID" (incl. "ID" pivot block\n",
+	fnrows_max, fncols_max, nb)) ;
+
+    /* current dimensions of frontal matrix: fnr-by-fnc */
+    DEBUG0 (("Current : "ID"-by-"ID" (excl "ID" pivot blocks)\n",
+		Work->fnr_curr, Work->fnc_curr, nb)) ;
+    ASSERT (Work->fnr_curr >= 0) ;
+    ASSERT ((Work->fnr_curr % 2 == 1) || Work->fnr_curr == 0) ;
+
+    /* required dimensions of frontal matrix: fnr_min-by-fnc_min */
+    fnrows_new = Work->fnrows_new + 1 ;
+    fncols_new = Work->fncols_new + 1 ;
+    ASSERT (fnrows_new >= 0) ;
+    if (fnrows_new % 2 == 0) fnrows_new++ ;
+    fnrows_new += nb ;
+    fncols_new += nb ;
+    fnr_min = MIN (fnrows_new, fnrows_max) ;
+    fnc_min = MIN (fncols_new, fncols_max) ;
+    minsize = fnr_min * fnc_min ;
+    if (INT_OVERFLOW ((double) fnr_min * (double) fnc_min * sizeof (Entry)))
+    {
+	/* :: the minimum front size is bigger than the integer maximum :: */
+	return (FALSE) ;
+    }
+    ASSERT (fnr_min >= 0) ;
+    ASSERT (fnr_min % 2 == 1) ;
+
+    DEBUG0 (("Min     : "ID"-by-"ID"\n", fnr_min, fnc_min)) ;
+
+    /* grow the front to fnr2-by-fnc2, but no bigger than the maximum,
+     * and no smaller than the minumum. */
+    DEBUG0 (("Desired : ("ID"+"ID")-by-("ID"+"ID")\n", fnr2, nb, fnc2, nb)) ;
+    fnr2 += nb ;
+    fnc2 += nb ;
+    ASSERT (fnr2 >= 0) ;
+    if (fnr2 % 2 == 0) fnr2++ ;
+    fnr2 = MAX (fnr2, fnr_min) ;
+    fnc2 = MAX (fnc2, fnc_min) ;
+    fnr2 = MIN (fnr2, fnrows_max) ;
+    fnc2 = MIN (fnc2, fncols_max) ;
+    DEBUG0 (("Try     : "ID"-by-"ID"\n", fnr2, fnc2)) ;
+    ASSERT (fnr2 >= 0) ;
+    ASSERT (fnr2 % 2 == 1) ;
+
+    s = ((double) fnr2) * ((double) fnc2) ;
+    if (INT_OVERFLOW (s * sizeof (Entry)))
+    {
+	/* :: frontal matrix size int overflow :: */
+	/* the desired front size is bigger than the integer maximum */
+	/* compute a such that a*a*s < Int_MAX / sizeof (Entry) */
+	double a = 0.9 * sqrt ((Int_MAX / sizeof (Entry)) / s) ;
+	fnr2 = MAX (fnr_min, a * fnr2) ;
+	fnc2 = MAX (fnc_min, a * fnc2) ;
+	/* the new frontal size is a*r*a*c = a*a*s */
+	newsize = fnr2 * fnc2 ;
+	ASSERT (fnr2 >= 0) ;
+	if (fnr2 % 2 == 0) fnr2++ ;
+	fnc2 = newsize / fnr2 ;
+    }
+
+    fnr2 = MAX (fnr2, fnr_min) ;
+    fnc2 = MAX (fnc2, fnc_min) ;
+    newsize = fnr2 * fnc2 ;
+
+    ASSERT (fnr2 >= 0) ;
+    ASSERT (fnr2 % 2 == 1) ;
+    ASSERT (fnr2 >= fnr_min) ;
+    ASSERT (fnc2 >= fnc_min) ;
+    ASSERT (newsize >= minsize) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free the current front if it is empty of any numerical values */
+    /* ---------------------------------------------------------------------- */
+
+    if (E [0] && do_what != 1)
+    {
+	/* free the current front, if it exists and has nothing in it */
+	DEBUG0 (("Freeing empty front\n")) ;
+	UMF_mem_free_tail_block (Numeric, E [0]) ;
+	E [0] = 0 ;
+	Work->Flublock = (Entry *) NULL ;
+	Work->Flblock  = (Entry *) NULL ;
+	Work->Fublock  = (Entry *) NULL ;
+	Work->Fcblock  = (Entry *) NULL ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the new front, doing garbage collection if necessary */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    UMF_allocfail = FALSE ;
+    if (UMF_gprob > 0)  /* a double relop, but ignore NaN case */
+    {
+	double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ;
+	DEBUG1 (("Check random %e %e\n", rrr, UMF_gprob)) ;
+	UMF_allocfail = rrr < UMF_gprob ;
+	if (UMF_allocfail) DEBUGm2 (("Random garbage collection (grow)\n")) ;
+    }
+#endif
+
+    DEBUG0 (("Attempt size: "ID"-by-"ID"\n", fnr2, fnc2)) ;
+    eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ;
+
+    if (!eloc)
+    {
+	/* Do garbage collection, realloc, and try again. Compact the current
+	 * contribution block in the front to fnrows-by-fncols.  Note that
+	 * there are no pivot rows/columns in current front.  Do not recompute
+	 * Fcpos in UMF_garbage_collection. */
+	DEBUGm3 (("get_memory from umf_grow_front\n")) ;
+	if (!UMF_get_memory (Numeric, Work, 1 + UNITS (Entry, newsize),
+	    Work->fnrows, Work->fncols, FALSE))
+	{
+	    /* :: out of memory in umf_grow_front :: */
+	    return (FALSE) ;	/* out of memory */
+	}
+	DEBUG0 (("Attempt size: "ID"-by-"ID" again\n", fnr2, fnc2)) ;
+	eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ;
+    }
+
+    /* try again with something smaller */
+    while ((fnr2 != fnr_min || fnc2 != fnc_min) && !eloc)
+    {
+	fnr2 = MIN (fnr2 - 2, fnr2 * UMF_REALLOC_REDUCTION) ;
+	fnc2 = MIN (fnc2 - 2, fnc2 * UMF_REALLOC_REDUCTION) ;
+	ASSERT (fnr_min >= 0) ;
+	ASSERT (fnr_min % 2 == 1) ;
+	fnr2 = MAX (fnr_min, fnr2) ;
+	fnc2 = MAX (fnc_min, fnc2) ;
+	ASSERT (fnr2 >= 0) ;
+	if (fnr2 % 2 == 0) fnr2++ ;
+	newsize = fnr2 * fnc2 ;
+	DEBUGm3 (("Attempt smaller size: "ID"-by-"ID" minsize "ID"-by-"ID"\n",
+	    fnr2, fnc2, fnr_min, fnc_min)) ;
+	eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ;
+    }
+
+    /* try again with the smallest possible size */
+    if (!eloc)
+    {
+	fnr2 = fnr_min ;
+	fnc2 = fnc_min ;
+	newsize = minsize ;
+	DEBUG0 (("Attempt minsize: "ID"-by-"ID"\n", fnr2, fnc2)) ;
+	eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ;
+    }
+
+    if (!eloc)
+    {
+	/* out of memory */
+	return (FALSE) ;
+    }
+
+    ASSERT (fnr2 >= 0) ;
+    ASSERT (fnr2 % 2 == 1) ;
+    ASSERT (fnr2 >= fnr_min && fnc2 >= fnc_min) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy the old frontal matrix into the new one */
+    /* ---------------------------------------------------------------------- */
+
+    /* old contribution block (if any) */
+    fnr_curr = Work->fnr_curr ;	    /* garbage collection can change fn*_curr */
+    ASSERT (fnr_curr >= 0) ;
+    ASSERT ((fnr_curr % 2 == 1) || fnr_curr == 0) ;
+    fnrows = Work->fnrows ;
+    fncols = Work->fncols ;
+    Fcold = Work->Fcblock ;
+
+    /* remove nb from the sizes */
+    fnr2 -= nb ;
+    fnc2 -= nb ;
+
+    /* new frontal matrix */
+    Work->Flublock = (Entry *) (Numeric->Memory + eloc) ;
+    Work->Flblock  = Work->Flublock + nb * nb ;
+    Work->Fublock  = Work->Flblock  + nb * fnr2 ;
+    Work->Fcblock  = Work->Fublock  + nb * fnc2 ;
+    Fcnew = Work->Fcblock ;
+
+    if (E [0])
+    {
+	/* copy the old contribution block into the new one */
+	for (j = 0 ; j < fncols ; j++)
+	{
+	    col = Fcols [j] ;
+	    DEBUG1 (("copy col "ID" \n",col)) ;
+	    ASSERT (col >= 0 && col < Work->n_col) ;
+	    for (i = 0 ; i < fnrows ; i++)
+	    {
+		Fcnew [i] = Fcold [i] ;
+	    }
+	    Fcnew += fnr2 ;
+	    Fcold += fnr_curr ;
+	    DEBUG1 (("new offset col "ID" "ID"\n",col, j * fnr2)) ;
+	    Fcpos [col] = j * fnr2 ;
+	}
+    }
+    else if (do_what == 2)
+    {
+	/* just find the new column offsets */
+	for (j = 0 ; j < fncols ; j++)
+	{
+	    col = Fcols [j] ;
+	    DEBUG1 (("new offset col "ID" "ID"\n",col, j * fnr2)) ;
+	    Fcpos [col] = j * fnr2 ;
+	}
+    }
+
+    /* free the old frontal matrix */
+    UMF_mem_free_tail_block (Numeric, E [0]) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* new frontal matrix size */
+    /* ---------------------------------------------------------------------- */
+
+    E [0] = eloc ;
+    Work->fnr_curr = fnr2 ;	    /* C block is fnr2-by-fnc2 */
+    Work->fnc_curr = fnc2 ;
+    Work->fcurr_size = newsize ;    /* including LU, L, U, and C blocks */
+    Work->do_grow = FALSE ;	    /* the front has just been grown */
+
+    ASSERT (Work->fnr_curr >= 0) ;
+    ASSERT (Work->fnr_curr % 2 == 1) ;
+    DEBUG0 (("Newly grown front: "ID"+"ID" by "ID"+"ID"\n", Work->fnr_curr,
+	nb, Work->fnc_curr, nb)) ;
+    return (TRUE) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_grow_front.h b/src/C/SuiteSparse/UMFPACK/Source/umf_grow_front.h
new file mode 100644
index 0000000..e63acd3
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_grow_front.h
@@ -0,0 +1,14 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_grow_front
+(
+    NumericType *Numeric,
+    Int fnr2,
+    Int fnc2,
+    WorkType *Work,
+    Int do_what
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_init_front.c b/src/C/SuiteSparse/UMFPACK/Source/umf_init_front.c
new file mode 100644
index 0000000..b82be9f
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_init_front.c
@@ -0,0 +1,267 @@
+/* ========================================================================== */
+/* === UMF_init_front ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_internal.h"
+#include "umf_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) ;
+
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_init_front.h b/src/C/SuiteSparse/UMFPACK/Source/umf_init_front.h
new file mode 100644
index 0000000..b7115fb
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_init_front.h
@@ -0,0 +1,11 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_init_front
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_internal.h b/src/C/SuiteSparse/UMFPACK/Source/umf_internal.h
new file mode 100644
index 0000000..7c231e8
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_internal.h
@@ -0,0 +1,734 @@
+/* ========================================================================== */
+/* === umf_internal.h ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    This file is for internal use in UMFPACK itself, and should not be included
+    in user code.  Use umfpack.h instead.  User-accessible file names and
+    routine names all start with the letters "umfpack_".  Non-user-accessible
+    file names and routine names all start with "umf_".
+*/
+
+#ifndef _UMF_INTERNAL
+#define _UMF_INTERNAL
+
+/* -------------------------------------------------------------------------- */
+/* ANSI standard include files */
+/* -------------------------------------------------------------------------- */
+
+/* from float.h:  DBL_EPSILON */
+#include <float.h>
+
+/* from string.h: strcmp */
+#include <string.h>
+
+/* when debugging, assert.h and the assert macro are used (see umf_dump.h) */
+
+/* -------------------------------------------------------------------------- */
+/* Architecture */
+/* -------------------------------------------------------------------------- */
+
+#if defined (__sun) || defined (MSOL2) || defined (ARCH_SOL2)
+#define UMF_SOL2
+#define UMFPACK_ARCHITECTURE "Sun Solaris"
+
+#elif defined (__sgi) || defined (MSGI) || defined (ARCH_SGI)
+#define UMF_SGI
+#define UMFPACK_ARCHITECTURE "SGI Irix"
+
+#elif defined (__linux) || defined (MGLNX86) || defined (ARCH_GLNX86)
+#define UMF_LINUX
+#define UMFPACK_ARCHITECTURE "Linux"
+
+#elif defined (_AIX) || defined (MIBM_RS) || defined (ARCH_IBM_RS)
+#define UMF_AIX
+#define UMFPACK_ARCHITECTURE "IBM AIX"
+
+#elif defined (__alpha) || defined (MALPHA) || defined (ARCH_ALPHA)
+#define UMF_ALPHA
+#define UMFPACK_ARCHITECTURE "Compaq Alpha"
+
+#elif defined (_WIN32) || defined (WIN32)
+#if defined (__MINGW32__)
+#define UMF_MINGW
+#elif defined (__CYGWIN32__)
+#define UMF_CYGWIN
+#else
+#define UMF_WINDOWS
+#endif
+#define UMFPACK_ARCHITECTURE "Microsoft Windows"
+
+#elif defined (__hppa) || defined (__hpux) || defined (MHPUX) || defined (ARCH_HPUX)
+#define UMF_HP
+#define UMFPACK_ARCHITECTURE "HP Unix"
+
+#elif defined (__hp700) || defined (MHP700) || defined (ARCH_HP700)
+#define UMF_HP
+#define UMFPACK_ARCHITECTURE "HP 700 Unix"
+
+#else
+/* If the architecture is unknown, and you call the BLAS, you may need to */
+/* define BLAS_BY_VALUE, BLAS_NO_UNDERSCORE, and/or BLAS_CHAR_ARG yourself. */
+#define UMFPACK_ARCHITECTURE "unknown"
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* basic definitions (see also amd_internal.h) */
+/* -------------------------------------------------------------------------- */
+
+#define ONES_COMPLEMENT(r) (-(r)-1)
+
+/* -------------------------------------------------------------------------- */
+/* AMD include file */
+/* -------------------------------------------------------------------------- */
+
+/* stdio.h, stdlib.h, limits.h, and math.h, NDEBUG definition, assert.h */
+#include "amd_internal.h"
+
+/* -------------------------------------------------------------------------- */
+/* MATLAB include files */
+/* -------------------------------------------------------------------------- */
+
+/* only used when compiling the UMFPACK mexFunction */
+#ifdef MATLAB_MEX_FILE
+#include "matrix.h"
+#include "mex.h"
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* Real/complex and int/UF_long definitions, double relops */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_version.h"
+
+/* -------------------------------------------------------------------------- */
+/* Compile-time configurations */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_config.h"
+
+/* -------------------------------------------------------------------------- */
+/* umfpack include file */
+/* -------------------------------------------------------------------------- */
+
+#include "umfpack.h"
+
+/* -------------------------------------------------------------------------- */
+/* for contents of Info.  This must correlate with umfpack.h */
+/* -------------------------------------------------------------------------- */
+
+#define ESTIMATE (UMFPACK_NUMERIC_SIZE_ESTIMATE - UMFPACK_NUMERIC_SIZE)
+#define ACTUAL 0
+
+/* -------------------------------------------------------------------------- */
+/* get a parameter from the Control array */
+/* -------------------------------------------------------------------------- */
+
+#define GET_CONTROL(i,default) \
+    ((Control != (double *) NULL) ? \
+	(SCALAR_IS_NAN (Control [i]) ? default : Control [i]) \
+	: default)
+
+/* -------------------------------------------------------------------------- */
+/* for clearing the external degree counters */
+/* -------------------------------------------------------------------------- */
+
+#define MAX_MARK(n) Int_MAX - (2*(n)+1)
+
+/* -------------------------------------------------------------------------- */
+/* convert number of Units to MBytes */
+/* -------------------------------------------------------------------------- */
+
+#define MBYTES(units) (((units) * sizeof (Unit)) / 1048576.0)
+
+/* -------------------------------------------------------------------------- */
+/* dense row/column macro */
+/* -------------------------------------------------------------------------- */
+
+/* In order for a row or column to be treated as "dense", it must have more */
+/* entries than the value returned by this macro.  n is the dimension of the */
+/* matrix, and alpha is the dense row/column control parameter. */
+
+/* Note: this is not defined if alpha is NaN or Inf: */
+#define UMFPACK_DENSE_DEGREE_THRESHOLD(alpha,n) \
+    ((Int) MAX (16.0, (alpha) * 16.0 * sqrt ((double) (n))))
+
+/* -------------------------------------------------------------------------- */
+/* PRINTF */
+/* -------------------------------------------------------------------------- */
+
+#define PRINTFk(k,params) { if (prl >= (k)) { PRINTF (params) ; } }
+#define PRINTF1(params) PRINTFk (1, params)
+#define PRINTF2(params) PRINTFk (2, params)
+#define PRINTF3(params) PRINTFk (3, params)
+#define PRINTF4(params) PRINTFk (4, params)
+#define PRINTF5(params) PRINTFk (5, params)
+#define PRINTF6(params) PRINTFk (6, params)
+
+/* -------------------------------------------------------------------------- */
+/* Fixed control parameters */
+/* -------------------------------------------------------------------------- */
+
+/* maximum number of columns to consider at one time, in a single front */
+#define MAX_CANDIDATES 128
+
+/* reduce Numeric->Memory request by this ratio, if allocation fails */
+#define UMF_REALLOC_REDUCTION (0.95)
+
+/* increase Numeric->Memory request by this ratio, if we need more */
+#define UMF_REALLOC_INCREASE (1.2)
+
+/* increase the dimensions of the current frontal matrix by this factor
+ * when it needs to grow. */
+#define UMF_FRONTAL_GROWTH (1.2)
+
+/* largest BLAS block size permitted */
+#define MAXNB 64
+
+/* if abs (y) < RECIPROCAL_TOLERANCE, then compute x/y.  Otherwise x*(1/y).
+ * Ignored if NRECIPROCAL is defined */
+#define RECIPROCAL_TOLERANCE 1e-12
+
+/* -------------------------------------------------------------------------- */
+/* Memory allocator */
+/* -------------------------------------------------------------------------- */
+
+/* See AMD/Source/amd_global.c and AMD/Source/amd.h for the
+ * definition of the memory allocator used by UMFPACK.  Versions 4.4 and
+ * earlier had their memory allocator definitions here.   Other global
+ * function pointers for UMFPACK are located in umf_global.c.
+ *
+ * The MATLAB mexFunction uses MATLAB's memory manager and mexPrintf, while the
+ * C-callable AMD library uses the ANSI C malloc, free, realloc, and printf
+ * routines.
+ */
+
+/* -------------------------------------------------------------------------- */
+/* Memory space definitions */
+/* -------------------------------------------------------------------------- */
+
+/* for memory alignment - assume double has worst case alignment */
+typedef double Align ;
+
+/* get number of bytes required to hold n items of a type: */
+/* note that this will not overflow, because sizeof (type) is always */
+/* greater than or equal to sizeof (Int) >= 2 */
+#define BYTES(type,n) (sizeof (type) * (n))
+
+/* ceiling of (b/u).  Assumes b >= 0 and u > 0 */
+#define CEILING(b,u) (((b) + (u) - 1) / (u))
+
+/* get number of Units required to hold n items of a type: */
+#define UNITS(type,n) (CEILING (BYTES (type, n), sizeof (Unit)))
+
+/* same as DUNITS, but use double instead of int to avoid overflow */
+#define DUNITS(type,n) (ceil (BYTES (type, (double) n) / sizeof (Unit)))
+
+union Unit_union
+{	/* memory is allocated in multiples of Unit */
+    struct
+    {
+	Int
+	    size,	/* size, in Units, of the block, excl. header block */
+			/* size >= 0: block is in use */
+			/* size < 0: block is free, of |size| Units */
+	    prevsize ;	/* size, in Units, of preceding block in S->Memory */
+			/* during garbage_collection, prevsize is set to -e-1 */
+			/* for element e, or positive (and thus a free block) */
+			/* otherwise */
+    } header ;		/* block header */
+    Align  xxxxxx ;	/* force alignment of blocks (xxxxxx is never used) */
+} ;
+
+typedef union Unit_union Unit ;
+
+/* get the size of an allocated block */
+#define GET_BLOCK_SIZE(p) (((p)-1)->header.size)
+
+/* -------------------------------------------------------------------------- */
+/* Numeric */
+/* -------------------------------------------------------------------------- */
+
+/*
+    NUMERIC_VALID and SYMBOLIC_VALID:
+    The different values of SYBOLIC_VALID and NUMERIC_VALID are chosen as a
+    first defense against corrupted *Symbolic or *Numeric pointers passed to an
+    UMFPACK routine.  They also ensure that the objects are used only by the
+    same version that created them (umfpack_di_*, umfpack_dl_*, umfpack_zi_*,
+    or umfpack_zl_*).  The values have also been changed since prior releases of
+    the code to ensure that all routines that operate on the objects are of the
+    same release.  The values themselves are purely arbitrary.  The are less
+    than the ANSI C required minimums of INT_MAX and LONG_MAX, respectively.
+*/
+
+#ifdef DINT
+#define NUMERIC_VALID  15977
+#define SYMBOLIC_VALID 41937
+#endif
+#ifdef DLONG
+#define NUMERIC_VALID  399789720
+#define SYMBOLIC_VALID 399192713
+#endif
+#ifdef ZINT
+#define NUMERIC_VALID  17957
+#define SYMBOLIC_VALID 40927
+#endif
+#ifdef ZLONG
+#define NUMERIC_VALID  129987754
+#define SYMBOLIC_VALID 110291734
+#endif
+
+typedef struct	/* NumericType */
+{
+    double
+	flops,		/* "true" flop count */
+	relpt,		/* relative pivot tolerance used */
+	relpt2,		/* relative pivot tolerance used for sym. */
+	droptol,
+	alloc_init,	/* initial allocation of Numeric->memory */
+	front_alloc_init, /* frontal matrix allocation parameter */
+	rsmin,		/* smallest row sum */
+	rsmax,		/* largest row sum  */
+	min_udiag,	/* smallest abs value on diagonal of D */
+	max_udiag,	/* smallest abs value on diagonal of D */
+	rcond ;		/* min (D) / max (D) */
+
+    Int
+	scale ;
+
+    Int valid ;		/* set to NUMERIC_VALID, for validity check */
+
+    /* Memory space for A and LU factors */
+    Unit
+	*Memory ;	/* working memory for A and LU factors */
+    Int
+	ihead,		/* pointer to tail of LU factors, in Numeric->Memory */
+	itail,		/* pointer to top of elements & tuples,  */
+			/* in Numeric->Memory */
+	ibig,		/* pointer to largest free block seen in tail */
+	size ;		/* size of Memory, in Units */
+
+    Int
+	*Rperm,		/* pointer to row perm array, size: n+1 */
+			/* after UMF_kernel:  Rperm [new] = old */
+			/* during UMF_kernel: Rperm [old] = new */
+	*Cperm,		/* pointer to col perm array, size: n+1 */
+			/* after UMF_kernel:  Cperm [new] = old */
+			/* during UMF_kernel: Cperm [old] = new */
+
+	*Upos,		/* see UMFPACK_get_numeric for a description */
+	*Lpos,
+	*Lip,
+	*Lilen,
+	*Uip,
+	*Uilen,
+	*Upattern ;	/* pattern of last row of U (if singular) */
+
+    Int
+	ulen,		/* length of Upattern */
+	npiv,		/* number of structural pivots found (sprank approx) */
+	nnzpiv ;	/* number of numerical (nonzero) pivots found */
+
+    Entry
+	*D ;		/* D [i] is the diagonal entry of U */
+
+    Int do_recip ;
+    double *Rs ;	/* scale factors for the rows of A and b */
+			/* do_recip FALSE: Divide row i by Rs [i] */
+			/* do_recip TRUE:  Multiply row i by Rs [i] */
+
+    Int
+	n_row, n_col,	/* A is n_row-by-n_row */
+	n1 ;		/* number of singletons */
+
+    /* for information only: */
+    Int
+	tail_usage,	/* amount of memory allocated in tail */
+			/* head_usage is Numeric->ihead */
+	init_usage,	/* memory usage just after UMF_kernel_init */
+	max_usage,	/* peak memory usage (excludes internal and external */
+			/* fragmentation in the tail) */
+	ngarbage,	/* number of garbage collections performed */
+	nrealloc,	/* number of reallocations performed */
+	ncostly,	/* number of costly reallocations performed */
+	isize,		/* size of integer pattern of L and U */
+	nLentries,	/* number of entries in L, excluding diagonal */
+	nUentries,	/* number of entries in U, including diagonal */
+			/* Some entries may be numerically zero. */
+	lnz,		/* number of nonzero entries in L, excl. diagonal */
+	all_lnz,	/* lnz plus entries dropped from L */
+	unz,		/* number of nonzero entries in U, excl. diagonal */
+	all_unz,	/* unz plus entries dropped form U */
+	maxfrsize ;	/* largest actual front size */
+
+    Int maxnrows, maxncols ;	/* not the same as Symbolic->maxnrows/cols* */
+
+} NumericType ;
+
+
+
+/* -------------------------------------------------------------------------- */
+/* Element tuples for connecting elements together in a matrix */
+/* -------------------------------------------------------------------------- */
+
+typedef struct	/* Tuple */
+{
+    /* The (e,f) tuples for the element lists */
+    Int
+	e,		/* element */
+	f ;		/* contribution to the row/col appears at this offset */
+
+} Tuple ;
+
+#define TUPLES(t) MAX (4, (t) + 1)
+
+/* Col_degree is aliased with Cperm, and Row_degree with Rperm */
+#define NON_PIVOTAL_COL(col) (Col_degree [col] >= 0)
+#define NON_PIVOTAL_ROW(row) (Row_degree [row] >= 0)
+
+/* -------------------------------------------------------------------------- */
+/* An element */
+/* -------------------------------------------------------------------------- */
+
+typedef struct	/* Element */
+{
+    Int
+
+	cdeg,		/* external column degree + cdeg0 offset */
+	rdeg,		/* external row degree    + rdeg0 offset */
+	nrowsleft,	/* number of rows remaining */
+	ncolsleft,	/* number of columns remaining */
+	nrows,		/* number of rows */
+	ncols,		/* number of columns */
+	next ;		/* for list link of sons, used during assembly only */
+
+    /* followed in memory by:
+    Int
+	col [0..ncols-1],	column indices of this element
+	row [0..nrows-1] ;	row indices of this element
+    Entry			(suitably aligned, see macro below)
+	C [0...nrows-1, 0...ncols-1] ;
+	size of C is nrows*ncols Entry's
+    */
+
+} Element ;
+
+/* macros for computing pointers to row/col indices, and contribution block: */
+
+#define GET_ELEMENT_SIZE(nr,nc) \
+(UNITS (Element, 1) + UNITS (Int, (nc) + (nr)) + UNITS (Entry, (nc) * (nr)))
+
+#define DGET_ELEMENT_SIZE(nr,nc) \
+(DUNITS (Element, 1) + DUNITS (Int, (nc) + (nr)) + DUNITS (Entry, (nc) * (nr)))
+
+#define GET_ELEMENT_COLS(ep,p,Cols) { \
+    ASSERT (p != (Unit *) NULL) ; \
+    ASSERT (p >= Numeric->Memory + Numeric->itail) ; \
+    ASSERT (p <= Numeric->Memory + Numeric->size) ; \
+    ep = (Element *) p ; \
+    p += UNITS (Element, 1) ; \
+    Cols = (Int *) p ; \
+}
+
+#define GET_ELEMENT_PATTERN(ep,p,Cols,Rows,ncm) { \
+    GET_ELEMENT_COLS (ep, p, Cols) ; \
+    ncm = ep->ncols ; \
+    Rows = Cols + ncm ; \
+}
+
+#define GET_ELEMENT(ep,p,Cols,Rows,ncm,nrm,C) { \
+    GET_ELEMENT_PATTERN (ep, p, Cols, Rows, ncm) ; \
+    nrm = ep->nrows ; \
+    p += UNITS (Int, ncm + nrm) ; \
+    C = (Entry *) p ; \
+}
+
+/* -------------------------------------------------------------------------- */
+/* Work data structure */
+/* -------------------------------------------------------------------------- */
+
+/*
+    This data structure holds items needed only during factorization.
+    All of this is freed when UMFPACK_numeric completes.  Note that some of
+    it is stored in the tail end of Numeric->S (namely, the Tuples and the
+    Elements).
+*/
+
+typedef struct	/* WorkType */
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* information about each row and col of A */
+    /* ---------------------------------------------------------------------- */
+
+    /*
+	Row_tuples:	pointer to tuple list (alias with Numeric->Uip)
+	Row_tlen:	number of tuples (alias with Numeric->Uilen)
+	Col_tuples:	pointer to tuple list (alias with Numeric->Lip)
+	Col_tlen:	number of tuples (alias with Numeric->Lilen)
+	Row_degree:	degree of the row or column (alias Numeric->Rperm)
+	Col_degree:	degree of the row or column (alias Numeric->Cperm)
+
+	The Row_degree and Col_degree are MATLAB-style colmmd approximations,
+	are equal to the sum of the sizes of the elements (contribution blocks)
+	in each row and column.  They are maintained when elements are created
+	and assembled.  They are used only during the pivot row and column
+	search.  They are not needed to represent the pattern of the remaining
+	matrix.
+    */
+
+    /* ---------------------------------------------------------------------- */
+    /* information about each element */
+    /* ---------------------------------------------------------------------- */
+
+    Int	*E ;		/* E [0 .. Work->elen-1] element "pointers" */
+			/* (offsets in Numeric->Memory) */
+
+    /* ---------------------------------------------------------------------- */
+    /* generic workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Entry *Wx, *Wy ;	/* each of size maxnrows+1 */
+
+    Int			/* Sizes:  nn = MAX (n_row, n_col) */
+	*Wp,		/* nn+1 */
+	*Wrp,		/* n_col+1 */
+	*Wm,		/* maxnrows+1 */
+	*Wio,		/* maxncols+1 */
+	*Woi,		/* maxncols+1 */
+	*Woo,		/* MAX (maxnrows,maxncols)+1 */
+	*Wrow,		/* pointer to Fcols, Wio, or Woi */
+	*NewRows,	/* list of rows to scan */
+	*NewCols ;	/* list of cols to scan */
+
+    /* ---------------------------------------------------------------------- */
+
+    Int
+	*Lpattern,	/* pattern of column of L, for one Lchain */
+	*Upattern,	/* pattern of row of U, for one Uchain */
+	ulen, llen ;	/* length of Upattern and Lpattern */
+
+    Int
+	*Diagonal_map,	/* used for symmetric pivoting, of size nn+1 */
+	*Diagonal_imap ;/* used for symmetric pivoting, of size nn+1 */
+
+    /* ---------------------------------------------------------------------- */
+
+    Int
+	n_row, n_col,	/* matrix is n_row-by-n_col */
+	nz,		/* nonzeros in the elements for this matrix */
+	n1,		/* number of row and col singletons */
+	elen,		/* max possible number of elements */
+	npiv,		/* number of pivot rows and columns so far */
+	ndiscard,	/* number of discarded pivot columns */
+	Wrpflag,
+	nel,		/* elements in use are in the range 1..nel */
+	noff_diagonal,
+	prior_element,
+	rdeg0, cdeg0,
+	rrdeg, ccdeg,
+	Candidates [MAX_CANDIDATES],	 /* current candidate pivot columns */
+	nCandidates,	/* number of candidates in Candidate set */
+	ksuper,
+	firstsuper,
+	jsuper,
+	ncand,		/* number of candidates (some not in Candidates[ ]) */
+	nextcand,	/* next candidate to place in Candidate search set */
+	lo,
+	hi,
+	pivrow,		/* current pivot row */
+	pivcol,		/* current pivot column */
+	do_extend,	/* true if the next pivot extends the current front */
+	do_update,	/* true if update should be applied */
+	nforced,	/* number of forced updates because of frontal growth */
+	any_skip,
+	do_scan2row,
+	do_scan2col,
+	do_grow,
+	pivot_case,
+	frontid,	/* id of current frontal matrix */
+	nfr ;		/* number of frontal matrices */
+
+    /* ---------------------------------------------------------------------- */
+    /* For row-merge tree */
+    /* ---------------------------------------------------------------------- */
+
+    Int
+	*Front_new1strow ;
+
+    /* ---------------------------------------------------------------------- */
+    /* current frontal matrix, F */
+    /* ---------------------------------------------------------------------- */
+
+    Int Pivrow [MAXNB],
+	Pivcol [MAXNB] ;
+
+    Entry
+	*Flublock,	/* LU block, nb-by-nb */
+	*Flblock,	/* L block,  fnr_curr-by-nb */
+	*Fublock,	/* U block,  nb-by-fnc_curr, or U' fnc_curr-by-nb */
+	*Fcblock ;	/* C block,  fnr_curr-by-fnc_curr */
+
+    Int
+	*Frows,		/* Frows [0.. ]: row indices of F */
+
+	*Fcols,		/* Fcols [0.. ]: column indices of F */
+
+	*Frpos,		/* position of row indices in F, or -1 if not present */
+			/* if Frows[i] == row, then Frpos[row] == i */
+
+	*Fcpos,		/* position of col indices in F, or -1 if not present */
+			/* if Fcols[j] == col, then */
+			/* Fcpos[col] == j*Work->fnr_curr */
+
+	fnrows,		/* number of rows in contribution block in F */
+	fncols,		/* number of columns in contribution block in F */
+	fnr_curr,	/* maximum # of rows in F (leading dimension) */
+	fnc_curr,	/* maximum # of columns in F */
+	fcurr_size,	/* current size of F */
+	fnrows_max,	/* max possible column-dimension (max # of rows) of F */
+	fncols_max,	/* max possible row-dimension (max # of columns) of F */
+	nb,
+	fnpiv,		/* number of pivots in F */
+	fnzeros,	/* number of explicit zero entries in LU block */
+	fscan_row,	/* where to start scanning rows of F in UMF_assemble */
+	fscan_col,	/* where to start scanning cols of F in UMF_assemble */
+	fnrows_new,	/* number of new row indices in F after pivot added */
+	fncols_new,	/* number of new col indices in F after pivot added */
+	pivrow_in_front,	/* true if current pivot row in Frows */
+	pivcol_in_front ;	/* true if current pivot column in Fcols */
+
+    /* ----------------------------------------------------------------------
+     * Current frontal matrix
+     * ----------------------------------------------------------------------
+     * The current frontal matrix is held as a single block of memory allocated
+     * from the "tail" end of Numeric->Memory.  It is subdivided into four
+     * parts: an LU block, an L block, a U block, and a C block.
+     *
+     * Let k = fnpiv, r = fnrows, and c = fncols for the following discussion.
+     * Let dr = fnr_curr and dc = fnc_curr.  Note that r <= dr and c <= dc.
+     *
+     * The LU block is of dimension nb-by-nb.  The first k-by-k part holds the
+     * "diagonal" part of the LU factors for these k pivot rows and columns.
+     * The k pivot row and column indices in this part are Pivrow [0..k-1] and
+     * Pivcol [0..k-1], respectively.
+     *
+     * The L block is of dimension dr-by-nb.  It holds the k pivot columns,
+     * except for the leading k-by-k part in the LU block.  Only the leading
+     * r-by-k part is in use.
+     *
+     * The U block is of dimension dc-by-nb.  It holds the k pivot rows,
+     * except for the leading k-by-k part in the LU block.  It is stored in
+     * row-oriented form.  Only the leading c-by-k part is in use.
+     *
+     * The C block is of dimension dr-by-dc.  It holds the current contribution
+     * block.  Only the leading r-by-c part is in use.  The column indices in
+     * the C block are Fcols [0..c-1], and the row indices are Frows [0..r-1].
+     *
+     * dr is always odd, to avoid bad cache behavior.
+     */
+
+} WorkType ;
+
+
+/* -------------------------------------------------------------------------- */
+/* Symbolic */
+/* -------------------------------------------------------------------------- */
+
+/*
+    This is is constructed by UMFPACK_symbolic, and is needed by UMFPACK_numeric
+    to factor the matrix.
+*/
+
+typedef struct	/* SymbolicType */
+{
+
+    double
+	num_mem_usage_est,	/* estimated max Numeric->Memory size */
+	num_mem_size_est,	/* estimated final Numeric->Memory size */
+	peak_sym_usage,		/* peak Symbolic and SymbolicWork usage */
+	sym,			/* symmetry of pattern */
+	dnum_mem_init_usage,	/* min Numeric->Memory for UMF_kernel_init */
+	amd_lunz,	/* nz in LU for AMD, with symmetric pivoting */
+	lunz_bound ;	/* max nx in LU, for arbitrary row pivoting */
+
+    Int valid,		/* set to SYMBOLIC_VALID, for validity check */
+	max_nchains,
+	nchains,
+	*Chain_start,
+	*Chain_maxrows,
+	*Chain_maxcols,
+	maxnrows,		/* largest number of rows in any front */
+	maxncols,		/* largest number of columns in any front */
+	*Front_npivcol,		/* Front_npivcol [j] = size of jth supercolumn*/
+	*Front_1strow,		/* first row index in front j */
+	*Front_leftmostdesc,	/* leftmost desc of front j */
+	*Front_parent,		/* super-column elimination tree */
+	*Cperm_init,		/* initial column ordering */
+	*Rperm_init,		/* initial row ordering */
+	*Cdeg, *Rdeg,
+	*Esize,
+	dense_row_threshold,
+	n1,			/* number of singletons */
+	nempty,			/* MIN (nempty_row, nempty_col) */
+	*Diagonal_map,		/* initial "diagonal" (after 2by2) */
+	esize,			/* size of Esize array */
+	nfr,
+	n_row, n_col,		/* matrix A is n_row-by-n_col */
+	nz,			/* nz of original matrix */
+	nb,			/* block size for BLAS 3 */
+	num_mem_init_usage,	/* min Numeric->Memory for UMF_kernel_init */
+	nempty_row, nempty_col,
+
+	strategy,
+	ordering,
+	fixQ,
+	prefer_diagonal,
+	nzaat,
+	nzdiag,
+	amd_dmax ;
+
+} SymbolicType ;
+
+
+/* -------------------------------------------------------------------------- */
+/* for debugging only: */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_dump.h"
+
+/* -------------------------------------------------------------------------- */
+/* for statement coverage testing only: */
+/* -------------------------------------------------------------------------- */
+
+#ifdef TESTING
+
+/* for testing integer overflow: */
+#ifdef TEST_FOR_INTEGER_OVERFLOW
+#undef MAX_MARK
+#define MAX_MARK(n) (3*(n))
+#endif
+
+/* for testing out-of-memory conditions: */
+#define UMF_TCOV_TEST
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+GLOBAL EXTERN int umf_fail, umf_fail_lo, umf_fail_hi ;
+GLOBAL EXTERN int umf_realloc_fail, umf_realloc_lo, umf_realloc_hi ;
+
+/* for testing malloc count: */
+#define UMF_MALLOC_COUNT
+
+#endif
+
+#endif
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_is_permutation.c b/src/C/SuiteSparse/UMFPACK/Source/umf_is_permutation.c
new file mode 100644
index 0000000..05ff965
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_is_permutation.c
@@ -0,0 +1,55 @@
+/* ========================================================================== */
+/* === UMF_is_permutation =================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Return TRUE if P is a r-permutation vector, FALSE otherwise */
+/* P [0..r-1] must be an r-permutation of 0..n-1 */
+
+#include "umf_internal.h"
+
+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) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_is_permutation.h b/src/C/SuiteSparse/UMFPACK/Source/umf_is_permutation.h
new file mode 100644
index 0000000..89256bd
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_is_permutation.h
@@ -0,0 +1,13 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_is_permutation
+(
+    const Int P [ ],
+    Int W [ ],
+    Int n,
+    Int r
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_kernel.c b/src/C/SuiteSparse/UMFPACK/Source/umf_kernel.c
new file mode 100644
index 0000000..e94522c
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_kernel.c
@@ -0,0 +1,299 @@
+/* ========================================================================== */
+/* === UMF_kernel =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Primary factorization routine.   Called by UMFPACK_numeric.
+    Returns:
+	UMFPACK_OK if successful,
+	UMFPACK_ERROR_out_of_memory if out of memory, or
+	UMFPACK_ERROR_different_pattern if pattern of matrix (Ap and/or Ai)
+	   has changed since the call to UMFPACK_*symbolic.
+*/
+
+#include "umf_internal.h"
+#include "umf_kernel_init.h"
+#include "umf_init_front.h"
+#include "umf_start_front.h"
+#include "umf_assemble.h"
+#include "umf_scale_column.h"
+#include "umf_local_search.h"
+#include "umf_create_element.h"
+#include "umf_extend_front.h"
+#include "umf_blas3_update.h"
+#include "umf_store_lu.h"
+#include "umf_kernel_wrapup.h"
+
+/* perform an action, and return if out of memory */
+#define DO(action) { if (! (action)) { return (UMFPACK_ERROR_out_of_memory) ; }}
+
+GLOBAL Int UMF_kernel
+(
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int j, f1, f2, chain, nchains, *Chain_start, status, fixQ, evaporate,
+	*Front_npivcol, jmax, nb, drop ;
+
+    /* ---------------------------------------------------------------------- */
+    /* initialize memory space and load the matrix. Optionally scale. */
+    /* ---------------------------------------------------------------------- */
+
+    if (!UMF_kernel_init (Ap, Ai, Ax,
+#ifdef COMPLEX
+	Az,
+#endif
+	Numeric, Work, Symbolic))
+    {
+	/* UMF_kernel_init is guaranteed to succeed, since UMFPACK_numeric */
+	/* either allocates enough space or if not, UMF_kernel does not get */
+	/* called.  So running out of memory here is a fatal error, and means */
+	/* that the user changed Ap and/or Ai since the call to */
+	/* UMFPACK_*symbolic. */
+	DEBUGm4 (("kernel init failed\n")) ;
+	return (UMFPACK_ERROR_different_pattern) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get the symbolic factorization */
+    /* ---------------------------------------------------------------------- */
+
+    nchains = Symbolic->nchains ;
+    Chain_start = Symbolic->Chain_start ;
+    Front_npivcol = Symbolic->Front_npivcol ;
+    nb = Symbolic->nb ;
+    fixQ = Symbolic->fixQ ;
+    drop = Numeric->droptol > 0.0 ;
+
+#ifndef NDEBUG
+    for (chain = 0 ; chain < nchains ; chain++)
+    {
+	Int i ;
+	f1 = Chain_start [chain] ;
+	f2 = Chain_start [chain+1] - 1 ;
+	DEBUG1 (("\nCHain: "ID" start "ID" end "ID"\n", chain, f1, f2)) ;
+	for (i = f1 ; i <= f2 ; i++)
+	{
+	    DEBUG1 (("Front "ID", npivcol "ID"\n", i, Front_npivcol [i])) ;
+	}
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* factorize each chain of frontal matrices */
+    /* ---------------------------------------------------------------------- */
+
+    for (chain = 0 ; chain < nchains ; chain++)
+    {
+	f1 = Chain_start [chain] ;
+	f2 = Chain_start [chain+1] - 1 ;
+
+	/* ------------------------------------------------------------------ */
+	/* get the initial frontal matrix size for this chain */
+	/* ------------------------------------------------------------------ */
+
+	DO (UMF_start_front (chain, Numeric, Work, Symbolic)) ;
+
+	/* ------------------------------------------------------------------ */
+	/* factorize each front in the chain */
+	/* ------------------------------------------------------------------ */
+
+	for (Work->frontid = f1 ; Work->frontid <= f2 ; Work->frontid++)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* Initialize the pivot column candidate set  */
+	    /* -------------------------------------------------------------- */
+
+	    Work->ncand = Front_npivcol [Work->frontid] ;
+	    Work->lo = Work->nextcand ;
+	    Work->hi = Work->nextcand + Work->ncand - 1 ;
+	    jmax = MIN (MAX_CANDIDATES, Work->ncand) ;
+	    DEBUGm1 ((">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Starting front "
+		ID", npivcol: "ID"\n", Work->frontid, Work->ncand)) ;
+	    if (fixQ)
+	    {
+		/* do not modify the column order */
+		jmax = 1 ;
+	    }
+	    DEBUGm1 (("Initial candidates: ")) ;
+	    for (j = 0 ; j < jmax ; j++)
+	    {
+		DEBUGm1 ((" "ID, Work->nextcand)) ;
+		ASSERT (Work->nextcand <= Work->hi) ;
+		Work->Candidates [j] = Work->nextcand++ ;
+	    }
+	    Work->nCandidates = jmax ;
+	    DEBUGm1 (("\n")) ;
+
+	    /* -------------------------------------------------------------- */
+	    /* Assemble and factorize the current frontal matrix */
+	    /* -------------------------------------------------------------- */
+
+	    while (Work->ncand > 0)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* get the pivot row and column */
+		/* ---------------------------------------------------------- */
+
+		status = UMF_local_search (Numeric, Work, Symbolic) ;
+		if (status == UMFPACK_ERROR_different_pattern)
+		{
+		    /* :: pattern change detected in umf_local_search :: */
+		    /* input matrix has changed since umfpack_*symbolic */
+		    DEBUGm4 (("local search failed\n")) ;
+		    return (UMFPACK_ERROR_different_pattern) ;
+		}
+		if (status == UMFPACK_WARNING_singular_matrix)
+		{
+		    /* no pivot found, discard and try again */
+		    continue ;
+		}
+
+		/* ---------------------------------------------------------- */
+		/* update if front not extended or too many zeros in L,U */
+		/* ---------------------------------------------------------- */
+
+		if (Work->do_update)
+		{
+		    UMF_blas3_update (Work) ;
+		    if (drop)
+		    {
+			DO (UMF_store_lu_drop (Numeric, Work)) ;
+		    }
+		    else
+		    {
+			DO (UMF_store_lu (Numeric, Work)) ;
+		    }
+		}
+
+		/* ---------------------------------------------------------- */
+		/* extend the frontal matrix, or start a new one */
+		/* ---------------------------------------------------------- */
+
+		if (Work->do_extend)
+		{
+		    /* extend the current front */
+		    DO (UMF_extend_front (Numeric, Work)) ;
+		}
+		else
+		{
+		    /* finish the current front (if any) and start a new one */
+		    DO (UMF_create_element (Numeric, Work, Symbolic)) ;
+		    DO (UMF_init_front (Numeric, Work)) ;
+		}
+
+		/* ---------------------------------------------------------- */
+		/* Numerical & symbolic assembly into current frontal matrix */
+		/* ---------------------------------------------------------- */
+
+		if (fixQ)
+		{
+		    UMF_assemble_fixq (Numeric, Work) ;
+		}
+		else
+		{
+		    UMF_assemble (Numeric, Work) ;
+		}
+
+		/* ---------------------------------------------------------- */
+		/* scale the pivot column */
+		/* ---------------------------------------------------------- */
+
+		UMF_scale_column (Numeric, Work) ;
+
+		/* ---------------------------------------------------------- */
+		/* Numerical update if enough pivots accumulated */
+		/* ---------------------------------------------------------- */
+
+		evaporate = Work->fnrows == 0 || Work->fncols == 0 ;
+		if (Work->fnpiv >= nb || evaporate)
+		{
+		    UMF_blas3_update (Work) ;
+		    if (drop)
+		    {
+			DO (UMF_store_lu_drop (Numeric, Work)) ;
+		    }
+		    else
+		    {
+			DO (UMF_store_lu (Numeric, Work)) ;
+		    }
+
+		}
+
+		Work->pivrow_in_front = FALSE ;
+		Work->pivcol_in_front = FALSE ;
+
+		/* ---------------------------------------------------------- */
+		/* If front is empty, evaporate it */
+		/* ---------------------------------------------------------- */
+
+		if (evaporate)
+		{
+		    /* This does not create an element, just evaporates it.
+		     * It ensures that a front is not 0-by-c or r-by-0.  No
+		     * memory is allocated, so it is guaranteed to succeed. */
+		    (void) UMF_create_element (Numeric, Work, Symbolic) ;
+		    Work->fnrows = 0 ;
+		    Work->fncols = 0 ;
+		}
+	    }
+	}
+
+	/* ------------------------------------------------------------------
+	 * Wrapup the current frontal matrix.  This is the last in a chain
+	 * in the column elimination tree.  The next frontal matrix
+	 * cannot overlap with the current one, which will be its sibling
+	 * in the column etree.
+	 * ------------------------------------------------------------------ */
+
+	UMF_blas3_update (Work) ;
+	if (drop)
+	{
+	    DO (UMF_store_lu_drop (Numeric, Work)) ;
+	}
+	else
+	{
+	    DO (UMF_store_lu (Numeric, Work)) ;
+	}
+	Work->fnrows_new = Work->fnrows ;
+	Work->fncols_new = Work->fncols ;
+	DO (UMF_create_element (Numeric, Work, Symbolic)) ;
+
+	/* ------------------------------------------------------------------ */
+	/* current front is now empty */
+	/* ------------------------------------------------------------------ */
+
+	Work->fnrows = 0 ;
+	Work->fncols = 0 ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* end the last Lchain and Uchain and finalize the LU factors */
+    /* ---------------------------------------------------------------------- */
+
+    UMF_kernel_wrapup (Numeric, Symbolic, Work) ;
+
+    /* note that the matrix may be singular (this is OK) */
+    return (UMFPACK_OK) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_kernel.h b/src/C/SuiteSparse/UMFPACK/Source/umf_kernel.h
new file mode 100644
index 0000000..4acd2ae
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_kernel.h
@@ -0,0 +1,18 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_kernel
+(
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_kernel_init.c b/src/C/SuiteSparse/UMFPACK/Source/umf_kernel_init.c
new file mode 100644
index 0000000..b15db9c
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_kernel_init.c
@@ -0,0 +1,1056 @@
+/* ========================================================================== */
+/* === UMF_kernel_init ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Initialize the kernel: scale the matrix, load the initial elements, and
+    build the tuple lists.
+
+    Returns TRUE if successful, FALSE if out of memory or if the pattern has
+    changed since UMFPACK_*symbolic.  UMFPACK_numeric allocates at least enough
+    space for UMF_kernel_init to succeed; otherwise it does not call
+    UMF_kernel_init.  So an out-of-memory condition means that the pattern must
+    have gotten larger.
+*/
+
+#include "umf_internal.h"
+#include "umf_tuple_lengths.h"
+#include "umf_build_tuples.h"
+#include "umf_mem_init_memoryspace.h"
+#include "umf_mem_alloc_element.h"
+#include "umf_mem_alloc_head_block.h"
+#include "umf_mem_alloc_tail_block.h"
+#include "umf_mem_free_tail_block.h"
+#include "umf_scale.h"
+
+/* ========================================================================== */
+/* === packsp =============================================================== */
+/* ========================================================================== */
+
+/* remove zero or small entries from a column of L or a row of U */
+
+PRIVATE Int packsp	/* returns new value of pnew */
+(
+    Int pnew,		/* index into Memory of next free space */
+    Int *p_p,		/* ptr to index of old pattern in Memory on input,
+			   new pattern on output */
+    Int *p_len,		/* ptr to length of old pattern on input,
+			   new pattern on output */
+    Int drop,		/* TRUE if small nonzero entries are to be dropped */
+    double droptol,	/* the drop tolerance */
+    Unit *Memory	/* contains the sparse vector on input and output */
+)
+{
+    Entry x ;
+    double s ;
+    Entry *Bx, *Bx2 ;
+    Int p, i, len, len_new, *Bi, *Bi2 ;
+
+    /* get the pointers to the sparse vector, and its length */
+    p = *p_p ;
+    len = *p_len ;
+    Bi = (Int   *) (Memory + p) ; p += UNITS (Int,   len) ;
+    Bx = (Entry *) (Memory + p) ; p += UNITS (Entry, len) ;
+    DEBUGm4 (("  p "ID" len "ID" pnew "ID"\n", p, len, pnew)) ;
+
+    /* the vector resides in Bi [0..len-1] and Bx [0..len-1] */
+
+    /* first, compact the vector in place */
+    len_new = 0 ;
+    for (p = 0 ; p < len ; p++)
+    {
+	i = Bi [p] ;
+	x = Bx [p] ;
+	DEBUGm4 (("    old vector: i "ID" value: ", i)) ;
+	EDEBUGk (-4, x) ;
+	DEBUGm4 (("\n")) ;
+	ASSERT (i >= 0) ;
+	/* skip if zero or below drop tolerance */
+	if (IS_ZERO (x)) continue ;
+	if (drop)
+	{
+	    APPROX_ABS (s, x) ;
+	    if (s <= droptol) continue ;
+	}
+	/* store the value back into the vector */
+	if (len_new != p)
+	{
+	    Bi [len_new] = i ;
+	    Bx [len_new] = x ;
+	}
+	len_new++ ;
+    }
+    ASSERT (len_new <= len) ;
+
+    /* the vector is now in Bi [0..len_new-1] and Bx [0..len_new-1] */
+
+#ifndef NDEBUG
+    for (p = 0 ; p < len_new ; p++)
+    {
+	DEBUGm4 (("    new vector: i "ID" value: ", Bi [p])) ;
+	EDEBUGk (-4, Bx [p]) ;
+	DEBUGm4 (("\n")) ;
+	ASSERT (Bi [p] >= 0) ;
+    }
+#endif
+
+    /* allocate new space for the compacted vector */
+    *p_p = pnew ;
+    *p_len = len_new ;
+    Bi2 = (Int   *) (Memory + pnew) ; pnew += UNITS (Int,   len_new) ;
+    Bx2 = (Entry *) (Memory + pnew) ; pnew += UNITS (Entry, len_new) ;
+    DEBUGm4 (("  pnew "ID" len_new "ID"\n", pnew, len_new)) ;
+
+    /* shift the vector upwards, into its new space */
+    for (p = 0 ; p < len_new ; p++)
+    {
+	Bi2 [p] = Bi [p] ;
+    }
+    for (p = 0 ; p < len_new ; p++)
+    {
+	Bx2 [p] = Bx [p] ;
+    }
+
+#ifndef NDEBUG
+    for (p = 0 ; p < len_new ; p++)
+    {
+	DEBUGm4 (("    packed vec: i "ID" value: ", Bi2 [p])) ;
+	EDEBUGk (-4, Bx2 [p]) ;
+	DEBUGm4 (("\n")) ;
+	ASSERT (Bi2 [p] >= 0) ;
+    }
+#endif
+
+    /* return the pointer to the space just after the new vector */
+    return (pnew) ;
+}
+
+
+/* ========================================================================== */
+/* === UMF_kernel_init ====================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMF_kernel_init
+(
+    const Int Ap [ ],		/* user's input matrix (not modified) */
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Entry x, pivot_value ;
+    double unused = 0, rsmin, rsmax, rs, droptol ;
+    Entry *D, *C, *Lval, **Rpx ;
+    double *Rs ;
+    Int row, k, oldcol, size, e, p1, p2, p, nz, *Rows, *Cols, *E, i, *Upos,
+	*Lpos, n_row, n_col, *Wp, *Cperm_init, *Frpos, *Fcpos, *Row_degree, nn,
+	*Row_tlen, *Col_degree, *Col_tlen, oldrow, newrow, ilast, *Wrp,
+	*Rperm_init, col, n_inner, prefer_diagonal, *Diagonal_map, nempty,
+	*Diagonal_imap, fixQ, rdeg, cdeg, nempty_col, *Esize, esize, pnew,
+	*Lip, *Uip, *Lilen, *Uilen, llen, pa, *Cdeg, *Rdeg, n1, clen, do_scale,
+	lnz, unz, lip, uip, k1, *Rperm, *Cperm, pivcol, *Li, lilen, drop,
+	**Rpi, nempty_row, dense_row_threshold, empty_elements, rpi, rpx ;
+    Element *ep ;
+    Unit *Memory ;
+#ifdef COMPLEX
+    Int split = SPLIT (Az) ;
+#endif
+#ifndef NRECIPROCAL
+    Int do_recip = FALSE ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG0 (("KERNEL INIT\n")) ;
+
+    n_row = Symbolic->n_row ;
+    n_col = Symbolic->n_col ;
+    nn = MAX (n_row, n_col) ;
+    n_inner = MIN (n_row, n_col) ;
+    nempty_col = Symbolic->nempty_col ;
+    nempty_row = Symbolic->nempty_row ;
+    nempty = MIN (nempty_row, nempty_col) ;
+    ASSERT (n_row > 0 && n_col > 0) ;
+    Cperm_init = Symbolic->Cperm_init ;
+    Rperm_init = Symbolic->Rperm_init ;
+    Cdeg = Symbolic->Cdeg ;
+    Rdeg = Symbolic->Rdeg ;
+    n1 = Symbolic->n1 ;
+    dense_row_threshold = Symbolic->dense_row_threshold ;
+    DEBUG0 (("Singletons: "ID"\n", n1)) ;
+    Work->nforced = 0 ;
+    Work->ndiscard = 0 ;
+    Work->noff_diagonal = 0 ;
+
+    nz = Ap [n_col] ;
+    if (nz < 0 || Ap [0] != 0 || nz != Symbolic->nz)
+    {
+	DEBUGm4 (("nz or Ap [0] bad\n")) ;
+	return (FALSE) ;	/* pattern changed */
+    }
+
+    prefer_diagonal = Symbolic->prefer_diagonal ;
+    Diagonal_map = Work->Diagonal_map ;
+    Diagonal_imap = Work->Diagonal_imap ;
+
+    /* ---------------------------------------------------------------------- */
+    /* initialize the Numeric->Memory space for LU, elements, and tuples */
+    /* ---------------------------------------------------------------------- */
+
+    UMF_mem_init_memoryspace (Numeric) ;
+    DEBUG1 (("Kernel init head usage, before allocs: "ID"\n", Numeric->ihead)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* initialize the Work and Numeric objects */
+    /* ---------------------------------------------------------------------- */
+
+    /* current front is empty */
+    Work->fnpiv = 0 ;
+    Work->fncols = 0 ;
+    Work->fnrows = 0 ;
+    Work->fncols_max = 0 ;
+    Work->fnrows_max = 0 ;
+    Work->fnzeros = 0 ;
+    Work->fcurr_size = 0 ;
+    Work->fnr_curr = 0 ;
+    Work->fnc_curr = 0 ;
+
+    Work->nz = nz ;
+    Work->prior_element = EMPTY ;
+    Work->ulen = 0 ;
+    Work->llen = 0 ;
+    Work->npiv = n1 ;
+    Work->frontid = 0 ;
+    Work->nextcand = n1 ;
+
+    Memory = Numeric->Memory ;
+    Rperm = Numeric->Rperm ;
+    Cperm = Numeric->Cperm ;
+    Row_degree = Numeric->Rperm ;
+    Col_degree = Numeric->Cperm ;
+    /* Row_tuples = Numeric->Uip ; not needed */
+    Row_tlen   = Numeric->Uilen ;
+    /* Col_tuples = Numeric->Lip ; not needed */
+    Col_tlen   = Numeric->Lilen ;
+
+    Lip = Numeric->Lip ;
+    Uip = Numeric->Uip ;
+    Lilen = Numeric->Lilen ;
+    Uilen = Numeric->Uilen ;
+
+    Frpos = Work->Frpos ;
+    Fcpos = Work->Fcpos ;
+    Wp = Work->Wp ;
+    Wrp = Work->Wrp ;
+
+    D = Numeric->D ;
+    Upos = Numeric->Upos ;
+    Lpos = Numeric->Lpos ;
+    for (k = 0 ; k < n_inner ; k++)
+    {
+	CLEAR (D [k]) ;
+    }
+
+    Rs = Numeric->Rs ;
+
+    for (row = 0 ; row <= n_row ; row++)
+    {
+	Lpos [row] = EMPTY ;
+	/* Row_tuples [row] = 0 ; set in UMF_build_tuples */
+	/* Row_degree [row] = 0 ; initialized below */
+	Row_tlen [row] = 0 ;
+	/* Frpos [row] = EMPTY ;  do this later */
+    }
+
+    for (col = 0 ; col <= n_col ; col++)
+    {
+	Upos [col] = EMPTY ;
+	/* Col_tuples [col] = 0 ; set in UMF_build_tuples */
+	/* Col_degree [col] = 0 ; initialized below */
+	Col_tlen [col] = 0 ;
+	Fcpos [col] = EMPTY ;
+	Wrp [col] = 0 ;
+    }
+    Work->Wrpflag = 1 ;
+
+    /* When cleared, Wp [0..nn] is < 0 */
+    for (i = 0 ; i <= nn ; i++)
+    {
+	Wp [i] = EMPTY ;
+    }
+    /* In col search, Wp [row] is set to a position, which is >= 0. */
+
+    /* When cleared, Wrp [0..n_col] is < Wrpflag */
+    /* In row search, Wrp [col] is set to Wrpflag. */
+
+    /* no need to initialize Wm, Wio, Woi, and Woo */
+
+    /* clear the external degree counters */
+    Work->cdeg0 = 1 ;
+    Work->rdeg0 = 1 ;
+
+    fixQ = Symbolic->fixQ ;
+
+    E = Work->E ;
+
+    Numeric->n_row = n_row ;
+    Numeric->n_col = n_col ;
+    Numeric->npiv = 0 ;
+    Numeric->nnzpiv = 0 ;
+    Numeric->min_udiag = 0.0 ;
+    Numeric->max_udiag = 0.0 ;
+    Numeric->rcond = 0.0 ;
+    Numeric->isize = 0 ;
+    Numeric->nLentries = 0 ;
+    Numeric->nUentries = 0 ;
+    Numeric->lnz = 0 ;
+    Numeric->unz = 0 ;
+    Numeric->all_lnz = 0 ;
+    Numeric->all_unz = 0 ;
+    Numeric->maxfrsize = 0 ;
+    Numeric->maxnrows = 0 ;
+    Numeric->maxncols = 0 ;
+    Numeric->flops = 0. ;
+    Numeric->n1 = n1 ;
+    droptol = Numeric->droptol ;
+    drop = (droptol > 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the scale factors, if requested, and check the input matrix */
+    /* ---------------------------------------------------------------------- */
+
+    /* UMFPACK_SCALE_SUM: Rs [i] = sum of the absolute values in row i.
+     * UMFPACK_SCALE_MAX: Rs [i] = max of the absolute values in row i.
+     *
+     * If A is complex, an approximate abs is used (|xreal| + |ximag|).
+     *
+     * If min (Rs [0..n_row]) >= RECIPROCAL_TOLERANCE, then the scale
+     * factors are inverted, and the rows of A are multiplied by the scale
+     * factors.  Otherwise, the rows are divided by the scale factors.  If
+     * NRECIPROCAL is defined, then the rows are always divided by the scale
+     * factors.
+     *
+     * For MATLAB (either built-in routine or mexFunction), or for gcc,
+     * the rows are always divided by the scale factors.
+     */
+
+    do_scale = (Numeric->scale != UMFPACK_SCALE_NONE) ;
+
+    if (do_scale)
+    {
+	int do_max = Numeric->scale == UMFPACK_SCALE_MAX ;
+	for (row = 0 ; row < n_row ; row++)
+	{
+	    Rs [row] = 0.0 ;
+	}
+	for (col = 0 ; col < n_col ; col++)
+	{
+	    ilast = EMPTY ;
+	    p1 = Ap [col] ;
+	    p2 = Ap [col+1] ;
+	    if (p1 > p2)
+	    {
+		/* invalid matrix */
+		DEBUGm4 (("invalid matrix (Ap)\n")) ;
+		return (FALSE) ;
+	    }
+	    for (p = p1 ; p < p2 ; p++)
+	    {
+		Entry aij ;
+		double value ;
+		row = Ai [p] ;
+		if (row <= ilast || row >= n_row)
+		{
+		    /* invalid matrix, columns must be sorted, no duplicates */
+		    DEBUGm4 (("invalid matrix (Ai)\n")) ;
+		    return (FALSE) ;
+		}
+		ASSIGN (aij, Ax, Az, p, split) ;
+		APPROX_ABS (value, aij) ;
+		rs = Rs [row] ;
+		if (!SCALAR_IS_NAN (rs))
+		{
+		    if (SCALAR_IS_NAN (value))
+		    {
+			/* if any entry in the row is NaN, then the scale factor
+			 * is NaN too (for now) and then set to 1.0 below */
+			Rs [row] = value ;
+		    }
+		    else if (do_max)
+		    {
+			Rs [row] = MAX (rs, value) ;
+		    }
+		    else
+		    {
+			Rs [row] += value ;
+		    }
+		}
+		DEBUG4 (("i "ID" j "ID" value %g,  Rs[i]: %g\n",
+		    row, col, value, Rs[row])) ;
+		ilast = row ;
+	    }
+	}
+	DEBUG2 (("Rs[0] = %30.20e\n", Rs [0])) ;
+	for (row = 0 ; row < n_row ; row++)
+	{
+	    rs = Rs [row] ;
+	    if (SCALAR_IS_ZERO (rs) || SCALAR_IS_NAN (rs))
+	    {
+		/* don't scale a completely zero row, or one with NaN's */
+		Rs [row] = 1.0 ;
+	    }
+	}
+	rsmin = Rs [0] ;
+	rsmax = Rs [0] ;
+	for (row = 0 ; row < n_row ; row++)
+	{
+	    DEBUG2 (("sum %30.20e ", Rs [row])) ;
+	    rsmin = MIN (rsmin, Rs [row]) ;
+	    rsmax = MAX (rsmax, Rs [row]) ;
+	    DEBUG2 (("Rs["ID"] = %30.20e\n", row, Rs [row])) ;
+	}
+#ifndef NRECIPROCAL
+	/* multiply by the reciprocal if Rs is not too small */
+	do_recip = (rsmin >= RECIPROCAL_TOLERANCE) ;
+	if (do_recip)
+	{
+	    /* invert the scale factors */
+	    for (row = 0 ; row < n_row ; row++)
+	    {
+		Rs [row] = 1.0 / Rs [row] ;
+	    }
+	}
+#endif
+    }
+    else
+    {
+	/* no scaling, rsmin and rsmax not computed */
+	rsmin = -1 ;
+	rsmax = -1 ;
+#ifndef NRECIPROCAL
+	do_recip = FALSE ;
+#endif
+	/* check the input matrix */
+	if (AMD_valid (n_row, n_col, Ap, Ai) != AMD_OK)
+	{
+	    /* matrix is invalid */
+	    return (FALSE) ;
+	}
+    }
+
+    Numeric->rsmin = rsmin ;
+    Numeric->rsmax = rsmax ;
+#ifndef NRECIPROCAL
+    Numeric->do_recip = do_recip ;
+#else
+    Numeric->do_recip = FALSE ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the inverse row Rperm_init permutation (use Frpos as temp) */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG3 (("\n\n===================LOAD_MATRIX:\n")) ;
+
+    for (newrow = 0 ; newrow < n_row ; newrow++)
+    {
+	oldrow = Rperm_init [newrow] ;
+	ASSERT (oldrow >= 0 && oldrow < n_row) ;
+	Frpos [oldrow] = newrow ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the diagonal imap if doing symmetric pivoting */
+    /* ---------------------------------------------------------------------- */
+
+    if (prefer_diagonal)
+    {
+	ASSERT (n_row == n_col) ;
+	ASSERT (nempty_col == Symbolic->nempty_row) ;
+	ASSERT (nempty_col == nempty) ;
+	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 */
+	}
+
+	Numeric->all_lnz += lnz ;
+	Numeric->all_unz += unz ;
+
+	/* allocate the column of L */
+	lip = p ;
+	p += UNITS (Int, lnz) ;
+	p += UNITS (Entry, lnz) ;
+
+	/* allocate the row of U */
+	uip = p ;
+	Rpi [k] = (Int *) (Memory + p) ;
+	p += UNITS (Int, unz) ;
+	Rpx [k] = (Entry *) (Memory + p) ;
+	/* p += UNITS (Entry, unz) ; (not needed) */
+
+	/* a single column of L (no Lchains) */
+	Lip [k] = lip ;
+	Lilen [k] = lnz ;
+
+	/* a single row of L (no Uchains) */
+	Uip [k] = uip ;
+	Uilen [k] = unz ;
+
+	Wp [k] = unz ;
+
+	/* save row and column inverse permutation */
+	k1 = ONES_COMPLEMENT (k) ;
+	Rperm [k] = k1 ;			/* aliased with Row_degree */
+	Cperm [k] = k1 ;			/* aliased with Col_degree */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* current frontal matrix is empty */
+    /* ---------------------------------------------------------------------- */
+
+    e = 0 ;
+    E [e] = 0 ;
+    Work->Flublock = (Entry *) NULL ;
+    Work->Flblock  = (Entry *) NULL ;
+    Work->Fublock  = (Entry *) NULL ;
+    Work->Fcblock  = (Entry *) NULL ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the column elements */
+    /* ---------------------------------------------------------------------- */
+
+    Esize = Symbolic->Esize ;
+    empty_elements = FALSE  ;
+    for (k = n1 ; k < n_col - nempty_col ; k++)
+    {
+	e = k - n1 + 1 ;
+	ASSERT (e < Work->elen) ;
+	esize = Esize ? Esize [k-n1] : Cdeg [k] ;
+	if (esize > 0)
+	{
+	    /* allocate an element for this column */
+	    E [e] = UMF_mem_alloc_element (Numeric, esize, 1, &Rows, &Cols, &C,
+		&size, &ep) ;
+	    if (E [e] <= 0)
+	    {
+		/* :: pattern change (out of memory for column elements) :: */
+		return (FALSE) ;	/* pattern has changed */
+	    }
+	    Cols [0] = k ;
+	    DEBUG0 (("Got column element e "ID" esize "ID"\n", e, esize)) ;
+	}
+	else
+	{
+	    /* all rows in this column are dense, or empty */
+	    E [e] = 0 ;
+	    empty_elements = TRUE  ;
+	    DEBUG0 (("column element e is empty "ID"\n", e)) ;
+	}
+    }
+    DEBUG0 (("e "ID" n_col "ID" nempty_col "ID" n1 "ID"\n", e, n_col,
+		nempty_col, n1)) ;
+    ASSERT (e == n_col - nempty_col - n1) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the row elements for dense rows of A (if any) */
+    /* ---------------------------------------------------------------------- */
+
+    if (Esize)
+    {
+	for (k = n1 ; k < n_row - nempty_row ; k++)
+	{
+	    rdeg = Rdeg [k] ;
+	    if (rdeg > dense_row_threshold)
+	    {
+		/* allocate an element for this dense row */
+		e++ ;
+		ASSERT (e < Work->elen) ;
+		E [e] = UMF_mem_alloc_element (Numeric, 1, rdeg, &Rows, &Cols,
+		    &C, &size, &ep) ;
+		if (E [e] <= 0)
+		{
+		    /* :: pattern change (out of memory for row elements) :: */
+		    return (FALSE) ;	/* pattern has changed */
+		}
+		Rows [0] = k ;
+		Rpi [k] = Cols ;
+		Rpx [k] = C ;
+		Wp [k] = rdeg ;
+		DEBUG0 (("Got row element e "ID" rdeg "ID"\n", e, rdeg)) ;
+	    }
+	}
+    }
+
+    /* elements are currently in the range 0 to e */
+    Work->nel = e ;
+
+    /* ---------------------------------------------------------------------- */
+    /* create the first n1 columns of L and U */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < n1 ; k++)
+    {
+	pivcol = Cperm_init [k] ;
+	p2 = Ap [pivcol+1] ;
+
+	/* get the kth column of L */
+	p = Lip [k] ;
+	Li = (Int *) (Memory + p) ;
+	lilen = Lilen [k] ;
+	p += UNITS (Int, lilen) ;
+	Lval = (Entry *) (Memory + p) ;
+
+	llen = 0 ;
+
+	for (pa = Ap [pivcol] ; pa < p2 ; pa++)
+	{
+	    oldrow = Ai [pa] ;
+	    newrow = Frpos [oldrow] ;
+	    ASSIGN (x, Ax, Az, pa, split) ;
+
+	    /* scale the value using the scale factors, Rs */
+	    if (do_scale)
+	    {
+#ifndef NRECIPROCAL
+		if (do_recip)
+		{
+		    SCALE (x, Rs [oldrow]) ;
+		}
+		else
+#endif
+		{
+		    SCALE_DIV (x, Rs [oldrow]) ;
+		}
+	    }
+
+	    if (newrow == k)
+	    {
+		/* this is the pivot entry itself */
+		ASSERT (oldrow == Rperm_init [k]) ;
+		D [k] = x ;
+	    }
+	    else if (newrow < k)
+	    {
+		/* this entry goes in a row of U */
+		DEBUG1 (("Singleton row of U: k "ID" newrow "ID"\n",
+		    k, newrow)) ;
+		if (--(Wp [newrow]) < 0)
+		{
+		    /* :: pattern change (singleton row too lengthy) :: */
+		    DEBUGm4 (("bad U singleton row (too lengthy)\n")) ;
+		    return (FALSE) ;	/* pattern changed */
+		}
+		*(Rpi [newrow]++) = k ;
+		*(Rpx [newrow]++) = x ;
+	    }
+	    else
+	    {
+		/* this entry goes in a column of L */
+		DEBUG1 (("Singleton col of L: k "ID" newrow "ID"\n",
+		    k, newrow)) ;
+		if (llen >= lilen)
+		{
+		    DEBUGm4 (("bad L singleton col (too lengthy)\n")) ;
+		    return (FALSE) ;	/* pattern changed */
+		}
+		Li   [llen] = newrow ;
+		Lval [llen] = x ;
+		llen++ ;
+	    }
+	}
+
+	if (llen != lilen)
+	{
+	    /* :: pattern change (singleton column too lengthy) :: */
+	    DEBUGm4 (("bad L singleton col (too short)\n")) ;
+	    return (FALSE) ;	/* pattern changed */
+	}
+
+	/* scale the column of L */
+	if (llen > 0)
+	{
+	    pivot_value = D [k] ;
+	    UMF_scale (llen, pivot_value, Lval) ;
+	}
+
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the elements and copy the columns of A */
+    /* ---------------------------------------------------------------------- */
+
+    /* also apply the row and column pre-ordering.  */
+    for (k = n1 ; k < n_col ; k++)
+    {
+	/* The newcol is k, which is what the name of the column is in the
+	 * UMFPACK kernel.  The user's name for the column is oldcol. */
+	oldcol = Cperm_init [k] ;
+
+	ASSERT (oldcol >= 0 && oldcol < n_col) ;
+
+	p2 = Ap [oldcol+1] ;
+
+	cdeg = Cdeg [k] ;
+	ASSERT (cdeg >= 0) ;
+	ASSERT (IMPLIES (
+	    (Symbolic->ordering != UMFPACK_ORDERING_GIVEN) && n1 > 0,
+	    cdeg > 1 || cdeg == 0)) ;
+
+	/* if fixQ: set Col_degree to 0 for the NON_PIVOTAL_COL macro */
+	Col_degree [k] = fixQ ? 0 : cdeg ;
+
+	/* get the element for this column (if any) */
+	e = k - n1 + 1 ;
+	if (k < n_col - nempty_col)
+	{
+	    esize = Esize ? Esize [k-n1] : cdeg ;
+	    if (E [e])
+	    {
+		Int ncols, nrows ;
+		Unit *pp ;
+		pp = Memory + E [e] ;
+		GET_ELEMENT (ep, pp, Cols, Rows, ncols, nrows, C) ;
+		ASSERT (ncols == 1) ;
+		ASSERT (nrows == esize) ;
+		ASSERT (Cols [0] == k) ;
+	    }
+	}
+	else
+	{
+	    ASSERT (cdeg == 0) ;
+	    esize = 0 ;
+	}
+
+	clen = 0 ;
+
+	for (pa = Ap [oldcol] ; pa < p2 ; pa++)
+	{
+	    oldrow = Ai [pa] ;
+	    newrow = Frpos [oldrow] ;
+	    ASSIGN (x, Ax, Az, pa, split) ;
+
+	    /* scale the value using the scale factors, Rs */
+	    if (do_scale)
+	    {
+#ifndef NRECIPROCAL
+		if (do_recip)
+		{
+		    /* multiply by the reciprocal */
+		    SCALE (x, Rs [oldrow]) ;
+		}
+		else
+#endif
+		{
+		    /* divide instead */
+		    SCALE_DIV (x, Rs [oldrow]) ;
+		}
+	    }
+
+	    rdeg = Rdeg [newrow] ;
+	    if (newrow < n1 || rdeg > dense_row_threshold)
+	    {
+		/* this entry goes in a row of U or into a dense row */
+		DEBUG1 (("Singleton/dense row of U: k "ID" newrow "ID"\n",
+		    k, newrow)) ;
+		if (--(Wp [newrow]) < 0)
+		{
+		    DEBUGm4 (("bad row of U or A (too lengthy)\n")) ;
+		    return (FALSE) ;	/* pattern changed */
+		}
+		*(Rpi [newrow]++) = k ;
+		*(Rpx [newrow]++) = x ;
+	    }
+	    else
+	    {
+		/* this entry goes in an initial element */
+		DEBUG1 (("In element k "ID" e "ID" newrow "ID"\n",
+		    k, e, newrow)) ;
+		if (clen >= esize)
+		{
+		    DEBUGm4 (("bad A column (too lengthy)\n")) ;
+		    return (FALSE) ;	/* pattern changed */
+		}
+		ASSERT (E [e]) ;
+		ASSERT (k < n_col - nempty_col) ;
+		Rows [clen] = newrow ;
+		C    [clen] = x ;
+		clen++ ;
+#ifndef NDEBUG
+		if (Diagonal_map && (newrow == Diagonal_map [k]))
+		{
+		    DEBUG0 (("Diagonal: old: row "ID" col "ID" : "
+			"new: row "ID" col "ID" : ",
+			oldrow, oldcol, newrow, k)) ;
+		    EDEBUGk (0, x) ;
+		}
+#endif
+	    }
+	}
+
+	if (clen != esize)
+	{
+	    /* :: pattern change (singleton column too short) :: */
+	    DEBUGm4 (("bad A column (too short)\n")) ;
+	    return (FALSE) ;	/* pattern changed */
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* free the Rpi and Rpx workspace at the tail end of memory */
+    /* ---------------------------------------------------------------------- */
+
+    UMF_mem_free_tail_block (Numeric, rpi) ;
+    UMF_mem_free_tail_block (Numeric, rpx) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* prune zeros and small entries from the singleton rows and columns */
+    /* ---------------------------------------------------------------------- */
+
+    if (n1 > 0)
+    {
+	pnew = Lip [0] ;
+	ASSERT (pnew == 1) ;
+	for (k = 0 ; k < n1 ; k++)
+	{
+	    DEBUGm4 (("\nPrune singleton L col "ID"\n", k)) ;
+	    pnew = packsp (pnew, &Lip [k], &Lilen [k], drop, droptol, Memory) ;
+	    Numeric->lnz += Lilen [k] ;
+	    DEBUGm4 (("\nPrune singleton U row "ID"\n", k)) ;
+	    pnew = packsp (pnew, &Uip [k], &Uilen [k], drop, droptol, Memory) ;
+	    Numeric->unz += Uilen [k] ;
+	}
+	/* free the unused space at the head of memory */
+	Numeric->ihead = pnew ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* initialize row degrees */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < n1 ; k++)
+    {
+	if (Wp [k] != 0)
+	{
+	    /* :: pattern change (singleton row too short) :: */
+	    DEBUGm4 (("bad U singleton row (too short)\n")) ;
+	    return (FALSE) ;	/* pattern changed */
+	}
+    }
+
+    for (k = n1 ; k < n_row ; k++)
+    {
+	DEBUG1 (("Initial row degree k "ID" oldrow "ID" Rdeg "ID"\n",
+	    k, Rperm_init [k], Rdeg [k])) ;
+	rdeg = Rdeg [k] ;
+	Row_degree [k] = rdeg ;
+	if (rdeg > dense_row_threshold && Wp [k] != 0)
+	{
+	    /* :: pattern change (dense row too short) :: */
+	    DEBUGm4 (("bad dense row (too short)\n")) ;
+	    return (FALSE) ;	/* pattern changed */
+	}
+    }
+
+#ifndef NDEBUG
+    if (prefer_diagonal)
+    {
+	Entry aij ;
+	Int *InvCperm, newcol ;
+	UMF_dump_diagonal_map (Diagonal_map, Diagonal_imap, 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, Az, p, split) ;
+		if (newrow == Diagonal_map [newcol])
+		{
+		    DEBUG0 (("old row "ID" col "ID" new row "ID" col "ID,
+			oldrow, oldcol, newrow, newcol)) ;
+		    EDEBUGk (0, aij) ;
+		    DEBUG0 ((" scaled ")) ;
+		    if (do_scale)
+		    {
+#ifndef NRECIPROCAL
+			if (do_recip)
+			{
+			    SCALE (aij, Rs [oldrow]) ;
+			}
+			else
+#endif
+			{
+			    SCALE_DIV (aij, Rs [oldrow]) ;
+			}
+		    }
+		    EDEBUGk (0, aij) ;
+		    DEBUG0 (("\n")) ;
+		}
+	    }
+	}
+	free (InvCperm) ;
+    }
+#endif
+
+    Col_degree [n_col] = 0 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* pack the element name space */
+    /* ---------------------------------------------------------------------- */
+
+    if (empty_elements)
+    {
+	Int e2 = 0 ;
+	DEBUG0 (("\n\n============= Packing element space\n")) ;
+	for (e = 1 ; e <= Work->nel ; e++)
+	{
+	    if (E [e])
+	    {
+		e2++ ;
+		E [e2] = E [e] ;
+	    }
+	}
+	Work->nel = e2 ;
+    }
+
+#ifndef NDEBUG
+    DEBUG0 (("Number of initial elements: "ID"\n", Work->nel)) ;
+    for (e = 0 ; e <= Work->nel ; e++) UMF_dump_element (Numeric, Work,e,TRUE) ;
+#endif
+
+    for (e = Work->nel + 1 ; e < Work->elen ; e++)
+    {
+	E [e] = 0 ;
+    }
+
+    /* Frpos no longer needed */
+    for (row = 0 ; row <= n_row ; row++)
+    {
+	Frpos [row] = EMPTY ;
+    }
+
+    /* clear Wp */
+    for (i = 0 ; i <= nn ; i++)
+    {
+	Wp [i] = EMPTY ;
+    }
+
+    DEBUG1 (("Kernel init head usage: "ID"\n", Numeric->ihead)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* build the tuple lists */
+    /* ---------------------------------------------------------------------- */
+
+    /* if the memory usage changes, then the pattern has changed */
+
+    (void) UMF_tuple_lengths (Numeric, Work, &unused) ;
+    if (!UMF_build_tuples (Numeric, Work))
+    {
+	/* :: pattern change (out of memory in umf_build_tuples) :: */
+	/* We ran out of memory, which can only mean that */
+	/* the pattern (Ap and or Ai) has changed (gotten larger). */
+	DEBUG0 (("Pattern has gotten larger - build tuples failed\n")) ;
+	return (FALSE) ;	/* pattern changed */
+    }
+
+    Numeric->init_usage = Numeric->max_usage ;
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the row merge sets */
+    /* ---------------------------------------------------------------------- */
+
+    for (i = 0 ; i <= Symbolic->nfr ; i++)
+    {
+	Work->Front_new1strow [i] = Symbolic->Front_1strow [i] ;
+    }
+
+#ifndef NDEBUG
+    UMF_dump_rowmerge (Numeric, Symbolic, Work) ;
+    DEBUG6 (("Column form of original matrix:\n")) ;
+    UMF_dump_col_matrix (Ax,
+#ifdef COMPLEX
+	Az,
+#endif
+	Ai, Ap, n_row, n_col, nz) ;
+    UMF_dump_memory (Numeric) ;
+    UMF_dump_matrix (Numeric, Work, FALSE) ;
+    DEBUG0 (("kernel init done...\n")) ;
+#endif
+
+    return (TRUE) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_kernel_init.h b/src/C/SuiteSparse/UMFPACK/Source/umf_kernel_init.h
new file mode 100644
index 0000000..312e8e8
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_kernel_init.h
@@ -0,0 +1,18 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_kernel_init
+(
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.c b/src/C/SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.c
new file mode 100644
index 0000000..98f2821
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.c
@@ -0,0 +1,466 @@
+/* ========================================================================== */
+/* === UMF_kernel_wrapup ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* The matrix is factorized.  Finish the LU data structure. */
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_kernel_wrapup
+(
+    NumericType *Numeric,
+    SymbolicType *Symbolic,
+    WorkType *Work
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Entry pivot_value ;
+    double d ;
+    Entry *D ;
+    Int i, k, col, row, llen, ulen, *ip, *Rperm, *Cperm, *Lilen, npiv, lp,
+	*Uilen, *Lip, *Uip, *Cperm_init, up, pivrow, pivcol, *Lpos, *Upos, *Wr,
+	*Wc, *Wp, *Frpos, *Fcpos, *Row_degree, *Col_degree, *Rperm_init,
+	n_row, n_col, n_inner, zero_pivot, nan_pivot, n1 ;
+
+#ifndef NDEBUG
+    UMF_dump_matrix (Numeric, Work, FALSE) ;
+#endif
+
+    DEBUG0 (("Kernel complete, Starting Kernel wrapup\n")) ;
+    n_row = Symbolic->n_row ;
+    n_col = Symbolic->n_col ;
+    n_inner = MIN (n_row, n_col) ;
+    Rperm = Numeric->Rperm ;
+    Cperm = Numeric->Cperm ;
+    Lilen = Numeric->Lilen ;
+    Uilen = Numeric->Uilen ;
+    Upos = Numeric->Upos ;
+    Lpos = Numeric->Lpos ;
+    Lip = Numeric->Lip ;
+    Uip = Numeric->Uip ;
+    D = Numeric->D ;
+
+    npiv = Work->npiv ;
+    Numeric->npiv = npiv ;
+    Numeric->ulen = Work->ulen ;
+
+    ASSERT (n_row == Numeric->n_row) ;
+    ASSERT (n_col == Symbolic->n_col) ;
+    DEBUG0 (("Wrap-up: npiv "ID" ulen "ID"\n", npiv, Numeric->ulen)) ;
+    ASSERT (npiv <= n_inner) ;
+
+    /* this will be nonzero only if matrix is singular or rectangular */
+    ASSERT (IMPLIES (npiv == n_col, Work->ulen == 0)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* find the smallest and largest entries in D */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+	pivot_value = D [k] ;
+	ABS (d, pivot_value) ;
+	zero_pivot = SCALAR_IS_ZERO (d) ;
+	nan_pivot = SCALAR_IS_NAN (d) ;
+
+	if (!zero_pivot)
+	{
+	    /* the pivot is nonzero, but might be Inf or NaN */
+	    Numeric->nnzpiv++ ;
+	}
+
+	if (k == 0)
+	{
+	    Numeric->min_udiag = d ;
+	    Numeric->max_udiag = d ;
+	}
+	else
+	{
+	    /* min (abs (diag (U))) behaves as follows:  If any entry is zero,
+	       then the result is zero (regardless of the presence of NaN's).
+	       Otherwise, if any entry is NaN, then the result is NaN.
+	       Otherwise, the result is the smallest absolute value on the
+	       diagonal of U.
+	    */
+
+	    if (SCALAR_IS_NONZERO (Numeric->min_udiag))
+	    {
+		if (zero_pivot || nan_pivot)
+		{
+		    Numeric->min_udiag = d ;
+		}
+		else if (!SCALAR_IS_NAN (Numeric->min_udiag))
+		{
+		    /* d and min_udiag are both non-NaN */
+		    Numeric->min_udiag = MIN (Numeric->min_udiag, d) ;
+		}
+	    }
+
+	    /*
+	       max (abs (diag (U))) behaves as follows:  If any entry is NaN
+	       then the result is NaN.  Otherise, the result is the largest
+	       absolute value on the diagonal of U.
+	    */
+
+	    if (nan_pivot)
+	    {
+		Numeric->max_udiag = d ;
+	    }
+	    else if (!SCALAR_IS_NAN (Numeric->max_udiag))
+	    {
+		/* d and max_udiag are both non-NaN */
+		Numeric->max_udiag = MAX (Numeric->max_udiag, d) ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* check if matrix is singular or rectangular */
+    /* ---------------------------------------------------------------------- */
+
+    Col_degree = Cperm ;	/* for NON_PIVOTAL_COL macro */
+    Row_degree = Rperm ;	/* for NON_PIVOTAL_ROW macro */
+
+    if (npiv < n_row)
+    {
+	/* finalize the row permutation */
+	k = npiv ;
+	DEBUGm3 (("Singular pivot rows "ID" to "ID"\n", k, n_row-1)) ;
+	for (row = 0 ; row < n_row ; row++)
+	{
+	    if (NON_PIVOTAL_ROW (row))
+	    {
+		Rperm [row] = ONES_COMPLEMENT (k) ;
+		DEBUGm3 (("Singular row "ID" is k: "ID" pivot row\n", row, k)) ;
+		ASSERT (!NON_PIVOTAL_ROW (row)) ;
+		Lpos [row] = EMPTY ;
+		Uip [row] = EMPTY ;
+		Uilen [row] = 0 ;
+		k++ ;
+	    }
+	}
+	ASSERT (k == n_row) ;
+    }
+
+    if (npiv < n_col)
+    {
+	/* finalize the col permutation */
+	k = npiv ;
+	DEBUGm3 (("Singular pivot cols "ID" to "ID"\n", k, n_col-1)) ;
+	for (col = 0 ; col < n_col ; col++)
+	{
+	    if (NON_PIVOTAL_COL (col))
+	    {
+		Cperm [col] = ONES_COMPLEMENT (k) ;
+		DEBUGm3 (("Singular col "ID" is k: "ID" pivot row\n", col, k)) ;
+		ASSERT (!NON_PIVOTAL_COL (col)) ;
+		Upos [col] = EMPTY ;
+		Lip [col] = EMPTY ;
+		Lilen [col] = 0 ;
+		k++ ;
+	    }
+	}
+	ASSERT (k == n_col) ;
+    }
+
+    if (npiv < n_inner)
+    {
+	/* finalize the diagonal of U */
+	DEBUGm3 (("Diag of U is zero, "ID" to "ID"\n", npiv, n_inner-1)) ;
+	for (k = npiv ; k < n_inner ; k++)
+	{
+	    CLEAR (D [k]) ;
+	}
+    }
+
+    /* save the pattern of the last row of U */
+    if (Numeric->ulen > 0)
+    {
+	DEBUGm3 (("Last row of U is not empty\n")) ;
+	Numeric->Upattern = Work->Upattern ;
+	Work->Upattern = (Int *) NULL ;
+    }
+
+    DEBUG2 (("Nnzpiv: "ID"  npiv "ID"\n", Numeric->nnzpiv, npiv)) ;
+    ASSERT (Numeric->nnzpiv <= npiv) ;
+    if (Numeric->nnzpiv < n_inner && !SCALAR_IS_NAN (Numeric->min_udiag))
+    {
+	/* the rest of the diagonal is zero, so min_udiag becomes 0,
+	 * unless it is already NaN. */
+	Numeric->min_udiag = 0.0 ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* size n_row, n_col workspaces that can be used here: */
+    /* ---------------------------------------------------------------------- */
+
+    Frpos = Work->Frpos ;	/* of size n_row+1 */
+    Fcpos = Work->Fcpos ;	/* of size n_col+1 */
+    Wp = Work->Wp ;		/* of size MAX(n_row,n_col)+1 */
+    /* Work->Upattern ;		cannot be used (in Numeric) */
+    Wr = Work->Lpattern ;	/* of size n_row+1 */
+    Wc = Work->Wrp ;		/* of size n_col+1 or bigger */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct Rperm from inverse permutations */
+    /* ---------------------------------------------------------------------- */
+
+    /* use Frpos for temporary copy of inverse row permutation [ */
+
+    for (pivrow = 0 ; pivrow < n_row ; pivrow++)
+    {
+	k = Rperm [pivrow] ;
+	ASSERT (k < 0) ;
+	k = ONES_COMPLEMENT (k) ;
+	ASSERT (k >= 0 && k < n_row) ;
+	Wp [k] = pivrow ;
+	Frpos [pivrow] = k ;
+    }
+    for (k = 0 ; k < n_row ; k++)
+    {
+	Rperm [k] = Wp [k] ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct Cperm from inverse permutation */
+    /* ---------------------------------------------------------------------- */
+
+    /* use Fcpos for temporary copy of inverse column permutation [ */
+
+    for (pivcol = 0 ; pivcol < n_col ; pivcol++)
+    {
+	k = Cperm [pivcol] ;
+	ASSERT (k < 0) ;
+	k = ONES_COMPLEMENT (k) ;
+	ASSERT (k >= 0 && k < n_col) ;
+	Wp [k] = pivcol ;
+	/* save a copy of the inverse column permutation in Fcpos */
+	Fcpos [pivcol] = k ;
+    }
+    for (k = 0 ; k < n_col ; k++)
+    {
+	Cperm [k] = Wp [k] ;
+    }
+
+#ifndef NDEBUG
+    for (k = 0 ; k < n_col ; k++)
+    {
+	col = Cperm [k] ;
+	ASSERT (col >= 0 && col < n_col) ;
+	ASSERT (Fcpos [col] == k) ;		/* col is the kth pivot */
+    }
+    for (k = 0 ; k < n_row ; k++)
+    {
+	row = Rperm [k] ;
+	ASSERT (row >= 0 && row < n_row) ;
+	ASSERT (Frpos [row] == k) ;		/* row is the kth pivot */
+    }
+#endif
+
+#ifndef NDEBUG
+    UMF_dump_lu (Numeric) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* permute Lpos, Upos, Lilen, Lip, Uilen, and Uip */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+	pivrow = Rperm [k] ;
+	Wr [k] = Uilen [pivrow] ;
+	Wp [k] = Uip [pivrow] ;
+    }
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+	Uilen [k] = Wr [k] ;
+	Uip [k] = Wp [k] ;
+    }
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+	pivrow = Rperm [k] ;
+	Wp [k] = Lpos [pivrow] ;
+    }
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+	Lpos [k] = Wp [k] ;
+    }
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+	pivcol = Cperm [k] ;
+	Wc [k] = Lilen [pivcol] ;
+	Wp [k] = Lip [pivcol] ;
+    }
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+	Lilen [k] = Wc [k] ;
+	Lip [k] = Wp [k] ;
+    }
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+	pivcol = Cperm [k] ;
+	Wp [k] = Upos [pivcol] ;
+    }
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+	Upos [k] = Wp [k] ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* terminate the last Uchain and last Lchain */
+    /* ---------------------------------------------------------------------- */
+
+    Upos [npiv] = EMPTY ;
+    Lpos [npiv] = EMPTY ;
+    Uip [npiv] = EMPTY ;
+    Lip [npiv] = EMPTY ;
+    Uilen [npiv] = 0 ;
+    Lilen [npiv] = 0 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert U to the new pivot order */
+    /* ---------------------------------------------------------------------- */
+
+    n1 = Symbolic->n1 ;
+
+    for (k = 0 ; k < n1 ; k++)
+    {
+	/* this is a singleton row of U */
+	ulen = Uilen [k] ;
+	DEBUG4 (("K "ID" New U.  ulen "ID" Singleton 1\n", k, ulen)) ;
+	if (ulen > 0)
+	{
+	    up = Uip [k] ;
+	    ip = (Int *) (Numeric->Memory + up) ;
+	    for (i = 0 ; i < ulen ; i++)
+	    {
+		col = *ip ;
+		DEBUG4 ((" old col "ID" new col "ID"\n", col, Fcpos [col]));
+		ASSERT (col >= 0 && col < n_col) ;
+		*ip++ = Fcpos [col] ;
+	    }
+	}
+    }
+
+    for (k = n1 ; k < npiv ; k++)
+    {
+	up = Uip [k] ;
+	if (up < 0)
+	{
+	    /* this is the start of a new Uchain (with a pattern) */
+	    ulen = Uilen [k] ;
+	    DEBUG4 (("K "ID" New U.  ulen "ID" End_Uchain 1\n", k, ulen)) ;
+	    if (ulen > 0)
+	    {
+		up = -up ;
+		ip = (Int *) (Numeric->Memory + up) ;
+		for (i = 0 ; i < ulen ; i++)
+		{
+		    col = *ip ;
+		    DEBUG4 ((" old col "ID" new col "ID"\n", col, Fcpos [col]));
+		    ASSERT (col >= 0 && col < n_col) ;
+		    *ip++ = Fcpos [col] ;
+		}
+	    }
+	}
+    }
+
+    ulen = Numeric->ulen ;
+    if (ulen > 0)
+    {
+	/* convert last pivot row of U to the new pivot order */
+	DEBUG4 (("K "ID" (last)\n", k)) ;
+	for (i = 0 ; i < ulen ; i++)
+	{
+	    col = Numeric->Upattern [i] ;
+	    DEBUG4 (("    old col "ID" new col "ID"\n", col, Fcpos [col])) ;
+	    Numeric->Upattern [i] = Fcpos [col] ;
+	}
+    }
+
+    /* Fcpos no longer needed ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* convert L to the new pivot order */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < n1 ; k++)
+    {
+	llen = Lilen [k] ;
+	DEBUG4 (("K "ID" New L.  llen "ID" Singleton col\n", k, llen)) ;
+	if (llen > 0)
+	{
+	    lp = Lip [k] ;
+	    ip = (Int *) (Numeric->Memory + lp) ;
+	    for (i = 0 ; i < llen ; i++)
+	    {
+		row = *ip ;
+		DEBUG4 (("    old row "ID" new row "ID"\n", row, Frpos [row])) ;
+		ASSERT (row >= 0 && row < n_row) ;
+		*ip++ = Frpos [row] ;
+	    }
+	}
+    }
+
+    for (k = n1 ; k < npiv ; k++)
+    {
+	llen = Lilen [k] ;
+	DEBUG4 (("K "ID" New L.  llen "ID" \n", k, llen)) ;
+	if (llen > 0)
+	{
+	    lp = Lip [k] ;
+	    if (lp < 0)
+	    {
+		/* this starts a new Lchain */
+		lp = -lp ;
+	    }
+	    ip = (Int *) (Numeric->Memory + lp) ;
+	    for (i = 0 ; i < llen ; i++)
+	    {
+		row = *ip ;
+		DEBUG4 (("    old row "ID" new row "ID"\n", row, Frpos [row])) ;
+		ASSERT (row >= 0 && row < n_row) ;
+		*ip++ = Frpos [row] ;
+	    }
+	}
+    }
+
+    /* Frpos no longer needed ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* combine symbolic and numeric permutations */
+    /* ---------------------------------------------------------------------- */
+
+    Cperm_init = Symbolic->Cperm_init ;
+    Rperm_init = Symbolic->Rperm_init ;
+
+    for (k = 0 ; k < n_row ; k++)
+    {
+	Rperm [k] = Rperm_init [Rperm [k]] ;
+    }
+
+    for (k = 0 ; k < n_col ; k++)
+    {
+	Cperm [k] = Cperm_init [Cperm [k]] ;
+    }
+
+    /* Work object will be freed immediately upon return (to UMF_kernel */
+    /* and then to UMFPACK_numeric). */
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.h b/src/C/SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.h
new file mode 100644
index 0000000..2cee302
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.h
@@ -0,0 +1,12 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_kernel_wrapup
+(
+    NumericType *Numeric,
+    SymbolicType *Symbolic,
+    WorkType *Work
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_local_search.c b/src/C/SuiteSparse/UMFPACK/Source/umf_local_search.c
new file mode 100644
index 0000000..6bc59a0
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_local_search.c
@@ -0,0 +1,1952 @@
+/* ========================================================================== */
+/* === UMF_local_search ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Perform pivot search to find pivot row and pivot column.
+    The pivot column is selected from the candidate set.  The candidate set
+    corresponds to a supercolumn from colamd or UMF_analyze.  The pivot column
+    is then removed from that set.  Constructs the pivot column pattern and
+    values.  Called by umf_kernel.  Returns UMFPACK_OK if successful, or
+    UMFPACK_WARNING_singular_matrix or UMFPACK_ERROR_different_pattern if not.
+*/
+
+#include "umf_internal.h"
+#include "umf_row_search.h"
+#include "umf_mem_free_tail_block.h"
+
+/* relaxed amalgamation control parameters are fixed at compile time */
+#define RELAX1 0.25
+#define SYM_RELAX1 0.0
+#define RELAX2 0.1
+#define RELAX3 0.125
+
+/* ========================================================================== */
+/* === remove_candidate ===================================================== */
+/* ========================================================================== */
+
+/* Remove a column from the set of candidate pivot columns. */
+
+PRIVATE void remove_candidate (Int jj, WorkType *Work, SymbolicType *Symbolic)
+{
+
+#ifndef NDEBUG
+    Int j ;
+    DEBUGm2 (("pivot column Candidates before remove: nCand "ID" ncand "ID
+	" lo "ID" hi "ID" jj "ID"\n", Work->nCandidates, Work->ncand,
+	Work->lo, Work->hi, jj)) ;
+    for (j = 0 ; j < Work->nCandidates ; j++)
+    {
+	Int col = Work->Candidates [j] ;
+	DEBUGm2 ((ID" ", col));
+	ASSERT (col >= 0 && col < Work->n_col) ;
+	/* ASSERT (NON_PIVOTAL_COL (col)) ; */
+	ASSERT (col >= Work->lo && col <= Work->hi) ;
+    }
+    DEBUGm2 (("\n")) ;
+#endif
+
+    if (Symbolic->fixQ)
+    {
+	DEBUGm2 (("FixQ\n")) ;
+	/* do not modify the column ordering */
+	ASSERT (Work->nCandidates == 1) ;
+	ASSERT (jj == 0) ;
+	if (Work->ncand > 1)
+	{
+	    Work->Candidates [0] = Work->nextcand++ ;
+	}
+	else
+	{
+	    Work->nCandidates = 0 ;
+	}
+    }
+    else
+    {
+	/* place the next candidate in the set */
+	if (Work->ncand > MAX_CANDIDATES)
+	{
+	    Work->Candidates [jj] = Work->nextcand++ ;
+	}
+	else
+	{
+	    ASSERT (Work->nCandidates == Work->ncand) ;
+	    Work->Candidates [jj] = Work->Candidates [Work->ncand - 1] ;
+	    Work->Candidates [Work->ncand - 1] = EMPTY ;
+	    Work->nCandidates-- ;
+	}
+    }
+    Work->ncand-- ;
+
+#ifndef NDEBUG
+    DEBUGm2 (("pivot column Candidates after remove: nCand "ID" ncand "ID
+	" lo "ID" hi "ID" jj "ID"\n", Work->nCandidates, Work->ncand, Work->lo,
+	Work->hi, jj)) ;
+    for (j = 0 ; j < Work->nCandidates ; j++)
+    {
+	Int col = Work->Candidates [j] ;
+	DEBUGm2 ((ID" ", col));
+	ASSERT (col >= 0 && col < Work->n_col) ;
+	/* ASSERT (NON_PIVOTAL_COL (col)) ; */
+	ASSERT (col >= Work->lo && col <= Work->hi) ;
+    }
+    DEBUGm2 (("\n")) ;
+    ASSERT (Work->ncand >= 0) ;
+    ASSERT (Work->nCandidates <= Work->ncand) ;
+#endif
+}
+
+/* ========================================================================== */
+/* === UMF_local_search ===================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMF_local_search
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    double relax1 ;
+    Entry *Flblock, *Fublock, *Fs, *Fcblock, *C, *Wx, *Wy, *Fu, *Flublock,
+	*Flu ;
+    Int pos, nrows, *Cols, *Rows, e, f, status, max_cdeg, fnzeros, nb, j, col,
+	i, row, cdeg_in, rdeg [2][2], fnpiv, nothing [2], new_LUsize,
+	pivrow [2][2], pivcol [2], *Wp, *Fcpos, *Frpos, new_fnzeros, cdeg_out,
+	*Wm, *Wio, *Woi, *Woo, *Frows, *Fcols, fnrows, fncols, *E, deg, nr_in,
+	nc, thiscost, bestcost, nr_out, do_update, extra_cols, extra_rows,
+	extra_zeros, relaxed_front, do_extend, fnr_curr, fnc_curr, tpi,
+	*Col_tuples, *Col_degree, *Col_tlen, jj, jcand [2], freebie [2],
+	did_rowmerge, fnrows_new [2][2], fncols_new [2][2], search_pivcol_out,
+	*Diagonal_map, *Diagonal_imap, row2, col2 ;
+    Unit *Memory, *p ;
+    Tuple *tp, *tpend, *tp1, *tp2 ;
+    Element *ep ;
+
+#ifndef NBLAS
+    Int blas_ok = TRUE ;
+#else
+#define blas_ok FALSE
+#endif
+
+#ifndef NDEBUG
+    Int debug_ok, n_row, n_col, *Row_degree ;
+    Row_degree = Numeric->Rperm ;	/* for NON_PIVOTAL_ROW macro only */
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    Memory = Numeric->Memory ;
+    E = Work->E ;
+    Col_degree = Numeric->Cperm ;
+
+    Col_tuples = Numeric->Lip ;
+    Col_tlen   = Numeric->Lilen ;
+
+    Wx = Work->Wx ;
+    Wy = Work->Wy ;
+    Wp = Work->Wp ;
+    Wm = Work->Wm ;
+    Woi = Work->Woi ;
+    Wio = Work->Wio ;
+    Woo = Work->Woo ;
+    Fcpos = Work->Fcpos ;
+    Frpos = Work->Frpos ;
+    Frows = Work->Frows ;
+    Fcols = Work->Fcols ;
+    fnrows = Work->fnrows ;
+    fncols = Work->fncols ;
+    nb = Work->nb ;
+    fnr_curr = Work->fnr_curr ;
+    fnc_curr = Work->fnc_curr ;
+    fnpiv = Work->fnpiv ;
+    nothing [0] = EMPTY ;
+    nothing [1] = EMPTY ;
+    relax1 = (Symbolic->prefer_diagonal) ? SYM_RELAX1 : RELAX1 ;
+    fnzeros = Work->fnzeros ;
+    new_fnzeros = fnzeros ;
+    jj = EMPTY ;
+
+    Fcblock = Work->Fcblock ;	    /* current contribution block */
+    Flblock = Work->Flblock ;	    /* current L block */
+    Fublock = Work->Fublock ;	    /* current U block */
+    Flublock = Work->Flublock ;	    /* current LU block */
+
+    /* The pivot column degree cannot exceed max_cdeg */
+    max_cdeg = Work->fnrows_max ;
+    ASSERT (Work->fnrows_max <= Symbolic->maxnrows) ;
+    ASSERT (Work->fncols_max <= Symbolic->maxncols) ;
+
+    if (fnrows == 0 && fncols == 0)
+    {
+	/* frontal matrix is empty */
+	Work->firstsuper = Work->ksuper ;
+    }
+
+#ifndef NDEBUG
+    n_row = Work->n_row ;
+    n_col = Work->n_col ;
+    DEBUG2 (("\n========LOCAL SEARCH:  current frontal matrix: ========= \n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+    if (UMF_debug > 0 || MAX (n_row, n_col) < 1000)
+    {
+	for (i = 0 ; i < MAX (n_row, n_col) ; i++)
+	{
+	    ASSERT (Wp [i] < 0) ;
+	}
+    }
+
+    DEBUGm2 ((ID" pivot column Candidates: lo "ID" hi "ID"\n",
+	Work->nCandidates, Work->lo, Work->hi)) ;
+    for (j = 0 ; j < Work->nCandidates ; j++)
+    {
+	col = Work->Candidates [j] ;
+	DEBUGm2 ((ID" ", col));
+	ASSERT (col >= 0 && col < n_col) ;
+	ASSERT (NON_PIVOTAL_COL (col)) ;
+	ASSERT (col >= Work->lo && col <= Work->hi) ;
+    }
+
+    DEBUGm2 (("\n")) ;
+    /* there are no 0-by-c or r-by-0 fronts, where c and r are > 0 */
+    /* a front is either 0-by-0, or r-by-c */
+    DEBUG2 (("\n\n::: "ID" : Npiv: "ID" + fnpiv "ID" = "ID". "
+	"size "ID"-by-"ID"\n", Work->frontid,
+	Work->npiv, Work->fnpiv, Work->npiv + Work->fnpiv, fnrows, fncols)) ;
+    ASSERT ((fnrows == 0 && fncols == 0) ||(fnrows != 0 && fncols != 0)) ;
+#endif
+
+    /* ====================================================================== */
+    /* === PIVOT SEARCH ===================================================== */
+    /* ====================================================================== */
+
+    /* initialize */
+
+    pivcol [IN] = EMPTY ;
+    pivcol [OUT] = EMPTY ;
+
+    cdeg_in = Int_MAX ;
+    cdeg_out = Int_MAX ;
+
+    pivrow [IN][IN] = EMPTY ;
+    pivrow [IN][OUT] = EMPTY ;
+    pivrow [OUT][IN] = EMPTY ;
+    pivrow [OUT][OUT] = EMPTY ;
+
+    rdeg [IN][IN] = Int_MAX ;
+    rdeg [IN][OUT] = Int_MAX ;
+    rdeg [OUT][IN] = Int_MAX ;
+    rdeg [OUT][OUT] = Int_MAX ;
+
+    freebie [IN] = FALSE ;
+    freebie [OUT] = FALSE ;
+
+    Work->pivot_case = EMPTY ;
+    bestcost = EMPTY ;
+
+    nr_out = EMPTY ;
+    nr_in = EMPTY ;
+
+    jcand [IN] = EMPTY ;
+    jcand [OUT] = EMPTY ;
+
+    fnrows_new [IN][IN] = EMPTY ;
+    fnrows_new [IN][OUT] = EMPTY ;
+    fnrows_new [OUT][IN] = EMPTY ;
+    fnrows_new [OUT][OUT] = EMPTY ;
+
+    fncols_new [IN][IN] = EMPTY ;
+    fncols_new [IN][OUT] = EMPTY ;
+    fncols_new [OUT][IN] = EMPTY ;
+    fncols_new [OUT][OUT] = EMPTY ;
+
+#ifndef NDEBUG
+	/* check Frpos */
+	DEBUG4 (("Check Frpos : fnrows "ID" col "ID" maxcdeg "ID"\n",
+		fnrows, pivcol [IN], max_cdeg)) ;
+	for (i = 0 ; i < fnrows ; i++)
+	{
+	    row = Frows [i] ;
+	    DEBUG4 (("  row: "ID"\n", row)) ;
+	    ASSERT (row >= 0 && row < n_row) ;
+	    ASSERT (Frpos [row] == i) ;
+	}
+	DEBUG4 (("All:\n")) ;
+	if (UMF_debug > 0 || n_row < 1000)
+	{
+	    Int cnt = fnrows ;
+	    for (row = 0 ; row < n_row ; row++)
+	    {
+		if (Frpos [row] == EMPTY)
+		{
+		    cnt++ ;
+		}
+		else
+		{
+		    DEBUG4 (("  row: "ID" pos "ID"\n", row, Frpos [row])) ;
+		}
+	    }
+	    ASSERT (cnt == n_row) ;
+	}
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* find shortest column in the front, and shortest column not in the */
+    /* front, from the candidate pivot column set */
+    /* ---------------------------------------------------------------------- */
+
+    /* If there are too many candidates, then only look at the first */
+    /* MAX_CANDIDATES of them.   Otherwise, if there are O(n) candidates, */
+    /* this code could take O(n^2) time. */
+
+    /* ------------------------------------------------------------------ */
+    /* look in the candidate set for the best column */
+    /* ------------------------------------------------------------------ */
+
+    DEBUG2 (("Max candidates %d, Work->ncand "ID" jmax "ID"\n",
+	MAX_CANDIDATES, Work->ncand, Work->nCandidates)) ;
+    col = Work->Candidates [0] ;
+    ASSERT (Work->nCandidates > 0) ;
+    DEBUG3 (("Pivot column candidate: "ID" j = "ID"\n", col, j)) ;
+    ASSERT (col >= 0 && col < n_col) ;
+
+    /* there is no Col_degree if fixQ is true */
+    deg = Symbolic->fixQ ? EMPTY : Col_degree [col] ;
+
+#ifndef NDEBUG
+    DEBUG3 (("Pivot column candidate: "ID" cost: "ID"  Fcpos[col] "ID"\n",
+	col, deg, Fcpos [col])) ;
+    UMF_dump_rowcol (1, Numeric, Work, col, !Symbolic->fixQ) ;
+    if (Symbolic->fixQ)
+    {
+	DEBUG1 (("FIXQ: Candidates "ID" pivcol "ID" npiv "ID" fnpiv "ID
+	    " ndiscard "ID "\n", Work->nCandidates, col, Work->npiv,
+	    Work->fnpiv, Work->ndiscard)) ;
+	ASSERT (Work->nCandidates == 1) ;
+	ASSERT (col == Work->npiv + Work->fnpiv + Work->ndiscard) ;
+    }
+#endif
+
+    if (Fcpos [col] >= 0)
+    {
+	/* best column in front, so far */
+	pivcol [IN] = col ;
+	cdeg_in = deg ;		/* ignored, if fixQ is true */
+	jcand [IN] = 0 ;
+    }
+    else
+    {
+	/* best column not in front, so far */
+	pivcol [OUT] = col ;
+	cdeg_out = deg ;	/* ignored, if fixQ is true */
+	jcand [OUT] = 0 ;
+    }
+
+    /* look at the rest of the candidates */
+    for (j = 1 ; j < Work->nCandidates ; j++)
+    {
+	col = Work->Candidates [j] ;
+
+	DEBUG3 (("Pivot col candidate: "ID" j = "ID"\n", col, j)) ;
+	ASSERT (col >= 0 && col < n_col) ;
+	ASSERT (!Symbolic->fixQ) ;
+	deg = Col_degree [col] ;
+#ifndef NDEBUG
+	DEBUG3 (("Pivot col candidate: "ID" cost: "ID" Fcpos[col] "ID"\n",
+		col, deg, Fcpos [col])) ;
+	UMF_dump_rowcol (1, Numeric, Work, col, !Symbolic->fixQ) ;
+#endif
+	if (Fcpos [col] >= 0)
+	{
+#ifndef NDEBUG
+	    Int fs ;
+	    fs = Fcpos [col] / fnr_curr ;
+	    ASSERT (fs >= 0 && fs < fncols) ;
+#endif
+	    if (deg < cdeg_in || (deg == cdeg_in && col < pivcol [IN]))
+	    {
+		/* best column in front, so far */
+		pivcol [IN] = col ;
+		cdeg_in = deg ;
+		jcand [IN] = j ;
+	    }
+	}
+	else
+	{
+	    if (deg < cdeg_out || (deg == cdeg_out && col < pivcol [OUT]))
+	    {
+		/* best column not in front, so far */
+		pivcol [OUT] = col ;
+		cdeg_out = deg ;
+		jcand [OUT] = j ;
+	    }
+	}
+    }
+
+    DEBUG2 (("Pivcol in "ID" out "ID"\n", pivcol [IN], pivcol [OUT])) ;
+    ASSERT ((pivcol [IN] >= 0 && pivcol [IN] < n_col)
+	|| (pivcol [OUT] >= 0 && pivcol [OUT] < n_col)) ;
+
+    cdeg_in = EMPTY ;
+    cdeg_out = EMPTY ;
+
+    /* ---------------------------------------------------------------------- */
+    /* construct candidate column in front, and search for pivot rows */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    /* check Frpos */
+    DEBUG4 (("Prior to col update: fnrows "ID" col "ID" maxcdeg "ID"\n",
+	    fnrows, pivcol [IN], max_cdeg)) ;
+    for (i = 0 ; i < fnrows ; i++)
+    {
+	row = Frows [i] ;
+	DEBUG4 (("  row: "ID"\n", row)) ;
+	ASSERT (row >= 0 && row < n_row) ;
+	ASSERT (Frpos [row] == i) ;
+    }
+    DEBUG4 (("All:\n")) ;
+    if (UMF_debug > 0 || n_row < 1000)
+    {
+	Int cnt = fnrows ;
+	for (row = 0 ; row < n_row ; row++)
+	{
+	    if (Frpos [row] == EMPTY)
+	    {
+		cnt++ ;
+	    }
+	    else
+	    {
+		DEBUG4 (("  row: "ID" pos "ID"\n", row, Frpos [row])) ;
+	    }
+	}
+	ASSERT (cnt == n_row) ;
+    }
+#endif
+
+    if (pivcol [IN] != EMPTY)
+    {
+
+#ifndef NDEBUG
+	DEBUG2 (("col[IN] column "ID" in front at position = "ID"\n",
+		pivcol [IN], Fcpos [pivcol [IN]])) ;
+	UMF_dump_rowcol (1, Numeric, Work, pivcol [IN], !Symbolic->fixQ) ;
+#endif
+
+	/* the only way we can have a pivcol[IN] is if the front is not empty */
+	ASSERT (fnrows > 0 && fncols > 0) ;
+
+	DEBUG4 (("Update pivot column:\n")) ;
+	Fs  = Fcblock  +  Fcpos [pivcol [IN]] ;
+	Fu  = Fublock  + (Fcpos [pivcol [IN]] / fnr_curr) ;
+	Flu = Flublock + fnpiv * nb ;
+
+	/* ------------------------------------------------------------------ */
+	/* copy the pivot column from the U block into the LU block */
+	/* ------------------------------------------------------------------ */
+
+	/* This copy is permanent if the pivcol [IN] is chosen. */
+	for (i = 0 ; i < fnpiv ; i++)
+	{
+	    Flu [i] = Fu [i*fnc_curr] ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* update the pivot column in the LU block using a triangular solve */
+	/* ------------------------------------------------------------------ */
+
+	/* This work will be discarded if the pivcol [OUT] is chosen instead.
+	 * It is permanent if the pivcol [IN] is chosen. */
+
+	if (fnpiv > 1)
+	{
+	    /* solve Lx=b, where b = U (:,k), stored in the LU block */
+
+#ifndef NBLAS
+	    BLAS_TRSV (fnpiv, Flublock, Flu, nb) ;
+#endif
+	    if (!blas_ok)
+	    {
+		/* use plain C code if no BLAS, or on integer overflow */
+		Entry *Flub = Flublock ;
+		for (j = 0 ; j < fnpiv ; j++)
+		{
+		    Entry Fuj = Flu [j] ;
+#pragma ivdep
+		    for (i = j+1 ; i < fnpiv ; i++)
+		    {
+			/* Flu [i] -= Flublock [i + j*nb] * Flu [j] ; */
+			MULT_SUB (Flu [i], Flub [i], Fuj) ;
+		    }
+		    Flub += nb ;
+		}
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* copy the pivot column from the C block into Wy */
+	/* ------------------------------------------------------------------ */
+
+	for (i = 0 ; i < fnrows ; i++)
+	{
+	    Wy [i] = Fs [i] ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* update the pivot column of L using a matrix-vector multiply */
+	/* ------------------------------------------------------------------ */
+
+	/* this work will be discarded if the pivcol [OUT] is chosen instead */
+
+#ifdef NBLAS
+	/* no BLAS available - use plain C code instead */
+	for (j = 0 ; j < fnpiv ; j++)
+	{
+	    Entry Fuj, *Flub = Flblock + j * fnr_curr ;
+	    Fuj = Flu [j] ;
+	    if (IS_NONZERO (Fuj))
+	    {
+#pragma ivdep
+		for (i = 0 ; i < fnrows ; i++)
+		{
+		    /* Wy [i] -= Flblock [i+j*fnr_curr] * Fuj ; */
+		    MULT_SUB (Wy [i], Flub [i], Fuj) ;
+		}
+	    }
+	    /* Flblock += fnr_curr ; */
+	}
+#else
+	/* Using 1-based notation:
+	 * Wy (1:fnrows) -= Flblock (1:fnrows,1:fnpiv) * Flu (1:fnpiv) */
+	BLAS_GEMV (fnrows, fnpiv, Flblock, Flu, Wy, fnr_curr) ;
+#endif
+
+	/* ------------------------------------------------------------------ */
+
+#ifndef NDEBUG
+	DEBUG2 (("Wy after update: fnrows="ID"\n", fnrows)) ;
+	DEBUG4 ((" fnpiv="ID" \n", fnpiv)) ;
+	for (i = 0 ; i < fnrows ; i++)
+	{
+	    DEBUG4 ((ID" "ID" "ID, i, Frows [i], Frpos [Frows [i]])) ;
+	    EDEBUG4 (Wy [i]) ;
+	    DEBUG4 (("\n")) ;
+	}
+#endif
+
+	/* ------------------------------------------------------------------ */
+	/* construct the candidate column */
+	/* ------------------------------------------------------------------ */
+
+	cdeg_in = fnrows ;
+
+#ifndef NDEBUG
+	/* check Frpos */
+	DEBUG4 (("After col update: fnrows "ID" col "ID" maxcdeg "ID"\n",
+		fnrows, pivcol [IN], max_cdeg)) ;
+	for (i = 0 ; i < fnrows ; i++)
+	{
+	    row = Frows [i] ;
+	    DEBUG4 (("  row: "ID"\n", row)) ;
+	    ASSERT (row >= 0 && row < n_row) ;
+	    ASSERT (Frpos [row] == i) ;
+	}
+	DEBUG4 (("All:\n")) ;
+	if (UMF_debug > 0 || n_row < 1000)
+	{
+	    Int cnt = fnrows ;
+	    for (row = 0 ; row < n_row ; row++)
+	    {
+		if (Frpos [row] == EMPTY)
+		{
+		    cnt++ ;
+		}
+		else
+		{
+		    DEBUG4 (("  row: "ID" pos "ID"\n", row, Frpos [row])) ;
+		}
+	    }
+	    ASSERT (cnt == n_row) ;
+	}
+#endif
+
+#ifndef NDEBUG
+	/* check Frpos */
+	DEBUG4 (("COL ASSEMBLE: cdeg "ID"\nREDUCE COL in "ID" max_cdeg "ID"\n",
+		cdeg_in, pivcol [IN], max_cdeg)) ;
+	for (i = 0 ; i < cdeg_in ; i++)
+	{
+	    row = Frows [i] ;
+	    ASSERT (row >= 0 && row < n_row) ;
+	    ASSERT (Frpos [row] == i) ;
+	}
+	if (UMF_debug > 0 || n_row < 1000)
+	{
+	    Int cnt = cdeg_in ;
+	    for (row = 0 ; row < n_row ; row++)
+	    {
+		if (Frpos [row] == EMPTY) cnt++ ;
+	    }
+	    ASSERT (cnt == n_row) ;
+	}
+#endif
+
+	/* assemble column into Wy */
+
+	ASSERT (pivcol [IN] >= 0 && pivcol [IN] < n_col) ;
+	ASSERT (NON_PIVOTAL_COL (pivcol [IN])) ;
+
+	tpi = Col_tuples [pivcol [IN]] ;
+	if (tpi)
+	{
+	    tp = (Tuple *) (Memory + tpi) ;
+	    tp1 = tp ;
+	    tp2 = tp ;
+	    tpend = tp + Col_tlen [pivcol [IN]] ;
+	    for ( ; tp < tpend ; tp++)
+	    {
+		e = tp->e ;
+		ASSERT (e > 0 && e <= Work->nel) ;
+		if (!E [e]) continue ;	/* element already deallocated */
+		f = tp->f ;
+		p = Memory + E [e] ;
+		ep = (Element *) p ;
+		p += UNITS (Element, 1) ;
+		Cols = (Int *) p ;
+		if (Cols [f] == EMPTY) continue ; /* column already assembled */
+		ASSERT (pivcol [IN] == Cols [f]) ;
+
+		Rows = Cols + ep->ncols ;
+		nrows = ep->nrows ;
+		p += UNITS (Int, ep->ncols + nrows) ;
+		C = ((Entry *) p) + f * nrows ;
+
+		for (i = 0 ; i < nrows ; i++)
+		{
+		    row = Rows [i] ;
+		    if (row >= 0) /* skip this if already gone from element */
+		    {
+			ASSERT (row < n_row) ;
+			pos = Frpos [row] ;
+			if (pos < 0)
+			{
+			    /* new entry in the pattern - save Frpos */
+			    ASSERT (cdeg_in < n_row) ;
+			    if (cdeg_in >= max_cdeg)
+			    {
+				/* :: pattern change (cdeg in failure) :: */
+				DEBUGm4 (("cdeg_in failure\n")) ;
+				return (UMFPACK_ERROR_different_pattern) ;
+			    }
+			    Frpos [row] = cdeg_in ;
+			    Frows [cdeg_in] = row ;
+			    Wy [cdeg_in++] = C [i] ;
+			}
+			else
+			{
+			    /* entry already in pattern - sum values in Wy */
+			    /* Wy [pos] += C [i] ; */
+			    ASSERT (pos < max_cdeg) ;
+			    ASSEMBLE (Wy [pos], C [i]) ;
+			}
+		    }
+		}
+		*tp2++ = *tp ;	/* leave the tuple in the list */
+	    }
+	    Col_tlen [pivcol [IN]] = tp2 - tp1 ;
+	}
+
+	/* ------------------------------------------------------------------ */
+
+#ifndef NDEBUG
+	/* check Frpos again */
+	DEBUG4 (("COL DONE: cdeg "ID"\nREDUCE COL in "ID" max_cdeg "ID"\n",
+		cdeg_in, pivcol [IN], max_cdeg)) ;
+	for (i = 0 ; i < cdeg_in ; i++)
+	{
+	    row = Frows [i] ;
+	    ASSERT (row >= 0 && row < n_row) ;
+	    ASSERT (Frpos [row] == i) ;
+	}
+	if (UMF_debug > 0 || n_row < 1000)
+	{
+	    Int cnt = cdeg_in ;
+	    for (row = 0 ; row < n_row ; row++)
+	    {
+		if (Frpos [row] == EMPTY) cnt++ ;
+	    }
+	    ASSERT (cnt == n_row) ;
+	}
+#endif
+
+#ifndef NDEBUG
+	DEBUG4 (("Reduced column: cdeg in  "ID" fnrows_max "ID"\n",
+	    cdeg_in, Work->fnrows_max)) ;
+	for (i = 0 ; i < cdeg_in ; i++)
+	{
+	    DEBUG4 ((" "ID" "ID" "ID, i, Frows [i], Frpos [Frows [i]])) ;
+	    EDEBUG4 (Wy [i]) ;
+	    DEBUG4 (("\n")) ;
+	    ASSERT (i == Frpos [Frows [i]]) ;
+	}
+	ASSERT (cdeg_in <= Work->fnrows_max) ;
+#endif
+
+	/* ------------------------------------------------------------------ */
+	/* cdeg_in is now the exact degree of this column */
+	/* ------------------------------------------------------------------ */
+
+	nr_in = cdeg_in - fnrows ;
+
+	/* since there are no 0-by-x fronts, if there is a pivcol [IN] the */
+	/* front must have at least one row. */
+	ASSERT (cdeg_in > 0) ;
+
+	/* new degree of pivcol [IN], excluding current front is nr_in */
+	/* column expands by nr_in rows */
+
+	/* ------------------------------------------------------------------ */
+	/* search for two candidate pivot rows */
+	/* ------------------------------------------------------------------ */
+
+	/* for the IN_IN pivot row (if any), */
+	/* extend the pattern in place, using Fcols */
+	status = UMF_row_search (Numeric, Work, Symbolic,
+	    fnrows, cdeg_in, Frows, Frpos,   /* pattern of column to search */
+	    pivrow [IN], rdeg [IN], Fcols, Wio, nothing, Wy,
+	    pivcol [IN], freebie) ;
+	ASSERT (!freebie [IN] && !freebie [OUT]) ;
+
+	/* ------------------------------------------------------------------ */
+	/* fatal error if matrix pattern has changed since symbolic analysis */
+	/* ------------------------------------------------------------------ */
+
+	if (status == UMFPACK_ERROR_different_pattern)
+	{
+	    /* :: pattern change (row search IN failure) :: */
+	    DEBUGm4 (("row search IN failure\n")) ;
+	    return (UMFPACK_ERROR_different_pattern) ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* we now must have a structural pivot */
+	/* ------------------------------------------------------------------ */
+
+	/* Since the pivcol[IN] exists, there must be at least one row in the */
+	/* current frontal matrix, and so we must have found a structural */
+	/* pivot.  The numerical value might be zero, of course. */
+
+	ASSERT (status != UMFPACK_WARNING_singular_matrix) ;
+
+	/* ------------------------------------------------------------------ */
+	/* evaluate IN_IN option */
+	/* ------------------------------------------------------------------ */
+
+	if (pivrow [IN][IN] != EMPTY)
+	{
+	    /* The current front would become an (implicit) LUson.
+	     * Both candidate pivot row and column are in the current front.
+	     * Cost is how much the current front would expand */
+
+	    /* pivrow[IN][IN] candidates are not found via row merge search */
+
+	    ASSERT (fnrows >= 0 && fncols >= 0) ;
+
+	    ASSERT (cdeg_in > 0) ;
+	    nc = rdeg [IN][IN] - fncols ;
+
+	    thiscost =
+		/* each column in front (except pivot column) grows by nr_in: */
+		(nr_in * (fncols - 1)) +
+		/* new columns not in old front: */
+		(nc * (cdeg_in - 1)) ;
+
+	    /* no extra cost to relaxed amalgamation */
+
+	    ASSERT (fnrows + nr_in == cdeg_in) ;
+	    ASSERT (fncols + nc == rdeg [IN][IN]) ;
+
+	    /* size of relaxed front (after pivot row column removed): */
+	    fnrows_new [IN][IN] = (fnrows-1) + nr_in ;
+	    fncols_new [IN][IN] = (fncols-1) + nc ;
+	    /* relaxed_front = fnrows_new [IN][IN] * fncols_new [IN][IN] ; */
+
+	    do_extend = TRUE ;
+
+	    DEBUG2 (("Evaluating option IN-IN:\n")) ;
+	    DEBUG2 (("Work->fnzeros "ID" fnpiv "ID" nr_in "ID" nc "ID"\n",
+		Work->fnzeros, fnpiv, nr_in, nc)) ;
+	    DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ;
+
+	    /* determine if BLAS-3 update should be applied before extending. */
+	    /* update if too many zero entries accumulate in the LU block */
+	    fnzeros = Work->fnzeros + fnpiv * (nr_in + nc) ;
+
+	    DEBUG2 (("fnzeros "ID"\n", fnzeros)) ;
+
+	    new_LUsize = (fnpiv+1) * (fnrows + nr_in + fncols + nc) ;
+
+	    DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ;
+
+	    /* There are fnpiv pivots currently in the front.  This one
+	     * will be the (fnpiv+1)st pivot, if it is extended. */
+
+	    /* RELAX2 parameter uses a double relop, but ignore NaN case: */
+	    do_update = fnpiv > 0 &&
+		(((double) fnzeros) / ((double) new_LUsize)) > RELAX2 ;
+
+	    DEBUG2 (("do_update "ID"\n", do_update))
+
+	    DEBUG2 (("option IN  IN : nr "ID" nc "ID" cost "ID"(0) relax "ID
+		"\n", nr_in, nc, thiscost, do_extend)) ;
+
+	    /* this is the best option seen so far */
+	    Work->pivot_case = IN_IN ;
+	    bestcost = thiscost ;
+
+	    /* do the amalgamation and extend the front */
+	    Work->do_extend = do_extend ;
+	    Work->do_update = do_update ;
+	    new_fnzeros = fnzeros ;
+
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* evaluate IN_OUT option */
+	/* ------------------------------------------------------------------ */
+
+	if (pivrow [IN][OUT] != EMPTY)
+	{
+	    /* The current front would become a Uson of the new front.
+	     * Candidate pivot column is in the current front, but the
+	     * candidate pivot row is not. */
+
+	    ASSERT (fnrows >= 0 && fncols > 0) ;
+	    ASSERT (cdeg_in > 0) ;
+
+	    /* must be at least one row outside the front */
+	    /* (the pivrow [IN][OUT] itself) */
+	    ASSERT (nr_in >= 1) ;
+
+	    /* count columns not in current front */
+	    nc = 0 ;
+#ifndef NDEBUG
+	    debug_ok = FALSE ;
+#endif
+	    for (i = 0 ; i < rdeg [IN][OUT] ; i++)
+	    {
+		col = Wio [i] ;
+		DEBUG4 (("counting col "ID" Fcpos[] = "ID"\n", col,
+		    Fcpos [col])) ;
+		ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+		if (Fcpos [col] < 0) nc++ ;
+#ifndef NDEBUG
+		/* we must see the pivot column somewhere */
+		if (col == pivcol [IN])
+		{
+		    ASSERT (Fcpos [col] >= 0) ;
+		    debug_ok = TRUE ;
+		}
+#endif
+	    }
+	    ASSERT (debug_ok) ;
+
+	    thiscost =
+		/* each row in front grows by nc: */
+		(nc * fnrows) +
+		/* new rows not affected by front: */
+		((nr_in-1) * (rdeg [IN][OUT]-1)) ;
+
+	    /* check the cost of relaxed IN_OUT amalgamation */
+
+	    extra_cols = ((fncols-1) + nc ) - (rdeg [IN][OUT] - 1) ;
+	    ASSERT (extra_cols >= 0) ;
+	    ASSERT (fncols + nc == extra_cols + rdeg [IN][OUT]) ;
+	    extra_zeros = (nr_in-1) * extra_cols ;	/* symbolic fill-in */
+
+	    ASSERT (fnrows + nr_in == cdeg_in) ;
+	    ASSERT (fncols + nc == rdeg [IN][OUT] + extra_cols) ;
+
+	    /* size of relaxed front (after pivot column removed): */
+	    fnrows_new [IN][OUT] = fnrows + (nr_in-1) ;
+	    fncols_new [IN][OUT] = (fncols-1) + nc ;
+	    relaxed_front = fnrows_new [IN][OUT] * fncols_new [IN][OUT] ;
+
+	    /* do relaxed amalgamation if the extra zeros are no more */
+	    /* than a fraction (default 0.25) of the relaxed front */
+	    /* if relax = 0: no extra zeros allowed */
+	    /* if relax = +inf: always amalgamate */
+
+	    /* relax parameter uses a double relop, but ignore NaN case: */
+	    if (extra_zeros == 0)
+	    {
+		do_extend = TRUE ;
+	    }
+	    else
+	    {
+		do_extend = ((double) extra_zeros) <
+		   (relax1 * (double) relaxed_front) ;
+	    }
+
+	    if (do_extend)
+	    {
+		/* count the cost of relaxed amalgamation */
+		thiscost += extra_zeros ;
+
+		DEBUG2 (("Evaluating option IN-OUT:\n")) ;
+		DEBUG2 (("Work->fnzeros "ID" fnpiv "ID" nr_in "ID" nc "ID"\n",
+		    Work->fnzeros, fnpiv, nr_in, nc)) ;
+		DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ;
+
+		/* determine if BLAS-3 update to be applied before extending. */
+		/* update if too many zero entries accumulate in the LU block */
+		fnzeros = Work->fnzeros + fnpiv * (nr_in + nc) ;
+
+		DEBUG2 (("fnzeros "ID"\n", fnzeros)) ;
+
+		new_LUsize = (fnpiv+1) * (fnrows + nr_in + fncols + nc) ;
+
+		DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ;
+
+		/* RELAX3 parameter uses a double relop, ignore NaN case: */
+		do_update = fnpiv > 0 &&
+		    (((double) fnzeros) / ((double) new_LUsize)) > RELAX3 ;
+		DEBUG2 (("do_update "ID"\n", do_update))
+
+	    }
+	    else
+	    {
+		/* the current front would not be extended */
+		do_update = fnpiv > 0 ;
+		fnzeros = 0 ;
+		DEBUG2 (("IN-OUT do_update forced true: "ID"\n", do_update)) ;
+
+		/* The new front would be just big enough to hold the new
+		 * pivot row and column. */
+		fnrows_new [IN][OUT] = cdeg_in - 1 ;
+		fncols_new [IN][OUT] = rdeg [IN][OUT] - 1 ;
+
+	    }
+
+	    DEBUG2 (("option IN  OUT: nr "ID" nc "ID" cost "ID"("ID") relax "ID
+		"\n", nr_in, nc, thiscost, extra_zeros, do_extend)) ;
+
+	    if (bestcost == EMPTY || thiscost < bestcost)
+	    {
+		/* this is the best option seen so far */
+		Work->pivot_case = IN_OUT ;
+		bestcost = thiscost ;
+		Work->do_extend = do_extend ;
+		Work->do_update = do_update ;
+		new_fnzeros = fnzeros ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct candidate column not in front, and search for pivot rows */
+    /* ---------------------------------------------------------------------- */
+
+    search_pivcol_out = (bestcost != 0 && pivcol [OUT] != EMPTY) ;
+    if (Symbolic->prefer_diagonal)
+    {
+	search_pivcol_out = search_pivcol_out && (pivrow [IN][IN] == EMPTY) ;
+    }
+
+    if (search_pivcol_out)
+    {
+
+#ifndef NDEBUG
+	DEBUG2 (("out_col column "ID" NOT in front at position = "ID"\n",
+		pivcol [OUT], Fcpos [pivcol [OUT]])) ;
+	UMF_dump_rowcol (1, Numeric, Work, pivcol [OUT], !Symbolic->fixQ) ;
+	DEBUG2 (("fncols "ID" fncols_max "ID"\n", fncols, Work->fncols_max)) ;
+	ASSERT (fncols < Work->fncols_max) ;
+#endif
+
+	/* Use Wx as temporary workspace to construct the pivcol [OUT] */
+
+
+	/* ------------------------------------------------------------------ */
+	/* construct the candidate column (currently not in the front) */
+	/* ------------------------------------------------------------------ */
+
+	/* Construct the column in Wx, Wm, using Wp for the positions: */
+	/* Wm [0..cdeg_out-1]	list of row indices in the column */
+	/* Wx [0..cdeg_out-1]	list of corresponding numerical values */
+	/* Wp [0..n-1] starts as all negative, and ends that way too. */
+
+	cdeg_out = 0 ;
+
+#ifndef NDEBUG
+	/* check Wp */
+	DEBUG4 (("COL ASSEMBLE: cdeg 0\nREDUCE COL out "ID"\n", pivcol [OUT])) ;
+	if (UMF_debug > 0 || MAX (n_row, n_col) < 1000)
+	{
+	    for (i = 0 ; i < MAX (n_row, n_col) ; i++)
+	    {
+		ASSERT (Wp [i] < 0) ;
+	    }
+	}
+	DEBUG4 (("max_cdeg: "ID"\n", max_cdeg)) ;
+#endif
+
+	ASSERT (pivcol [OUT] >= 0 && pivcol [OUT] < n_col) ;
+	ASSERT (NON_PIVOTAL_COL (pivcol [OUT])) ;
+
+	tpi = Col_tuples [pivcol [OUT]] ;
+	if (tpi)
+	{
+	    tp = (Tuple *) (Memory + tpi) ;
+	    tp1 = tp ;
+	    tp2 = tp ;
+	    tpend = tp + Col_tlen [pivcol [OUT]] ;
+	    for ( ; tp < tpend ; tp++)
+	    {
+		e = tp->e ;
+		ASSERT (e > 0 && e <= Work->nel) ;
+		if (!E [e]) continue ;	/* element already deallocated */
+		f = tp->f ;
+		p = Memory + E [e] ;
+		ep = (Element *) p ;
+		p += UNITS (Element, 1) ;
+		Cols = (Int *) p ;
+		if (Cols [f] == EMPTY) continue ; /* column already assembled */
+		ASSERT (pivcol [OUT] == Cols [f]) ;
+
+		Rows = Cols + ep->ncols ;
+		nrows = ep->nrows ;
+		p += UNITS (Int, ep->ncols + nrows) ;
+		C = ((Entry *) p) + f * nrows ;
+
+		for (i = 0 ; i < nrows ; i++)
+		{
+		    row = Rows [i] ;
+		    if (row >= 0) /* skip this if already gone from element */
+		    {
+			ASSERT (row < n_row) ;
+			pos = Wp [row] ;
+			if (pos < 0)
+			{
+			    /* new entry in the pattern - save Wp */
+			    ASSERT (cdeg_out < n_row) ;
+			    if (cdeg_out >= max_cdeg)
+			    {
+				/* :: pattern change (cdeg out failure) :: */
+				DEBUGm4 (("cdeg out failure\n")) ;
+				return (UMFPACK_ERROR_different_pattern) ;
+			    }
+			    Wp [row] = cdeg_out ;
+			    Wm [cdeg_out] = row ;
+			    Wx [cdeg_out++] = C [i] ;
+			}
+			else
+			{
+			    /* entry already in pattern - sum the values */
+			    /* Wx [pos] += C [i] ; */
+			    ASSEMBLE (Wx [pos], C [i]) ;
+			}
+		    }
+		}
+		*tp2++ = *tp ;	/* leave the tuple in the list */
+	    }
+	    Col_tlen [pivcol [OUT]] = tp2 - tp1 ;
+	}
+
+	/* ------------------------------------------------------------------ */
+
+#ifndef NDEBUG
+	DEBUG4 (("Reduced column: cdeg out "ID"\n", cdeg_out)) ;
+	for (i = 0 ; i < cdeg_out ; i++)
+	{
+	    DEBUG4 ((" "ID" "ID" "ID, i, Wm [i], Wp [Wm [i]])) ;
+	    EDEBUG4 (Wx [i]) ;
+	    DEBUG4 (("\n")) ;
+	    ASSERT (i == Wp [Wm [i]]) ;
+	}
+#endif
+
+	/* ------------------------------------------------------------------ */
+	/* new degree of pivcol [OUT] is cdeg_out */
+	/* ------------------------------------------------------------------ */
+
+	/* search for two candidate pivot rows */
+	status = UMF_row_search (Numeric, Work, Symbolic,
+	    0, cdeg_out, Wm, Wp, /* pattern of column to search */
+	    pivrow [OUT], rdeg [OUT], Woi, Woo, pivrow [IN], Wx,
+	    pivcol [OUT], freebie) ;
+
+	/* ------------------------------------------------------------------ */
+	/* fatal error if matrix pattern has changed since symbolic analysis */
+	/* ------------------------------------------------------------------ */
+
+	if (status == UMFPACK_ERROR_different_pattern)
+	{
+	    /* :: pattern change detected in umf_local_search :: */
+	    return (UMFPACK_ERROR_different_pattern) ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* Clear Wp */
+	/* ------------------------------------------------------------------ */
+
+	for (i = 0 ; i < cdeg_out ; i++)
+	{
+	    Wp [Wm [i]] = EMPTY ;	/* clear Wp */
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* check for rectangular, singular matrix */
+	/* ------------------------------------------------------------------ */
+
+	if (status == UMFPACK_WARNING_singular_matrix)
+	{
+	    /* Pivot column is empty, and row-merge set is empty too.  The
+	     * matrix is structurally singular.  The current frontal matrix must
+	     * be empty, too.  It it weren't, and pivcol [OUT] exists, then
+	     * there would be at least one row that could be selected.  Since
+	     * the current front is empty, pivcol [IN] must also be EMPTY.
+	     */
+
+	    DEBUGm4 (("Note: pivcol [OUT]: "ID" discard\n", pivcol [OUT])) ;
+	    ASSERT ((Work->fnrows == 0 && Work->fncols == 0)) ;
+	    ASSERT (pivcol [IN] == EMPTY) ;
+
+	    /* remove the failed pivcol [OUT] from candidate set */
+	    ASSERT (pivcol [OUT] == Work->Candidates [jcand [OUT]]) ;
+	    remove_candidate (jcand [OUT], Work, Symbolic) ;
+	    Work->ndiscard++ ;
+
+	    /* delete all of the tuples, and all contributions to this column */
+	    DEBUG1 (("Prune tuples of dead outcol: "ID"\n", pivcol [OUT])) ;
+	    Col_tlen [pivcol [OUT]] = 0 ;
+	    UMF_mem_free_tail_block (Numeric, Col_tuples [pivcol [OUT]]) ;
+	    Col_tuples [pivcol [OUT]] = 0 ;
+
+	    /* no pivot found at all */
+	    return (UMFPACK_WARNING_singular_matrix) ;
+	}
+
+	/* ------------------------------------------------------------------ */
+
+	if (freebie [IN])
+	{
+	    /* the "in" row is the same as the "in" row for the "in" column */
+	    Woi = Fcols ;
+	    rdeg [OUT][IN] = rdeg [IN][IN] ;
+	    DEBUG4 (("Freebie in, row "ID"\n", pivrow [IN][IN])) ;
+	}
+
+	if (freebie [OUT])
+	{
+	    /* the "out" row is the same as the "out" row for the "in" column */
+	    Woo = Wio ;
+	    rdeg [OUT][OUT] = rdeg [IN][OUT] ;
+	    DEBUG4 (("Freebie out, row "ID"\n", pivrow [IN][OUT])) ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* evaluate OUT_IN option */
+	/* ------------------------------------------------------------------ */
+
+	if (pivrow [OUT][IN] != EMPTY)
+	{
+	    /* The current front would become an Lson of the new front.
+	     * The candidate pivot row is in the current front, but the
+	     * candidate pivot column is not. */
+
+	    ASSERT (fnrows > 0 && fncols >= 0) ;
+
+	    did_rowmerge = (cdeg_out == 0) ;
+	    if (did_rowmerge)
+	    {
+		/* pivrow [OUT][IN] was found via row merge search */
+		/* it is not (yet) in the pivot column pattern (add it now) */
+		DEBUGm4 (("did row merge OUT col, IN row\n")) ;
+		Wm [0] = pivrow [OUT][IN] ;
+		CLEAR (Wx [0]) ;
+		cdeg_out = 1 ;
+		ASSERT (nr_out == EMPTY) ;
+	    }
+
+	    nc = rdeg [OUT][IN] - fncols ;
+	    ASSERT (nc >= 1) ;
+
+	    /* count rows not in current front */
+	    nr_out = 0 ;
+#ifndef NDEBUG
+	    debug_ok = FALSE ;
+#endif
+	    for (i = 0 ; i < cdeg_out ; i++)
+	    {
+		row = Wm [i] ;
+		ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;
+		if (Frpos [row] < 0 || Frpos [row] >= fnrows) nr_out++ ;
+#ifndef NDEBUG
+		/* we must see the pivot row somewhere */
+		if (row == pivrow [OUT][IN])
+		{
+		    ASSERT (Frpos [row] >= 0) ;
+		    debug_ok = TRUE ;
+		}
+#endif
+	    }
+	    ASSERT (debug_ok) ;
+
+	    thiscost =
+		/* each column in front grows by nr_out: */
+		(nr_out * fncols) +
+		/* new cols not affected by front: */
+		((nc-1) * (cdeg_out-1)) ;
+
+	    /* check the cost of relaxed OUT_IN amalgamation */
+
+	    extra_rows = ((fnrows-1) + nr_out) - (cdeg_out - 1) ;
+	    ASSERT (extra_rows >= 0) ;
+	    ASSERT (fnrows + nr_out == extra_rows + cdeg_out) ;
+	    extra_zeros = (nc-1) * extra_rows ;	/* symbolic fill-in */
+
+	    ASSERT (fnrows + nr_out == cdeg_out + extra_rows) ;
+	    ASSERT (fncols + nc == rdeg [OUT][IN]) ;
+
+	    /* size of relaxed front (after pivot row removed): */
+	    fnrows_new [OUT][IN] = (fnrows-1) + nr_out ;
+	    fncols_new [OUT][IN] = fncols + (nc-1) ;
+	    relaxed_front = fnrows_new [OUT][IN] * fncols_new [OUT][IN] ;
+
+	    /* do relaxed amalgamation if the extra zeros are no more */
+	    /* than a fraction (default 0.25) of the relaxed front */
+	    /* if relax = 0: no extra zeros allowed */
+	    /* if relax = +inf: always amalgamate */
+	    if (did_rowmerge)
+	    {
+		do_extend = FALSE ;
+	    }
+	    else
+	    {
+		/* relax parameter uses a double relop, but ignore NaN case: */
+		if (extra_zeros == 0)
+		{
+		    do_extend = TRUE ;
+		}
+		else
+		{
+		    do_extend = ((double) extra_zeros) <
+		       (relax1 * (double) relaxed_front) ;
+		}
+	    }
+
+	    if (do_extend)
+	    {
+		/* count the cost of relaxed amalgamation */
+		thiscost += extra_zeros ;
+
+		DEBUG2 (("Evaluating option OUT-IN:\n")) ;
+		DEBUG2 ((" Work->fnzeros "ID" fnpiv "ID" nr_out "ID" nc "ID"\n",
+		Work->fnzeros, fnpiv, nr_out, nc)) ;
+		DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ;
+
+		/* determine if BLAS-3 update to be applied before extending. */
+		/* update if too many zero entries accumulate in the LU block */
+		fnzeros = Work->fnzeros + fnpiv * (nr_out + nc) ;
+
+		DEBUG2 (("fnzeros "ID"\n", fnzeros)) ;
+
+		new_LUsize = (fnpiv+1) * (fnrows + nr_out + fncols + nc) ;
+
+		DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ;
+
+		/* RELAX3 parameter uses a double relop, ignore NaN case: */
+		do_update = fnpiv > 0 &&
+		    (((double) fnzeros) / ((double) new_LUsize)) > RELAX3 ;
+		DEBUG2 (("do_update "ID"\n", do_update))
+	    }
+	    else
+	    {
+		/* the current front would not be extended */
+		do_update = fnpiv > 0 ;
+		fnzeros = 0 ;
+		DEBUG2 (("OUT-IN do_update forced true: "ID"\n", do_update)) ;
+
+		/* The new front would be just big enough to hold the new
+		 * pivot row and column. */
+		fnrows_new [OUT][IN] = cdeg_out - 1 ;
+		fncols_new [OUT][IN] = rdeg [OUT][IN] - 1 ;
+	    }
+
+	    DEBUG2 (("option OUT IN : nr "ID" nc "ID" cost "ID"("ID") relax "ID
+		"\n", nr_out, nc, thiscost, extra_zeros, do_extend)) ;
+
+	    if (bestcost == EMPTY || thiscost < bestcost)
+	    {
+		/* this is the best option seen so far */
+		Work->pivot_case = OUT_IN ;
+		bestcost = thiscost ;
+		Work->do_extend = do_extend ;
+		Work->do_update = do_update ;
+		new_fnzeros = fnzeros ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* evaluate OUT_OUT option */
+	/* ------------------------------------------------------------------ */
+
+	if (pivrow [OUT][OUT] != EMPTY)
+	{
+	    /* Neither the candidate pivot row nor the candidate pivot column
+	     * are in the current front. */
+
+	    ASSERT (fnrows >= 0 && fncols >= 0) ;
+
+	    did_rowmerge = (cdeg_out == 0) ;
+	    if (did_rowmerge)
+	    {
+		/* pivrow [OUT][OUT] was found via row merge search */
+		/* it is not (yet) in the pivot column pattern (add it now) */
+		DEBUGm4 (("did row merge OUT col, OUT row\n")) ;
+		Wm [0] = pivrow [OUT][OUT] ;
+		CLEAR (Wx [0]) ;
+		cdeg_out = 1 ;
+		ASSERT (nr_out == EMPTY) ;
+		nr_out = 1 ;
+	    }
+
+	    if (fnrows == 0 && fncols == 0)
+	    {
+		/* the current front is completely empty */
+		ASSERT (fnpiv == 0) ;
+		nc = rdeg [OUT][OUT] ;
+		extra_cols = 0 ;
+		nr_out = cdeg_out ;
+		extra_rows = 0 ;
+		extra_zeros = 0 ;
+
+		thiscost = (nc-1) * (cdeg_out-1) ; /* new columns only */
+
+		/* size of new front: */
+		fnrows_new [OUT][OUT] = nr_out-1 ;
+		fncols_new [OUT][OUT] = nc-1 ;
+		relaxed_front = fnrows_new [OUT][OUT] * fncols_new [OUT][OUT] ;
+	    }
+	    else
+	    {
+
+		/* count rows not in current front */
+		if (nr_out == EMPTY)
+		{
+		    nr_out = 0 ;
+#ifndef NDEBUG
+		    debug_ok = FALSE ;
+#endif
+		    for (i = 0 ; i < cdeg_out ; i++)
+		    {
+			row = Wm [i] ;
+			ASSERT (row >= 0 && row < n_row) ;
+			ASSERT (NON_PIVOTAL_ROW (row)) ;
+			if (Frpos [row] < 0 || Frpos [row] >= fnrows) nr_out++ ;
+#ifndef NDEBUG
+			/* we must see the pivot row somewhere */
+			if (row == pivrow [OUT][OUT])
+			{
+			    ASSERT (Frpos [row] < 0 || Frpos [row] >= fnrows) ;
+			    debug_ok = TRUE ;
+			}
+#endif
+		    }
+		    ASSERT (debug_ok) ;
+		}
+
+		/* count columns not in current front */
+		nc = 0 ;
+#ifndef NDEBUG
+		debug_ok = FALSE ;
+#endif
+		for (i = 0 ; i < rdeg [OUT][OUT] ; i++)
+		{
+		    col = Woo [i] ;
+		    ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+		    if (Fcpos [col] < 0) nc++ ;
+#ifndef NDEBUG
+		    /* we must see the pivot column somewhere */
+		    if (col == pivcol [OUT])
+		    {
+			ASSERT (Fcpos [col] < 0) ;
+			debug_ok = TRUE ;
+		    }
+#endif
+		}
+		ASSERT (debug_ok) ;
+
+		extra_cols = (fncols + (nc-1)) - (rdeg [OUT][OUT] - 1) ;
+		extra_rows = (fnrows + (nr_out-1)) - (cdeg_out - 1) ;
+		ASSERT (extra_rows >= 0) ;
+		ASSERT (extra_cols >= 0) ;
+		extra_zeros = ((nc-1) * extra_rows) + ((nr_out-1) * extra_cols);
+
+		ASSERT (fnrows + nr_out == cdeg_out + extra_rows) ;
+		ASSERT (fncols + nc == rdeg [OUT][OUT] + extra_cols) ;
+
+		thiscost =
+		    /* new columns: */
+		    ((nc-1) * (cdeg_out-1)) +
+		    /* old columns in front grow by nr_out-1: */
+		    ((nr_out-1) * (fncols - extra_cols)) ;
+
+		/* size of relaxed front: */
+		fnrows_new [OUT][OUT] = fnrows + (nr_out-1) ;
+		fncols_new [OUT][OUT] = fncols + (nc-1) ;
+		relaxed_front = fnrows_new [OUT][OUT] * fncols_new [OUT][OUT] ;
+
+	    }
+
+	    /* do relaxed amalgamation if the extra zeros are no more */
+	    /* than a fraction (default 0.25) of the relaxed front */
+	    /* if relax = 0: no extra zeros allowed */
+	    /* if relax = +inf: always amalgamate */
+	    if (did_rowmerge)
+	    {
+		do_extend = FALSE ;
+	    }
+	    else
+	    {
+		/* relax parameter uses a double relop, but ignore NaN case: */
+		if (extra_zeros == 0)
+		{
+		    do_extend = TRUE ;
+		}
+		else
+		{
+		    do_extend = ((double) extra_zeros) <
+		       (relax1 * (double) relaxed_front) ;
+		}
+	    }
+
+	    if (do_extend)
+	    {
+		/* count the cost of relaxed amalgamation */
+		thiscost += extra_zeros ;
+
+		DEBUG2 (("Evaluating option OUT-OUT:\n")) ;
+		DEBUG2 (("Work->fnzeros "ID" fnpiv "ID" nr_out "ID" nc "ID"\n",
+		    Work->fnzeros, fnpiv, nr_out, nc)) ;
+		DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ;
+
+		/* determine if BLAS-3 update to be applied before extending. */
+		/* update if too many zero entries accumulate in the LU block */
+		fnzeros = Work->fnzeros + fnpiv * (nr_out + nc) ;
+
+		DEBUG2 (("fnzeros "ID"\n", fnzeros)) ;
+
+		new_LUsize = (fnpiv+1) * (fnrows + nr_out + fncols + nc) ;
+
+		DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ;
+
+		/* RELAX3 parameter uses a double relop, ignore NaN case: */
+		do_update = fnpiv > 0 &&
+		    (((double) fnzeros) / ((double) new_LUsize)) > RELAX3 ;
+		DEBUG2 (("do_update "ID"\n", do_update))
+	    }
+	    else
+	    {
+		/* the current front would not be extended */
+		do_update = fnpiv > 0 ;
+		fnzeros = 0 ;
+		DEBUG2 (("OUT-OUT do_update forced true: "ID"\n", do_update)) ;
+
+		/* The new front would be just big enough to hold the new
+		 * pivot row and column. */
+		fnrows_new [OUT][OUT] = cdeg_out - 1 ;
+		fncols_new [OUT][OUT] = rdeg [OUT][OUT] - 1 ;
+	    }
+
+	    DEBUG2 (("option OUT OUT: nr "ID" nc "ID" cost "ID"\n",
+		rdeg [OUT][OUT], cdeg_out, thiscost)) ;
+
+	    if (bestcost == EMPTY || thiscost < bestcost)
+	    {
+		/* this is the best option seen so far */
+		Work->pivot_case = OUT_OUT ;
+		bestcost = thiscost ;
+		Work->do_extend = do_extend ;
+		Work->do_update = do_update ;
+		new_fnzeros = fnzeros ;
+	    }
+	}
+    }
+
+    /* At this point, a structural pivot has been found. */
+    /* It may be numerically zero, however. */
+    ASSERT (Work->pivot_case != EMPTY) ;
+    DEBUG2 (("local search, best option "ID", best cost "ID"\n",
+	Work->pivot_case, bestcost)) ;
+
+    /* ====================================================================== */
+    /* Pivot row and column, and extension, now determined */
+    /* ====================================================================== */
+
+    Work->fnzeros = new_fnzeros ;
+
+    /* ---------------------------------------------------------------------- */
+    /* finalize the pivot row and column */
+    /* ---------------------------------------------------------------------- */
+
+    switch (Work->pivot_case)
+    {
+	case IN_IN:
+	    DEBUG2 (("IN-IN option selected\n")) ;
+	    ASSERT (fnrows > 0 && fncols > 0) ;
+	    Work->pivcol_in_front = TRUE ;
+	    Work->pivrow_in_front = TRUE ;
+	    Work->pivcol = pivcol [IN] ;
+	    Work->pivrow = pivrow [IN][IN] ;
+	    Work->ccdeg = nr_in ;
+	    Work->Wrow = Fcols ;
+	    Work->rrdeg = rdeg [IN][IN] ;
+	    jj = jcand [IN] ;
+	    Work->fnrows_new = fnrows_new [IN][IN] ;
+	    Work->fncols_new = fncols_new [IN][IN] ;
+	    break ;
+
+	case IN_OUT:
+	    DEBUG2 (("IN-OUT option selected\n")) ;
+	    ASSERT (fnrows >= 0 && fncols > 0) ;
+	    Work->pivcol_in_front = TRUE ;
+	    Work->pivrow_in_front = FALSE ;
+	    Work->pivcol = pivcol [IN] ;
+	    Work->pivrow = pivrow [IN][OUT] ;
+	    Work->ccdeg = nr_in ;
+	    Work->Wrow = Wio ;
+	    Work->rrdeg = rdeg [IN][OUT] ;
+	    jj = jcand [IN] ;
+	    Work->fnrows_new = fnrows_new [IN][OUT] ;
+	    Work->fncols_new = fncols_new [IN][OUT] ;
+	    break ;
+
+	case OUT_IN:
+	    DEBUG2 (("OUT-IN option selected\n")) ;
+	    ASSERT (fnrows > 0 && fncols >= 0) ;
+	    Work->pivcol_in_front = FALSE ;
+	    Work->pivrow_in_front = TRUE ;
+	    Work->pivcol = pivcol [OUT] ;
+	    Work->pivrow = pivrow [OUT][IN] ;
+	    Work->ccdeg = cdeg_out ;
+	    /* Wrow might be equivalenced to Fcols (Freebie in): */
+	    Work->Wrow = Woi ;
+	    Work->rrdeg = rdeg [OUT][IN] ;
+	    /* Work->Wrow[0..fncols-1] is not there.  See Fcols instead */
+	    jj = jcand [OUT] ;
+	    Work->fnrows_new = fnrows_new [OUT][IN] ;
+	    Work->fncols_new = fncols_new [OUT][IN] ;
+	    break ;
+
+	case OUT_OUT:
+	    DEBUG2 (("OUT-OUT option selected\n")) ;
+	    ASSERT (fnrows >= 0 && fncols >= 0) ;
+	    Work->pivcol_in_front = FALSE ;
+	    Work->pivrow_in_front = FALSE ;
+	    Work->pivcol = pivcol [OUT] ;
+	    Work->pivrow = pivrow [OUT][OUT] ;
+	    Work->ccdeg = cdeg_out ;
+	    /* Wrow might be equivalenced to Wio (Freebie out): */
+	    Work->Wrow = Woo ;
+	    Work->rrdeg = rdeg [OUT][OUT] ;
+	    jj = jcand [OUT] ;
+	    Work->fnrows_new = fnrows_new [OUT][OUT] ;
+	    Work->fncols_new = fncols_new [OUT][OUT] ;
+	    break ;
+
+    }
+
+    ASSERT (IMPLIES (fnrows == 0 && fncols == 0, Work->pivot_case == OUT_OUT)) ;
+
+    if (!Work->pivcol_in_front && pivcol [IN] != EMPTY)
+    {
+	/* clear Frpos if pivcol [IN] was searched, but not selected */
+	for (i = fnrows ; i < cdeg_in ; i++)
+	{
+	    Frpos [Frows [i]] = EMPTY;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* Pivot row and column have been found */
+    /* ---------------------------------------------------------------------- */
+
+    /* ---------------------------------------------------------------------- */
+    /* remove pivot column from candidate pivot column set */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (jj >= 0 && jj < Work->nCandidates) ;
+    ASSERT (Work->pivcol == Work->Candidates [jj]) ;
+    remove_candidate (jj, Work, Symbolic) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check for frontal matrix growth */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG1 (("Check frontal growth:\n")) ;
+    DEBUG1 (("fnrows_new "ID" + 1 = "ID",  fnr_curr "ID"\n",
+	    Work->fnrows_new, Work->fnrows_new + 1, fnr_curr)) ;
+    DEBUG1 (("fncols_new "ID" + 1 = "ID",  fnc_curr "ID"\n",
+	    Work->fncols_new, Work->fncols_new + 1, fnc_curr)) ;
+
+    Work->do_grow = (Work->fnrows_new + 1 > fnr_curr
+		  || Work->fncols_new + 1 > fnc_curr) ;
+    if (Work->do_grow)
+    {
+	DEBUG0 (("\nNeed to grow frontal matrix, force do_update true\n")) ;
+	/* If the front must grow, then apply the pending updates and remove
+	 * the current pivot rows/columns from the front prior to growing the
+	 * front.  This frees up as much space as possible for the new front. */
+	if (!Work->do_update && fnpiv > 0)
+	{
+	    /* This update would not have to be done if the current front
+	     * was big enough. */
+	    Work->nforced++ ;
+	    Work->do_update = TRUE ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* current pivot column */
+    /* ---------------------------------------------------------------------- */
+
+    /*
+	c1) If pivot column index is in the current front:
+
+	    The pivot column pattern is in Frows [0 .. fnrows-1] and
+	    the extension is in Frows [fnrows ... fnrows+ccdeg-1].
+
+	    Frpos [Frows [0 .. fnrows+ccdeg-1]] is
+	    equal to 0 .. fnrows+ccdeg-1.  Wm is not needed.
+
+	    The values are in Wy [0 .. fnrows+ccdeg-1].
+
+	c2) Otherwise, if the pivot column index is not in the current front:
+
+	    c2a) If the front is being extended, old row indices in the the
+		pivot column pattern are in Frows [0 .. fnrows-1].
+
+		All entries are in Wm [0 ... ccdeg-1], with values in
+		Wx [0 .. ccdeg-1].  These may include entries already in
+		Frows [0 .. fnrows-1].
+
+		Frpos [Frows [0 .. fnrows-1]] is equal to 0 .. fnrows-1.
+		Frpos [Wm [0 .. ccdeg-1]] for new entries is < 0.
+
+	    c2b) If the front is not being extended, then the entire pivot
+		column pattern is in Wm [0 .. ccdeg-1].  It includes
+		the pivot row index.  It is does not contain the pattern
+		Frows [0..fnrows-1].  The intersection of these two
+		sets may or may not be empty.  The values are in Wx [0..ccdeg-1]
+
+	In both cases c1 and c2, Frpos [Frows [0 .. fnrows-1]] is equal
+	to 0 .. fnrows-1, which is the pattern of the current front.
+	Any entry of Frpos that is not specified above is < 0.
+    */
+
+
+#ifndef NDEBUG
+    DEBUG2 (("\n\nSEARCH DONE: Pivot col "ID" in: ("ID") pivot row "ID" in: ("ID
+	") extend: "ID"\n\n", Work->pivcol, Work->pivcol_in_front,
+	Work->pivrow, Work->pivrow_in_front, Work->do_extend)) ;
+    UMF_dump_rowcol (1, Numeric, Work, Work->pivcol, !Symbolic->fixQ) ;
+    DEBUG2 (("Pivot col "ID": fnrows "ID" ccdeg "ID"\n", Work->pivcol, fnrows,
+	Work->ccdeg)) ;
+    if (Work->pivcol_in_front)	/* case c1 */
+    {
+	Int found = FALSE ;
+	DEBUG3 (("Pivcol in front\n")) ;
+	for (i = 0 ; i < fnrows ; i++)
+	{
+	    row = Frows [i] ;
+	    DEBUG3 ((ID":   row:: "ID" in front ", i, row)) ;
+	    ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;
+	    ASSERT (Frpos [row] == i) ;
+	    EDEBUG3 (Wy [i]) ;
+	    if (row == Work->pivrow)
+	    {
+		DEBUG3 ((" <- pivrow")) ;
+		found = TRUE ;
+	    }
+	    DEBUG3 (("\n")) ;
+	}
+	ASSERT (found == Work->pivrow_in_front) ;
+	found = FALSE ;
+	for (i = fnrows ; i < fnrows + Work->ccdeg ; i++)
+	{
+	    row = Frows [i] ;
+	    DEBUG3 ((ID":   row:: "ID" (new)", i, row)) ;
+	    ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;
+	    ASSERT (Frpos [row] == i) ;
+	    EDEBUG3 (Wy [i]) ;
+	    if (row == Work->pivrow)
+	    {
+		DEBUG3 ((" <- pivrow")) ;
+		found = TRUE ;
+	    }
+	    DEBUG3 (("\n")) ;
+	}
+	ASSERT (found == !Work->pivrow_in_front) ;
+    }
+    else
+    {
+	if (Work->do_extend)
+	{
+	    Int found = FALSE ;
+	    DEBUG3 (("Pivcol not in front (extend)\n")) ;
+	    for (i = 0 ; i < fnrows ; i++)
+	    {
+		row = Frows [i] ;
+		DEBUG3 ((ID":   row:: "ID" in front ", i, row)) ;
+		ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;
+		ASSERT (Frpos [row] == i) ;
+		if (row == Work->pivrow)
+		{
+		    DEBUG3 ((" <- pivrow")) ;
+		    found = TRUE ;
+		}
+		DEBUG3 (("\n")) ;
+	    }
+	    ASSERT (found == Work->pivrow_in_front) ;
+	    found = FALSE ;
+	    DEBUG3 (("----\n")) ;
+	    for (i = 0 ; i < Work->ccdeg ; i++)
+	    {
+		row = Wm [i] ;
+		ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;
+		DEBUG3 ((ID":   row:: "ID" ", i, row)) ;
+		EDEBUG3 (Wx [i]) ;
+		if (Frpos [row] < 0)
+		{
+		    DEBUG3 ((" (new) ")) ;
+		}
+		if (row == Work->pivrow)
+		{
+		    DEBUG3 ((" <- pivrow")) ;
+		    found = TRUE ;
+		    /* ... */
+		    if (Work->pivrow_in_front) ASSERT (Frpos [row] >= 0) ;
+		    else ASSERT (Frpos [row] < 0) ;
+		}
+		DEBUG3 (("\n")) ;
+	    }
+	    ASSERT (found) ;
+	}
+	else
+	{
+	    Int found = FALSE ;
+	    DEBUG3 (("Pivcol not in front (no extend)\n")) ;
+	    for (i = 0 ; i < Work->ccdeg ; i++)
+	    {
+		row = Wm [i] ;
+		ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;
+		DEBUG3 ((ID":   row:: "ID" ", i, row)) ;
+		EDEBUG3 (Wx [i]) ;
+		DEBUG3 ((" (new) ")) ;
+		if (row == Work->pivrow)
+		{
+		    DEBUG3 ((" <- pivrow")) ;
+		    found = TRUE ;
+		}
+		DEBUG3 (("\n")) ;
+	    }
+	    ASSERT (found) ;
+	}
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* current pivot row */
+    /* ---------------------------------------------------------------------- */
+
+    /*
+	r1) If the pivot row index is in the current front:
+
+	    The pivot row pattern is in Fcols [0..fncols-1] and the extenson is
+	    in Wrow [fncols .. rrdeg-1].  If the pivot column is in the current
+	    front, then Fcols and Wrow are equivalenced.
+
+	r2)  If the pivot row index is not in the current front:
+
+	    r2a) If the front is being extended, the pivot row pattern is in
+		Fcols [0 .. fncols-1].  New entries are in Wrow [0 .. rrdeg-1],
+		but these may include entries already in Fcols [0 .. fncols-1].
+
+	    r2b) Otherwise, the pivot row pattern is Wrow [0 .. rrdeg-1].
+
+	Fcpos [Fcols [0..fncols-1]] is (0..fncols-1) * fnr_curr.
+	All other entries in Fcpos are < 0.
+
+	These conditions are asserted below.
+
+	------------------------------------------------------------------------
+	Other items in Work structure that are relevant:
+
+	pivcol: the pivot column index
+	pivrow: the pivot column index
+
+	rrdeg:
+	ccdeg:
+
+	fnrows: the number of rows in the currnt contribution block
+	fncols: the number of columns in the current contribution block
+
+	fnrows_new: the number of rows in the new contribution block
+	fncols_new: the number of rows in the new contribution block
+
+	------------------------------------------------------------------------
+    */
+
+
+#ifndef NDEBUG
+    UMF_dump_rowcol (0, Numeric, Work, Work->pivrow, TRUE) ;
+    DEBUG2 (("Pivot row "ID":\n", Work->pivrow)) ;
+    if (Work->pivrow_in_front)
+    {
+	Int found = FALSE ;
+	for (i = 0 ; i < fncols ; i++)
+	{
+	    col = Fcols [i] ;
+	    DEBUG3 (("   col:: "ID" in front\n", col)) ;
+	    ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+	    ASSERT (Fcpos [col] == i * fnr_curr) ;
+	    if (col == Work->pivcol) found = TRUE ;
+	}
+	ASSERT (found == Work->pivcol_in_front) ;
+	found = FALSE ;
+	ASSERT (IMPLIES (Work->pivcol_in_front, Fcols == Work->Wrow)) ;
+	for (i = fncols ; i < Work->rrdeg ; i++)
+	{
+	    col = Work->Wrow [i] ;
+	    ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+	    ASSERT (Fcpos [col] < 0) ;
+	    if (col == Work->pivcol) found = TRUE ;
+	    else DEBUG3 (("   col:: "ID" (new)\n", col)) ;
+	}
+	ASSERT (found == !Work->pivcol_in_front) ;
+    }
+    else
+    {
+	if (Work->do_extend)
+	{
+	    Int found = FALSE ;
+	    for (i = 0 ; i < fncols ; i++)
+	    {
+		col = Fcols [i] ;
+		DEBUG3 (("   col:: "ID" in front\n", col)) ;
+		ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+		ASSERT (Fcpos [col] == i * fnr_curr) ;
+		if (col == Work->pivcol) found = TRUE ;
+	    }
+	    ASSERT (found == Work->pivcol_in_front) ;
+	    found = FALSE ;
+	    for (i = 0 ; i < Work->rrdeg ; i++)
+	    {
+		col = Work->Wrow [i] ;
+		ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+		if (Fcpos [col] >= 0) continue ;
+		if (col == Work->pivcol) found = TRUE ;
+		else DEBUG3 (("   col:: "ID" (new, extend)\n", col)) ;
+	    }
+	    ASSERT (found == !Work->pivcol_in_front) ;
+	}
+	else
+	{
+	    Int found = FALSE ;
+	    for (i = 0 ; i < Work->rrdeg ; i++)
+	    {
+		col = Work->Wrow [i] ;
+		ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+		if (col == Work->pivcol) found = TRUE ;
+		else DEBUG3 (("   col:: "ID" (all new)\n", col)) ;
+	    }
+	    ASSERT (found) ;
+	}
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* determine whether to do scan2-row and scan2-col */
+    /* ---------------------------------------------------------------------- */
+
+    if (Work->do_extend)
+    {
+	Work->do_scan2row = (fncols > 0) ;
+	Work->do_scan2col = (fnrows > 0) ;
+    }
+    else
+    {
+	Work->do_scan2row = (fncols > 0) && Work->pivrow_in_front ;
+	Work->do_scan2col = (fnrows > 0) && Work->pivcol_in_front ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG2 (("LOCAL SEARCH DONE: pivot column "ID" pivot row: "ID"\n",
+	Work->pivcol, Work->pivrow)) ;
+    DEBUG2 (("do_extend: "ID"\n", Work->do_extend)) ;
+    DEBUG2 (("do_update: "ID"\n", Work->do_update)) ;
+    DEBUG2 (("do_grow:   "ID"\n", Work->do_grow)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* keep track of the diagonal */
+    /* ---------------------------------------------------------------------- */
+
+    if (Symbolic->prefer_diagonal
+	&& 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) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_local_search.h b/src/C/SuiteSparse/UMFPACK/Source/umf_local_search.h
new file mode 100644
index 0000000..bd039f4
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_local_search.h
@@ -0,0 +1,12 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_local_search
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_lsolve.c b/src/C/SuiteSparse/UMFPACK/Source/umf_lsolve.c
new file mode 100644
index 0000000..a8c0c2d
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_lsolve.c
@@ -0,0 +1,151 @@
+/* ========================================================================== */
+/* === UMF_lsolve =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*  solves Lx = b, where L is the lower triangular factor of a matrix */
+/*  B is overwritten with the solution X. */
+/*  Returns the floating point operation count */
+
+#include "umf_internal.h"
+
+GLOBAL double UMF_lsolve
+(
+    NumericType *Numeric,
+    Entry X [ ],		/* b on input, solution x on output */
+    Int Pattern [ ]		/* a work array of size n */
+)
+{
+    Entry xk ;
+    Entry *xp, *Lval ;
+    Int k, deg, *ip, j, row, *Lpos, *Lilen, *Lip, llen, lp, newLchain,
+	pos, npiv, n1, *Li ;
+
+    /* ---------------------------------------------------------------------- */
+
+    if (Numeric->n_row != Numeric->n_col) return (0.) ;
+    npiv = Numeric->npiv ;
+    Lpos = Numeric->Lpos ;
+    Lilen = Numeric->Lilen ;
+    Lip = Numeric->Lip ;
+    n1 = Numeric->n1 ;
+
+#ifndef NDEBUG
+    DEBUG4 (("Lsolve start:\n")) ;
+    for (j = 0 ; j < Numeric->n_row ; j++)
+    {
+	DEBUG4 (("Lsolve start "ID": ", j)) ;
+	EDEBUG4 (X [j]) ;
+	DEBUG4 (("\n")) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* singletons */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < n1 ; k++)
+    {
+	DEBUG4 (("Singleton k "ID"\n", k)) ;
+	xk = X [k] ;
+	deg = Lilen [k] ;
+	if (deg > 0 && IS_NONZERO (xk))
+	{
+	    lp = Lip [k] ;
+	    Li = (Int *) (Numeric->Memory + lp) ;
+	    lp += UNITS (Int, deg) ;
+	    Lval = (Entry *) (Numeric->Memory + lp) ;
+	    for (j = 0 ; j < deg ; j++)
+	    {
+		DEBUG4 (("  row "ID"  k "ID" value", Li [j], k)) ;
+		EDEBUG4 (Lval [j]) ;
+		DEBUG4 (("\n")) ;
+		/* X [Li [j]] -= xk * Lval [j] ; */
+		MULT_SUB (X [Li [j]], xk, Lval [j]) ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* rest of L */
+    /* ---------------------------------------------------------------------- */
+
+    deg = 0 ;
+
+    for (k = n1 ; k < npiv ; k++)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* make column of L in Pattern [0..deg-1] */
+	/* ------------------------------------------------------------------ */
+
+	lp = Lip [k] ;
+	newLchain = (lp < 0) ;
+	if (newLchain)
+	{
+	    lp = -lp ;
+	    deg = 0 ;
+	    DEBUG4 (("start of chain for column of L\n")) ;
+	}
+
+	/* remove pivot row */
+	pos = Lpos [k] ;
+	if (pos != EMPTY)
+	{
+	    DEBUG4 (("  k "ID" removing row "ID" at position "ID"\n",
+	    k, Pattern [pos], pos)) ;
+	    ASSERT (!newLchain) ;
+	    ASSERT (deg > 0) ;
+	    ASSERT (pos >= 0 && pos < deg) ;
+	    ASSERT (Pattern [pos] == k) ;
+	    Pattern [pos] = Pattern [--deg] ;
+	}
+
+	/* concatenate the pattern */
+	ip = (Int *) (Numeric->Memory + lp) ;
+	llen = Lilen [k] ;
+	for (j = 0 ; j < llen ; j++)
+	{
+	    row = *ip++ ;
+	    DEBUG4 (("  row "ID"  k "ID"\n", row, k)) ;
+	    ASSERT (row > k) ;
+	    Pattern [deg++] = row ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* use column k of L */
+	/* ------------------------------------------------------------------ */
+
+	xk = X [k] ;
+	if (IS_NONZERO (xk))
+	{
+	    xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ;
+	    for (j = 0 ; j < deg ; j++)
+	    {
+		DEBUG4 (("  row "ID"  k "ID" value", Pattern [j], k)) ;
+		EDEBUG4 (*xp) ;
+		DEBUG4 (("\n")) ;
+		/* X [Pattern [j]] -= xk * (*xp) ; */
+		MULT_SUB (X [Pattern [j]], xk, *xp) ;
+		xp++ ;
+	    }
+	}
+    }
+
+#ifndef NDEBUG
+    for (j = 0 ; j < Numeric->n_row ; j++)
+    {
+	DEBUG4 (("Lsolve done "ID": ", j)) ;
+	EDEBUG4 (X [j]) ;
+	DEBUG4 (("\n")) ;
+    }
+    DEBUG4 (("Lsolve done.\n")) ;
+#endif
+
+    return (MULTSUB_FLOPS * ((double) Numeric->lnz)) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_lsolve.h b/src/C/SuiteSparse/UMFPACK/Source/umf_lsolve.h
new file mode 100644
index 0000000..187b950
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_lsolve.h
@@ -0,0 +1,12 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL double UMF_lsolve
+(
+    NumericType *Numeric,
+    Entry X [ ],
+    Int Pattern [ ]
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_ltsolve.c b/src/C/SuiteSparse/UMFPACK/Source/umf_ltsolve.c
new file mode 100644
index 0000000..383cf9b
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_ltsolve.c
@@ -0,0 +1,225 @@
+/* ========================================================================== */
+/* === UMF_ltsolve ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*  Solves L'x = b or L.'x=b, where L is the lower triangular factor of a */
+/*  matrix.  B is overwritten with the solution X. */
+/*  Returns the floating point operation count */
+
+#include "umf_internal.h"
+
+GLOBAL double
+#ifdef CONJUGATE_SOLVE
+UMF_lhsolve			/* solve L'x=b  (complex conjugate transpose) */
+#else
+UMF_ltsolve			/* solve L.'x=b (array transpose) */
+#endif
+(
+    NumericType *Numeric,
+    Entry X [ ],		/* b on input, solution x on output */
+    Int Pattern [ ]		/* a work array of size n */
+)
+{
+    Entry xk ;
+    Entry *xp, *Lval ;
+    Int k, deg, *ip, j, row, *Lpos, *Lilen, kstart, kend, *Lip, llen,
+	lp, pos, npiv, n1, *Li ;
+
+    /* ---------------------------------------------------------------------- */
+
+    if (Numeric->n_row != Numeric->n_col) return (0.) ;
+    npiv = Numeric->npiv ;
+    Lpos = Numeric->Lpos ;
+    Lilen = Numeric->Lilen ;
+    Lip = Numeric->Lip ;
+    kstart = npiv ;
+    n1 = Numeric->n1 ;
+
+#ifndef NDEBUG
+    DEBUG4 (("Ltsolve start:\n")) ;
+    for (j = 0 ; j < Numeric->n_row ; j++)
+    {
+	DEBUG4 (("Ltsolve start "ID": ", j)) ;
+	EDEBUG4 (X [j]) ;
+	DEBUG4 (("\n")) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* non-singletons */
+    /* ---------------------------------------------------------------------- */
+
+    for (kend = npiv-1 ; kend >= n1 ; kend = kstart-1)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* find the start of this Lchain */
+	/* ------------------------------------------------------------------ */
+
+	/* for (kstart = kend ; kstart >= 0 && Lip [kstart] > 0 ; kstart--) ; */
+	kstart = kend ;
+	while (kstart >= 0 && Lip [kstart] > 0)
+	{
+	    kstart-- ;
+	}
+
+	/* the Lchain goes from kstart to kend */
+
+	/* ------------------------------------------------------------------ */
+	/* scan the whole chain to find the pattern of the last column of L */
+	/* ------------------------------------------------------------------ */
+
+	deg = 0 ;
+	DEBUG4 (("start of chain for column of L\n")) ;
+	for (k = kstart ; k <= kend ; k++)
+	{
+	    ASSERT (k >= 0 && k < npiv) ;
+
+	    /* -------------------------------------------------------------- */
+	    /* make column k of L in Pattern [0..deg-1] */
+	    /* -------------------------------------------------------------- */
+
+	    /* remove pivot row */
+	    pos = Lpos [k] ;
+	    if (pos != EMPTY)
+	    {
+		DEBUG4 (("  k "ID" removing row "ID" at position "ID"\n",
+		k, Pattern [pos], pos)) ;
+		ASSERT (k != kstart) ;
+		ASSERT (deg > 0) ;
+		ASSERT (pos >= 0 && pos < deg) ;
+		ASSERT (Pattern [pos] == k) ;
+		Pattern [pos] = Pattern [--deg] ;
+	    }
+
+	    /* concatenate the pattern */
+	    lp = Lip [k] ;
+	    if (k == kstart)
+	    {
+		lp = -lp ;
+	    }
+	    ASSERT (lp > 0) ;
+	    ip = (Int *) (Numeric->Memory + lp) ;
+	    llen = Lilen [k] ;
+	    for (j = 0 ; j < llen ; j++)
+	    {
+		row = *ip++ ;
+		DEBUG4 (("  row "ID"  k "ID"\n", row, k)) ;
+		ASSERT (row > k) ;
+		Pattern [deg++] = row ;
+	    }
+
+	}
+	/* Pattern [0..deg-1] is now the pattern of column kend */
+
+	/* ------------------------------------------------------------------ */
+	/* solve using this chain, in reverse order */
+	/* ------------------------------------------------------------------ */
+
+	DEBUG4 (("Unwinding Lchain\n")) ;
+	for (k = kend ; k >= kstart ; k--)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* use column k of L */
+	    /* -------------------------------------------------------------- */
+
+	    ASSERT (k >= 0 && k < npiv) ;
+	    lp = Lip [k] ;
+	    if (k == kstart)
+	    {
+		lp = -lp ;
+	    }
+	    ASSERT (lp > 0) ;
+	    llen = Lilen [k] ;
+	    xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ;
+	    xk = X [k] ;
+	    for (j = 0 ; j < deg ; j++)
+	    {
+		DEBUG4 (("  row "ID"  k "ID" value", Pattern [j], k)) ;
+		EDEBUG4 (*xp) ;
+		DEBUG4 (("\n")) ;
+
+#ifdef CONJUGATE_SOLVE
+		/* xk -= X [Pattern [j]] * conjugate (*xp) ; */
+		MULT_SUB_CONJ (xk, X [Pattern [j]], *xp) ;
+#else
+		/* xk -= X [Pattern [j]] * (*xp) ; */
+		MULT_SUB (xk, X [Pattern [j]], *xp) ;
+#endif
+
+		xp++ ;
+	    }
+	    X [k] = xk ;
+
+	    /* -------------------------------------------------------------- */
+	    /* construct column k-1 of L */
+	    /* -------------------------------------------------------------- */
+
+	    /* un-concatenate the pattern */
+	    deg -= llen ;
+
+	    /* add pivot row */
+	    pos = Lpos [k] ;
+	    if (pos != EMPTY)
+	    {
+		DEBUG4 (("  k "ID" adding row "ID" at position "ID"\n",
+		k, k, pos)) ;
+		ASSERT (k != kstart) ;
+		ASSERT (pos >= 0 && pos <= deg) ;
+		Pattern [deg++] = Pattern [pos] ;
+		Pattern [pos] = k ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* singletons */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = n1 - 1 ; k >= 0 ; k--)
+    {
+	DEBUG4 (("Singleton k "ID"\n", k)) ;
+	deg = Lilen [k] ;
+	if (deg > 0)
+	{
+	    xk = X [k] ;
+	    lp = Lip [k] ;
+	    Li = (Int *) (Numeric->Memory + lp) ;
+	    lp += UNITS (Int, deg) ;
+	    Lval = (Entry *) (Numeric->Memory + lp) ;
+	    for (j = 0 ; j < deg ; j++)
+	    {
+		DEBUG4 (("  row "ID"  k "ID" value", Li [j], k)) ;
+		EDEBUG4 (Lval [j]) ;
+		DEBUG4 (("\n")) ;
+#ifdef CONJUGATE_SOLVE
+		/* xk -= X [Li [j]] * conjugate (Lval [j]) ; */
+		MULT_SUB_CONJ (xk, X [Li [j]], Lval [j]) ;
+#else
+		/* xk -= X [Li [j]] * Lval [j] ; */
+		MULT_SUB (xk, X [Li [j]], Lval [j]) ;
+#endif
+	    }
+	    X [k] = xk ;
+	}
+    }
+
+#ifndef NDEBUG
+    for (j = 0 ; j < Numeric->n_row ; j++)
+    {
+	DEBUG4 (("Ltsolve done "ID": ", j)) ;
+	EDEBUG4 (X [j]) ;
+	DEBUG4 (("\n")) ;
+    }
+    DEBUG4 (("Ltsolve done.\n")) ;
+#endif
+
+    return (MULTSUB_FLOPS * ((double) Numeric->lnz)) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_ltsolve.h b/src/C/SuiteSparse/UMFPACK/Source/umf_ltsolve.h
new file mode 100644
index 0000000..ba5995a
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_ltsolve.h
@@ -0,0 +1,19 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL double UMF_ltsolve
+(
+    NumericType *Numeric,
+    Entry X [ ],
+    Int Pattern [ ]
+) ;
+
+GLOBAL double UMF_lhsolve
+(
+    NumericType *Numeric,
+    Entry X [ ],
+    Int Pattern [ ]
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_malloc.c b/src/C/SuiteSparse/UMFPACK/Source/umf_malloc.c
new file mode 100644
index 0000000..97c43fd
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_malloc.c
@@ -0,0 +1,91 @@
+/* ========================================================================== */
+/* === UMF_malloc =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Allocate a block of n objects, each of a given size.  This routine does not
+    handle the case when the size is 1 (allocating char's) because of potential
+    integer overflow.  UMFPACK never does that.
+    Also maintains the UMFPACK malloc count.
+*/
+
+#include "umf_internal.h"
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+
+/*
+    UMF_malloc_count is a count of the objects malloc'd by UMFPACK.  If you
+    suspect a memory leak in your program (caused by not properly destroying
+    the Symbolic and Numeric objects) then compile with -DUMF_MALLOC_COUNT and
+    check value of UMF_malloc_count.  By default, UMF_MALLOC_COUNT is not
+    defined, and thus UMFPACK has no global variables.
+*/
+
+GLOBAL Int UMF_malloc_count = 0 ;
+
+#endif
+
+#ifdef UMF_TCOV_TEST
+/* For exhaustive statement coverage testing only! */
+GLOBAL int umf_fail, umf_fail_lo, umf_fail_hi ;
+GLOBAL int umf_realloc_fail, umf_realloc_lo, umf_realloc_hi ;
+#endif
+
+GLOBAL void *UMF_malloc
+(
+    Int n_objects,
+    size_t size_of_object
+)
+{
+    size_t size ;
+    void *p ;
+
+#ifdef UMF_TCOV_TEST
+    /* For exhaustive statement coverage testing only! */
+    /* Pretend to fail, to test out-of-memory conditions. */
+    umf_fail-- ;
+    if (umf_fail <= umf_fail_hi && umf_fail >= umf_fail_lo)
+    {
+	DEBUG0 (("umf_malloc: Pretend to fail %d %d %d\n",
+	    umf_fail, umf_fail_hi, umf_fail_lo)) ;
+	return ((void *) NULL) ;
+    }
+#endif
+
+    DEBUG0 (("UMF_malloc: ")) ;
+
+    /* make sure that we allocate something */
+    n_objects = MAX (1, n_objects) ;
+
+    size = (size_t) n_objects ;
+    ASSERT (size_of_object > 1) ;
+    if (size > Int_MAX / size_of_object)
+    {
+	/* object is too big for integer pointer arithmetic */
+	return ((void *) NULL) ;
+    }
+    size *= size_of_object ;
+
+    /* see AMD/Source/amd_global.c for the memory allocator selection */
+    p = amd_malloc (size) ;
+
+    DEBUG0 ((ID"\n", (Int) p)) ;
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+    if (p)
+    {
+	/* One more object has been malloc'ed.  Keep track of the count. */
+	/* (purely for sanity checks). */
+	UMF_malloc_count++ ;
+	DEBUG0 (("  successful, new malloc count: "ID"\n", UMF_malloc_count)) ;
+    }
+#endif
+
+    return (p) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_malloc.h b/src/C/SuiteSparse/UMFPACK/Source/umf_malloc.h
new file mode 100644
index 0000000..486a491
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_malloc.h
@@ -0,0 +1,25 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+#ifndef _UMF_MALLOC
+#define _UMF_MALLOC
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+GLOBAL EXTERN Int UMF_malloc_count ;
+#endif
+
+GLOBAL void *UMF_malloc
+(
+    Int n_objects,
+    size_t size_of_object
+) ;
+
+#endif
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_element.c b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_element.c
new file mode 100644
index 0000000..73553bd
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_element.c
@@ -0,0 +1,82 @@
+/* ========================================================================== */
+/* === UMF_mem_alloc_element ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* The UMF_mem_* routines manage the Numeric->Memory memory space. */
+
+/* Allocate a nrows-by-ncols element, and initialize it. */
+/* Returns the index into Numeric->Memory if successful, or 0 on failure. */
+
+#include "umf_internal.h"
+#include "umf_mem_alloc_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) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_element.h b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_element.h
new file mode 100644
index 0000000..4463071
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_element.h
@@ -0,0 +1,17 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_mem_alloc_element
+(
+    NumericType *Numeric,
+    Int nrows,
+    Int ncols,
+    Int **Rows,
+    Int **Cols,
+    Entry **C,
+    Int *size,
+    Element **epout
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_head_block.c b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_head_block.c
new file mode 100644
index 0000000..bc9cd22
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_head_block.c
@@ -0,0 +1,54 @@
+/* ========================================================================== */
+/* === UMF_mem_alloc_head_block ============================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* The UMF_mem_* routines manage the Numeric->Memory memory space. */
+
+/* allocate nunits from head of Numeric->Memory.  No header allocated. */
+/* Returns the index into Numeric->Memory if successful, or 0 on failure. */
+
+#include "umf_internal.h"
+
+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) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_head_block.h b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_head_block.h
new file mode 100644
index 0000000..d861330
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_head_block.h
@@ -0,0 +1,11 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_mem_alloc_head_block
+(
+    NumericType *Numeric,
+    Int nunits
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_tail_block.c b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_tail_block.c
new file mode 100644
index 0000000..afe8ee1
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_tail_block.c
@@ -0,0 +1,133 @@
+/* ========================================================================== */
+/* === UMF_mem_alloc_tail_block ============================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* The UMF_mem_* routines manage the Numeric->Memory memory space. */
+
+#include "umf_internal.h"
+
+/* 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) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_tail_block.h b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_tail_block.h
new file mode 100644
index 0000000..91ae285
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_tail_block.h
@@ -0,0 +1,11 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_mem_alloc_tail_block
+(
+    NumericType *Numeric,
+    Int nunits
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_mem_free_tail_block.c b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_free_tail_block.c
new file mode 100644
index 0000000..6aea23a
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_free_tail_block.c
@@ -0,0 +1,142 @@
+/* ========================================================================== */
+/* === UMF_mem_free_tail_block ============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* The UMF_mem_* routines manage the Numeric->Memory memory space. */
+
+/* free a block from the tail of Numeric->memory */
+
+#include "umf_internal.h"
+
+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))) ;
+
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_mem_free_tail_block.h b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_free_tail_block.h
new file mode 100644
index 0000000..15c4c3b
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_free_tail_block.h
@@ -0,0 +1,11 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_mem_free_tail_block
+(
+    NumericType *Numeric,
+    Int i
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_mem_init_memoryspace.c b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_init_memoryspace.c
new file mode 100644
index 0000000..3b4e0c0
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_init_memoryspace.c
@@ -0,0 +1,64 @@
+/* ========================================================================== */
+/* === UMF_mem_init_memoryspace ============================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* The UMF_mem_* routines manage the Numeric->Memory memory space. */
+
+#include "umf_internal.h"
+
+/* 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
+
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_mem_init_memoryspace.h b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_init_memoryspace.h
new file mode 100644
index 0000000..30a09b8
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_mem_init_memoryspace.h
@@ -0,0 +1,10 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_mem_init_memoryspace
+(
+    NumericType *Numeric
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_multicompile.c b/src/C/SuiteSparse/UMFPACK/Source/umf_multicompile.c
new file mode 100644
index 0000000..ffafef3
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_multicompile.c
@@ -0,0 +1,58 @@
+/* ========================================================================== */
+/* === UMF_multicompile ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* This file is not needed if you have the Unix/Linux "make" command for
+ * compiling UMFPACK.  Microsoft Visual Studio cannot be configured to compile
+ * one file multiple times, with different -D flags.  In this case, you can
+ * use this file instead.  To use this file, see the Demo/simple_compile file.
+ *
+ * This file includes the following source files:
+ *
+ *	umf_ltsolve.c
+ *	umf_utsolve.c
+ *	umf_triplet.c
+ *	umf_assemble.c
+ *	umf_store_lu.c
+ *	umfpack_solve.c
+ *
+ * This file simply compiles the above files with different pre-#define'd flags,
+ * by defining the flags and then #include'ing the source files themselves.
+ * This is a rather unconventional approach, since by convention #include is
+ * supposed to be used with *.h files not *.c.  However, it is one way of
+ * working around the limitations of Microsoft Visual Studio.
+ *
+ * You still need to compile all files separately as well, with none of the
+ * pre-#define'd terms listed below.
+ */
+
+/* compile the complex conjugate forward/backsolves */
+#define CONJUGATE_SOLVE
+#include "umf_ltsolve.c"
+#include "umf_utsolve.c"
+
+/* compile umf_triplet with DO_MAP, DO_VALUES and DO_MAP, and just DO_VALUES */
+#define DO_MAP
+#include "umf_triplet.c"
+#define DO_VALUES
+#include "umf_triplet.c"
+#undef DO_MAP
+#include "umf_triplet.c"
+
+/* compile the FIXQ version of umf_assemble */
+#define FIXQ
+#include "umf_assemble.c"
+
+/* compile the DROP version of umf_store_lu */
+#define DROP
+#include "umf_store_lu.c"
+
+/* compile umfpack_wsolve */
+#define WSOLVE
+#include "umfpack_solve.c"
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_realloc.c b/src/C/SuiteSparse/UMFPACK/Source/umf_realloc.c
new file mode 100644
index 0000000..8504d0b
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_realloc.c
@@ -0,0 +1,75 @@
+/* ========================================================================== */
+/* === UMF_realloc ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Realloc a block previously allocated by UMF_malloc.
+    Return NULL on failure (in which case the block is still allocated, and will
+    be kept at is present size).  This routine is only used for Numeric->Memory.
+*/
+
+#include "umf_internal.h"
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+#include "umf_malloc.h"
+#endif
+
+GLOBAL void *UMF_realloc
+(
+    void *p,
+    Int n_objects,
+    size_t size_of_object
+)
+{
+    size_t size ;
+    void *p2 ;
+
+#ifdef UMF_TCOV_TEST
+    /* For exhaustive statement coverage testing only! */
+    /* Pretend to fail, to test out-of-memory conditions. */
+    umf_realloc_fail-- ;
+    if (umf_realloc_fail <= umf_realloc_hi &&
+	umf_realloc_fail >= umf_realloc_lo)
+    {
+	return ((void *) NULL) ;
+    }
+#endif
+
+    /* make sure that we allocate something */
+    n_objects = MAX (1, n_objects) ;
+
+    size = (size_t) n_objects ;
+    ASSERT (size_of_object > 1) ;
+    if (size > Int_MAX / size_of_object)
+    {
+	/* :: int overflow in umf_realloc :: */
+	return ((void *) NULL) ;
+    }
+    size *= size_of_object ;
+
+    DEBUG0 (("UMF_realloc: "ID" n_objects "ID"  size_of_object "ID"\n",
+	(Int) p, n_objects, (Int) size_of_object)) ;
+
+    /* see AMD/Source/amd_global.c for the memory allocator selection */
+    p2 = amd_realloc (p, size) ;
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+    /* If p didn't exist on input, and p2 exists, then a new object has been
+     * allocated. */
+    if (p == (void *) NULL && p2 != (void *) NULL)
+    {
+	UMF_malloc_count++ ;
+    }
+#endif
+
+    DEBUG0 (("UMF_realloc: "ID" new malloc count "ID"\n",
+	(Int) p2, UMF_malloc_count)) ;
+
+    return (p2) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_realloc.h b/src/C/SuiteSparse/UMFPACK/Source/umf_realloc.h
new file mode 100644
index 0000000..b55c30e
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_realloc.h
@@ -0,0 +1,12 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void *UMF_realloc
+(
+    void *p,
+    Int n_objects,
+    size_t size_of_object
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_report_perm.c b/src/C/SuiteSparse/UMFPACK/Source/umf_report_perm.c
new file mode 100644
index 0000000..bc25faa
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_report_perm.c
@@ -0,0 +1,85 @@
+/* ========================================================================== */
+/* === UMF_report_perm ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_internal.h"
+
+#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) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_report_perm.h b/src/C/SuiteSparse/UMFPACK/Source/umf_report_perm.h
new file mode 100644
index 0000000..dd81936
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_report_perm.h
@@ -0,0 +1,14 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_report_perm
+(
+    Int n,
+    const Int P [ ],
+    Int W [ ],
+    Int prl,
+    Int user
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_report_vector.c b/src/C/SuiteSparse/UMFPACK/Source/umf_report_vector.c
new file mode 100644
index 0000000..7587204
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_report_vector.c
@@ -0,0 +1,110 @@
+/* ========================================================================== */
+/* === UMF_report_vector ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_internal.h"
+
+/* ========================================================================== */
+/* === print_value ========================================================== */
+/* ========================================================================== */
+
+PRIVATE void print_value
+(
+    Int i,
+    const double Xx [ ],
+    const double Xz [ ],    /* used for complex case only */
+    Int scalar		    /* if true, then print real part only */
+)
+{
+    Entry xi ;
+    /* if Xz is null, then X is in "merged" format (compatible with Entry, */
+    /* and ANSI C99 double _Complex type). */
+    PRINTF (("    "ID" :", INDEX (i))) ;
+    if (scalar)
+    {
+	PRINT_SCALAR (Xx [i]) ;
+    }
+    else
+    {
+	ASSIGN (xi, Xx, Xz, i, SPLIT (Xz)) ;
+	PRINT_ENTRY (xi) ;
+    }
+    PRINTF (("\n")) ;
+}
+
+/* ========================================================================== */
+/* === UMF_report_vector ==================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMF_report_vector
+(
+    Int n,
+    const double Xx [ ],
+    const double Xz [ ],
+    Int prl,
+    Int user,
+    Int scalar
+)
+{
+    Int n2, i ;
+
+    if (user || prl >= 4)
+    {
+	PRINTF (("dense vector, n = "ID". ", n)) ;
+    }
+
+    if (user)
+    {
+	if (!Xx)
+	{
+	    PRINTF (("ERROR: vector not present\n\n")) ;
+	    return (UMFPACK_ERROR_argument_missing) ;
+	}
+	if (n < 0)
+	{
+	    PRINTF (("ERROR: length of vector is < 0\n\n")) ;
+	    return (UMFPACK_ERROR_n_nonpositive) ;
+	}
+    }
+
+    if (user || prl >= 4)
+    {
+	PRINTF4 (("\n")) ;
+    }
+
+    if (prl == 4)
+    {
+	/* print level of 4 */
+	n2 = MIN (10, n) ;
+	for (i = 0 ; i < n2 ; i++)
+	{
+	    print_value (i, Xx, Xz, scalar) ;
+	}
+	if (n2 < n)
+	{
+	    PRINTF (("    ...\n")) ;
+	    print_value (n-1, Xx, Xz, scalar) ;
+	}
+    }
+    else if (prl > 4)
+    {
+	/* print level 4 or more */
+	for (i = 0 ; i < n ; i++)
+	{
+	    print_value  (i, Xx, Xz, scalar) ;
+	}
+    }
+
+    PRINTF4 (("    dense vector ")) ;
+    if (user || prl >= 4)
+    {
+	PRINTF (("OK\n\n")) ;
+    }
+    return (UMFPACK_OK) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_report_vector.h b/src/C/SuiteSparse/UMFPACK/Source/umf_report_vector.h
new file mode 100644
index 0000000..665a8d4
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_report_vector.h
@@ -0,0 +1,15 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_report_vector
+(
+    Int n,
+    const double Xx [ ],
+    const double Xz [ ],
+    Int prl,
+    Int user,
+    Int scalar
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_row_search.c b/src/C/SuiteSparse/UMFPACK/Source/umf_row_search.c
new file mode 100644
index 0000000..aefb36d
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_row_search.c
@@ -0,0 +1,837 @@
+/* ========================================================================== */
+/* === UMF_row_search ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Find two candidate pivot rows in a column: the best one in the front,
+    and the best one not in the front.  Return the two pivot row patterns and
+    their exact degrees.  Called by UMF_local_search.
+
+    Returns UMFPACK_OK if successful, or UMFPACK_WARNING_singular_matrix or
+    UMFPACK_ERROR_different_pattern if not.
+
+*/
+
+#include "umf_internal.h"
+#include "umf_row_search.h"
+
+GLOBAL Int UMF_row_search
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic,
+    Int cdeg0,			/* length of column in Front */
+    Int cdeg1,			/* length of column outside Front */
+    const Int Pattern [ ],	/* pattern of column, Pattern [0..cdeg1 -1] */
+    const Int Pos [ ],		/* Pos [Pattern [0..cdeg1 -1]] = 0..cdeg1 -1 */
+    Int pivrow [2],		/* pivrow [IN] and pivrow [OUT] */
+    Int rdeg [2],		/* rdeg [IN] and rdeg [OUT] */
+    Int W_i [ ],		/* pattern of pivrow [IN], */
+				/* either Fcols or Woi */
+    Int W_o [ ],		/* pattern of pivrow [OUT], */
+				/* either Wio or Woo */
+    Int prior_pivrow [2],	/* the two other rows just scanned, if any */
+    const Entry Wxy [ ],	/* numerical values Wxy [0..cdeg1-1],
+				   either Wx or Wy */
+
+    Int pivcol,			/* the candidate column being searched */
+    Int freebie [ ]
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    double maxval, toler, toler2, value, pivot [2] ;
+    Int i, row, deg, col, *Frpos, fnrows, *E, j, ncols, *Cols, *Rows,
+	e, f, Wrpflag, *Fcpos, fncols, tpi, max_rdeg, nans_in_col, was_offdiag,
+	diag_row, prefer_diagonal, *Wrp, found, *Diagonal_map ;
+    Tuple *tp, *tpend, *tp1, *tp2 ;
+    Unit *Memory, *p ;
+    Element *ep ;
+    Int *Row_tuples, *Row_degree, *Row_tlen ;
+
+#ifndef NDEBUG
+    Int *Col_degree ;
+    DEBUG2 (("Row_search:\n")) ;
+    for (i = 0 ; i < cdeg1 ; i++)
+    {
+	row = Pattern [i] ;
+	DEBUG4 (("   row: "ID"\n", row)) ;
+	ASSERT (row >= 0 && row < Numeric->n_row) ;
+	ASSERT (i == Pos [row]) ;
+    }
+    /* If row is not in Pattern [0..cdeg1-1], then Pos [row] == EMPTY */
+    if (UMF_debug > 0 || Numeric->n_row < 1000)
+    {
+	Int cnt = cdeg1 ;
+	DEBUG4 (("Scan all rows:\n")) ;
+	for (row = 0 ; row < Numeric->n_row ; row++)
+	{
+	    if (Pos [row] < 0)
+	    {
+		cnt++ ;
+	    }
+	    else
+	    {
+		DEBUG4 (("   row: "ID" pos "ID"\n", row, Pos [row])) ;
+	    }
+	}
+	ASSERT (cnt == Numeric->n_row) ;
+    }
+    Col_degree = Numeric->Cperm ;   /* for NON_PIVOTAL_COL macro only */
+    ASSERT (pivcol >= 0 && pivcol < Work->n_col) ;
+    ASSERT (NON_PIVOTAL_COL (pivcol)) ;
+#endif
+
+    pivot [IN] = 0. ;
+    pivot [OUT] = 0. ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    Row_degree = Numeric->Rperm ;
+    Row_tuples = Numeric->Uip ;
+    Row_tlen   = Numeric->Uilen ;
+    Wrp = Work->Wrp ;
+    Frpos = Work->Frpos ;
+    E = Work->E ;
+    Memory = Numeric->Memory ;
+    fnrows = Work->fnrows ;
+
+    prefer_diagonal = Symbolic->prefer_diagonal ;
+    Diagonal_map = Work->Diagonal_map ;
+
+    if (Diagonal_map)
+    {
+	diag_row = Diagonal_map [pivcol] ;
+	was_offdiag = diag_row < 0 ;
+	if (was_offdiag)
+	{
+	    /* the "diagonal" entry in this column was permuted here by an
+	     * earlier pivot choice.  The tighter off-diagonal tolerance will
+	     * be used instead of the symmetric tolerance. */
+	    diag_row = FLIP (diag_row) ;
+	}
+	ASSERT (diag_row >= 0 && diag_row < Numeric->n_row) ;
+    }
+    else
+    {
+	diag_row = EMPTY ;	/* unused */
+	was_offdiag = EMPTY ;	/* unused */
+    }
+
+    /* pivot row degree cannot exceed max_rdeg */
+    max_rdeg = Work->fncols_max ;
+
+    /* ---------------------------------------------------------------------- */
+    /* scan pivot column for candidate rows */
+    /* ---------------------------------------------------------------------- */
+
+    maxval = 0.0 ;
+    nans_in_col = FALSE ;
+
+    for (i = 0 ; i < cdeg1 ; i++)
+    {
+	APPROX_ABS (value, Wxy [i]) ;
+	if (SCALAR_IS_NAN (value))
+	{
+	    nans_in_col = TRUE ;
+	    maxval = value ;
+	    break ;
+	}
+	/* This test can now ignore the NaN case: */
+	maxval = MAX (maxval, value) ;
+    }
+
+    /* if maxval is zero, the matrix is numerically singular */
+
+    toler = Numeric->relpt * maxval ;
+    toler2 = Numeric->relpt2 * maxval ;
+    toler2 = was_offdiag ? toler : toler2 ;
+
+    DEBUG5 (("Row_search begins [ maxval %g toler %g %g\n",
+	maxval, toler, toler2)) ;
+    if (SCALAR_IS_NAN (toler) || SCALAR_IS_NAN (toler2))
+    {
+	nans_in_col = TRUE ;
+    }
+
+    if (!nans_in_col)
+    {
+
+	/* look for the diagonal entry, if it exists */
+	found = FALSE ;
+	ASSERT (!SCALAR_IS_NAN (toler)) ;
+
+	if (prefer_diagonal)
+	{
+	    ASSERT (diag_row != EMPTY) ;
+	    i = Pos [diag_row] ;
+	    if (i >= 0)
+	    {
+		double a ;
+		ASSERT (i < cdeg1) ;
+		ASSERT (diag_row == Pattern [i]) ;
+
+		APPROX_ABS (a, Wxy [i]) ;
+
+		ASSERT (!SCALAR_IS_NAN (a)) ;
+		ASSERT (!SCALAR_IS_NAN (toler2)) ;
+
+		if (SCALAR_IS_NONZERO (a) && a >= toler2)
+		{
+		    /* found it! */
+		    DEBUG3 (("Symmetric pivot: "ID" "ID"\n", pivcol, diag_row));
+		    found = TRUE ;
+		    if (Frpos [diag_row] >= 0 && Frpos [diag_row] < fnrows)
+		    {
+			pivrow [IN] = diag_row ;
+			pivrow [OUT] = EMPTY ;
+		    }
+		    else
+		    {
+			pivrow [IN] = EMPTY ;
+			pivrow [OUT] = diag_row ;
+		    }
+		}
+	    }
+	}
+
+	/* either no diagonal found, or we didn't look for it */
+	if (!found)
+	{
+	    if (cdeg0 > 0)
+	    {
+
+		/* this is a column in the front */
+		for (i = 0 ; i < cdeg0 ; i++)
+		{
+		    double a ;
+		    APPROX_ABS (a, Wxy [i]) ;
+		    ASSERT (!SCALAR_IS_NAN (a)) ;
+		    ASSERT (!SCALAR_IS_NAN (toler)) ;
+		    if (SCALAR_IS_NONZERO (a) && a >= toler)
+		    {
+			row = Pattern [i] ;
+			deg = Row_degree [row] ;
+#ifndef NDEBUG
+			DEBUG6 ((ID" candidate row "ID" deg "ID" absval %g\n",
+			    i, row, deg, a)) ;
+			UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ;
+#endif
+			ASSERT (Frpos [row] >= 0 && Frpos [row] < fnrows) ;
+			ASSERT (Frpos [row] == i) ;
+			/* row is in the current front */
+			DEBUG4 ((" in front\n")) ;
+			if (deg < rdeg [IN]
+			    /* break ties by picking the largest entry: */
+			       || (deg == rdeg [IN] && a > pivot [IN])
+			    /* break ties by picking the diagonal entry: */
+			    /* || (deg == rdeg [IN] && row == diag_row) */
+			   )
+			{
+			    /* best row in front, so far */
+			    pivrow [IN] = row ;
+			    rdeg [IN] = deg ;
+			    pivot [IN] = a ;
+			}
+		    }
+		}
+		for ( ; i < cdeg1 ; i++)
+		{
+		    double a ;
+		    APPROX_ABS (a, Wxy [i]) ;
+		    ASSERT (!SCALAR_IS_NAN (a)) ;
+		    ASSERT (!SCALAR_IS_NAN (toler)) ;
+		    if (SCALAR_IS_NONZERO (a) && a >= toler)
+		    {
+			row = Pattern [i] ;
+			deg = Row_degree [row] ;
+#ifndef NDEBUG
+			DEBUG6 ((ID" candidate row "ID" deg "ID" absval %g\n",
+			    i, row, deg, a)) ;
+			UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ;
+#endif
+			ASSERT (Frpos [row] == i) ;
+			/* row is not in the current front */
+			DEBUG4 ((" NOT in front\n")) ;
+			if (deg < rdeg [OUT]
+			    /* break ties by picking the largest entry: */
+			       || (deg == rdeg [OUT] && a > pivot [OUT])
+			    /* break ties by picking the diagonal entry: */
+			    /* || (deg == rdeg [OUT] && row == diag_row) */
+			   )
+			{
+			    /* best row not in front, so far */
+			    pivrow [OUT] = row ;
+			    rdeg [OUT] = deg ;
+			    pivot [OUT] = a ;
+			}
+		    }
+		}
+
+	    }
+	    else
+	    {
+
+		/* this column is not in the front */
+		for (i = 0 ; i < cdeg1 ; i++)
+		{
+		    double a ;
+		    APPROX_ABS (a, Wxy [i]) ;
+		    ASSERT (!SCALAR_IS_NAN (a)) ;
+		    ASSERT (!SCALAR_IS_NAN (toler)) ;
+		    if (SCALAR_IS_NONZERO (a) && a >= toler)
+		    {
+			row = Pattern [i] ;
+			deg = Row_degree [row] ;
+#ifndef NDEBUG
+			DEBUG6 ((ID" candidate row "ID" deg "ID" absval %g\n",
+			    i, row, deg, a)) ;
+			UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ;
+#endif
+			if (Frpos [row] >= 0 && Frpos [row] < fnrows)
+			{
+			    /* row is in the current front */
+			    DEBUG4 ((" in front\n")) ;
+			    if (deg < rdeg [IN]
+			    /* break ties by picking the largest entry: */
+			       || (deg == rdeg [IN] && a > pivot [IN])
+			    /* break ties by picking the diagonal entry: */
+			    /* || (deg == rdeg [IN] && row == diag_row) */
+			       )
+			    {
+				/* best row in front, so far */
+				pivrow [IN] = row ;
+				rdeg [IN] = deg ;
+				pivot [IN] = a ;
+			    }
+			}
+			else
+			{
+			    /* row is not in the current front */
+			    DEBUG4 ((" NOT in front\n")) ;
+			    if (deg < rdeg [OUT]
+			    /* break ties by picking the largest entry: */
+			       || (deg == rdeg[OUT] && a > pivot [OUT])
+			    /* break ties by picking the diagonal entry: */
+			    /* || (deg == rdeg[OUT] && row == diag_row) */
+			       )
+			    {
+				/* best row not in front, so far */
+				pivrow [OUT] = row ;
+				rdeg [OUT] = deg ;
+				pivot [OUT] = a ;
+			    }
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* NaN handling */
+    /* ---------------------------------------------------------------------- */
+
+    /* if cdeg1 > 0 then we must have found a pivot row ... unless NaN's */
+    /* exist.  Try with no numerical tests if no pivot found. */
+
+    if (cdeg1 > 0 && pivrow [IN] == EMPTY && pivrow [OUT] == EMPTY)
+    {
+	/* cleanup for the NaN case */
+	DEBUG0 (("Found a NaN in pivot column!\n")) ;
+
+	/* grab the first entry in the pivot column, ignoring degree, */
+	/* numerical stability, and symmetric preference */
+	row = Pattern [0] ;
+	deg = Row_degree [row] ;
+	if (Frpos [row] >= 0 && Frpos [row] < fnrows)
+	{
+	    /* row is in the current front */
+	    DEBUG4 ((" in front\n")) ;
+	    pivrow [IN] = row ;
+	    rdeg [IN] = deg ;
+	}
+	else
+	{
+	    /* row is not in the current front */
+	    DEBUG4 ((" NOT in front\n")) ;
+	    pivrow [OUT] = row ;
+	    rdeg [OUT] = deg ;
+	}
+
+	/* We are now guaranteed to have a pivot, no matter how broken */
+	/* (non-IEEE compliant) the underlying numerical operators are. */
+	/* This is particularly a problem for Microsoft compilers (they do */
+	/* not handle NaN's properly). Now try to find a sparser pivot, if */
+	/* possible. */
+
+	for (i = 1 ; i < cdeg1 ; i++)
+	{
+	    row = Pattern [i] ;
+	    deg = Row_degree [row] ;
+
+	    if (Frpos [row] >= 0 && Frpos [row] < fnrows)
+	    {
+		/* row is in the current front */
+		DEBUG4 ((" in front\n")) ;
+		if (deg < rdeg [IN] || (deg == rdeg [IN] && row == diag_row))
+		{
+		    /* best row in front, so far */
+		    pivrow [IN] = row ;
+		    rdeg [IN] = deg ;
+		}
+	    }
+	    else
+	    {
+		/* row is not in the current front */
+		DEBUG4 ((" NOT in front\n")) ;
+		if (deg < rdeg [OUT] || (deg == rdeg [OUT] && row == diag_row))
+		{
+		    /* best row not in front, so far */
+		    pivrow [OUT] = row ;
+		    rdeg [OUT] = deg ;
+		}
+	    }
+	}
+    }
+
+    /* We found a pivot if there are entries (even zero ones) in pivot col */
+    ASSERT (IMPLIES (cdeg1 > 0, pivrow[IN] != EMPTY || pivrow[OUT] != EMPTY)) ;
+
+    /* If there are no entries in the pivot column, then no pivot is found */
+    ASSERT (IMPLIES (cdeg1 == 0, pivrow[IN] == EMPTY && pivrow[OUT] == EMPTY)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check for singular matrix */
+    /* ---------------------------------------------------------------------- */
+
+    if (cdeg1  == 0)
+    {
+	if (fnrows > 0)
+	{
+	    /*
+		Get the pivrow [OUT][IN] from the current front.
+		The frontal matrix looks like this:
+
+			pivcol[OUT]
+			|
+			v
+		x x x x 0   <- so grab this row as the pivrow [OUT][IN].
+		x x x x 0
+		x x x x 0
+		0 0 0 0 0
+
+		The current frontal matrix has some rows in it.  The degree
+		of the pivcol[OUT] is zero.  The column is empty, and the
+		current front does not contribute to it.
+
+	    */
+	    pivrow [IN] = Work->Frows [0] ;
+	    DEBUGm4 (("Got zero pivrow[OUT][IN] "ID" from current front\n",
+		pivrow [IN])) ;
+	}
+	else
+	{
+
+	    /*
+		Get a pivot row from the row-merge tree, use as
+		pivrow [OUT][OUT].   pivrow [IN] remains EMPTY.
+		This can only happen if the current front is 0-by-0.
+	    */
+
+	    Int *Front_leftmostdesc, *Front_1strow, *Front_new1strow, row1,
+		row2, fleftmost, nfr, n_row, frontid ;
+
+	    ASSERT (Work->fncols == 0) ;
+
+	    Front_leftmostdesc = Symbolic->Front_leftmostdesc ;
+	    Front_1strow = Symbolic->Front_1strow ;
+	    Front_new1strow = Work->Front_new1strow ;
+	    nfr = Symbolic->nfr ;
+	    n_row = Numeric->n_row ;
+	    frontid = Work->frontid ;
+
+	    DEBUGm4 (("Note: pivcol: "ID" is empty front "ID"\n",
+		pivcol, frontid)) ;
+#ifndef NDEBUG
+	    DEBUG1 (("Calling dump rowmerge\n")) ;
+	    UMF_dump_rowmerge (Numeric, Symbolic, Work) ;
+#endif
+
+	    /* Row-merge set is the non-pivotal rows in the range */
+	    /* Front_new1strow [Front_leftmostdesc [frontid]] to */
+	    /* Front_1strow [frontid+1] - 1. */
+	    /* If this is empty, then use the empty rows, in the range */
+	    /* Front_new1strow [nfr] to n_row-1. */
+	    /* If this too is empty, then pivrow [OUT] will be empty. */
+	    /* In both cases, update Front_new1strow [...]. */
+
+	    fleftmost = Front_leftmostdesc [frontid] ;
+	    row1 = Front_new1strow [fleftmost] ;
+	    row2 = Front_1strow [frontid+1] - 1 ;
+	    DEBUG1 (("Leftmost: "ID" Rows ["ID" to "ID"] srch ["ID" to "ID"]\n",
+		fleftmost, Front_1strow [frontid], row2, row1, row2)) ;
+
+	    /* look in the range row1 ... row2 */
+	    for (row = row1 ; row <= row2 ; row++)
+	    {
+		DEBUG3 (("   Row: "ID"\n", row)) ;
+		if (NON_PIVOTAL_ROW (row))
+		{
+		    /* found it */
+		    DEBUG3 (("   Row: "ID" found\n", row)) ;
+		    ASSERT (Frpos [row] == EMPTY) ;
+		    pivrow [OUT] = row ;
+		    DEBUGm4 (("got row merge pivrow %d\n", pivrow [OUT])) ;
+		    break ;
+		}
+	    }
+	    Front_new1strow [fleftmost] = row ;
+
+	    if (pivrow [OUT] == EMPTY)
+	    {
+		/* not found, look in empty row set in "dummy" front */
+		row1 = Front_new1strow [nfr] ;
+		row2 = n_row-1 ;
+		DEBUG3 (("Empty: "ID" Rows ["ID" to "ID"] srch["ID" to "ID"]\n",
+		    nfr, Front_1strow [nfr], row2, row1, row2)) ;
+
+		/* look in the range row1 ... row2 */
+		for (row = row1 ; row <= row2 ; row++)
+		{
+		    DEBUG3 (("   Empty Row: "ID"\n", row)) ;
+		    if (NON_PIVOTAL_ROW (row))
+		    {
+			/* found it */
+			DEBUG3 (("   Empty Row: "ID" found\n", row)) ;
+			ASSERT (Frpos [row] == EMPTY) ;
+			pivrow [OUT] = row ;
+			DEBUGm4 (("got dummy row pivrow %d\n", pivrow [OUT])) ;
+			break ;
+		    }
+		}
+		Front_new1strow [nfr] = row ;
+	    }
+
+	    if (pivrow [OUT] == EMPTY)
+	    {
+		/* Row-merge set is empty.  We can just discard */
+		/* the candidate pivot column. */
+		DEBUG0 (("Note: row-merge set empty\n")) ;
+		DEBUGm4 (("got no pivrow \n")) ;
+		return (UMFPACK_WARNING_singular_matrix) ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the candidate row in the front, if any */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    /* check Wrp */
+    ASSERT (Work->Wrpflag > 0) ;
+    if (UMF_debug > 0 || Work->n_col < 1000)
+    {
+	for (i = 0 ; i < Work->n_col ; i++)
+	{
+	    ASSERT (Wrp [i] < Work->Wrpflag) ;
+	}
+    }
+#endif
+
+#ifndef NDEBUG
+    DEBUG4 (("pivrow [IN]: "ID"\n", pivrow [IN])) ;
+    UMF_dump_rowcol (0, Numeric, Work, pivrow [IN], TRUE) ;
+#endif
+
+    if (pivrow [IN] != EMPTY)
+    {
+
+	/* the row merge candidate row is not pivrow [IN] */
+	freebie [IN] = (pivrow [IN] == prior_pivrow [IN]) && (cdeg1  > 0) ;
+	ASSERT (cdeg1  >= 0) ;
+
+	if (!freebie [IN])
+	{
+	    /* include current front in the degree of this row */
+
+	    Fcpos = Work->Fcpos ;
+	    fncols = Work->fncols ;
+
+	    Wrpflag = Work->Wrpflag ;
+
+	    /* -------------------------------------------------------------- */
+	    /* construct the pattern of the IN row */
+	    /* -------------------------------------------------------------- */
+
+#ifndef NDEBUG
+	    /* check Fcols */
+	    DEBUG5 (("ROW ASSEMBLE: rdeg "ID"\nREDUCE ROW "ID"\n",
+		fncols, pivrow [IN])) ;
+	    for (j = 0 ; j < fncols ; j++)
+	    {
+		col = Work->Fcols [j] ;
+		ASSERT (col >= 0 && col < Work->n_col) ;
+		ASSERT (Fcpos [col] >= 0) ;
+	    }
+	    if (UMF_debug > 0 || Work->n_col < 1000)
+	    {
+		Int cnt = fncols ;
+		for (col = 0 ; col < Work->n_col ; col++)
+		{
+		    if (Fcpos [col] < 0) cnt++ ;
+		}
+		ASSERT (cnt == Work->n_col) ;
+	    }
+#endif
+
+	    rdeg [IN] = fncols ;
+
+	    ASSERT (pivrow [IN] >= 0 && pivrow [IN] < Work->n_row) ;
+	    ASSERT (NON_PIVOTAL_ROW (pivrow [IN])) ;
+
+	    /* add the pivot column itself */
+	    ASSERT (Wrp [pivcol] != Wrpflag) ;
+	    if (Fcpos [pivcol] < 0)
+	    {
+		DEBUG3 (("Adding pivot col to pivrow [IN] pattern\n")) ;
+		if (rdeg [IN] >= max_rdeg)
+		{
+		    /* :: pattern change (in) :: */
+		    return (UMFPACK_ERROR_different_pattern) ;
+		}
+		Wrp [pivcol] = Wrpflag ;
+		W_i [rdeg [IN]++] = pivcol ;
+	    }
+
+	    tpi = Row_tuples [pivrow [IN]] ;
+	    if (tpi)
+	    {
+		tp = (Tuple *) (Memory + tpi) ;
+		tp1 = tp ;
+		tp2 = tp ;
+		tpend = tp + Row_tlen [pivrow [IN]] ;
+		for ( ; tp < tpend ; tp++)
+		{
+		    e = tp->e ;
+		    ASSERT (e > 0 && e <= Work->nel) ;
+		    if (!E [e])
+		    {
+			continue ;	/* element already deallocated */
+		    }
+		    f = tp->f ;
+		    p = Memory + E [e] ;
+		    ep = (Element *) p ;
+		    p += UNITS (Element, 1) ;
+		    Cols = (Int *) p ;
+		    ncols = ep->ncols ;
+		    Rows = Cols + ncols ;
+		    if (Rows [f] == EMPTY)
+		    {
+			continue ;	/* row already assembled */
+		    }
+		    ASSERT (pivrow [IN] == Rows [f]) ;
+
+		    for (j = 0 ; j < ncols ; j++)
+		    {
+			col = Cols [j] ;
+			ASSERT (col >= EMPTY && col < Work->n_col) ;
+			if ((col >= 0) && (Wrp [col] != Wrpflag)
+			    && Fcpos [col] <0)
+			{
+			    ASSERT (NON_PIVOTAL_COL (col)) ;
+			    if (rdeg [IN] >= max_rdeg)
+			    {
+				/* :: pattern change (rdeg in failure) :: */
+				DEBUGm4 (("rdeg [IN] >= max_rdeg failure\n")) ;
+				return (UMFPACK_ERROR_different_pattern) ;
+			    }
+			    Wrp [col] = Wrpflag ;
+			    W_i [rdeg [IN]++] = col ;
+			}
+		    }
+
+		    *tp2++ = *tp ;	/* leave the tuple in the list */
+		}
+		Row_tlen [pivrow [IN]] = tp2 - tp1 ;
+	    }
+
+#ifndef NDEBUG
+	    DEBUG4 (("Reduced IN row:\n")) ;
+	    for (j = 0 ; j < fncols ; j++)
+	    {
+		DEBUG6 ((" "ID" "ID" "ID"\n",
+		    j, Work->Fcols [j], Fcpos [Work->Fcols [j]])) ;
+		ASSERT (Fcpos [Work->Fcols [j]] >= 0) ;
+	    }
+	    for (j = fncols ; j < rdeg [IN] ; j++)
+	    {
+		DEBUG6 ((" "ID" "ID" "ID"\n", j, W_i [j], Wrp [W_i [j]]));
+		ASSERT (W_i [j] >= 0 && W_i [j] < Work->n_col) ;
+		ASSERT (Wrp [W_i [j]] == Wrpflag) ;
+	    }
+	    /* mark the end of the pattern in case we scan it by mistake */
+	    /* Note that this means W_i must be of size >= fncols_max + 1 */
+	    W_i [rdeg [IN]] = EMPTY ;
+#endif
+
+	    /* rdeg [IN] is now the exact degree of the IN row */
+
+	    /* clear Work->Wrp. */
+	    Work->Wrpflag++ ;
+	    /* All Wrp [0..n_col] is now < Wrpflag */
+	}
+    }
+
+#ifndef NDEBUG
+    /* check Wrp */
+    if (UMF_debug > 0 || Work->n_col < 1000)
+    {
+	for (i = 0 ; i < Work->n_col ; i++)
+	{
+	    ASSERT (Wrp [i] < Work->Wrpflag) ;
+	}
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the candidate row not in the front, if any */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    DEBUG4 (("pivrow [OUT]: "ID"\n", pivrow [OUT])) ;
+    UMF_dump_rowcol (0, Numeric, Work, pivrow [OUT], TRUE) ;
+#endif
+
+    /* If this is a candidate row from the row merge set, force it to be */
+    /* scanned (ignore prior_pivrow [OUT]). */
+
+    if (pivrow [OUT] != EMPTY)
+    {
+	freebie [OUT] = (pivrow [OUT] == prior_pivrow [OUT]) && cdeg1  > 0 ;
+	ASSERT (cdeg1  >= 0) ;
+
+	if (!freebie [OUT])
+	{
+
+	    Wrpflag = Work->Wrpflag ;
+
+	    /* -------------------------------------------------------------- */
+	    /* construct the pattern of the row */
+	    /* -------------------------------------------------------------- */
+
+	    rdeg [OUT] = 0 ;
+
+	    ASSERT (pivrow [OUT] >= 0 && pivrow [OUT] < Work->n_row) ;
+	    ASSERT (NON_PIVOTAL_ROW (pivrow [OUT])) ;
+
+	    /* add the pivot column itself */
+	    ASSERT (Wrp [pivcol] != Wrpflag) ;
+	    DEBUG3 (("Adding pivot col to pivrow [OUT] pattern\n")) ;
+	    if (rdeg [OUT] >= max_rdeg)
+	    {
+		/* :: pattern change (out) :: */
+		return (UMFPACK_ERROR_different_pattern) ;
+	    }
+	    Wrp [pivcol] = Wrpflag ;
+	    W_o [rdeg [OUT]++] = pivcol ;
+
+	    tpi = Row_tuples [pivrow [OUT]] ;
+	    if (tpi)
+	    {
+		tp = (Tuple *) (Memory + tpi) ;
+		tp1 = tp ;
+		tp2 = tp ;
+		tpend = tp + Row_tlen [pivrow [OUT]] ;
+		for ( ; tp < tpend ; tp++)
+		{
+		    e = tp->e ;
+		    ASSERT (e > 0 && e <= Work->nel) ;
+		    if (!E [e])
+		    {
+			continue ;	/* element already deallocated */
+		    }
+		    f = tp->f ;
+		    p = Memory + E [e] ;
+		    ep = (Element *) p ;
+		    p += UNITS (Element, 1) ;
+		    Cols = (Int *) p ;
+		    ncols = ep->ncols ;
+		    Rows = Cols + ncols ;
+		    if (Rows [f] == EMPTY)
+		    {
+			continue ;	/* row already assembled */
+		    }
+		    ASSERT (pivrow [OUT] == Rows [f]) ;
+
+		    for (j = 0 ; j < ncols ; j++)
+		    {
+			col = Cols [j] ;
+			ASSERT (col >= EMPTY && col < Work->n_col) ;
+			if ((col >= 0) && (Wrp [col] != Wrpflag))
+			{
+			    ASSERT (NON_PIVOTAL_COL (col)) ;
+			    if (rdeg [OUT] >= max_rdeg)
+			    {
+				/* :: pattern change (rdeg out failure) :: */
+				DEBUGm4 (("rdeg [OUT] failure\n")) ;
+				return (UMFPACK_ERROR_different_pattern) ;
+			    }
+			    Wrp [col] = Wrpflag ;
+			    W_o [rdeg [OUT]++] = col ;
+			}
+		    }
+		    *tp2++ = *tp ;	/* leave the tuple in the list */
+		}
+		Row_tlen [pivrow [OUT]] = tp2 - tp1 ;
+	    }
+
+#ifndef NDEBUG
+	    DEBUG4 (("Reduced row OUT:\n")) ;
+	    for (j = 0 ; j < rdeg [OUT] ; j++)
+	    {
+		DEBUG6 ((" "ID" "ID" "ID"\n", j, W_o [j], Wrp [W_o [j]])) ;
+		ASSERT (W_o [j] >= 0 && W_o [j] < Work->n_col) ;
+		ASSERT (Wrp [W_o [j]] == Wrpflag) ;
+	    }
+	    /* mark the end of the pattern in case we scan it by mistake */
+	    /* Note that this means W_o must be of size >= fncols_max + 1 */
+	    W_o [rdeg [OUT]] = EMPTY ;
+#endif
+
+	    /* rdeg [OUT] is now the exact degree of the row */
+
+	    /* clear Work->Wrp. */
+	    Work->Wrpflag++ ;
+	    /* All Wrp [0..n] is now < Wrpflag */
+
+	}
+
+    }
+    DEBUG5 (("Row_search end ] \n")) ;
+
+#ifndef NDEBUG
+    /* check Wrp */
+    if (UMF_debug > 0 || Work->n_col < 1000)
+    {
+	for (i = 0 ; i < Work->n_col ; i++)
+	{
+	    ASSERT (Wrp [i] < Work->Wrpflag) ;
+	}
+    }
+#endif
+
+    return (UMFPACK_OK) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_row_search.h b/src/C/SuiteSparse/UMFPACK/Source/umf_row_search.h
new file mode 100644
index 0000000..8a9dac0
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_row_search.h
@@ -0,0 +1,32 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_row_search
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic,
+    Int cdeg0,
+    Int cdeg1,
+    const Int Pattern [ ],
+    const Int Pos [ ],
+    Int pivrow [2],
+    Int rdeg [2],
+    Int W_i [ ],
+    Int W_o [ ],
+    Int prior_pivrow [2],
+    const Entry Wxy [ ],
+    Int pivcol,
+    Int freebie [2]
+) ;
+
+#define IN 0
+#define OUT 1
+
+#define IN_IN 0
+#define IN_OUT 1
+#define OUT_IN 2
+#define OUT_OUT 3
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_scale.c b/src/C/SuiteSparse/UMFPACK/Source/umf_scale.c
new file mode 100644
index 0000000..c716bee
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_scale.c
@@ -0,0 +1,81 @@
+/* ========================================================================== */
+/* === UMF_scale ============================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Divide a vector of stride 1 by the pivot value. */
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_scale
+(
+    Int n,
+    Entry pivot,
+    Entry X [ ]
+)
+{
+    Entry x ;
+    double s ;
+    Int i ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the approximate absolute value of the pivot, and select method */
+    /* ---------------------------------------------------------------------- */
+
+    APPROX_ABS (s, pivot) ;
+
+    if (s < RECIPROCAL_TOLERANCE || IS_NAN (pivot))
+    {
+	/* ------------------------------------------------------------------ */
+	/* tiny, or zero, pivot case */
+	/* ------------------------------------------------------------------ */
+
+	/* The pivot is tiny, or NaN.  Do not divide zero by the pivot value,
+	 * and do not multiply by 1/pivot, either. */
+
+	for (i = 0 ; i < n ; i++)
+	{
+	    /* X [i] /= pivot ; */
+	    x = X [i] ;
+
+#ifndef NO_DIVIDE_BY_ZERO
+	    if (IS_NONZERO (x))
+	    {
+		DIV (X [i], x, pivot) ;
+	    }
+#else
+	    /* Do not divide by zero */
+	    if (IS_NONZERO (x) && IS_NONZERO (pivot))
+	    {
+		DIV (X [i], x, pivot) ;
+	    }
+#endif
+
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* normal case */
+	/* ------------------------------------------------------------------ */
+
+	/* The pivot is not tiny, and is not NaN.   Don't bother to check for
+	 * zeros in the pivot column, X.  This is slightly more accurate than
+	 * multiplying by 1/pivot (but slightly slower), particularly if the
+	 * pivot column consists of only IEEE subnormals. */
+
+	for (i = 0 ; i < n ; i++)
+	{
+	    /* X [i] /= pivot ; */
+	    x = X [i] ;
+	    DIV (X [i], x, pivot) ;
+	}
+    }
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_scale.h b/src/C/SuiteSparse/UMFPACK/Source/umf_scale.h
new file mode 100644
index 0000000..5b24afb
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_scale.h
@@ -0,0 +1,12 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_scale
+(
+    Int n,
+    Entry alpha,
+    Entry X [ ]
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_scale_column.c b/src/C/SuiteSparse/UMFPACK/Source/umf_scale_column.c
new file mode 100644
index 0000000..ace38bc
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_scale_column.c
@@ -0,0 +1,433 @@
+/* ========================================================================== */
+/* === UMF_scale_column ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Scale the current pivot column, move the pivot row and column into place,
+    and log the permutation.
+*/
+
+#include "umf_internal.h"
+#include "umf_mem_free_tail_block.h"
+#include "umf_scale.h"
+
+/* ========================================================================== */
+/* === shift_pivot_row ====================================================== */
+/* ========================================================================== */
+
+/* Except for the BLAS, most of the time is typically spent in the following
+ * shift_pivot_row routine.  It copies the pivot row into the U block, and
+ * then fills in the whole in the C block by shifting the last row of C into
+ * the row vacated by the pivot row.
+ */
+
+PRIVATE void shift_pivot_row (Entry *Fd, Entry *Fs, Entry *Fe, Int len, Int d)
+{
+    Int j ;
+#pragma ivdep
+    for (j = 0 ; j < len ; j++)
+    {
+	Fd [j]   = Fs [j*d] ;
+	Fs [j*d] = Fe [j*d] ;
+    }
+}
+
+/* ========================================================================== */
+/* === UMF_scale_column ===================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_scale_column
+(
+    NumericType *Numeric,
+    WorkType *Work
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Entry pivot_value ;
+    Entry *Fcol, *Flublock, *Flblock, *Fublock, *Fcblock ;
+    Int k, k1, fnr_curr, fnrows, fncols, *Frpos, *Fcpos, pivrow, pivcol,
+	*Frows, *Fcols, fnc_curr, fnpiv, *Row_tuples, nb,
+	*Col_tuples, *Rperm, *Cperm, fspos, col2, row2 ;
+#ifndef NDEBUG
+    Int *Col_degree, *Row_degree ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    fnrows = Work->fnrows ;
+    fncols = Work->fncols ;
+    fnpiv = Work->fnpiv ;
+
+    /* ---------------------------------------------------------------------- */
+
+    Rperm = Numeric->Rperm ;
+    Cperm = Numeric->Cperm ;
+
+    /* ---------------------------------------------------------------------- */
+
+    Flublock = Work->Flublock ;
+    Flblock  = Work->Flblock ;
+    Fublock  = Work->Fublock ;
+    Fcblock  = Work->Fcblock ;
+
+    fnr_curr = Work->fnr_curr ;
+    fnc_curr = Work->fnc_curr ;
+    Frpos = Work->Frpos ;
+    Fcpos = Work->Fcpos ;
+    Frows = Work->Frows ;
+    Fcols = Work->Fcols ;
+    pivrow = Work->pivrow ;
+    pivcol = Work->pivcol ;
+
+    ASSERT (pivrow >= 0 && pivrow < Work->n_row) ;
+    ASSERT (pivcol >= 0 && pivcol < Work->n_col) ;
+
+#ifndef NDEBUG
+    Col_degree = Numeric->Cperm ;	/* for NON_PIVOTAL_COL macro */
+    Row_degree = Numeric->Rperm ;	/* for NON_PIVOTAL_ROW macro */
+#endif
+
+    Row_tuples = Numeric->Uip ;
+    Col_tuples = Numeric->Lip ;
+    nb = Work->nb ;
+
+#ifndef NDEBUG
+    ASSERT (fnrows == Work->fnrows_new + 1) ;
+    ASSERT (fncols == Work->fncols_new + 1) ;
+    DEBUG1 (("SCALE COL: fnrows "ID" fncols "ID"\n", fnrows, fncols)) ;
+    DEBUG2 (("\nFrontal matrix, including all space:\n"
+		"fnr_curr "ID" fnc_curr "ID" nb    "ID"\n"
+		"fnrows   "ID" fncols   "ID" fnpiv "ID"\n",
+		fnr_curr, fnc_curr, nb, fnrows, fncols, fnpiv)) ;
+    DEBUG2 (("\nJust the active part:\n")) ;
+    DEBUG7 (("C  block: ")) ;
+    UMF_dump_dense (Fcblock,  fnr_curr, fnrows, fncols) ;
+    DEBUG7 (("L  block: ")) ;
+    UMF_dump_dense (Flblock,  fnr_curr, fnrows, fnpiv);
+    DEBUG7 (("U' block: ")) ;
+    UMF_dump_dense (Fublock,  fnc_curr, fncols, fnpiv) ;
+    DEBUG7 (("LU block: ")) ;
+    UMF_dump_dense (Flublock, nb, fnpiv, fnpiv) ;
+#endif
+
+    /* ====================================================================== */
+    /* === Shift pivot row and column ======================================= */
+    /* ====================================================================== */
+
+    /* ---------------------------------------------------------------------- */
+    /* move pivot column into place */
+    /* ---------------------------------------------------------------------- */
+
+    /* Note that the pivot column is already in place.  Just shift the last
+     * column into the position vacated by the pivot column. */
+
+    fspos = Fcpos [pivcol] ;
+
+    /* one less column in the contribution block */
+    fncols = --(Work->fncols) ;
+
+    if (fspos != fncols * fnr_curr)
+    {
+
+	Int fs = fspos / fnr_curr ;
+
+	DEBUG6 (("Shift pivot column in front\n")) ;
+	DEBUG6 (("fspos: "ID" flpos: "ID"\n", fspos, fncols * fnr_curr)) ;
+
+	/* ------------------------------------------------------------------ */
+	/* move Fe => Fs */
+	/* ------------------------------------------------------------------ */
+
+	/* column of the contribution block: */
+	{
+	    /* Fs: current position of pivot column in contribution block */
+	    /* Fe: position of last column in contribution block */
+	    Int i ;
+	    Entry *Fs, *Fe ;
+	    Fs = Fcblock + fspos ;
+	    Fe = Fcblock + fncols * fnr_curr ;
+#pragma ivdep
+	    for (i = 0 ; i < fnrows ; i++)
+	    {
+		Fs [i] = Fe [i] ;
+	    }
+	}
+
+	/* column of the U2 block */
+	{
+	    /* Fs: current position of pivot column in U block */
+	    /* Fe: last column in U block */
+	    Int i ;
+	    Entry *Fs, *Fe ;
+	    Fs = Fublock + fs ;
+	    Fe = Fublock + fncols ;
+#pragma ivdep
+	    for (i = 0 ; i < fnpiv ; i++)
+	    {
+		Fs [i * fnc_curr] = Fe [i * fnc_curr] ;
+	    }
+	}
+
+	/* move column Fe to Fs in the Fcols pattern */
+	col2 = Fcols [fncols] ;
+	Fcols [fs] = col2 ;
+	Fcpos [col2] = fspos ;
+    }
+
+    /* pivot column is no longer in the frontal matrix */
+    Fcpos [pivcol] = EMPTY ;
+
+#ifndef NDEBUG
+    DEBUG2 (("\nFrontal matrix after col swap, including all space:\n"
+		"fnr_curr "ID" fnc_curr "ID" nb    "ID"\n"
+		"fnrows   "ID" fncols   "ID" fnpiv "ID"\n",
+		fnr_curr, fnc_curr, nb,
+		fnrows, fncols, fnpiv)) ;
+    DEBUG2 (("\nJust the active part:\n")) ;
+    DEBUG7 (("C  block: ")) ;
+    UMF_dump_dense (Fcblock,  fnr_curr, fnrows, fncols) ;
+    DEBUG7 (("L  block: ")) ;
+    UMF_dump_dense (Flblock,  fnr_curr, fnrows, fnpiv+1);
+    DEBUG7 (("U' block: ")) ;
+    UMF_dump_dense (Fublock,  fnc_curr, fncols, fnpiv) ;
+    DEBUG7 (("LU block: ")) ;
+    UMF_dump_dense (Flublock, nb, fnpiv, fnpiv+1) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* move pivot row into place */
+    /* ---------------------------------------------------------------------- */
+
+    fspos = Frpos [pivrow] ;
+
+    /* one less row in the contribution block */
+    fnrows = --(Work->fnrows) ;
+
+    DEBUG6 (("Swap/shift pivot row in front:\n")) ;
+    DEBUG6 (("fspos: "ID" flpos: "ID"\n", fspos, fnrows)) ;
+
+    if (fspos == fnrows)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* move Fs => Fd */
+	/* ------------------------------------------------------------------ */
+
+	DEBUG6 (("row case 1\n")) ;
+
+	/* row of the contribution block: */
+	{
+	    Int j ;
+	    Entry *Fd, *Fs ;
+	    Fd = Fublock + fnpiv * fnc_curr ;
+	    Fs = Fcblock + fspos ;
+#pragma ivdep
+	    for (j = 0 ; j < fncols ; j++)
+	    {
+		Fd [j] = Fs [j * fnr_curr] ;
+	    }
+	}
+
+	/* row of the L2 block: */
+	if (Work->pivrow_in_front)
+	{
+	    Int j ;
+	    Entry *Fd, *Fs ;
+	    Fd = Flublock + fnpiv ;
+	    Fs = Flblock  + fspos ;
+#pragma ivdep
+	    for (j = 0 ; j <= fnpiv ; j++)
+	    {
+		Fd [j * nb] = Fs [j * fnr_curr] ;
+	    }
+	}
+	else
+	{
+	    Int j ;
+	    Entry *Fd, *Fs ;
+	    Fd = Flublock + fnpiv ;
+	    Fs = Flblock  + fspos ;
+#pragma ivdep
+	    for (j = 0 ; j < fnpiv ; j++)
+	    {
+		ASSERT (IS_ZERO (Fs [j * fnr_curr])) ;
+		CLEAR (Fd [j * nb]) ;
+	    }
+	    Fd [fnpiv * nb] = Fs [fnpiv * fnr_curr] ;
+	}
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* move Fs => Fd */
+	/* move Fe => Fs */
+	/* ------------------------------------------------------------------ */
+
+	DEBUG6 (("row case 2\n")) ;
+	/* this is the most common case, by far */
+
+	/* row of the contribution block: */
+	{
+	    /* Fd: destination of pivot row on U block */
+	    /* Fs: current position of pivot row in contribution block */
+	    /* Fe: position of last row in contribution block */
+	    Entry *Fd, *Fs, *Fe ;
+	    Fd = Fublock + fnpiv * fnc_curr ;
+	    Fs = Fcblock + fspos ;
+	    Fe = Fcblock + fnrows ;
+	    shift_pivot_row (Fd, Fs, Fe, fncols, fnr_curr) ;
+	}
+
+	/* row of the L2 block: */
+	if (Work->pivrow_in_front)
+	{
+	    /* Fd: destination of pivot row in LU block */
+	    /* Fs: current position of pivot row in L block */
+	    /* Fe: last row in L block */
+	    Int j ;
+	    Entry *Fd, *Fs, *Fe ;
+	    Fd = Flublock + fnpiv ;
+	    Fs = Flblock  + fspos ;
+	    Fe = Flblock  + fnrows ;
+#pragma ivdep
+	    for (j = 0 ; j <= fnpiv ; j++)
+	    {
+		Fd [j * nb]       = Fs [j * fnr_curr] ;
+		Fs [j * fnr_curr] = Fe [j * fnr_curr] ;
+	    }
+	}
+	else
+	{
+	    Int j ;
+	    Entry *Fd, *Fs, *Fe ;
+	    Fd = Flublock + fnpiv ;
+	    Fs = Flblock  + fspos ;
+	    Fe = Flblock  + fnrows ;
+#pragma ivdep
+	    for (j = 0 ; j < fnpiv ; j++)
+	    {
+		ASSERT (IS_ZERO (Fs [j * fnr_curr])) ;
+		CLEAR (Fd [j * nb]) ;
+		Fs [j * fnr_curr] = Fe [j * fnr_curr] ;
+	    }
+	    Fd [fnpiv * nb]       = Fs [fnpiv * fnr_curr] ;
+	    Fs [fnpiv * fnr_curr] = Fe [fnpiv * fnr_curr] ;
+	}
+
+	/* move row Fe to Fs in the Frows pattern */
+	row2 = Frows [fnrows] ;
+	Frows [fspos] = row2 ;
+	Frpos [row2] = fspos ;
+
+    }
+    /* pivot row is no longer in the frontal matrix */
+    Frpos [pivrow] = EMPTY ;
+
+#ifndef NDEBUG
+    DEBUG2 (("\nFrontal matrix after row swap, including all space:\n"
+		"fnr_curr "ID" fnc_curr "ID" nb    "ID"\n"
+		"fnrows   "ID" fncols   "ID" fnpiv "ID"\n",
+		Work->fnr_curr, Work->fnc_curr, Work->nb,
+		Work->fnrows, Work->fncols, Work->fnpiv)) ;
+    DEBUG2 (("\nJust the active part:\n")) ;
+    DEBUG7 (("C  block: ")) ;
+    UMF_dump_dense (Fcblock,  fnr_curr, fnrows, fncols) ;
+    DEBUG7 (("L  block: ")) ;
+    UMF_dump_dense (Flblock,  fnr_curr, fnrows, fnpiv+1);
+    DEBUG7 (("U' block: ")) ;
+    UMF_dump_dense (Fublock,  fnc_curr, fncols, fnpiv+1) ;
+    DEBUG7 (("LU block: ")) ;
+    UMF_dump_dense (Flublock, nb, fnpiv+1, fnpiv+1) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* Frpos [row] >= 0 for each row in pivot column pattern.   */
+    /* offset into pattern is given by:				*/
+    /* Frpos [row] == offset - 1				*/
+    /* Frpos [pivrow] is EMPTY */
+
+    /* Fcpos [col] >= 0 for each col in pivot row pattern.	*/
+    /* Fcpos [col] == (offset - 1) * fnr_curr			*/
+    /* Fcpos [pivcol] is EMPTY */
+
+    /* Fcols [0..fncols-1] is the pivot row pattern (excl pivot cols) */
+    /* Frows [0..fnrows-1] is the pivot col pattern (excl pivot rows) */
+
+    /* ====================================================================== */
+    /* === scale pivot column =============================================== */
+    /* ====================================================================== */
+
+    /* pivot column (except for pivot entry itself) */
+    Fcol = Flblock + fnpiv * fnr_curr ;
+    /* fnpiv-th pivot in frontal matrix located in Flublock (fnpiv, fnpiv) */
+    pivot_value = Flublock [fnpiv + fnpiv * nb] ;
+
+    /* this is the kth global pivot */
+    k = Work->npiv + fnpiv ;
+
+    DEBUG4 (("Pivot value: ")) ;
+    EDEBUG4 (pivot_value) ;
+    DEBUG4 (("\n")) ;
+
+    UMF_scale (fnrows, pivot_value, Fcol) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* deallocate the pivot row and pivot column tuples */
+    /* ---------------------------------------------------------------------- */
+
+    UMF_mem_free_tail_block (Numeric, Row_tuples [pivrow]) ;
+    UMF_mem_free_tail_block (Numeric, Col_tuples [pivcol]) ;
+
+    Row_tuples [pivrow] = 0 ;
+    Col_tuples [pivcol] = 0 ;
+
+    DEBUG5 (("number of pivots prior to this one: "ID"\n", k)) ;
+    ASSERT (NON_PIVOTAL_ROW (pivrow)) ;
+    ASSERT (NON_PIVOTAL_COL (pivcol)) ;
+
+    /* save row and column inverse permutation */
+    k1 = ONES_COMPLEMENT (k) ;
+    Rperm [pivrow] = k1 ;			/* aliased with Row_degree */
+    Cperm [pivcol] = k1 ;			/* aliased with Col_degree */
+
+    ASSERT (!NON_PIVOTAL_ROW (pivrow)) ;
+    ASSERT (!NON_PIVOTAL_COL (pivcol)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* Keep track of the pivot order.  This is the kth pivot row and column. */
+    /* ---------------------------------------------------------------------- */
+
+    /* keep track of pivot rows and columns in the LU, L, and U blocks */
+    ASSERT (fnpiv < MAXNB) ;
+    Work->Pivrow [fnpiv] = pivrow ;
+    Work->Pivcol [fnpiv] = pivcol ;
+
+    /* ====================================================================== */
+    /* === one step in the factorization is done ============================ */
+    /* ====================================================================== */
+
+    /* One more step is done, except for pending updates to the U and C blocks
+     * of this frontal matrix.  Those are saved up, and applied by
+     * UMF_blas3_update when enough pivots have accumulated.   Also, the
+     * LU factors for these pending pivots have not yet been stored. */
+
+    Work->fnpiv++ ;
+
+#ifndef NDEBUG
+    DEBUG7 (("Current frontal matrix: (after pivcol scale)\n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_scale_column.h b/src/C/SuiteSparse/UMFPACK/Source/umf_scale_column.h
new file mode 100644
index 0000000..166a4e5
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_scale_column.h
@@ -0,0 +1,11 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_scale_column
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_set_stats.c b/src/C/SuiteSparse/UMFPACK/Source/umf_set_stats.c
new file mode 100644
index 0000000..1458763
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_set_stats.c
@@ -0,0 +1,133 @@
+/* ========================================================================== */
+/* === UMF_set_stats ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Sets statistics in Info array.  Calculates everything in double precision,
+    rather than Int or size_t, so that usage estimates can be computed even if
+    the problem is so large that it would cause integer overflow.
+
+    This routine has many double relop's, but the NaN case is ignored.
+*/
+
+#include "umf_internal.h"
+#include "umf_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 ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_set_stats.h b/src/C/SuiteSparse/UMFPACK/Source/umf_set_stats.h
new file mode 100644
index 0000000..deb654d
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_set_stats.h
@@ -0,0 +1,24 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_set_stats
+(
+    double Info [ ],
+    SymbolicType *Symbolic,
+    double max_usage,
+    double num_mem_size,
+    double flops,
+    double lnz,
+    double unz,
+    double maxfrsize,
+    double ulen,
+    double npiv,
+    double maxnrows,
+    double maxncols,
+    Int scale,
+    Int prefer_diagonal,
+    Int what
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_singletons.c b/src/C/SuiteSparse/UMFPACK/Source/umf_singletons.c
new file mode 100644
index 0000000..88b12db
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_singletons.c
@@ -0,0 +1,915 @@
+/* ========================================================================== */
+/* === UMF_singletons ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Find and order the row and column singletons of a matrix A.  If there are
+ * row and column singletons, the output is a row and column permutation such
+ * that the matrix is in the following form:
+ *
+ *	x x x x x x x x x
+ *	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) ;
+	    DEBUG0 (("empty k "ID"\n", k)) ;
+	    nempty++ ;
+	    Xperm [nx - nempty] = x ;
+	}
+	else if (deg > 0)
+	{
+	    /* this row/col is nonempty in the pruned submatrix */
+	    ASSERT (s < nx - nempty) ;
+	    Xperm [s++] = x ;
+	    max_deg = MAX (max_deg, deg) ;
+	}
+	else
+	{
+	    /* This is a singleton row/column - it is already ordered.
+	     * Just clear the flag. */
+	    Xdeg [x] = FLIP (deg) ;
+	}
+    }
+    ASSERT (s == nx - nempty) ;
+    *p_max_deg = max_deg ;
+    return (nempty) ;
+}
+
+/* ========================================================================== */
+/* === UMF_singletons ======================================================= */
+/* ========================================================================== */
+
+GLOBAL Int UMF_singletons
+(
+
+    /* input, not modified: */
+    Int n_row,
+    Int n_col,
+    const Int Ap [ ],	    /* size n_col+1 */
+    const Int Ai [ ],	    /* size nz = Ap [n_col] */
+    const Int Quser [ ],    /* size n_col if present */
+    Int strategy,	    /* strategy requested by user */
+
+    /* output, not defined on input: */
+    Int Cdeg [ ],	/* size n_col */
+    Int Cperm [ ],	/* size n_col */
+    Int Rdeg [ ],	/* size n_row */
+    Int Rperm [ ],	/* size n_row */
+    Int InvRperm [ ],	/* size n_row, the inverse of Rperm */
+    Int *p_n1,		/* # of col and row singletons */
+    Int *p_n1c,		/* # of col singletons */
+    Int *p_n1r,		/* # of row singletons */
+    Int *p_nempty_col,	/* # of empty columns in pruned submatrix */
+    Int *p_nempty_row,	/* # of empty columns in pruned submatrix */
+    Int *p_is_sym,	/* TRUE if pruned submatrix is square and has been
+			 * symmetrically permuted by Cperm and Rperm */
+    Int *p_max_rdeg,	/* maximum Rdeg in pruned submatrix */
+
+    /* workspace, not defined on input or output */
+    Int Rp [ ],		/* size n_row+1 */
+    Int Ri [ ],		/* size nz */
+    Int W [ ],		/* size n_row */
+    Int Next [ ]	/* size MAX (n_row, n_col) */
+)
+{
+    Int n1, s, col, row, p, p1, p2, cdeg, last_row, is_sym, k,
+	nempty_row, nempty_col, max_cdeg, max_rdeg, n1c, n1r ;
+
+    /* ---------------------------------------------------------------------- */
+    /* initializations */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    UMF_dump_start ( ) ;
+    DEBUGm4 (("Starting umf_singletons\n")) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* scan the columns, check for errors and count row degrees */
+    /* ---------------------------------------------------------------------- */
+
+    if (Ap [0] != 0 || Ap [n_col] < 0)
+    {
+	return (UMFPACK_ERROR_invalid_matrix) ;
+    }
+    for (row = 0 ; row < n_row ; row++)
+    {
+	Rdeg [row] = 0 ;
+    }
+    for (col = 0 ; col < n_col ; col++)
+    {
+	p1 = Ap [col] ;
+	p2 = Ap [col+1] ;
+	cdeg = p2 - p1 ;
+	if (cdeg < 0)
+	{
+	    return (UMFPACK_ERROR_invalid_matrix) ;
+	}
+	last_row = EMPTY ;
+	for (p = p1 ; p < p2 ; p++)
+	{
+	    row = Ai [p] ;
+	    if (row <= last_row || row >= n_row)
+	    {
+		return (UMFPACK_ERROR_invalid_matrix) ;
+	    }
+	    Rdeg [row]++ ;
+	    last_row = row ;
+	}
+	Cdeg [col] = cdeg ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* find singletons */
+    /* ---------------------------------------------------------------------- */
+
+    if (Quser != (Int *) NULL)
+    {
+	/* user has provided an input column ordering */
+	if (strategy == UMFPACK_STRATEGY_UNSYMMETRIC)
+	{
+	    /* look for singletons, but respect the user's input permutation */
+	    n1 = find_user_singletons (n_row, n_col, Ap, Ai, Quser,
+		    Cdeg, Rdeg, Cperm, Rperm, &n1r, &n1c, Rp, Ri, W) ;
+	}
+	else
+	{
+	    /* do not look for singletons if Quser given and strategy is
+	     * not unsymmetric */
+	    n1 = 0 ;
+	    n1r = 0 ;
+	    n1c = 0 ;
+	}
+    }
+    else
+    {
+	/* look for singletons anywhere */
+	n1 = find_any_singletons (n_row, n_col, Ap, Ai,
+		Cdeg, Rdeg, Cperm, Rperm, &n1r, &n1c, Rp, Ri, W, Next) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* eliminate empty columns and complete the column permutation */
+    /* ---------------------------------------------------------------------- */
+
+    nempty_col = finish_permutation (n1, n_col, Cdeg, Quser, Cperm, &max_cdeg) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* eliminate empty rows and complete the row permutation */
+    /* ---------------------------------------------------------------------- */
+
+    if (Quser != (Int *) NULL && strategy == UMFPACK_STRATEGY_SYMMETRIC)
+    {
+	/* rows should be symmetrically permuted according to Quser */
+	ASSERT (n_row == n_col) ;
+	nempty_row = finish_permutation (n1, n_row, Rdeg, Quser, Rperm,
+	    &max_rdeg) ;
+    }
+    else
+    {
+	/* rows should not be symmetrically permuted according to Quser */
+	nempty_row = finish_permutation (n1, n_row, Rdeg, (Int *) NULL, Rperm,
+	    &max_rdeg) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the inverse of Rperm */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < n_row ; k++)
+    {
+	ASSERT (Rperm [k] >= 0 && Rperm [k] < n_row) ;
+	InvRperm [Rperm [k]] = k ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* see if pruned submatrix is square and has been symmetrically permuted */
+    /* ---------------------------------------------------------------------- */
+
+    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) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_singletons.h b/src/C/SuiteSparse/UMFPACK/Source/umf_singletons.h
new file mode 100644
index 0000000..1d3316f
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_singletons.h
@@ -0,0 +1,31 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_singletons
+(
+    Int n_row,
+    Int n_col,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const Int Quser [ ],
+    Int strategy,
+    Int Cdeg [ ],
+    Int Cperm [ ],
+    Int Rdeg [ ],
+    Int Rperm [ ],
+    Int InvRperm [ ],
+    Int *n1,
+    Int *n1c,
+    Int *n1r,
+    Int *nempty_col,
+    Int *nempty_row,
+    Int *is_sym,
+    Int *max_rdeg,
+    Int Rp [ ],
+    Int Ri [ ],
+    Int W [ ],
+    Int Next [ ]
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_solve.c b/src/C/SuiteSparse/UMFPACK/Source/umf_solve.c
new file mode 100644
index 0000000..8f37ec0
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_solve.c
@@ -0,0 +1,1395 @@
+/* ========================================================================== */
+/* === UMF_solve ============================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Not user-callable.  Solves a linear system using the numerical factorization
+    computed by UMFPACK_numeric.  No workspace is dynamically allocated.  Counts
+    flops, but excludes floating-point comparisons (thus real abs (...) are
+    zero flops, but complex abs (...) takes 6 flops).
+
+    Returns UMFPACK_OK if successful, UMFPACK_ERROR_argument_missing if
+    required arguments are missing, UMFPACK_ERROR_invalid_system if the sys
+    string is not valid or if the matrix A is not square.
+
+    Uses the sparse backward error method of Arioli, Demmel, and Duff
+    (Solving sparse linear systems with sparse backward error, SIAM J. Matrix
+    Analysis and Applic., vol 10, pp. 165-190).
+
+    Added on option that allows the complex A and X to be split differently
+    than B, Oct 10, 2005.  Contributed by David Bateman.
+*/
+
+#include "umf_internal.h"
+#include "umf_lsolve.h"
+#include "umf_usolve.h"
+#include "umf_ltsolve.h"
+#include "umf_utsolve.h"
+#include "umf_report_vector.h"
+
+PRIVATE Int do_step
+(
+    double omega [3],
+    Int step,
+    const double B2 [ ],
+    Entry X [ ],
+    const Entry W [ ],
+    const double Y [ ],
+    const double Z2 [ ],
+    Entry S [ ],
+    Int n,
+    double Info [UMFPACK_INFO]
+) ;
+
+/* ========================================================================== */
+/* === UMF_solve ============================================================ */
+/* ========================================================================== */
+
+GLOBAL Int UMF_solve
+(
+    Int sys,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+    double Xx [ ],
+    const double Bx [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+    double Xz [ ],
+    const double Bz [ ],
+#endif
+    NumericType *Numeric,
+    Int irstep,
+    double Info [UMFPACK_INFO],
+    Int Pattern [ ],		/* size n */
+    double SolveWork [ ]	/* if irstep>0 real:  size 5*n.  complex:10*n */
+				/* otherwise   real:  size   n.  complex: 4*n */
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Entry axx, wi, xj, zi, xi, aij, bi ;
+    double omega [3], d, z2i, yi, flops ;
+    Entry *W, *Z, *S, *X ;
+    double *Z2, *Y, *B2, *Rs ;
+    Int *Rperm, *Cperm, i, n, p, step, j, nz, status, p2, do_scale ;
+#ifdef COMPLEX
+    Int AXsplit ;
+    Int Bsplit ;
+#endif
+#ifndef NRECIPROCAL
+    Int do_recip = Numeric->do_recip ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* initializations */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    UMF_dump_lu (Numeric) ;
+    ASSERT (Numeric && Xx && Bx && Pattern && SolveWork && Info) ;
+#endif
+
+    nz = 0 ;
+    omega [0] = 0. ;
+    omega [1] = 0. ;
+    omega [2] = 0. ;
+    Rperm = Numeric->Rperm ;
+    Cperm = Numeric->Cperm ;
+    Rs = Numeric->Rs ;		/* row scale factors */
+    do_scale = (Rs != (double *) NULL) ;
+    flops = 0 ;
+    Info [UMFPACK_SOLVE_FLOPS] = 0 ;
+    Info [UMFPACK_IR_TAKEN] = 0 ;
+    Info [UMFPACK_IR_ATTEMPTED] = 0 ;
+
+    /* UMFPACK_solve does not call this routine if A is rectangular */
+    ASSERT (Numeric->n_row == Numeric->n_col) ;
+    n = Numeric->n_row ;
+    if (Numeric->nnzpiv < n
+	|| SCALAR_IS_ZERO (Numeric->rcond) || SCALAR_IS_NAN (Numeric->rcond))
+    {
+	/* Note that systems involving just L return UMFPACK_OK, even if */
+	/* A is singular (L is always has a unit diagonal). */
+	DEBUGm4 (("Note, matrix is singular in umf_solve\n")) ;
+	status = UMFPACK_WARNING_singular_matrix ;
+	irstep = 0 ;
+    }
+    else
+    {
+	status = UMFPACK_OK ;
+    }
+    irstep = MAX (0, irstep) ;			/* make sure irstep is >= 0 */
+
+    W = (Entry *) SolveWork ;			/* Entry W [0..n-1] */
+
+    Z = (Entry *) NULL ;	/* unused if no iterative refinement */
+    S = (Entry *) NULL ;
+    Y = (double *) NULL ;
+    Z2 = (double *) NULL ;
+    B2 = (double *) NULL ;
+
+#ifdef COMPLEX
+    if (irstep > 0)
+    {
+	if (!Ap || !Ai || !Ax)
+	{
+	    return (UMFPACK_ERROR_argument_missing) ;
+	}
+	/* A, B, and X in split format if Az, Bz, and Xz present */
+	AXsplit = SPLIT (Az) || SPLIT(Xz);
+	Z = (Entry *) (SolveWork + 4*n) ;	/* Entry Z [0..n-1] */
+	S = (Entry *) (SolveWork + 6*n) ;	/* Entry S [0..n-1] */
+	Y = (double *) (SolveWork + 8*n) ;	/* double Y [0..n-1] */
+	B2 = (double *) (SolveWork + 9*n) ;	/* double B2 [0..n-1] */
+	Z2 = (double *) Z ;		/* double Z2 [0..n-1], equiv. to Z */
+    }
+    else
+    {
+      /* A is ignored, only  look at X for split/packed cases */
+      AXsplit = SPLIT(Xz);
+    }
+    Bsplit = SPLIT (Bz);
+
+    if (AXsplit)
+    {
+	X = (Entry *) (SolveWork + 2*n) ;	/* Entry X [0..n-1] */
+    }
+    else
+    {
+	X = (Entry *) Xx ;			/* Entry X [0..n-1] */
+    }
+#else
+    X = (Entry *) Xx ;				/* Entry X [0..n-1] */
+    if (irstep > 0)
+    {
+	if (!Ap || !Ai || !Ax)
+	{
+	    return (UMFPACK_ERROR_argument_missing) ;
+	}
+	Z = (Entry *) (SolveWork + n) ;		/* Entry Z [0..n-1] */
+	S = (Entry *) (SolveWork + 2*n) ;	/* Entry S [0..n-1] */
+	Y = (double *) (SolveWork + 3*n) ;	/* double Y [0..n-1] */
+	B2 = (double *) (SolveWork + 4*n) ;	/* double B2 [0..n-1] */
+	Z2 = (double *) Z ;		/* double Z2 [0..n-1], equiv. to Z */
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* determine which system to solve */
+    /* ---------------------------------------------------------------------- */
+
+    if (sys == UMFPACK_A)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* solve A x = b with optional iterative refinement */
+	/* ------------------------------------------------------------------ */
+
+	if (irstep > 0)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* using iterative refinement:  compute Y and B2 */
+	    /* -------------------------------------------------------------- */
+
+	    nz = Ap [n] ;
+	    Info [UMFPACK_NZ] = nz ;
+
+	    /* A is stored by column */
+	    /* Y (i) = ||R A_i||, 1-norm of row i of R A */
+	    for (i = 0 ; i < n ; i++)
+	    {
+		Y [i] = 0. ;
+	    }
+	    flops += (ABS_FLOPS + 1) * nz ;
+	    p2 = Ap [n] ;
+	    for (p = 0 ; p < p2 ; p++)
+	    {
+		/* Y [Ai [p]] += ABS (Ax [p]) ; */
+	        ASSIGN (aij, Ax, Az, p, AXsplit) ;
+		ABS (d, aij) ;
+		Y [Ai [p]] += d ;
+	    }
+
+	    /* B2 = abs (B) */
+	    flops += ABS_FLOPS * n ;
+	    for (i = 0 ; i < n ; i++)
+	    {
+		/* B2 [i] = ABS (B [i]) ; */
+		ASSIGN (bi, Bx, Bz, i, Bsplit) ;
+		ABS (B2 [i], bi) ;
+	    }
+
+	    /* scale Y and B2. */
+	    if (do_scale)
+	    {
+		/* Y = R Y */
+		/* B2 = R B2 */
+#ifndef NRECIPROCAL
+		if (do_recip)
+		{
+		    /* multiply by the scale factors */
+		    for (i = 0 ; i < n ; i++)
+		    {
+			Y [i]  *= Rs [i] ;
+			B2 [i] *= Rs [i] ;
+		    }
+		}
+		else
+#endif
+		{
+		    /* divide by the scale factors */
+		    for (i = 0 ; i < n ; i++)
+		    {
+			Y [i]  /= Rs [i] ;
+			B2 [i] /= Rs [i] ;
+		    }
+		}
+
+		flops += 2 * n ;
+	    }
+
+	}
+
+	for (step = 0 ; step <= irstep ; step++)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* Solve A x = b (step 0): */
+	    /*  x = Q (U \ (L \ (P R b))) */
+	    /* and then perform iterative refinement (step > 0): */
+	    /*  x = x + Q (U \ (L \ (P R (b - A x)))) */
+	    /* -------------------------------------------------------------- */
+
+	    if (step == 0)
+	    {
+		if (do_scale)
+		{
+		    /* W = P R b, using X as workspace, since Z is not
+		     * allocated if irstep = 0. */
+#ifndef NRECIPROCAL
+		    if (do_recip)
+		    {
+			/* multiply by the scale factors */
+			for (i = 0 ; i < n ; i++)
+			{
+			    ASSIGN (X [i], Bx, Bz, i, Bsplit) ;
+			    SCALE (X [i], Rs [i]) ;
+			}
+		    }
+		    else
+#endif
+		    {
+			/* divide by the scale factors */
+			for (i = 0 ; i < n ; i++)
+			{
+			    ASSIGN (X [i], Bx, Bz, i, Bsplit) ;
+			    SCALE_DIV (X [i], Rs [i]) ;
+			}
+		    }
+		    flops += SCALE_FLOPS * n ;
+		    for (i = 0 ; i < n ; i++)
+		    {
+			W [i] = X [Rperm [i]] ;
+		    }
+		}
+		else
+		{
+		    /* W = P b, since the row scaling R = I */
+		    for (i = 0 ; i < n ; i++)
+		    {
+			/* W [i] = B [Rperm [i]] ; */
+			ASSIGN (W [i], Bx, Bz, Rperm [i], Bsplit) ;
+		    }
+		}
+	    }
+	    else
+	    {
+		for (i = 0 ; i < n ; i++)
+		{
+		    /* Z [i] = B [i] ; */
+		    ASSIGN (Z [i], Bx, Bz, i, Bsplit) ;
+		}
+		flops += MULTSUB_FLOPS * nz ;
+		for (i = 0 ; i < n ; i++)
+		{
+		    xi = X [i] ;
+		    p2 = Ap [i+1] ;
+		    for (p = Ap [i] ; p < p2 ; p++)
+		    {
+			/* Z [Ai [p]] -= Ax [p] * xi ; */
+			ASSIGN (aij, Ax, Az, p, AXsplit) ;
+			MULT_SUB (Z [Ai [p]], aij, xi) ;
+		    }
+		}
+		/* scale, Z = R Z */
+		if (do_scale)
+		{
+#ifndef NRECIPROCAL
+		    if (do_recip)
+		    {
+			/* multiply by the scale factors */
+			for (i = 0 ; i < n ; i++)
+			{
+			    SCALE (Z [i], Rs [i]) ;
+			}
+		    }
+		    else
+#endif
+		    {
+			/* divide by the scale factors */
+			for (i = 0 ; i < n ; i++)
+			{
+			    SCALE_DIV (Z [i], Rs [i]) ;
+			}
+		    }
+		    flops += SCALE_FLOPS * n ;
+		}
+		for (i = 0 ; i < n ; i++)
+		{
+		    W [i] = Z [Rperm [i]] ;
+		}
+	    }
+
+	    flops += UMF_lsolve (Numeric, W, Pattern) ;
+	    flops += UMF_usolve (Numeric, W, Pattern) ;
+
+	    if (step == 0)
+	    {
+		for (i = 0 ; i < n ; i++)
+		{
+		    X [Cperm [i]] = W [i] ;
+		}
+	    }
+	    else
+	    {
+		flops += ASSEMBLE_FLOPS * n ;
+		for (i = 0 ; i < n ; i++)
+		{
+		    /* X [Cperm [i]] += W [i] ; */
+		    ASSEMBLE (X [Cperm [i]], W [i]) ;
+		}
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* sparse backward error estimate */
+	    /* -------------------------------------------------------------- */
+
+	    if (irstep > 0)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* A is stored by column */
+		/* W (i) = R (b - A x)_i, residual */
+		/* Z2 (i) = R (|A||x|)_i */
+		/* ---------------------------------------------------------- */
+
+		for (i = 0 ; i < n ; i++)
+		{
+		    /* W [i] = B [i] ; */
+		    ASSIGN (W [i], Bx, Bz, i, Bsplit) ;
+		    Z2 [i] = 0. ;
+		}
+		flops += (MULT_FLOPS + DECREMENT_FLOPS + ABS_FLOPS + 1) * nz ;
+		for (j = 0 ; j < n ; j++)
+		{
+		    xj = X [j] ;
+		    p2 = Ap [j+1] ;
+		    for (p = Ap [j] ; p < p2 ; p++)
+		    {
+			i = Ai [p] ;
+
+			/* axx = Ax [p] * xj ; */
+			ASSIGN (aij, Ax, Az, p, AXsplit) ;
+			MULT (axx, aij, xj) ;
+
+			/* W [i] -= axx ; */
+			DECREMENT (W [i], axx) ;
+
+			/* Z2 [i] += ABS (axx) ; */
+			ABS (d, axx) ;
+			Z2 [i] += d ;
+		    }
+		}
+
+		/* scale W and Z2 */
+		if (do_scale)
+		{
+		    /* Z2 = R Z2 */
+		    /* W = R W */
+#ifndef NRECIPROCAL
+		    if (do_recip)
+		    {
+			/* multiply by the scale factors */
+			for (i = 0 ; i < n ; i++)
+			{
+			    SCALE (W [i], Rs [i]) ;
+			    Z2 [i] *= Rs [i] ;
+			}
+		    }
+		    else
+#endif
+		    {
+			/* divide by the scale factors */
+			for (i = 0 ; i < n ; i++)
+			{
+			    SCALE_DIV (W [i], Rs [i]) ;
+			    Z2 [i] /= Rs [i] ;
+			}
+		    }
+		    flops += (SCALE_FLOPS + 1) * n ;
+		}
+
+		flops += (2*ABS_FLOPS + 5) * n ;
+		if (do_step (omega, step, B2, X, W, Y, Z2, S, n, Info))
+		{
+		    /* iterative refinement is done */
+		    break ;
+		}
+
+	    }
+
+	}
+
+    }
+    else if (sys == UMFPACK_At)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* solve A' x = b with optional iterative refinement */
+	/* ------------------------------------------------------------------ */
+
+	/* A' is the complex conjugate transpose */
+
+	if (irstep > 0)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* using iterative refinement:  compute Y */
+	    /* -------------------------------------------------------------- */
+
+	    nz = Ap [n] ;
+	    Info [UMFPACK_NZ] = nz ;
+
+	    /* A' is stored by row */
+	    /* Y (i) = ||(A' R)_i||, 1-norm of row i of A' R */
+
+	    if (do_scale)
+	    {
+		flops += (ABS_FLOPS + 2) * nz ;
+#ifndef NRECIPROCAL
+		if (do_recip)
+		{
+		    /* multiply by the scale factors */
+		    for (i = 0 ; i < n ; i++)
+		    {
+			yi = 0. ;
+			p2 = Ap [i+1] ;
+			for (p = Ap [i] ; p < p2 ; p++)
+			{
+			    /* yi += ABS (Ax [p]) * Rs [Ai [p]] ; */
+			    /* note that abs (aij) is the same as
+			     * abs (conj (aij)) */
+			    ASSIGN (aij, Ax, Az, p, AXsplit) ;
+			    ABS (d, aij) ;
+			    yi += (d * Rs [Ai [p]]) ;
+			}
+			Y [i] = yi ;
+		    }
+		}
+		else
+#endif
+		{
+		    /* divide by the scale factors */
+		    for (i = 0 ; i < n ; i++)
+		    {
+			yi = 0. ;
+			p2 = Ap [i+1] ;
+			for (p = Ap [i] ; p < p2 ; p++)
+			{
+			    /* yi += ABS (Ax [p]) / Rs [Ai [p]] ; */
+			    /* note that abs (aij) is the same as
+			     * abs (conj (aij)) */
+			    ASSIGN (aij, Ax, Az, p, AXsplit) ;
+			    ABS (d, aij) ;
+			    yi += (d / Rs [Ai [p]]) ;
+			}
+			Y [i] = yi ;
+		    }
+		}
+	    }
+	    else
+	    {
+		/* no scaling */
+		flops += (ABS_FLOPS + 1) * nz ;
+		for (i = 0 ; i < n ; i++)
+		{
+		    yi = 0. ;
+		    p2 = Ap [i+1] ;
+		    for (p = Ap [i] ; p < p2 ; p++)
+		    {
+			/* yi += ABS (Ax [p]) ; */
+			/* note that abs (aij) is the same as
+			 * abs (conj (aij)) */
+			ASSIGN (aij, Ax, Az, p, AXsplit) ;
+			ABS (d, aij) ;
+			yi += d ;
+		    }
+		    Y [i] = yi ;
+		}
+	    }
+
+	    /* B2 = abs (B) */
+	    for (i = 0 ; i < n ; i++)
+	    {
+		/* B2 [i] = ABS (B [i]) ; */
+		ASSIGN (bi, Bx, Bz, i, Bsplit) ;
+		ABS (B2 [i], bi) ;
+	    }
+
+	}
+
+	for (step = 0 ; step <= irstep ; step++)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* Solve A' x = b (step 0): */
+	    /*	x = R P' (L' \ (U' \ (Q' b))) */
+	    /* and then perform iterative refinement (step > 0): */
+	    /*	x = x + R P' (L' \ (U' \ (Q' (b - A' x)))) */
+	    /* -------------------------------------------------------------- */
+
+	    if (step == 0)
+	    {
+		/* W = Q' b */
+		for (i = 0 ; i < n ; i++)
+		{
+		    /* W [i] = B [Cperm [i]] ; */
+		    ASSIGN (W [i], Bx, Bz, Cperm [i], Bsplit) ;
+		}
+	    }
+	    else
+	    {
+		/* Z = b - A' x */
+		for (i = 0 ; i < n ; i++)
+		{
+		    /* Z [i] = B [i] ; */
+		    ASSIGN (Z [i], Bx, Bz, i, Bsplit) ;
+		}
+		flops += MULTSUB_FLOPS * nz ;
+		for (i = 0 ; i < n ; i++)
+		{
+		    zi = Z [i] ;
+		    p2 = Ap [i+1] ;
+		    for (p = Ap [i] ; p < p2 ; p++)
+		    {
+			/* zi -= conjugate (Ax [p]) * X [Ai [p]] ; */
+			ASSIGN (aij, Ax, Az, p, Bsplit) ;
+			MULT_SUB_CONJ (zi, X [Ai [p]], aij) ;
+		    }
+		    Z [i] = zi ;
+		}
+		/* W = Q' Z */
+		for (i = 0 ; i < n ; i++)
+		{
+		    W [i] = Z [Cperm [i]] ;
+		}
+	    }
+
+	    flops += UMF_uhsolve (Numeric, W, Pattern) ;
+	    flops += UMF_lhsolve (Numeric, W, Pattern) ;
+
+	    if (step == 0)
+	    {
+
+		/* X = R P' W */
+		/* do not use Z, since it isn't allocated if irstep = 0 */
+
+		/* X = P' W */
+		for (i = 0 ; i < n ; i++)
+		{
+		    X [Rperm [i]] = W [i] ;
+		}
+		if (do_scale)
+		{
+		    /* X = R X */
+#ifndef NRECIPROCAL
+		    if (do_recip)
+		    {
+			/* multiply by the scale factors */
+			for (i = 0 ; i < n ; i++)
+			{
+			    SCALE (X [i], Rs [i]) ;
+			}
+		    }
+		    else
+#endif
+		    {
+			/* divide by the scale factors */
+			for (i = 0 ; i < n ; i++)
+			{
+			    SCALE_DIV (X [i], Rs [i]) ;
+			}
+		    }
+		    flops += SCALE_FLOPS * n ;
+		}
+
+	    }
+	    else
+	    {
+
+		/* Z = P' W */
+		for (i = 0 ; i < n ; i++)
+		{
+		    Z [Rperm [i]] = W [i] ;
+		}
+		if (do_scale)
+		{
+		    /* Z = R Z */
+#ifndef NRECIPROCAL
+		    if (do_recip)
+		    {
+			/* multiply by the scale factors */
+			for (i = 0 ; i < n ; i++)
+			{
+			    SCALE (Z [i], Rs [i]) ;
+			}
+		    }
+		    else
+#endif
+		    {
+			/* divide by the scale factors */
+			for (i = 0 ; i < n ; i++)
+			{
+			    SCALE_DIV (Z [i], Rs [i]) ;
+			}
+		    }
+		    flops += SCALE_FLOPS * n ;
+		}
+
+		flops += ASSEMBLE_FLOPS * n ;
+		/* X += Z */
+		for (i = 0 ; i < n ; i++)
+		{
+		    /* X [i] += Z [i] ; was +=W[i] in v4.3, which is wrong */
+		    ASSEMBLE (X [i], Z [i]) ;	/* bug fix, v4.3.1 */
+		}
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* sparse backward error estimate */
+	    /* -------------------------------------------------------------- */
+
+	    if (irstep > 0)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* A' is stored by row */
+		/* W (i) = (b - A' x)_i, residual */
+		/* Z2 (i) = (|A'||x|)_i */
+		/* ---------------------------------------------------------- */
+
+		flops += (MULT_FLOPS + DECREMENT_FLOPS + ABS_FLOPS + 1) * nz ;
+		for (i = 0 ; i < n ; i++)
+		{
+		    /* wi = B [i] ; */
+		    ASSIGN (wi, Bx, Bz, i, Bsplit) ;
+		    z2i = 0. ;
+		    p2 = Ap [i+1] ;
+		    for (p = Ap [i] ; p < p2 ; p++)
+		    {
+			/* axx = conjugate (Ax [p]) * X [Ai [p]] ; */
+			ASSIGN (aij, Ax, Az, p, AXsplit) ;
+			MULT_CONJ (axx, X [Ai [p]], aij) ;
+
+			/* wi -= axx ; */
+			DECREMENT (wi, axx) ;
+
+			/* z2i += ABS (axx) ; */
+			ABS (d, axx) ;
+			z2i += d ;
+		    }
+		    W [i] = wi ;
+		    Z2 [i] = z2i ;
+		}
+
+		flops += (2*ABS_FLOPS + 5) * n ;
+		if (do_step (omega, step, B2, X, W, Y, Z2, S, n, Info))
+		{
+		    /* iterative refinement is done */
+		    break ;
+		}
+
+	    }
+
+	}
+
+    }
+    else if (sys == UMFPACK_Aat)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* solve A.' x = b with optional iterative refinement */
+	/* ------------------------------------------------------------------ */
+
+	/* A' is the array transpose */
+
+	if (irstep > 0)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* using iterative refinement:  compute Y */
+	    /* -------------------------------------------------------------- */
+
+	    nz = Ap [n] ;
+	    Info [UMFPACK_NZ] = nz ;
+
+	    /* A.' is stored by row */
+	    /* Y (i) = ||(A.' R)_i||, 1-norm of row i of A.' R */
+
+	    if (do_scale)
+	    {
+		flops += (ABS_FLOPS + 2) * nz ;
+#ifndef NRECIPROCAL
+		if (do_recip)
+		{
+		    /* multiply by the scale factors */
+		    for (i = 0 ; i < n ; i++)
+		    {
+			yi = 0. ;
+			p2 = Ap [i+1] ;
+			for (p = Ap [i] ; p < p2 ; p++)
+			{
+			    /* yi += ABS (Ax [p]) * Rs [Ai [p]] ; */
+			    /* note that A.' is the array transpose,
+			     * so no conjugate */
+			    ASSIGN (aij, Ax, Az, p, AXsplit) ;
+			    ABS (d, aij) ;
+			    yi += (d * Rs [Ai [p]]) ;
+			}
+			Y [i] = yi ;
+		    }
+		}
+		else
+#endif
+		{
+		    /* divide by the scale factors */
+		    for (i = 0 ; i < n ; i++)
+		    {
+			yi = 0. ;
+			p2 = Ap [i+1] ;
+			for (p = Ap [i] ; p < p2 ; p++)
+			{
+			    /* yi += ABS (Ax [p]) / Rs [Ai [p]] ; */
+			    /* note that A.' is the array transpose,
+			     * so no conjugate */
+			    ASSIGN (aij, Ax, Az, p, AXsplit) ;
+			    ABS (d, aij) ;
+			    yi += (d / Rs [Ai [p]]) ;
+			}
+			Y [i] = yi ;
+		    }
+		}
+	    }
+	    else
+	    {
+		/* no scaling */
+		flops += (ABS_FLOPS + 1) * nz ;
+		for (i = 0 ; i < n ; i++)
+		{
+		    yi = 0. ;
+		    p2 = Ap [i+1] ;
+		    for (p = Ap [i] ; p < p2 ; p++)
+		    {
+			/* yi += ABS (Ax [p]) */
+			/* note that A.' is the array transpose,
+			 * so no conjugate */
+			ASSIGN (aij, Ax, Az, p, AXsplit) ;
+			ABS (d, aij) ;
+			yi += d ;
+		    }
+		    Y [i] = yi ;
+		}
+	    }
+
+	    /* B2 = abs (B) */
+	    for (i = 0 ; i < n ; i++)
+	    {
+		/* B2 [i] = ABS (B [i]) ; */
+		ASSIGN (bi, Bx, Bz, i, Bsplit) ;
+		ABS (B2 [i], bi) ;
+	    }
+
+	}
+
+	for (step = 0 ; step <= irstep ; step++)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* Solve A.' x = b (step 0): */
+	    /*	x = R P' (L.' \ (U.' \ (Q' b))) */
+	    /* and then perform iterative refinement (step > 0): */
+	    /*	x = x + R P' (L.' \ (U.' \ (Q' (b - A.' x)))) */
+	    /* -------------------------------------------------------------- */
+
+	    if (step == 0)
+	    {
+		/* W = Q' b */
+		for (i = 0 ; i < n ; i++)
+		{
+		    /* W [i] = B [Cperm [i]] ; */
+		    ASSIGN (W [i], Bx, Bz, Cperm [i], Bsplit) ;
+		}
+	    }
+	    else
+	    {
+		/* Z = b - A.' x */
+		for (i = 0 ; i < n ; i++)
+		{
+		    /* Z [i] = B [i] ; */
+		    ASSIGN (Z [i], Bx, Bz, i, Bsplit) ;
+		}
+		flops += MULTSUB_FLOPS * nz ;
+		for (i = 0 ; i < n ; i++)
+		{
+		    zi = Z [i] ;
+		    p2 = Ap [i+1] ;
+		    for (p = Ap [i] ; p < p2 ; p++)
+		    {
+			/* zi -= Ax [p] * X [Ai [p]] ; */
+			ASSIGN (aij, Ax, Az, p, AXsplit) ;
+			MULT_SUB (zi, aij, X [Ai [p]]) ;
+		    }
+		    Z [i] = zi ;
+		}
+		/* W = Q' Z */
+		for (i = 0 ; i < n ; i++)
+		{
+		    W [i] = Z [Cperm [i]] ;
+		}
+	    }
+
+	    flops += UMF_utsolve (Numeric, W, Pattern) ;
+	    flops += UMF_ltsolve (Numeric, W, Pattern) ;
+
+	    if (step == 0)
+	    {
+
+		/* X = R P' W */
+		/* do not use Z, since it isn't allocated if irstep = 0 */
+
+		/* X = P' W */
+		for (i = 0 ; i < n ; i++)
+		{
+		    X [Rperm [i]] = W [i] ;
+		}
+		if (do_scale)
+		{
+		    /* X = R X */
+#ifndef NRECIPROCAL
+		    if (do_recip)
+		    {
+			/* multiply by the scale factors */
+			for (i = 0 ; i < n ; i++)
+			{
+			    SCALE (X [i], Rs [i]) ;
+			}
+		    }
+		    else
+#endif
+		    {
+			/* divide by the scale factors */
+			for (i = 0 ; i < n ; i++)
+			{
+			    SCALE_DIV (X [i], Rs [i]) ;
+			}
+		    }
+		    flops += SCALE_FLOPS * n ;
+		}
+
+	    }
+	    else
+	    {
+
+		/* Z = P' W */
+		for (i = 0 ; i < n ; i++)
+		{
+		    Z [Rperm [i]] = W [i] ;
+		}
+		if (do_scale)
+		{
+		    /* Z = R Z */
+#ifndef NRECIPROCAL
+		    if (do_recip)
+		    {
+			/* multiply by the scale factors */
+			for (i = 0 ; i < n ; i++)
+			{
+			    SCALE (Z [i], Rs [i]) ;
+			}
+		    }
+		    else
+#endif
+		    {
+			/* divide by the scale factors */
+			for (i = 0 ; i < n ; i++)
+			{
+			    SCALE_DIV (Z [i], Rs [i]) ;
+			}
+		    }
+		    flops += SCALE_FLOPS * n ;
+		}
+
+		flops += ASSEMBLE_FLOPS * n ;
+		/* X += Z */
+		for (i = 0 ; i < n ; i++)
+		{
+		    /* X [i] += Z [i] ; was +=W[i] in v4.3, which is wrong */
+		    ASSEMBLE (X [i], Z [i]) ;	/* bug fix, v4.3.1 */
+		}
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* sparse backward error estimate */
+	    /* -------------------------------------------------------------- */
+
+	    if (irstep > 0)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* A.' is stored by row */
+		/* W (i) = (b - A.' x)_i, residual */
+		/* Z (i) = (|A.'||x|)_i */
+		/* ---------------------------------------------------------- */
+
+		flops += (MULT_FLOPS + DECREMENT_FLOPS + ABS_FLOPS + 1) * nz ;
+		for (i = 0 ; i < n ; i++)
+		{
+		    /* wi = B [i] ; */
+		    ASSIGN (wi, Bx, Bz, i, Bsplit) ;
+		    z2i = 0. ;
+		    p2 = Ap [i+1] ;
+		    for (p = Ap [i] ; p < p2 ; p++)
+		    {
+			/* axx = Ax [p] * X [Ai [p]] ; */
+			ASSIGN (aij, Ax, Az, p, AXsplit) ;
+			MULT (axx, aij, X [Ai [p]]) ;
+
+			/* wi -= axx ; */
+			DECREMENT (wi, axx) ;
+
+			/* z2i += ABS (axx) ; */
+			ABS (d, axx) ;
+			z2i += d ;
+		    }
+		    W [i] = wi ;
+		    Z2 [i] = z2i ;
+		}
+
+		flops += (2*ABS_FLOPS + 5) * n ;
+		if (do_step (omega, step, B2, X, W, Y, Z2, S, n, Info))
+		{
+		    /* iterative refinement is done */
+		    break ;
+		}
+
+	    }
+
+	}
+
+    }
+    else if (sys == UMFPACK_Pt_L)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* Solve P'Lx=b:  x = L \ Pb */
+	/* ------------------------------------------------------------------ */
+
+	for (i = 0 ; i < n ; i++)
+	{
+	    /* X [i] = B [Rperm [i]] ; */
+	    ASSIGN (X [i], Bx, Bz, Rperm [i], Bsplit) ;
+	}
+	flops = UMF_lsolve (Numeric, X, Pattern) ;
+	status = UMFPACK_OK ;
+
+    }
+    else if (sys == UMFPACK_L)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* Solve Lx=b:  x = L \ b */
+	/* ------------------------------------------------------------------ */
+
+	for (i = 0 ; i < n ; i++)
+	{
+	    /* X [i] = B [i] ; */
+	    ASSIGN (X [i], Bx, Bz, i, Bsplit) ;
+	}
+	flops = UMF_lsolve (Numeric, X, Pattern) ;
+	status = UMFPACK_OK ;
+
+    }
+    else if (sys == UMFPACK_Lt_P)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* Solve L'Px=b:  x = P' (L' \ b) */
+	/* ------------------------------------------------------------------ */
+
+	for (i = 0 ; i < n ; i++)
+	{
+	    /* W [i] = B [i] ; */
+	    ASSIGN (W [i], Bx, Bz, i, Bsplit) ;
+	}
+	flops = UMF_lhsolve (Numeric, W, Pattern) ;
+	for (i = 0 ; i < n ; i++)
+	{
+	    X [Rperm [i]] = W [i] ;
+	}
+	status = UMFPACK_OK ;
+
+    }
+    else if (sys == UMFPACK_Lat_P)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* Solve L.'Px=b:  x = P' (L.' \ b) */
+	/* ------------------------------------------------------------------ */
+
+	for (i = 0 ; i < n ; i++)
+	{
+	    /* W [i] = B [i] ; */
+	    ASSIGN (W [i], Bx, Bz, i, Bsplit) ;
+	}
+	flops = UMF_ltsolve (Numeric, W, Pattern) ;
+	for (i = 0 ; i < n ; i++)
+	{
+	    X [Rperm [i]] = W [i] ;
+	}
+	status = UMFPACK_OK ;
+
+    }
+    else if (sys == UMFPACK_Lt)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* Solve L'x=b:  x = L' \ b */
+	/* ------------------------------------------------------------------ */
+
+	for (i = 0 ; i < n ; i++)
+	{
+	    /* X [i] = B [i] ; */
+	    ASSIGN (X [i], Bx, Bz, i, Bsplit) ;
+	}
+	flops = UMF_lhsolve (Numeric, X, Pattern) ;
+	status = UMFPACK_OK ;
+
+    }
+    else if (sys == UMFPACK_Lat)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* Solve L.'x=b:  x = L.' \ b */
+	/* ------------------------------------------------------------------ */
+
+	for (i = 0 ; i < n ; i++)
+	{
+	    /* X [i] = B [i] ; */
+	    ASSIGN (X [i], Bx, Bz, i, Bsplit) ;
+	}
+	flops = UMF_ltsolve (Numeric, X, Pattern) ;
+	status = UMFPACK_OK ;
+
+    }
+    else if (sys == UMFPACK_U_Qt)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* Solve UQ'x=b:  x = Q (U \ b) */
+	/* ------------------------------------------------------------------ */
+
+	for (i = 0 ; i < n ; i++)
+	{
+	    /* W [i] = B [i] ; */
+	    ASSIGN (W [i], Bx, Bz, i, Bsplit) ;
+	}
+	flops = UMF_usolve (Numeric, W, Pattern) ;
+	for (i = 0 ; i < n ; i++)
+	{
+	    X [Cperm [i]] = W [i] ;
+	}
+
+    }
+    else if (sys == UMFPACK_U)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* Solve Ux=b:  x = U \ b */
+	/* ------------------------------------------------------------------ */
+
+	for (i = 0 ; i < n ; i++)
+	{
+	    /* X [i] = B [i] ; */
+	    ASSIGN (X [i], Bx, Bz, i, Bsplit) ;
+	}
+	flops = UMF_usolve (Numeric, X, Pattern) ;
+
+    }
+    else if (sys == UMFPACK_Q_Ut)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* Solve QU'x=b:  x = U' \ Q'b */
+	/* ------------------------------------------------------------------ */
+
+	for (i = 0 ; i < n ; i++)
+	{
+	    /* X [i] = B [Cperm [i]] ; */
+	    ASSIGN (X [i], Bx, Bz, Cperm [i], Bsplit) ;
+	}
+	flops = UMF_uhsolve (Numeric, X, Pattern) ;
+
+    }
+    else if (sys == UMFPACK_Q_Uat)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* Solve QU.'x=b:  x = U.' \ Q'b */
+	/* ------------------------------------------------------------------ */
+
+	for (i = 0 ; i < n ; i++)
+	{
+	    /* X [i] = B [Cperm [i]] ; */
+	    ASSIGN (X [i], Bx, Bz, Cperm [i], Bsplit) ;
+	}
+	flops = UMF_utsolve (Numeric, X, Pattern) ;
+
+    }
+    else if (sys == UMFPACK_Ut)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* Solve U'x=b:  x = U' \ b */
+	/* ------------------------------------------------------------------ */
+
+	for (i = 0 ; i < n ; i++)
+	{
+	    /* X [i] = B [i] ; */
+	  ASSIGN (X [i], Bx, Bz, i, Bsplit) ;
+	}
+	flops = UMF_uhsolve (Numeric, X, Pattern) ;
+
+    }
+    else if (sys == UMFPACK_Uat)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* Solve U'x=b:  x = U' \ b */
+	/* ------------------------------------------------------------------ */
+
+	for (i = 0 ; i < n ; i++)
+	{
+	    /* X [i] = B [i] ; */
+	    ASSIGN (X [i], Bx, Bz, i, Bsplit) ;
+	}
+	flops = UMF_utsolve (Numeric, X, Pattern) ;
+
+    }
+    else
+    {
+	return (UMFPACK_ERROR_invalid_system) ;
+    }
+
+#ifdef COMPLEX
+    /* copy the solution back, from Entry X [ ] to double Xx [ ] and Xz [ ] */
+    if (AXsplit)
+    {
+	for (i = 0 ; i < n ; i++)
+	{
+	    Xx [i] = REAL_COMPONENT (X [i]) ;
+	    Xz [i] = IMAG_COMPONENT (X [i]) ;
+	}
+    }
+#endif
+
+    /* return UMFPACK_OK, or UMFPACK_WARNING_singular_matrix */
+    /* Note that systems involving just L will return UMFPACK_OK */
+    Info [UMFPACK_SOLVE_FLOPS] = flops ;
+    return (status) ;
+}
+
+
+/* ========================================================================== */
+/* === do_step ============================================================== */
+/* ========================================================================== */
+
+/* Perform one step of iterative refinement, for A x = b or A' x = b */
+
+PRIVATE Int do_step		/* return TRUE if iterative refinement done */
+(
+    double omega [3],
+    Int step,			/* which step of iterative refinement to do */
+    const double B2 [ ],	/* abs (B) */
+    Entry X [ ],
+    const Entry W [ ],
+    const double Y [ ],
+    const double Z2 [ ],
+    Entry S [ ],
+    Int n,
+    double Info [UMFPACK_INFO]
+)
+{
+    double last_omega [3], tau, nctau, d1, wd1, d2, wd2, xi, yix, wi, xnorm ;
+    Int i ;
+
+    /* DBL_EPSILON is a standard ANSI C term defined in <float.h> */
+    /* 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) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_solve.h b/src/C/SuiteSparse/UMFPACK/Source/umf_solve.h
new file mode 100644
index 0000000..6eb1cf0
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_solve.h
@@ -0,0 +1,25 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_solve
+(
+    Int sys,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+    double Xx [ ],
+    const double Bx [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+    double Xz [ ],
+    const double Bz [ ],
+#endif
+    NumericType *Numeric,
+    Int irstep,
+    double Info [UMFPACK_INFO],
+    Int Pattern [ ],
+    double SolveWork [ ]
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_start_front.c b/src/C/SuiteSparse/UMFPACK/Source/umf_start_front.c
new file mode 100644
index 0000000..cff6ad4
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_start_front.c
@@ -0,0 +1,283 @@
+/* ========================================================================== */
+/* === UMF_start_front ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Allocate the initial frontal matrix working array for a single chain.  The
+ * front does not have to be big enough, since if it's too small it will get
+ * reallocated.  The size computed here is just an estimate. */
+
+#include "umf_internal.h"
+#include "umf_grow_front.h"
+
+GLOBAL Int UMF_start_front    /* returns TRUE if successful, FALSE otherwise */
+(
+    Int chain,
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+)
+{
+    double maxbytes ;
+    Int fnrows_max, fncols_max, fnr2, fnc2, fsize, fcurr_size, maxfrsize,
+	overflow, nb, f, cdeg ;
+
+    nb = Symbolic->nb ;
+    fnrows_max = Symbolic->Chain_maxrows [chain] ;
+    fncols_max = Symbolic->Chain_maxcols [chain] ;
+
+    DEBUGm2 (("Start Front for chain "ID".  fnrows_max "ID" fncols_max "ID"\n",
+	chain, fnrows_max, fncols_max)) ;
+
+    Work->fnrows_max = fnrows_max ;
+    Work->fncols_max = fncols_max ;
+    Work->any_skip = FALSE ;
+
+    maxbytes = sizeof (Entry) *
+	(double) (fnrows_max + nb) * (double) (fncols_max + nb) ;
+    fcurr_size = Work->fcurr_size ;
+
+    if (Symbolic->prefer_diagonal)
+    {
+	/* Get a rough upper bound on the degree of the first pivot column in
+	 * this front.  Note that Col_degree is not maintained if diagonal
+	 * pivoting is preferred.  For most matrices, the first pivot column
+	 * of the first frontal matrix of a new chain has only one tuple in
+	 * it anyway, so this bound is exact in that case. */
+	Int col, tpi, e, *E, *Col_tuples, *Col_tlen, *Cols ;
+	Tuple *tp, *tpend ;
+	Unit *Memory, *p ;
+	Element *ep ;
+	E = Work->E ;
+	Memory = Numeric->Memory ;
+	Col_tuples = Numeric->Lip ;
+	Col_tlen = Numeric->Lilen ;
+	col = Work->nextcand ;
+	tpi = Col_tuples [col] ;
+	tp = (Tuple *) Memory + tpi ;
+	tpend = tp + Col_tlen [col] ;
+	cdeg = 0 ;
+	DEBUGm3 (("\n=============== start front: col "ID" tlen "ID"\n",
+		col, Col_tlen [col])) ;
+	for ( ; tp < tpend ; tp++)
+	{
+	    DEBUG1 (("Tuple ("ID","ID")\n", tp->e, tp->f)) ;
+	    e = tp->e ;
+	    if (!E [e]) continue ;
+	    f = tp->f ;
+	    p = Memory + E [e] ;
+	    ep = (Element *) p ;
+	    p += UNITS (Element, 1) ;
+	    Cols = (Int *) p ;
+	    if (Cols [f] == EMPTY) continue ;
+	    DEBUG1 (("  nrowsleft "ID"\n", ep->nrowsleft)) ;
+	    cdeg += ep->nrowsleft ;
+	}
+#ifndef NDEBUG
+	DEBUGm3 (("start front cdeg: "ID" col "ID"\n", cdeg, col)) ;
+	UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+#endif
+
+	/* cdeg is now the rough upper bound on the degree of the next pivot
+	 * column. */
+
+	/* If AMD was called, we know the maximum number of nonzeros in any
+	 * column of L.  Use this as an upper bound for cdeg, but add 2 to
+	 * account for a small amount of off-diagonal pivoting. */
+	if (Symbolic->amd_dmax > 0)
+	{
+	    cdeg = MIN (cdeg, Symbolic->amd_dmax) ;
+	}
+
+	/* Increase it to account for larger columns later on.
+	 * Also ensure that it's larger than zero. */
+	cdeg += 2 ;
+
+	/* cdeg cannot be larger than fnrows_max */
+	cdeg = MIN (cdeg, fnrows_max) ;
+
+    }
+    else
+    {
+	/* don't do the above cdeg computation */
+	cdeg = 0 ;
+    }
+
+    DEBUGm2 (("fnrows max "ID" fncols_max "ID"\n", fnrows_max, fncols_max)) ;
+
+    /* the current frontal matrix is empty */
+    ASSERT (Work->fnrows == 0 && Work->fncols == 0 && Work->fnpiv == 0) ;
+
+    /* maximum row dimension is always odd, to avoid bad cache effects */
+    ASSERT (fnrows_max >= 0) ;
+    ASSERT (fnrows_max % 2 == 1) ;
+
+    /* ----------------------------------------------------------------------
+     * allocate working array for current frontal matrix:
+     * minimum size: 1-by-1
+     * maximum size: fnrows_max-by-fncols_max
+     * desired size:
+     *
+     *   if Numeric->front_alloc_init >= 0:
+     *
+     *	    for unsymmetric matrices:
+     *	    Numeric->front_alloc_init * (fnrows_max-by-fncols_max)
+     *
+     *	    for symmetric matrices (diagonal pivoting preference, actually):
+     *	    Numeric->front_alloc_init * (fnrows_max-by-fncols_max), or
+     *	    cdeg*cdeg, whichever is smaller.
+     *
+     *   if Numeric->front_alloc_init < 0:
+     *	    allocate a front of size -Numeric->front_alloc_init.
+     *
+     * Allocate the whole thing if it's small (less than 2*nb^2).  Make sure the
+     * leading dimension of the frontal matrix is odd.
+     *
+     * Also allocate the nb-by-nb LU block, the dr-by-nb L block, and the
+     * nb-by-dc U block.
+     * ---------------------------------------------------------------------- */
+
+    /* get the maximum front size, avoiding integer overflow */
+    overflow = INT_OVERFLOW (maxbytes) ;
+    if (overflow)
+    {
+	/* :: int overflow, max front size :: */
+	maxfrsize = Int_MAX / sizeof (Entry) ;
+    }
+    else
+    {
+	maxfrsize = (fnrows_max + nb) * (fncols_max + nb) ;
+    }
+    ASSERT (!INT_OVERFLOW ((double) maxfrsize * sizeof (Entry))) ;
+
+    if (Numeric->front_alloc_init < 0)
+    {
+	/* allocate a front of -Numeric->front_alloc_init entries */
+	fsize = -Numeric->front_alloc_init ;
+	fsize = MAX (1, fsize) ;
+    }
+    else
+    {
+	if (INT_OVERFLOW (Numeric->front_alloc_init * maxbytes))
+	{
+	    /* :: int overflow, requested front size :: */
+	    fsize = Int_MAX / sizeof (Entry) ;
+	}
+	else
+	{
+	    fsize = Numeric->front_alloc_init * maxfrsize ;
+	}
+
+	if (cdeg > 0)
+	{
+	    /* diagonal pivoting is in use.  cdeg was computed above */
+	    Int fsize2 ;
+
+	    /* add the L and U blocks */
+	    cdeg += nb ;
+
+	    if (INT_OVERFLOW (((double) cdeg * (double) cdeg) * sizeof (Entry)))
+	    {
+		/* :: int overflow, symmetric front size :: */
+		fsize2 = Int_MAX / sizeof (Entry) ;
+	    }
+	    else
+	    {
+		fsize2 = MAX (cdeg * cdeg, fcurr_size) ;
+	    }
+	    fsize = MIN (fsize, fsize2) ;
+	}
+    }
+
+    fsize = MAX (fsize, 2*nb*nb) ;
+
+    /* fsize and maxfrsize are now safe from integer overflow.  They both
+     * include the size of the pivot blocks. */
+    ASSERT (!INT_OVERFLOW ((double) fsize * sizeof (Entry))) ;
+
+    Work->fnrows_new = 0 ;
+    Work->fncols_new = 0 ;
+
+    /* desired size is fnr2-by-fnc2 (includes L and U blocks): */
+    DEBUGm2 (("    fsize "ID"  fcurr_size "ID"\n", fsize, fcurr_size)) ;
+    DEBUGm2 (("    maxfrsize "ID"  fnr_curr "ID" fnc_curr "ID"\n", maxfrsize,
+	Work->fnr_curr, Work->fnc_curr)) ;
+
+    if (fsize >= maxfrsize && !overflow)
+    {
+	/* max working array is small, allocate all of it */
+	fnr2 = fnrows_max + nb ;
+	fnc2 = fncols_max + nb ;
+	fsize = maxfrsize ;
+	DEBUGm1 (("   sufficient for ("ID"+"ID")-by-("ID"+"ID")\n",
+	    fnrows_max, nb, fncols_max, nb)) ;
+    }
+    else
+    {
+	/* allocate a smaller working array */
+	if (fnrows_max <= fncols_max)
+	{
+	    fnr2 = (Int) sqrt ((double) fsize) ;
+	    /* make sure fnr2 is odd */
+	    fnr2 = MAX (fnr2, 1) ;
+	    if (fnr2 % 2 == 0) fnr2++ ;
+	    fnr2 = MIN (fnr2, fnrows_max + nb) ;
+	    fnc2 = fsize / fnr2 ;
+	}
+	else
+	{
+	    fnc2 = (Int) sqrt ((double) fsize) ;
+	    fnc2 = MIN (fnc2, fncols_max + nb) ;
+	    fnr2 = fsize / fnc2 ;
+	    /* make sure fnr2 is odd */
+	    fnr2 = MAX (fnr2, 1) ;
+	    if (fnr2 % 2 == 0)
+	    {
+		fnr2++ ;
+		fnc2 = fsize / fnr2 ;
+	    }
+	}
+	DEBUGm1 (("   smaller "ID"-by-"ID"\n", fnr2, fnc2)) ;
+    }
+    fnr2 = MIN (fnr2, fnrows_max + nb) ;
+    fnc2 = MIN (fnc2, fncols_max + nb) ;
+    ASSERT (fnr2 % 2 == 1) ;
+    ASSERT (fnr2 * fnc2 <= fsize) ;
+
+    fnr2 -= nb ;
+    fnc2 -= nb ;
+    ASSERT (fnr2 >= 0) ;
+    ASSERT (fnc2 >= 0) ;
+
+    if (fsize > fcurr_size)
+    {
+	DEBUGm1 (("   Grow front \n")) ;
+	Work->do_grow = TRUE ;
+	if (!UMF_grow_front (Numeric, fnr2, fnc2, Work, -1))
+	{
+	    /* since the minimum front size is 1-by-1, it would be nearly
+	     * impossible to run out of memory here. */
+	    DEBUGm4 (("out of memory: start front\n")) ;
+	    return (FALSE) ;
+	}
+    }
+    else
+    {
+	/* use the existing front */
+	DEBUGm1 (("   existing front ok\n")) ;
+	Work->fnr_curr = fnr2 ;
+	Work->fnc_curr = fnc2 ;
+	Work->Flblock  = Work->Flublock + nb * nb ;
+	Work->Fublock  = Work->Flblock  + nb * fnr2 ;
+	Work->Fcblock  = Work->Fublock  + nb * fnc2 ;
+    }
+    ASSERT (Work->Flblock  == Work->Flublock + Work->nb*Work->nb) ;
+    ASSERT (Work->Fublock  == Work->Flblock  + Work->fnr_curr*Work->nb) ;
+    ASSERT (Work->Fcblock  == Work->Fublock  + Work->nb*Work->fnc_curr) ;
+    return (TRUE) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_start_front.h b/src/C/SuiteSparse/UMFPACK/Source/umf_start_front.h
new file mode 100644
index 0000000..d6d63b3
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_start_front.h
@@ -0,0 +1,13 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_start_front
+(
+    Int chain,
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_store_lu.c b/src/C/SuiteSparse/UMFPACK/Source/umf_store_lu.c
new file mode 100644
index 0000000..4235917
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_store_lu.c
@@ -0,0 +1,1056 @@
+/* ========================================================================== */
+/* === UMF_store_lu ========================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Store the LU factors.  Called by the kernel.
+    Returns TRUE if successful, FALSE if out of memory.
+*/
+
+#include "umf_internal.h"
+#include "umf_mem_alloc_head_block.h"
+#include "umf_get_memory.h"
+
+/* ========================================================================== */
+
+#ifdef DROP
+GLOBAL Int UMF_store_lu_drop
+#else
+GLOBAL Int UMF_store_lu
+#endif
+(
+    NumericType *Numeric,
+    WorkType *Work
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Entry pivot_value ;
+#ifdef DROP
+    double droptol ;
+#endif
+    Entry *D, *Lval, *Uval, *Fl1, *Fl2, *Fu1, *Fu2,
+	*Flublock, *Flblock, *Fublock ;
+    Int i, k, fnr_curr, fnrows, fncols, row, col, pivrow, pivcol, *Frows,
+	*Fcols, *Lpattern, *Upattern, *Lpos, *Upos, llen, ulen, fnc_curr, fnpiv,
+	uilen, lnz, unz, nb, *Lilen,
+	*Uilen, *Lip, *Uip, *Li, *Ui, pivcol_position, newLchain, newUchain,
+	pivrow_position, p, size, lip, uip, lnzi, lnzx, unzx, lnz2i, lnz2x,
+	unz2i, unz2x, zero_pivot, *Pivrow, *Pivcol, kk,
+	Lnz [MAXNB] ;
+
+#ifndef NDEBUG
+    Int *Col_degree, *Row_degree ;
+#endif
+
+#ifdef DROP
+    Int all_lnz, all_unz ;
+    droptol = Numeric->droptol ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    fnrows = Work->fnrows ;
+    fncols = Work->fncols ;
+    fnpiv = Work->fnpiv ;
+
+    Lpos = Numeric->Lpos ;
+    Upos = Numeric->Upos ;
+    Lilen = Numeric->Lilen ;
+    Uilen = Numeric->Uilen ;
+
+    Lip = Numeric->Lip ;
+    Uip = Numeric->Uip ;
+    D = Numeric->D ;
+
+    Flublock = Work->Flublock ;
+    Flblock  = Work->Flblock ;
+    Fublock  = Work->Fublock ;
+
+    fnr_curr = Work->fnr_curr ;
+    fnc_curr = Work->fnc_curr ;
+    Frows = Work->Frows ;
+    Fcols = Work->Fcols ;
+
+#ifndef NDEBUG
+    Col_degree = Numeric->Cperm ;	/* for NON_PIVOTAL_COL macro */
+    Row_degree = Numeric->Rperm ;	/* for NON_PIVOTAL_ROW macro */
+#endif
+
+    Lpattern = Work->Lpattern ;
+    llen = Work->llen ;
+    Upattern = Work->Upattern ;
+    ulen = Work->ulen ;
+
+    nb = Work->nb ;
+
+#ifndef NDEBUG
+    DEBUG1 (("\nSTORE LU: fnrows "ID
+	" fncols "ID"\n", fnrows, fncols)) ;
+
+    DEBUG2 (("\nFrontal matrix, including all space:\n"
+		"fnr_curr "ID" fnc_curr "ID" nb    "ID"\n"
+		"fnrows   "ID" fncols   "ID" fnpiv "ID"\n",
+		fnr_curr, fnc_curr, nb, fnrows, fncols, fnpiv)) ;
+
+    DEBUG2 (("\nJust the active part:\n")) ;
+    DEBUG7 (("C  block: ")) ;
+    UMF_dump_dense (Work->Fcblock,  fnr_curr, fnrows, fncols) ;
+    DEBUG7 (("L  block: ")) ;
+    UMF_dump_dense (Work->Flblock,  fnr_curr, fnrows, fnpiv);
+    DEBUG7 (("U' block: ")) ;
+    UMF_dump_dense (Work->Fublock,  fnc_curr, fncols, fnpiv) ;
+    DEBUG7 (("LU block: ")) ;
+    UMF_dump_dense (Work->Flublock, nb, fnpiv, fnpiv) ;
+    DEBUG7 (("Current frontal matrix: (prior to store LU)\n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+    Pivrow = Work->Pivrow ;
+    Pivcol = Work->Pivcol ;
+
+    /* ---------------------------------------------------------------------- */
+    /* store the columns of L */
+    /* ---------------------------------------------------------------------- */
+
+    for (kk = 0 ; kk < fnpiv ; kk++)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* one more pivot row and column is being stored into L and U */
+	/* ------------------------------------------------------------------ */
+
+	k = Work->npiv + kk ;
+
+	/* ------------------------------------------------------------------ */
+	/* find the kth pivot row and pivot column */
+	/* ------------------------------------------------------------------ */
+
+	pivrow = Pivrow [kk] ;
+	pivcol = Pivcol [kk] ;
+
+#ifndef NDEBUG
+	ASSERT (pivrow >= 0 && pivrow < Work->n_row) ;
+	ASSERT (pivcol >= 0 && pivcol < Work->n_col) ;
+
+	DEBUGm4 ((
+	"\n -------------------------------------------------------------"
+	"Store LU: step " ID"\n", k))  ;
+	ASSERT (k < MIN (Work->n_row, Work->n_col)) ;
+	DEBUG2 (("Store column of L, k = "ID", llen "ID"\n", k, llen)) ;
+	for (i = 0 ; i < llen ; i++)
+	{
+	    row = Lpattern [i] ;
+	    ASSERT (row >= 0 && row < Work->n_row) ;
+	    DEBUG2 (("    Lpattern["ID"] "ID" Lpos "ID, i, row, Lpos [row])) ;
+	    if (row == pivrow) DEBUG2 ((" <- pivot row")) ;
+	    DEBUG2 (("\n")) ;
+	    ASSERT (i == Lpos [row]) ;
+	}
+#endif
+
+	/* ------------------------------------------------------------------ */
+	/* remove pivot row from L */
+	/* ------------------------------------------------------------------ */
+
+	/* remove pivot row index from current column of L */
+	/* if a new Lchain starts, then all entries are removed later */
+	DEBUG2 (("Removing pivrow from Lpattern, k = "ID"\n", k)) ;
+	ASSERT (!NON_PIVOTAL_ROW (pivrow)) ;
+	pivrow_position = Lpos [pivrow] ;
+	if (pivrow_position != EMPTY)
+	{
+	    /* place the last entry in the column in the */
+	    /* position of the pivot row index */
+	    ASSERT (pivrow == Lpattern [pivrow_position]) ;
+	    row = Lpattern [--llen] ;
+	    /* ASSERT (NON_PIVOTAL_ROW (row)) ; */
+	    Lpattern [pivrow_position] = row ;
+	    Lpos [row] = pivrow_position ;
+	    Lpos [pivrow] = EMPTY ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* store the pivot value, for the diagonal matrix D */
+	/* ------------------------------------------------------------------ */
+
+	/* kk-th column of LU block */
+	Fl1 = Flublock + kk * nb ;
+
+	/* kk-th column of L in the L block */
+	Fl2 = Flblock + kk * fnr_curr ;
+
+	/* kk-th pivot in frontal matrix located in Flublock [kk, kk] */
+	pivot_value = Fl1 [kk] ;
+
+	D [k] = pivot_value ;
+	zero_pivot = IS_ZERO (pivot_value) ;
+
+	DEBUG4 (("Pivot D["ID"]=", k)) ;
+	EDEBUG4 (pivot_value) ;
+	DEBUG4 (("\n")) ;
+
+	/* ------------------------------------------------------------------ */
+	/* count nonzeros in kth column of L */
+	/* ------------------------------------------------------------------ */
+
+	lnz = 0 ;
+	lnz2i = 0 ;
+	lnz2x = llen ;
+
+#ifdef DROP
+	    all_lnz = 0 ;
+
+	    for (i = kk + 1 ; i < fnpiv ; i++)
+	    {
+		Entry x ;
+		double s ;
+		x = Fl1 [i] ;
+		if (IS_ZERO (x)) continue ;
+		all_lnz++ ;
+		APPROX_ABS (s, x) ;
+		if (s <= droptol) continue ;
+		lnz++ ;
+		if (Lpos [Pivrow [i]] == EMPTY) lnz2i++ ;
+	    }
+
+	    for (i = 0 ; i < fnrows ; i++)
+	    {
+		Entry x ;
+		double s ;
+		x = Fl2 [i] ;
+		if (IS_ZERO (x)) continue ;
+		all_lnz++ ;
+		APPROX_ABS (s, x) ;
+		if (s <= droptol) continue ;
+		lnz++ ;
+		if (Lpos [Frows [i]] == EMPTY) lnz2i++ ;
+	    }
+
+#else
+
+	    for (i = kk + 1 ; i < fnpiv ; i++)
+	    {
+		if (IS_ZERO (Fl1 [i])) continue ;
+		lnz++ ;
+		if (Lpos [Pivrow [i]] == EMPTY) lnz2i++ ;
+	    }
+
+	    for (i = 0 ; i < fnrows ; i++)
+	    {
+		if (IS_ZERO (Fl2 [i])) continue ;
+		lnz++ ;
+		if (Lpos [Frows [i]] == EMPTY) lnz2i++ ;
+	    }
+
+#endif
+
+	lnz2x += lnz2i ;
+
+	/* determine if we start a new Lchain or continue the old one */
+	if (llen == 0 || zero_pivot)
+	{
+	    /* llen == 0 means there is no prior Lchain */
+	    /* D [k] == 0 means the pivot column is empty */
+	    newLchain = TRUE ;
+	}
+	else
+	{
+	    newLchain =
+		    /* storage for starting a new Lchain */
+		    UNITS (Entry, lnz) + UNITS (Int, lnz)
+		<=
+		    /* storage for continuing a prior Lchain */
+		    UNITS (Entry, lnz2x) + UNITS (Int, lnz2i) ;
+	}
+
+	if (newLchain)
+	{
+	    /* start a new chain for column k of L */
+	    DEBUG2 (("Start new Lchain, k = "ID"\n", k)) ;
+
+	    pivrow_position = EMPTY ;
+
+	    /* clear the prior Lpattern */
+	    for (i = 0 ; i < llen ; i++)
+	    {
+		row = Lpattern [i] ;
+		Lpos [row] = EMPTY ;
+	    }
+	    llen = 0 ;
+
+	    lnzi = lnz ;
+	    lnzx = lnz ;
+	}
+	else
+	{
+	    /* continue the prior Lchain */
+	    DEBUG2 (("Continue  Lchain, k = "ID"\n", k)) ;
+	    lnzi = lnz2i ;
+	    lnzx = lnz2x ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* allocate space for the column of L */
+	/* ------------------------------------------------------------------ */
+
+	size = UNITS (Int, lnzi) + UNITS (Entry, lnzx) ;
+
+#ifndef NDEBUG
+	UMF_allocfail = FALSE ;
+	if (UMF_gprob > 0)
+	{
+	    double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ;
+	    DEBUG4 (("Check random %e %e\n", rrr, UMF_gprob)) ;
+	    UMF_allocfail = rrr < UMF_gprob ;
+	    if (UMF_allocfail) DEBUGm2 (("Random garbage coll. (store LU)\n"));
+	}
+#endif
+
+	p = UMF_mem_alloc_head_block (Numeric, size) ;
+	if (!p)
+	{
+	    Int r2, c2 ;
+	    /* Do garbage collection, realloc, and try again. */
+	    /* Note that there are pivot rows/columns in current front. */
+	    if (Work->do_grow)
+	    {
+		/* full compaction of current frontal matrix, since
+		 * UMF_grow_front will be called next anyway. */
+		r2 = fnrows ;
+		c2 = fncols ;
+	    }
+	    else
+	    {
+		/* partial compaction. */
+		r2 = MAX (fnrows, Work->fnrows_new + 1) ;
+		c2 = MAX (fncols, Work->fncols_new + 1) ;
+	    }
+	    DEBUGm3 (("get_memory from umf_store_lu:\n")) ;
+	    if (!UMF_get_memory (Numeric, Work, size, r2, c2, TRUE))
+	    {
+		DEBUGm4 (("out of memory: store LU (1)\n")) ;
+		return (FALSE) ;	/* out of memory */
+	    }
+	    p = UMF_mem_alloc_head_block (Numeric, size) ;
+	    if (!p)
+	    {
+		DEBUGm4 (("out of memory: store LU (2)\n")) ;
+		return (FALSE) ;	/* out of memory */
+	    }
+	    /* garbage collection may have moved the current front */
+	    fnc_curr = Work->fnc_curr ;
+	    fnr_curr = Work->fnr_curr ;
+	    Flublock = Work->Flublock ;
+	    Flblock  = Work->Flblock ;
+	    Fublock  = Work->Fublock ;
+	    Fl1 = Flublock + kk * nb ;
+	    Fl2 = Flblock  + kk * fnr_curr ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* store the column of L */
+	/* ------------------------------------------------------------------ */
+
+	lip = p ;
+
+	Li = (Int *) (Numeric->Memory + p) ;
+	p += UNITS (Int, lnzi) ;
+	Lval = (Entry *) (Numeric->Memory + p) ;
+	p += UNITS (Entry, lnzx) ;
+
+	for (i = 0 ; i < lnzx ; i++)
+	{
+	    CLEAR (Lval [i]) ;
+	}
+
+	/* store the numerical entries */
+
+	if (newLchain)
+	{
+	    /* flag the first column in the Lchain by negating Lip [k] */
+	    lip = -lip ;
+
+	    ASSERT (llen == 0) ;
+
+#ifdef DROP
+
+		for (i = kk + 1 ; i < fnpiv ; i++)
+		{
+		    Entry x ;
+		    double s ;
+		    Int row2, pos ;
+		    x = Fl1 [i] ;
+		    APPROX_ABS (s, x) ;
+		    if (s <= droptol) continue ;
+		    row2 = Pivrow [i] ;
+		    pos = llen++ ;
+		    Lpattern [pos] = row2 ;
+		    Lpos [row2] = pos ;
+		    Li [pos] = row2 ;
+		    Lval [pos] = x ;
+		}
+
+		for (i = 0 ; i < fnrows ; i++)
+		{
+		    Entry x ;
+		    double s ;
+		    Int row2, pos ;
+		    x = Fl2 [i] ;
+		    APPROX_ABS (s, x) ;
+		    if (s <= droptol) continue ;
+		    row2 = Frows [i] ;
+		    pos = llen++ ;
+		    Lpattern [pos] = row2 ;
+		    Lpos [row2] = pos ;
+		    Li [pos] = row2 ;
+		    Lval [pos] = x ;
+		}
+
+#else
+
+		for (i = kk + 1 ; i < fnpiv ; i++)
+		{
+		    Entry x ;
+		    Int row2, pos ;
+		    x = Fl1 [i] ;
+		    if (IS_ZERO (x)) continue ;
+		    row2 = Pivrow [i] ;
+		    pos = llen++ ;
+		    Lpattern [pos] = row2 ;
+		    Lpos [row2] = pos ;
+		    Li [pos] = row2 ;
+		    Lval [pos] = x ;
+		}
+
+		for (i = 0 ; i < fnrows ; i++)
+		{
+		    Entry x ;
+		    Int row2, pos ;
+		    x = Fl2 [i] ;
+		    if (IS_ZERO (x)) continue ;
+		    row2 = Frows [i] ;
+		    pos = llen++ ;
+		    Lpattern [pos] = row2 ;
+		    Lpos [row2] = pos ;
+		    Li [pos] = row2 ;
+		    Lval [pos] = x ;
+		}
+
+#endif
+
+	}
+	else
+	{
+	    ASSERT (llen > 0) ;
+
+#ifdef DROP
+
+		for (i = kk + 1 ; i < fnpiv ; i++)
+		{
+		    Entry x ;
+		    double s ;
+		    Int row2, pos ;
+		    x = Fl1 [i] ;
+		    APPROX_ABS (s, x) ;
+		    if (s <= droptol) continue ;
+		    row2 = Pivrow [i] ;
+		    pos = Lpos [row2] ;
+		    if (pos == EMPTY)
+		    {
+			pos = llen++ ;
+			Lpattern [pos] = row2 ;
+			Lpos [row2] = pos ;
+			*Li++ = row2 ;
+		    }
+		    Lval [pos] = x ;
+		}
+
+		for (i = 0 ; i < fnrows ; i++)
+		{
+		    Entry x ;
+		    double s ;
+		    Int row2, pos ;
+		    x = Fl2 [i] ;
+		    APPROX_ABS (s, x) ;
+		    if (s <= droptol) continue ;
+		    row2 = Frows [i] ;
+		    pos = Lpos [row2] ;
+		    if (pos == EMPTY)
+		    {
+			pos = llen++ ;
+			Lpattern [pos] = row2 ;
+			Lpos [row2] = pos ;
+			*Li++ = row2 ;
+		    }
+		    Lval [pos] = x ;
+		}
+
+#else
+
+		for (i = kk + 1 ; i < fnpiv ; i++)
+		{
+		    Entry x ;
+		    Int row2, pos ;
+		    x = Fl1 [i] ;
+		    if (IS_ZERO (x)) continue ;
+		    row2 = Pivrow [i] ;
+		    pos = Lpos [row2] ;
+		    if (pos == EMPTY)
+		    {
+			pos = llen++ ;
+			Lpattern [pos] = row2 ;
+			Lpos [row2] = pos ;
+			*Li++ = row2 ;
+		    }
+		    Lval [pos] = x ;
+		}
+
+		for (i = 0 ; i < fnrows ; i++)
+		{
+		    Entry x ;
+		    Int row2, pos ;
+		    x = Fl2 [i] ;
+		    if (IS_ZERO (x)) continue ;
+		    row2 = Frows [i] ;
+		    pos = Lpos [row2] ;
+		    if (pos == EMPTY)
+		    {
+			pos = llen++ ;
+			Lpattern [pos] = row2 ;
+			Lpos [row2] = pos ;
+			*Li++ = row2 ;
+		    }
+		    Lval [pos] = x ;
+		}
+
+#endif
+
+	}
+	DEBUG4 (("llen "ID" lnzx "ID"\n", llen, lnzx)) ;
+	ASSERT (llen == lnzx) ;
+	ASSERT (lnz <= llen) ;
+	DEBUG4 (("lnz "ID" \n", lnz)) ;
+
+#ifdef DROP
+
+	    DEBUG4 (("all_lnz "ID" \n", all_lnz)) ;
+	    ASSERT (lnz <= all_lnz) ;
+	    Numeric->lnz += lnz ;
+	    Numeric->all_lnz += all_lnz ;
+	    Lnz [kk] = all_lnz ;
+
+#else
+
+	    Numeric->lnz += lnz ;
+	    Numeric->all_lnz += lnz ;
+	    Lnz [kk] = lnz ;
+#endif
+
+	Numeric->nLentries += lnzx ;
+	Work->llen = llen ;
+	Numeric->isize += lnzi ;
+
+	/* ------------------------------------------------------------------ */
+	/* the pivot column is fully assembled and scaled, and is now the */
+	/* k-th column of L */
+	/* ------------------------------------------------------------------ */
+
+	Lpos [pivrow] = pivrow_position ;	/* not aliased */
+	Lip [pivcol] = lip ;			/* aliased with Col_tuples */
+	Lilen [pivcol] = lnzi ;			/* aliased with Col_tlen */
+
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* store the rows of U */
+    /* ---------------------------------------------------------------------- */
+
+    for (kk = 0 ; kk < fnpiv ; kk++)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* one more pivot row and column is being stored into L and U */
+	/* ------------------------------------------------------------------ */
+
+	k = Work->npiv + kk ;
+
+	/* ------------------------------------------------------------------ */
+	/* find the kth pivot row and pivot column */
+	/* ------------------------------------------------------------------ */
+
+	pivrow = Pivrow [kk] ;
+	pivcol = Pivcol [kk] ;
+
+#ifndef NDEBUG
+	ASSERT (pivrow >= 0 && pivrow < Work->n_row) ;
+	ASSERT (pivcol >= 0 && pivcol < Work->n_col) ;
+
+	DEBUG2 (("Store row of U, k = "ID", ulen "ID"\n", k, ulen)) ;
+	for (i = 0 ; i < ulen ; i++)
+	{
+	    col = Upattern [i] ;
+	    DEBUG2 (("    Upattern["ID"] "ID, i, col)) ;
+	    if (col == pivcol) DEBUG2 ((" <- pivot col")) ;
+	    DEBUG2 (("\n")) ;
+	    ASSERT (col >= 0 && col < Work->n_col) ;
+	    ASSERT (i == Upos [col]) ;
+	}
+#endif
+
+	/* ------------------------------------------------------------------ */
+	/* get the pivot value, for the diagonal matrix D */
+	/* ------------------------------------------------------------------ */
+
+	zero_pivot = IS_ZERO (D [k]) ;
+
+	/* ------------------------------------------------------------------ */
+	/* count the nonzeros in the row of U */
+	/* ------------------------------------------------------------------ */
+
+	/* kk-th row of U in the LU block */
+	Fu1 = Flublock + kk ;
+
+	/* kk-th row of U in the U block */
+	Fu2 = Fublock + kk * fnc_curr ;
+
+	unz = 0 ;
+	unz2i = 0 ;
+	unz2x = ulen ;
+	DEBUG2 (("unz2x is "ID", lnzx "ID"\n", unz2x, lnzx)) ;
+
+	/* if row k does not end a Uchain, pivcol not included in ulen */
+	ASSERT (!NON_PIVOTAL_COL (pivcol)) ;
+	pivcol_position = Upos [pivcol] ;
+	if (pivcol_position != EMPTY)
+	{
+	    unz2x-- ;
+	    DEBUG2 (("(exclude pivcol) unz2x is now "ID"\n", unz2x)) ;
+	}
+
+	ASSERT (unz2x >= 0) ;
+
+#ifdef DROP
+	    all_unz = 0 ;
+
+	    for (i = kk + 1 ; i < fnpiv ; i++)
+	    {
+		Entry x ;
+		double s ;
+		x = Fu1 [i*nb] ;
+		if (IS_ZERO (x)) continue ;
+		all_unz++ ;
+		APPROX_ABS (s, x) ;
+		if (s <= droptol) continue ;
+		unz++ ;
+		if (Upos [Pivcol [i]] == EMPTY) unz2i++ ;
+	    }
+
+	    for (i = 0 ; i < fncols ; i++)
+	    {
+		Entry x ;
+		double s ;
+		x = Fu2 [i] ;
+		if (IS_ZERO (x)) continue ;
+		all_unz++ ;
+		APPROX_ABS (s, x) ;
+		if (s <= droptol) continue ;
+		unz++ ;
+		if (Upos [Fcols [i]] == EMPTY) unz2i++ ;
+	    }
+
+#else
+
+	    for (i = kk + 1 ; i < fnpiv ; i++)
+	    {
+		if (IS_ZERO (Fu1 [i*nb])) continue ;
+		unz++ ;
+		if (Upos [Pivcol [i]] == EMPTY) unz2i++ ;
+	    }
+
+	    for (i = 0 ; i < fncols ; i++)
+	    {
+		if (IS_ZERO (Fu2 [i])) continue ;
+		unz++ ;
+		if (Upos [Fcols [i]] == EMPTY) unz2i++ ;
+	    }
+
+#endif
+
+	unz2x += unz2i ;
+
+	ASSERT (IMPLIES (k == 0, ulen == 0)) ;
+
+	/* determine if we start a new Uchain or continue the old one */
+	if (ulen == 0 || zero_pivot)
+	{
+	    /* ulen == 0 means there is no prior Uchain */
+	    /* D [k] == 0 means the matrix is singular (pivot row might */
+	    /* not be empty, however, but start a new Uchain to prune zero */
+	    /* entries for the deg > 0 test in UMF_u*solve) */
+	    newUchain = TRUE ;
+	}
+	else
+	{
+	    newUchain =
+		    /* approximate storage for starting a new Uchain */
+		    UNITS (Entry, unz) + UNITS (Int, unz)
+		<=
+		    /* approximate storage for continuing a prior Uchain */
+		    UNITS (Entry, unz2x) + UNITS (Int, unz2i) ;
+
+	    /* this would be exact, except for the Int to Unit rounding, */
+	    /* because the Upattern is stored only at the end of the Uchain */
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* allocate space for the row of U */
+	/* ------------------------------------------------------------------ */
+
+	size = 0 ;
+	if (newUchain)
+	{
+	    /* store the pattern of the last row in the prior Uchain */
+	    size += UNITS (Int, ulen) ;
+	    unzx = unz ;
+	}
+	else
+	{
+	    unzx = unz2x ;
+	}
+	size += UNITS (Entry, unzx) ;
+
+#ifndef NDEBUG
+	UMF_allocfail = FALSE ;
+	if (UMF_gprob > 0)
+	{
+	    double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ;
+	    DEBUG4 (("Check random %e %e\n", rrr, UMF_gprob)) ;
+	    UMF_allocfail = rrr < UMF_gprob ;
+	    if (UMF_allocfail) DEBUGm2 (("Random garbage coll. (store LU)\n"));
+	}
+#endif
+
+	p = UMF_mem_alloc_head_block (Numeric, size) ;
+	if (!p)
+	{
+	    Int r2, c2 ;
+	    /* Do garbage collection, realloc, and try again. */
+	    /* Note that there are pivot rows/columns in current front. */
+	    if (Work->do_grow)
+	    {
+		/* full compaction of current frontal matrix, since
+		 * UMF_grow_front will be called next anyway. */
+		r2 = fnrows ;
+		c2 = fncols ;
+	    }
+	    else
+	    {
+		/* partial compaction. */
+		r2 = MAX (fnrows, Work->fnrows_new + 1) ;
+		c2 = MAX (fncols, Work->fncols_new + 1) ;
+	    }
+	    DEBUGm3 (("get_memory from umf_store_lu:\n")) ;
+	    if (!UMF_get_memory (Numeric, Work, size, r2, c2, TRUE))
+	    {
+		/* :: get memory, column of L :: */
+		DEBUGm4 (("out of memory: store LU (1)\n")) ;
+		return (FALSE) ;	/* out of memory */
+	    }
+	    p = UMF_mem_alloc_head_block (Numeric, size) ;
+	    if (!p)
+	    {
+		/* :: out of memory, column of U :: */
+		DEBUGm4 (("out of memory: store LU (2)\n")) ;
+		return (FALSE) ;	/* out of memory */
+	    }
+	    /* garbage collection may have moved the current front */
+	    fnc_curr = Work->fnc_curr ;
+	    fnr_curr = Work->fnr_curr ;
+	    Flublock = Work->Flublock ;
+	    Flblock  = Work->Flblock ;
+	    Fublock  = Work->Fublock ;
+	    Fu1 = Flublock + kk ;
+	    Fu2 = Fublock  + kk * fnc_curr ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* store the row of U */
+	/* ------------------------------------------------------------------ */
+
+	uip = p ;
+
+	if (newUchain)
+	{
+	    /* starting a new Uchain - flag this by negating Uip [k] */
+	    uip = -uip ;
+	    DEBUG2 (("Start new Uchain, k = "ID"\n", k)) ;
+
+	    pivcol_position = EMPTY ;
+
+	    /* end the prior Uchain */
+	    /* save the current Upattern, and then */
+	    /* clear it and start a new Upattern */
+	    DEBUG2 (("Ending prior chain, k-1 = "ID"\n", k-1)) ;
+	    uilen = ulen ;
+	    Ui = (Int *) (Numeric->Memory + p) ;
+	    Numeric->isize += ulen ;
+	    p += UNITS (Int, ulen) ;
+	    for (i = 0 ; i < ulen ; i++)
+	    {
+		col = Upattern [i] ;
+		ASSERT (col >= 0 && col < Work->n_col) ;
+		Upos [col] = EMPTY ;
+		Ui [i] = col ;
+	    }
+
+	    ulen = 0 ;
+
+	}
+	else
+	{
+	    /* continue the prior Uchain */
+	    DEBUG2 (("Continue  Uchain, k = "ID"\n", k)) ;
+	    ASSERT (k > 0) ;
+
+	    /* remove pivot col index from current row of U */
+	    /* if a new Uchain starts, then all entries are removed later */
+	    DEBUG2 (("Removing pivcol from Upattern, k = "ID"\n", k)) ;
+
+	    if (pivcol_position != EMPTY)
+	    {
+		/* place the last entry in the row in the */
+		/* position of the pivot col index */
+		ASSERT (pivcol == Upattern [pivcol_position]) ;
+		col = Upattern [--ulen] ;
+		ASSERT (col >= 0 && col < Work->n_col) ;
+		Upattern [pivcol_position] = col ;
+		Upos [col] = pivcol_position ;
+		Upos [pivcol] = EMPTY ;
+	    }
+
+	    /* this row continues the Uchain.  Keep track of how much */
+	    /* to trim from the k-th length to get the length of the */
+	    /* (k-1)st row of U */
+	    uilen = unz2i ;
+
+	}
+
+	Uval = (Entry *) (Numeric->Memory + p) ;
+	/* p += UNITS (Entry, unzx), no need to increment p */
+
+	for (i = 0 ; i < unzx ; i++)
+	{
+	    CLEAR (Uval [i]) ;
+	}
+
+	if (newUchain)
+	{
+	    ASSERT (ulen == 0) ;
+
+#ifdef DROP
+
+		for (i = kk + 1 ; i < fnpiv ; i++)
+		{
+		    Entry x ;
+		    double s ;
+		    Int col2, pos ;
+		    x = Fu1 [i*nb] ;
+		    APPROX_ABS (s, x) ;
+		    if (s <= droptol) continue ;
+		    col2 = Pivcol [i] ;
+		    pos = ulen++ ;
+		    Upattern [pos] = col2 ;
+		    Upos [col2] = pos ;
+		    Uval [pos] = x ;
+		}
+
+		for (i = 0 ; i < fncols ; i++)
+		{
+		    Entry x ;
+		    double s ;
+		    Int col2, pos ;
+		    x = Fu2 [i] ;
+		    APPROX_ABS (s, x) ;
+		    if (s <= droptol) continue ;
+		    col2 = Fcols [i] ;
+		    pos = ulen++ ;
+		    Upattern [pos] = col2 ;
+		    Upos [col2] = pos ;
+		    Uval [pos] = x ;
+		}
+
+#else
+
+		for (i = kk + 1 ; i < fnpiv ; i++)
+		{
+		    Entry x ;
+		    Int col2, pos ;
+		    x = Fu1 [i*nb] ;
+		    if (IS_ZERO (x)) continue ;
+		    col2 = Pivcol [i] ;
+		    pos = ulen++ ;
+		    Upattern [pos] = col2 ;
+		    Upos [col2] = pos ;
+		    Uval [pos] = x ;
+		}
+
+		for (i = 0 ; i < fncols ; i++)
+		{
+		    Entry x ;
+		    Int col2, pos ;
+		    x = Fu2 [i] ;
+		    if (IS_ZERO (x)) continue ;
+		    col2 = Fcols [i] ;
+		    pos = ulen++ ;
+		    Upattern [pos] = col2 ;
+		    Upos [col2] = pos ;
+		    Uval [pos] = x ;
+		}
+
+#endif
+
+	}
+	else
+	{
+
+	    ASSERT (ulen > 0) ;
+
+	    /* store the numerical entries and find new nonzeros */
+
+#ifdef DROP
+
+		for (i = kk + 1 ; i < fnpiv ; i++)
+		{
+		    Entry x ;
+		    double s ;
+		    Int col2, pos ;
+		    x = Fu1 [i*nb] ;
+		    APPROX_ABS (s, x) ;
+		    if (s <= droptol) continue ;
+		    col2 = Pivcol [i] ;
+		    pos = Upos [col2] ;
+		    if (pos == EMPTY)
+		    {
+			pos = ulen++ ;
+			Upattern [pos] = col2 ;
+			Upos [col2] = pos ;
+		    }
+		    Uval [pos] = x ;
+		}
+
+		for (i = 0 ; i < fncols ; i++)
+		{
+		    Entry x ;
+		    double s ;
+		    Int col2, pos ;
+		    x = Fu2 [i] ;
+		    APPROX_ABS (s, x) ;
+		    if (s <= droptol) continue ;
+		    col2 = Fcols [i] ;
+		    pos = Upos [col2] ;
+		    if (pos == EMPTY)
+		    {
+			pos = ulen++ ;
+			Upattern [pos] = col2 ;
+			Upos [col2] = pos ;
+		    }
+		    Uval [pos] = x ;
+		}
+
+#else
+
+		for (i = kk + 1 ; i < fnpiv ; i++)
+		{
+		    Entry x ;
+		    Int col2, pos ;
+		    x = Fu1 [i*nb] ;
+		    if (IS_ZERO (x)) continue ;
+		    col2 = Pivcol [i] ;
+		    pos = Upos [col2] ;
+		    if (pos == EMPTY)
+		    {
+			pos = ulen++ ;
+			Upattern [pos] = col2 ;
+			Upos [col2] = pos ;
+		    }
+		    Uval [pos] = x ;
+		}
+
+		for (i = 0 ; i < fncols ; i++)
+		{
+		    Entry x ;
+		    Int col2, pos ;
+		    x = Fu2 [i] ;
+		    if (IS_ZERO (x)) continue ;
+		    col2 = Fcols [i] ;
+		    pos = Upos [col2] ;
+		    if (pos == EMPTY)
+		    {
+			pos = ulen++ ;
+			Upattern [pos] = col2 ;
+			Upos [col2] = pos ;
+		    }
+		    Uval [pos] = x ;
+		}
+
+#endif
+
+	}
+
+	ASSERT (ulen == unzx) ;
+	ASSERT (unz <= ulen) ;
+	DEBUG4 (("unz "ID" \n", unz)) ;
+
+#ifdef DROP
+
+	    DEBUG4 (("all_unz "ID" \n", all_unz)) ;
+	    ASSERT (unz <= all_unz) ;
+	    Numeric->unz += unz ;
+	    Numeric->all_unz += all_unz ;
+	    /* count the "true" flops, based on LU pattern only */
+	    Numeric->flops += DIV_FLOPS * Lnz [kk]	/* scale pivot column */
+		+ MULTSUB_FLOPS * (Lnz [kk] * all_unz) ;    /* outer product */
+
+#else
+
+	    Numeric->unz += unz ;
+	    Numeric->all_unz += unz ;
+	    /* count the "true" flops, based on LU pattern only */
+	    Numeric->flops += DIV_FLOPS * Lnz [kk]	/* scale pivot column */
+		+ MULTSUB_FLOPS * (Lnz [kk] * unz) ;    /* outer product */
+#endif
+
+	Numeric->nUentries += unzx ;
+	Work->ulen = ulen ;
+	DEBUG1 (("Work->ulen = "ID" at end of pivot step, k: "ID"\n", ulen, k));
+
+	/* ------------------------------------------------------------------ */
+	/* the pivot row is the k-th row of U */
+	/* ------------------------------------------------------------------ */
+
+	Upos [pivcol] = pivcol_position ;	/* not aliased */
+	Uip [pivrow] = uip ;			/* aliased with Row_tuples */
+	Uilen [pivrow] = uilen ;		/* aliased with Row_tlen */
+
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* no more pivots in frontal working array */
+    /* ---------------------------------------------------------------------- */
+
+    Work->npiv += fnpiv ;
+    Work->fnpiv = 0 ;
+    Work->fnzeros = 0 ;
+    return (TRUE) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_store_lu.h b/src/C/SuiteSparse/UMFPACK/Source/umf_store_lu.h
new file mode 100644
index 0000000..b78528f
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_store_lu.h
@@ -0,0 +1,17 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_store_lu
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
+
+GLOBAL Int UMF_store_lu_drop
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_symbolic_usage.c b/src/C/SuiteSparse/UMFPACK/Source/umf_symbolic_usage.c
new file mode 100644
index 0000000..dff210e
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_symbolic_usage.c
@@ -0,0 +1,45 @@
+/* ========================================================================== */
+/* === UMF_symbolic_usage =================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Returns the final size of the Symbolic object, in Units */
+
+#include "umf_internal.h"
+
+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) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_symbolic_usage.h b/src/C/SuiteSparse/UMFPACK/Source/umf_symbolic_usage.h
new file mode 100644
index 0000000..fbe979a
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_symbolic_usage.h
@@ -0,0 +1,15 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL double UMF_symbolic_usage
+(
+    Int n_row,
+    Int n_col,
+    Int nchains,
+    Int nfr,
+    Int esize,
+    Int prefer_diagonal
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_transpose.c b/src/C/SuiteSparse/UMFPACK/Source/umf_transpose.c
new file mode 100644
index 0000000..85cd34d
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_transpose.c
@@ -0,0 +1,400 @@
+/* ========================================================================== */
+/* === UMF_transpose ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*  Not user-callable.  Computes a permuted transpose, R = (A (P,Q(1:nq)))' in
+	MATLAB notation, where R is in column-form.  A is n_row-by-n_col, the
+	row-form matrix R is n_row-by-nq, where nq <= n_col.  A may be singular.
+	The complex version can do transpose (') or array transpose (.').
+
+	Uses Gustavson's method (Two Fast Algorithms for Sparse Matrices:
+	Multiplication and Permuted Transposition, ACM Trans. on Math. Softw.,
+	vol 4, no 3, pp. 250-269).
+*/
+
+#include "umf_internal.h"
+#include "umf_is_permutation.h"
+
+GLOBAL Int UMF_transpose
+(
+    Int n_row,			/* A is n_row-by-n_col */
+    Int n_col,
+    const Int Ap [ ],		/* size n_col+1 */
+    const Int Ai [ ],		/* size nz = Ap [n_col] */
+    const double Ax [ ],	/* size nz if present */
+
+    const Int P [ ],	/* P [k] = i means original row i is kth row in A(P,Q)*/
+			/* P is identity if not present */
+			/* size n_row, if present */
+
+    const Int Q [ ],	/* Q [k] = j means original col j is kth col in A(P,Q)*/
+			/* Q is identity if not present */
+			/* size nq, if present */
+    Int nq,		/* size of Q, ignored if Q is (Int *) NULL */
+
+			/* output matrix: Rp, Ri, Rx, and Rz: */
+    Int Rp [ ],		/* size n_row+1 */
+    Int Ri [ ],		/* size nz */
+    double Rx [ ],	/* size nz, if present */
+
+    Int W [ ],		/* size max (n_row,n_col) workspace */
+
+    Int check		/* if true, then check inputs */
+#ifdef COMPLEX
+    , const double Az [ ]	/* size nz */
+    , double Rz [ ]		/* size nz */
+    , Int do_conjugate		/* if true, then do conjugate transpose */
+				/* otherwise, do array transpose */
+#endif
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int i, j, k, p, bp, newj, do_values ;
+#ifdef COMPLEX
+    Int split ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    Int nz ;
+    ASSERT (n_col >= 0) ;
+    nz = (Ap != (Int *) NULL) ? Ap [n_col] : 0 ;
+    DEBUG2 (("UMF_transpose: "ID"-by-"ID" nz "ID"\n", n_row, n_col, nz)) ;
+#endif
+
+    if (check)
+    {
+	/* UMFPACK_symbolic skips this check */
+	/* UMFPACK_transpose always does this check */
+	if (!Ai || !Ap || !Ri || !Rp || !W)
+	{
+	    return (UMFPACK_ERROR_argument_missing) ;
+	}
+	if (n_row <= 0 || n_col <= 0)		/* n_row,n_col must be > 0 */
+	{
+	    return (UMFPACK_ERROR_n_nonpositive) ;
+	}
+	if (!UMF_is_permutation (P, W, n_row, n_row) ||
+	    !UMF_is_permutation (Q, W, nq, nq))
+	{
+	    return (UMFPACK_ERROR_invalid_permutation) ;
+	}
+	if (AMD_valid (n_row, n_col, Ap, Ai) != AMD_OK)
+	{
+	    return (UMFPACK_ERROR_invalid_matrix) ;
+	}
+    }
+
+#ifndef NDEBUG
+    DEBUG2 (("UMF_transpose, input matrix:\n")) ;
+    UMF_dump_col_matrix (Ax,
+#ifdef COMPLEX
+	Az,
+#endif
+	Ai, Ap, n_row, n_col, nz) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* count the entries in each row of A */
+    /* ---------------------------------------------------------------------- */
+
+    /* use W as workspace for RowCount */
+
+    for (i = 0 ; i < n_row ; i++)
+    {
+	W [i] = 0 ;
+	Rp [i] = 0 ;
+    }
+
+    if (Q != (Int *) NULL)
+    {
+	for (newj = 0 ; newj < nq ; newj++)
+	{
+	    j = Q [newj] ;
+	    ASSERT (j >= 0 && j < n_col) ;
+	    for (p = Ap [j] ; p < Ap [j+1] ; p++)
+	    {
+		i = Ai [p] ;
+		ASSERT (i >= 0 && i < n_row) ;
+		W [i]++ ;
+	    }
+	}
+    }
+    else
+    {
+	for (j = 0 ; j < n_col ; j++)
+	{
+	    for (p = Ap [j] ; p < Ap [j+1] ; p++)
+	    {
+		i = Ai [p] ;
+		ASSERT (i >= 0 && i < n_row) ;
+		W [i]++ ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the row pointers for R = A (P,Q) */
+    /* ---------------------------------------------------------------------- */
+
+    if (P != (Int *) NULL)
+    {
+	Rp [0] = 0 ;
+	for (k = 0 ; k < n_row ; k++)
+	{
+	    i = P [k] ;
+	    ASSERT (i >= 0 && i < n_row) ;
+	    Rp [k+1] = Rp [k] + W [i] ;
+	}
+	for (k = 0 ; k < n_row ; k++)
+	{
+	    i = P [k] ;
+	    ASSERT (i >= 0 && i < n_row) ;
+	    W [i] = Rp [k] ;
+	}
+    }
+    else
+    {
+	Rp [0] = 0 ;
+	for (i = 0 ; i < n_row ; i++)
+	{
+	    Rp [i+1] = Rp [i] + W [i] ;
+	}
+	for (i = 0 ; i < n_row ; i++)
+	{
+	    W [i] = Rp [i] ;
+	}
+    }
+    ASSERT (Rp [n_row] <= Ap [n_col]) ;
+
+    /* at this point, W holds the permuted row pointers */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the row form of B */
+    /* ---------------------------------------------------------------------- */
+
+    do_values = Ax && Rx ;
+
+#ifdef COMPLEX
+    split = SPLIT (Az) && SPLIT (Rz) ;
+
+    if (do_conjugate && do_values)
+    {
+	if (Q != (Int *) NULL)
+	{
+	    if (split)
+	    {
+		/* R = A (P,Q)' */
+		for (newj = 0 ; newj < nq ; newj++)
+		{
+		    j = Q [newj] ;
+		    ASSERT (j >= 0 && j < n_col) ;
+		    for (p = Ap [j] ; p < Ap [j+1] ; p++)
+		    {
+			bp = W [Ai [p]]++ ;
+			Ri [bp] = newj ;
+			Rx [bp] = Ax [p] ;
+			Rz [bp] = -Az [p] ;
+		    }
+		}
+	    }
+	    else
+	    {
+		/* R = A (P,Q)' (merged complex values) */
+		for (newj = 0 ; newj < nq ; newj++)
+		{
+		    j = Q [newj] ;
+		    ASSERT (j >= 0 && j < n_col) ;
+		    for (p = Ap [j] ; p < Ap [j+1] ; p++)
+		    {
+			bp = W [Ai [p]]++ ;
+			Ri [bp] = newj ;
+			Rx [2*bp] = Ax [2*p] ;
+			Rx [2*bp+1] = -Ax [2*p+1] ;
+		    }
+		}
+	    }
+	}
+	else
+	{
+	    if (split)
+	    {
+		/* R = A (P,:)' */
+		for (j = 0 ; j < n_col ; j++)
+		{
+		    for (p = Ap [j] ; p < Ap [j+1] ; p++)
+		    {
+			bp = W [Ai [p]]++ ;
+			Ri [bp] = j ;
+			Rx [bp] = Ax [p] ;
+			Rz [bp] = -Az [p] ;
+		    }
+		}
+	    }
+	    else
+	    {
+		/* R = A (P,:)' (merged complex values) */
+		for (j = 0 ; j < n_col ; j++)
+		{
+		    for (p = Ap [j] ; p < Ap [j+1] ; p++)
+		    {
+			bp = W [Ai [p]]++ ;
+			Ri [bp] = j ;
+			Rx [2*bp] = Ax [2*p] ;
+			Rx [2*bp+1] = -Ax [2*p+1] ;
+		    }
+		}
+	    }
+	}
+    }
+    else
+#endif
+    {
+	if (Q != (Int *) NULL)
+	{
+	    if (do_values)
+	    {
+#ifdef COMPLEX
+		if (split)
+#endif
+		{
+		    /* R = A (P,Q).' */
+		    for (newj = 0 ; newj < nq ; newj++)
+		    {
+			j = Q [newj] ;
+			ASSERT (j >= 0 && j < n_col) ;
+			for (p = Ap [j] ; p < Ap [j+1] ; p++)
+			{
+			    bp = W [Ai [p]]++ ;
+			    Ri [bp] = newj ;
+			    Rx [bp] = Ax [p] ;
+#ifdef COMPLEX
+			    Rz [bp] = Az [p] ;
+#endif
+			}
+		    }
+		}
+#ifdef COMPLEX
+		else
+		{
+		    /* R = A (P,Q).' (merged complex values) */
+		    for (newj = 0 ; newj < nq ; newj++)
+		    {
+			j = Q [newj] ;
+			ASSERT (j >= 0 && j < n_col) ;
+			for (p = Ap [j] ; p < Ap [j+1] ; p++)
+			{
+			    bp = W [Ai [p]]++ ;
+			    Ri [bp] = newj ;
+			    Rx [2*bp] = Ax [2*p] ;
+			    Rx [2*bp+1] = Ax [2*p+1] ;
+			}
+		    }
+		}
+#endif
+	    }
+	    else
+	    {
+		/* R = pattern of A (P,Q).' */
+		for (newj = 0 ; newj < nq ; newj++)
+		{
+		    j = Q [newj] ;
+		    ASSERT (j >= 0 && j < n_col) ;
+		    for (p = Ap [j] ; p < Ap [j+1] ; p++)
+		    {
+			Ri [W [Ai [p]]++] = newj ;
+		    }
+		}
+	    }
+	}
+	else
+	{
+	    if (do_values)
+	    {
+#ifdef COMPLEX
+		if (split)
+#endif
+		{
+		    /* R = A (P,:).' */
+		    for (j = 0 ; j < n_col ; j++)
+		    {
+			for (p = Ap [j] ; p < Ap [j+1] ; p++)
+			{
+			    bp = W [Ai [p]]++ ;
+			    Ri [bp] = j ;
+			    Rx [bp] = Ax [p] ;
+#ifdef COMPLEX
+			    Rz [bp] = Az [p] ;
+#endif
+			}
+		    }
+		}
+#ifdef COMPLEX
+		else
+		{
+		    /* R = A (P,:).' (merged complex values) */
+		    for (j = 0 ; j < n_col ; j++)
+		    {
+			for (p = Ap [j] ; p < Ap [j+1] ; p++)
+			{
+			    bp = W [Ai [p]]++ ;
+			    Ri [bp] = j ;
+			    Rx [2*bp] = Ax [2*p] ;
+			    Rx [2*bp+1] = Ax [2*p+1] ;
+			}
+		    }
+		}
+#endif
+	    }
+	    else
+	    {
+		/* R = pattern of A (P,:).' */
+		for (j = 0 ; j < n_col ; j++)
+		{
+		    for (p = Ap [j] ; p < Ap [j+1] ; p++)
+		    {
+			Ri [W [Ai [p]]++] = j ;
+		    }
+		}
+	    }
+	}
+    }
+
+#ifndef NDEBUG
+    for (k = 0 ; k < n_row ; k++)
+    {
+	if (P != (Int *) NULL)
+	{
+	    i = P [k] ;
+	}
+	else
+	{
+	    i = k ;
+	}
+	DEBUG3 ((ID":  W[i] "ID" Rp[k+1] "ID"\n", i, W [i], Rp [k+1])) ;
+	ASSERT (W [i] == Rp [k+1]) ;
+    }
+    DEBUG2 (("UMF_transpose, output matrix:\n")) ;
+    UMF_dump_col_matrix (Rx,
+#ifdef COMPLEX
+	Rz,
+#endif
+	Ri, Rp, n_col, n_row, Rp [n_row]) ;
+    ASSERT (AMD_valid (n_col, n_row, Rp, Ri) == AMD_OK) ;
+#endif
+
+    return (UMFPACK_OK) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_transpose.h b/src/C/SuiteSparse/UMFPACK/Source/umf_transpose.h
new file mode 100644
index 0000000..5d44106
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_transpose.h
@@ -0,0 +1,27 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_transpose
+(
+    Int n_row,
+    Int n_col,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+    const Int P [ ],
+    const Int Q [ ],
+    Int nq,
+    Int Rp [ ],
+    Int Ri [ ],
+    double Rx [ ],
+    Int W [ ],
+    Int check
+#ifdef COMPLEX
+    , const double Az [ ]
+    , double Rz [ ]
+    , Int do_conjugate
+#endif
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_triplet.c b/src/C/SuiteSparse/UMFPACK/Source/umf_triplet.c
new file mode 100644
index 0000000..363e7a4
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_triplet.c
@@ -0,0 +1,428 @@
+/* ========================================================================== */
+/* === UMF_triplet ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Not user callable.  Converts triplet input to column-oriented form.
+    Duplicate entries may exist (they are summed in the output).  The columns
+    of the column-oriented form are in sorted order.  The input is not modified.
+    Returns 1 if OK, 0 if an error occurred.
+
+    Compiled into four different routines for each version (di, dl, zi, zl),
+    for a total of 16 different routines.
+*/
+
+#include "umf_internal.h"
+
+#ifdef DO_MAP
+#ifdef DO_VALUES
+GLOBAL Int UMF_triplet_map_x
+#else
+GLOBAL Int UMF_triplet_map_nox
+#endif
+#else
+#ifdef DO_VALUES
+GLOBAL Int UMF_triplet_nomap_x
+#else
+GLOBAL Int UMF_triplet_nomap_nox
+#endif
+#endif
+(
+    Int n_row,
+    Int n_col,
+    Int nz,
+    const Int Ti [ ],		/* size nz */
+    const Int Tj [ ],		/* size nz */
+    Int Ap [ ],			/* size n_col + 1 */
+    Int Ai [ ],			/* size nz */
+    Int Rp [ ],			/* size n_row + 1 */
+    Int Rj [ ],			/* size nz */
+    Int W [ ],			/* size max (n_row, n_col) */
+    Int RowCount [ ]		/* size n_row */
+#ifdef DO_VALUES
+    , const double Tx [ ]	/* size nz */
+    , double Ax [ ]		/* size nz */
+    , double Rx [ ]		/* size nz */
+#ifdef COMPLEX
+    , const double Tz [ ]	/* size nz */
+    , double Az [ ]		/* size nz */
+    , double Rz [ ]		/* size nz */
+#endif
+#endif
+#ifdef DO_MAP
+    , Int Map [ ]		/* size nz */
+    , Int Map2 [ ]		/* size nz */
+#endif
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int i, j, k, p, cp, p1, p2, pdest, pj ;
+#ifdef DO_MAP
+    Int duplicates ;
+#endif
+#ifdef DO_VALUES
+#ifdef COMPLEX
+    Int split = SPLIT (Tz) && SPLIT (Az) && SPLIT (Rz) ;
+#endif
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* count the entries in each row (also counting duplicates) */
+    /* ---------------------------------------------------------------------- */
+
+    /* use W as workspace for row counts (including duplicates) */
+    for (i = 0 ; i < n_row ; i++)
+    {
+	W [i] = 0 ;
+    }
+
+    for (k = 0 ; k < nz ; k++)
+    {
+	i = Ti [k] ;
+	j = Tj [k] ;
+	if (i < 0 || i >= n_row || j < 0 || j >= n_col)
+	{
+	    return (UMFPACK_ERROR_invalid_matrix) ;
+	}
+	W [i]++ ;
+#ifndef NDEBUG
+	DEBUG1 ((ID " triplet: "ID" "ID" ", k, i, j)) ;
+#ifdef DO_VALUES
+	{
+	    Entry tt ;
+	    ASSIGN (tt, Tx, Tz, k, split) ;
+	    EDEBUG2 (tt) ;
+	    DEBUG1 (("\n")) ;
+	}
+#endif
+#endif
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the row pointers */
+    /* ---------------------------------------------------------------------- */
+
+    Rp [0] = 0 ;
+    for (i = 0 ; i < n_row ; i++)
+    {
+	Rp [i+1] = Rp [i] + W [i] ;
+	W [i] = Rp [i] ;
+    }
+
+    /* W is now equal to the row pointers */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the row form */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < nz ; k++)
+    {
+	p = W [Ti [k]]++ ;
+#ifdef DO_MAP
+	Map [k] = p ;
+#endif
+	Rj [p] = Tj [k] ;
+#ifdef DO_VALUES
+#ifdef COMPLEX
+	if (split)
+	{
+	    Rx [p] = Tx [k] ;
+	    Rz [p] = Tz [k] ;
+	}
+	else
+	{
+	    Rx [2*p  ] = Tx [2*k  ] ;
+	    Rx [2*p+1] = Tx [2*k+1] ;
+	}
+#else
+	Rx [p] = Tx [k] ;
+#endif
+#endif
+    }
+
+    /* Rp stays the same, but W [i] is advanced to the start of row i+1 */
+
+#ifndef NDEBUG
+    for (i = 0 ; i < n_row ; i++)
+    {
+	ASSERT (W [i] == Rp [i+1]) ;
+    }
+#ifdef DO_MAP
+    for (k = 0 ; k < nz ; k++)
+    {
+	/* make sure that kth triplet is mapped correctly */
+	p = Map [k] ;
+	DEBUG1 (("First row map: Map ["ID"] = "ID"\n", k, p)) ;
+	i = Ti [k] ;
+	j = Tj [k] ;
+	ASSERT (j == Rj [p]) ;
+	ASSERT (Rp [i] <= p && p < Rp [i+1]) ;
+    }
+#endif
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* sum up duplicates */
+    /* ---------------------------------------------------------------------- */
+
+    /* use W [j] to hold position in Ri/Rx/Rz of a_ij, for row i [ */
+
+    for (j = 0 ; j < n_col ; j++)
+    {
+	W [j] = EMPTY ;
+    }
+
+#ifdef DO_MAP
+    duplicates = FALSE ;
+#endif
+
+    for (i = 0 ; i < n_row ; i++)
+    {
+	p1 = Rp [i] ;
+	p2 = Rp [i+1] ;
+	pdest = p1 ;
+	/* At this point, W [j] < p1 holds true for all columns j, */
+	/* because Ri/Rx/Rz is stored in row oriented order. */
+#ifndef NDEBUG
+	if (UMF_debug >= -2)
+	{
+	    for (j = 0 ; j < n_col ; j++)
+	    {
+		ASSERT (W [j] < p1) ;
+	    }
+	}
+#endif
+	for (p = p1 ; p < p2 ; p++)
+	{
+	    j = Rj [p] ;
+	    ASSERT (j >= 0 && j < n_col) ;
+	    pj = W [j] ;
+	    if (pj >= p1)
+	    {
+		/* this column index, j, is already in row i, at position pj */
+		ASSERT (pj < p) ;
+		ASSERT (Rj [pj] == j) ;
+#ifdef DO_MAP
+		Map2 [p] = pj ;
+		duplicates = TRUE ;
+#endif
+#ifdef DO_VALUES
+		/* sum the entry */
+#ifdef COMPLEX
+		if (split)
+		{
+		    Rx [pj] += Rx [p] ;
+		    Rz [pj] += Rz [p] ;
+		}
+		else
+		{
+		    Rx[2*pj  ] += Rx[2*p  ] ;
+		    Rx[2*pj+1] += Rx[2*p+1] ;
+		}
+#else
+		Rx [pj] += Rx [p] ;
+#endif
+#endif
+	    }
+	    else
+	    {
+		/* keep the entry */
+		/* also keep track in W[j] of position of a_ij for case above */
+		W [j] = pdest ;
+#ifdef DO_MAP
+		Map2 [p] = pdest ;
+#endif
+		/* no need to move the entry if pdest is equal to p */
+		if (pdest != p)
+		{
+		    Rj [pdest] = j ;
+#ifdef DO_VALUES
+#ifdef COMPLEX
+		    if (split)
+		    {
+			Rx [pdest] = Rx [p] ;
+			Rz [pdest] = Rz [p] ;
+		    }
+		    else
+		    {
+			Rx [2*pdest  ] = Rx [2*p  ] ;
+			Rx [2*pdest+1] = Rx [2*p+1] ;
+		    }
+#else
+		    Rx [pdest] = Rx [p] ;
+#endif
+#endif
+		}
+		pdest++ ;
+	    }
+	}
+	RowCount [i] = pdest - p1 ;
+    }
+
+    /* done using W for position of a_ij ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* merge Map and Map2 into a single Map */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef DO_MAP
+    if (duplicates)
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    Map [k] = Map2 [Map [k]] ;
+	}
+    }
+#ifndef NDEBUG
+    else
+    {
+	/* no duplicates, so no need to recompute Map */
+	for (k = 0 ; k < nz ; k++)
+	{
+	    ASSERT (Map2 [k] == k) ;
+	}
+    }
+    for (k = 0 ; k < nz ; k++)
+    {
+	/* make sure that kth triplet is mapped correctly */
+	p = Map [k] ;
+	DEBUG1 (("Second row map: Map ["ID"] = "ID"\n", k, p)) ;
+	i = Ti [k] ;
+	j = Tj [k] ;
+	ASSERT (j == Rj [p]) ;
+	ASSERT (Rp [i] <= p && p < Rp [i+1]) ;
+    }
+#endif
+#endif
+
+    /* now the kth triplet maps to p = Map [k], and thus to Rj/Rx [p] */
+
+    /* ---------------------------------------------------------------------- */
+    /* count the entries in each column */
+    /* ---------------------------------------------------------------------- */
+
+    /* [ use W as work space for column counts of A */
+    for (j = 0 ; j < n_col ; j++)
+    {
+	W [j] = 0 ;
+    }
+
+    for (i = 0 ; i < n_row ; i++)
+    {
+	for (p = Rp [i] ; p < Rp [i] + RowCount [i] ; p++)
+	{
+	    j = Rj [p] ;
+	    ASSERT (j >= 0 && j < n_col) ;
+	    W [j]++ ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* create the column pointers */
+    /* ---------------------------------------------------------------------- */
+
+    Ap [0] = 0 ;
+    for (j = 0 ; j < n_col ; j++)
+    {
+	Ap [j+1] = Ap [j] + W [j] ;
+    }
+    /* done using W as workspace for column counts of A ] */
+
+    for (j = 0 ; j < n_col ; j++)
+    {
+	W [j] = Ap [j] ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the column form */
+    /* ---------------------------------------------------------------------- */
+
+    for (i = 0 ; i < n_row ; i++)
+    {
+	for (p = Rp [i] ; p < Rp [i] + RowCount [i] ; p++)
+	{
+	    cp = W [Rj [p]]++ ;
+#ifdef DO_MAP
+	    Map2 [p] = cp ;
+#endif
+	    Ai [cp] = i ;
+#ifdef DO_VALUES
+#ifdef COMPLEX
+	    if (split)
+	    {
+		Ax [cp] = Rx [p] ;
+		Az [cp] = Rz [p] ;
+	    }
+	    else
+	    {
+		Ax [2*cp  ] = Rx [2*p  ] ;
+		Ax [2*cp+1] = Rx [2*p+1] ;
+	    }
+#else
+	    Ax [cp] = Rx [p] ;
+#endif
+#endif
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* merge Map and Map2 into a single Map */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef DO_MAP
+    for (k = 0 ; k < nz ; k++)
+    {
+	Map [k] = Map2 [Map [k]] ;
+    }
+#endif
+
+    /* now the kth triplet maps to p = Map [k], and thus to Ai/Ax [p] */
+
+#ifndef NDEBUG
+    for (j = 0 ; j < n_col ; j++)
+    {
+	ASSERT (W [j] == Ap [j+1]) ;
+    }
+
+    UMF_dump_col_matrix (
+#ifdef DO_VALUES
+	Ax,
+#ifdef COMPLEX
+	Az,
+#endif
+#else
+	(double *) NULL,
+#ifdef COMPLEX
+	(double *) NULL,
+#endif
+#endif
+	Ai, Ap, n_row, n_col, nz) ;
+
+#ifdef DO_MAP
+    for (k = 0 ; k < nz ; k++)
+    {
+	/* make sure that kth triplet is mapped correctly */
+	p = Map [k] ;
+	DEBUG1 (("Col map: Map ["ID"] = "ID"\t", k, p)) ;
+	i = Ti [k] ;
+	j = Tj [k] ;
+	ASSERT (i == Ai [p]) ;
+	DEBUG1 (("   i "ID" j "ID" Ap[j] "ID" p "ID" Ap[j+1] "ID"\n",
+		i, j, Ap [j], p, Ap [j+1])) ;
+	ASSERT (Ap [j] <= p && p < Ap [j+1]) ;
+    }
+#endif
+#endif
+
+    return (UMFPACK_OK) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_triplet.h b/src/C/SuiteSparse/UMFPACK/Source/umf_triplet.h
new file mode 100644
index 0000000..5a3a9d9
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_triplet.h
@@ -0,0 +1,85 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_triplet_map_x
+(
+    Int n_row,
+    Int n_col,
+    Int nz,
+    const Int Ti [ ],
+    const Int Tj [ ],
+    Int Ap [ ],
+    Int Ai [ ],
+    Int Rp [ ],
+    Int Rj [ ],
+    Int W [ ],
+    Int RowCount [ ]
+    , const double Tx [ ]
+    , double Ax [ ]
+    , double Rx [ ]
+#ifdef COMPLEX
+    , const double Tz [ ]
+    , double Az [ ]
+    , double Rz [ ]
+#endif
+    , Int Map [ ]
+    , Int Map2 [ ]
+) ;
+
+GLOBAL Int UMF_triplet_map_nox
+(
+    Int n_row,
+    Int n_col,
+    Int nz,
+    const Int Ti [ ],
+    const Int Tj [ ],
+    Int Ap [ ],
+    Int Ai [ ],
+    Int Rp [ ],
+    Int Rj [ ],
+    Int W [ ],
+    Int RowCount [ ]
+    , Int Map [ ]
+    , Int Map2 [ ]
+) ;
+
+GLOBAL Int UMF_triplet_nomap_x
+(
+    Int n_row,
+    Int n_col,
+    Int nz,
+    const Int Ti [ ],
+    const Int Tj [ ],
+    Int Ap [ ],
+    Int Ai [ ],
+    Int Rp [ ],
+    Int Rj [ ],
+    Int W [ ],
+    Int RowCount [ ]
+    , const double Tx [ ]
+    , double Ax [ ]
+    , double Rx [ ]
+#ifdef COMPLEX
+    , const double Tz [ ]
+    , double Az [ ]
+    , double Rz [ ]
+#endif
+) ;
+
+GLOBAL Int UMF_triplet_nomap_nox
+(
+    Int n_row,
+    Int n_col,
+    Int nz,
+    const Int Ti [ ],
+    const Int Tj [ ],
+    Int Ap [ ],
+    Int Ai [ ],
+    Int Rp [ ],
+    Int Rj [ ],
+    Int W [ ],
+    Int RowCount [ ]
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_tuple_lengths.c b/src/C/SuiteSparse/UMFPACK/Source/umf_tuple_lengths.c
new file mode 100644
index 0000000..cd8f9ea
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_tuple_lengths.c
@@ -0,0 +1,135 @@
+/* ========================================================================== */
+/* === UMF_tuple_lengths ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Determine the tuple list lengths, and the amount of memory required for */
+/* them.  Return the amount of memory needed to store all the tuples. */
+/* This routine assumes that the tuple lists themselves are either already */
+/* deallocated, or will be shortly (so Row[ ].tlen and Col[ ].tlen are */
+/* overwritten) */
+
+#include "umf_internal.h"
+
+GLOBAL Int UMF_tuple_lengths	    /* return memory usage */
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    double *p_dusage		    /* output argument */
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    double dusage ;
+    Int e, nrows, ncols, nel, i, *Rows, *Cols, row, col, n_row, n_col, *E,
+	*Row_degree, *Row_tlen, *Col_degree, *Col_tlen, usage, n1 ;
+    Element *ep ;
+    Unit *p ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    E = Work->E ;
+    Row_degree = Numeric->Rperm ;   /* for NON_PIVOTAL_ROW macro only */
+    Col_degree = Numeric->Cperm ;   /* for NON_PIVOTAL_COL macro only */
+    Row_tlen   = Numeric->Uilen ;
+    Col_tlen   = Numeric->Lilen ;
+    n_row = Work->n_row ;
+    n_col = Work->n_col ;
+    n1 = Work->n1 ;
+    nel = Work->nel ;
+
+    DEBUG3 (("TUPLE_LENGTHS: n_row "ID" n_col "ID" nel "ID"\n",
+	n_row, n_col, nel)) ;
+    ASSERT (nel < Work->elen) ;
+
+    /* tuple list lengths already initialized to zero */
+
+    /* ---------------------------------------------------------------------- */
+    /* scan each element: count tuple list lengths (include element 0) */
+    /* ---------------------------------------------------------------------- */
+
+    for (e = 1 ; e <= nel ; e++)	/* for all elements, in any order */
+    {
+	if (E [e])
+	{
+#ifndef NDEBUG
+	    UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+	    p = Numeric->Memory + E [e] ;
+	    GET_ELEMENT_PATTERN (ep, p, Cols, Rows, ncols) ;
+	    nrows = ep->nrows ;
+	    for (i = 0 ; i < nrows ; i++)
+	    {
+		row = Rows [i] ;
+		ASSERT (row == EMPTY || (row >= n1 && row < n_row)) ;
+		if (row >= n1)
+		{
+		    ASSERT (NON_PIVOTAL_ROW (row)) ;
+		    Row_tlen [row] ++ ;
+		}
+	    }
+	    for (i = 0 ; i < ncols ; i++)
+	    {
+		col = Cols [i] ;
+		ASSERT (col == EMPTY || (col >= n1 && col < n_col)) ;
+		if (col >= n1)
+		{
+		    ASSERT (NON_PIVOTAL_COL (col)) ;
+		    Col_tlen [col] ++ ;
+		}
+	    }
+	}
+    }
+
+    /* note: tuple lengths are now modified, but the tuple lists are not */
+    /* updated to reflect that fact. */
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the required memory to hold all the tuple lists */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG0 (("UMF_build_tuples_usage\n")) ;
+
+    usage = 0 ;
+    dusage = 0 ;
+
+    ASSERT (Col_tlen && Col_degree) ;
+
+    for (col = n1 ; col < n_col ; col++)
+    {
+	if (NON_PIVOTAL_COL (col))
+	{
+	    usage  += 1 +  UNITS (Tuple, TUPLES (Col_tlen [col])) ;
+	    dusage += 1 + DUNITS (Tuple, TUPLES (Col_tlen [col])) ;
+	    DEBUG0 ((" col: "ID" tlen "ID" usage so far: "ID"\n",
+		     col, Col_tlen [col], usage)) ;
+	}
+    }
+
+    ASSERT (Row_tlen && Row_degree) ;
+
+    for (row = n1 ; row < n_row ; row++)
+    {
+	if (NON_PIVOTAL_ROW (row))
+	{
+	    usage  += 1 +  UNITS (Tuple, TUPLES (Row_tlen [row])) ;
+	    dusage += 1 + DUNITS (Tuple, TUPLES (Row_tlen [row])) ;
+	    DEBUG0 ((" row: "ID" tlen "ID" usage so far: "ID"\n",
+		     row, Row_tlen [row], usage)) ;
+	}
+    }
+
+    DEBUG0 (("UMF_build_tuples_usage "ID" %g\n", usage, dusage)) ;
+
+    *p_dusage = dusage ;
+    return (usage) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_tuple_lengths.h b/src/C/SuiteSparse/UMFPACK/Source/umf_tuple_lengths.h
new file mode 100644
index 0000000..e859092
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_tuple_lengths.h
@@ -0,0 +1,12 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_tuple_lengths
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    double *dusage
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_usolve.c b/src/C/SuiteSparse/UMFPACK/Source/umf_usolve.c
new file mode 100644
index 0000000..043ebc4
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_usolve.c
@@ -0,0 +1,226 @@
+/* ========================================================================== */
+/* === UMF_usolve =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*  solves Ux = b, where U is the upper triangular factor of a matrix. */
+/*  B is overwritten with the solution X. */
+/*  Returns the floating point operation count */
+
+#include "umf_internal.h"
+
+GLOBAL double UMF_usolve
+(
+    NumericType *Numeric,
+    Entry X [ ],		/* b on input, solution x on output */
+    Int Pattern [ ]		/* a work array of size n */
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Entry xk ;
+    Entry *xp, *D, *Uval ;
+    Int k, deg, j, *ip, col, *Upos, *Uilen, pos,
+	*Uip, n, ulen, up, newUchain, npiv, n1, *Ui ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    if (Numeric->n_row != Numeric->n_col) return (0.) ;
+    n = Numeric->n_row ;
+    npiv = Numeric->npiv ;
+    Upos = Numeric->Upos ;
+    Uilen = Numeric->Uilen ;
+    Uip = Numeric->Uip ;
+    D = Numeric->D ;
+    n1 = Numeric->n1 ;
+
+#ifndef NDEBUG
+    DEBUG4 (("Usolve start:  npiv = "ID" n = "ID"\n", npiv, n)) ;
+    for (j = 0 ; j < n ; j++)
+    {
+	DEBUG4 (("Usolve start "ID": ", j)) ;
+	EDEBUG4 (X [j]) ;
+	DEBUG4 (("\n")) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* singular case */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NO_DIVIDE_BY_ZERO
+    /* handle the singular part of D, up to just before the last pivot */
+    for (k = n-1 ; k >= npiv ; k--)
+    {
+	/* This is an *** intentional *** divide-by-zero, to get Inf or Nan,
+	 * as appropriate.  It is not a bug. */
+	ASSERT (IS_ZERO (D [k])) ;
+	xk = X [k] ;
+	/* X [k] = xk / D [k] ; */
+	DIV (X [k], xk, D [k]) ;
+    }
+#else
+    /* Do not divide by zero */
+#endif
+
+    deg = Numeric->ulen ;
+    if (deg > 0)
+    {
+	/* :: make last pivot row of U (singular matrices only) :: */
+	for (j = 0 ; j < deg ; j++)
+	{
+	    DEBUG1 (("Last row of U: j="ID"\n", j)) ;
+	    DEBUG1 (("Last row of U: Upattern[j]="ID"\n",
+		Numeric->Upattern [j]) );
+	    Pattern [j] = Numeric->Upattern [j] ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* nonsingletons */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = npiv-1 ; k >= n1 ; k--)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* use row k of U */
+	/* ------------------------------------------------------------------ */
+
+	up = Uip [k] ;
+	ulen = Uilen [k] ;
+	newUchain = (up < 0) ;
+	if (newUchain)
+	{
+	    up = -up ;
+	    xp = (Entry *) (Numeric->Memory + up + UNITS (Int, ulen)) ;
+	}
+	else
+	{
+	    xp = (Entry *) (Numeric->Memory + up) ;
+	}
+
+	xk = X [k] ;
+	for (j = 0 ; j < deg ; j++)
+	{
+	    DEBUG4 (("  k "ID" col "ID" value", k, Pattern [j])) ;
+	    EDEBUG4 (*xp) ;
+	    DEBUG4 (("\n")) ;
+	    /* xk -= X [Pattern [j]] * (*xp) ; */
+	    MULT_SUB (xk, X [Pattern [j]], *xp) ;
+	    xp++ ;
+	}
+
+#ifndef NO_DIVIDE_BY_ZERO
+	/* Go ahead and divide by zero if D [k] is zero */
+	/* X [k] = xk / D [k] ; */
+	DIV (X [k], xk, D [k]) ;
+#else
+	/* Do not divide by zero */
+	if (IS_NONZERO (D [k]))
+	{
+	    /* X [k] = xk / D [k] ; */
+	    DIV (X [k], xk, D [k]) ;
+	}
+#endif
+
+	/* ------------------------------------------------------------------ */
+	/* make row k-1 of U in Pattern [0..deg-1] */
+	/* ------------------------------------------------------------------ */
+
+	if (k == n1) break ;
+
+	if (newUchain)
+	{
+	    /* next row is a new Uchain */
+	    deg = ulen ;
+	    ASSERT (IMPLIES (k == 0, deg == 0)) ;
+	    DEBUG4 (("end of chain for row of U "ID" deg "ID"\n", k-1, deg)) ;
+	    ip = (Int *) (Numeric->Memory + up) ;
+	    for (j = 0 ; j < deg ; j++)
+	    {
+		col = *ip++ ;
+		DEBUG4 (("  k "ID" col "ID"\n", k-1, col)) ;
+		ASSERT (k <= col) ;
+		Pattern [j] = col ;
+	    }
+	}
+	else
+	{
+	    deg -= ulen ;
+	    DEBUG4 (("middle of chain for row of U "ID" deg "ID"\n", k, deg)) ;
+	    ASSERT (deg >= 0) ;
+	    pos = Upos [k] ;
+	    if (pos != EMPTY)
+	    {
+		/* add the pivot column */
+		DEBUG4 (("k "ID" add pivot entry at pos "ID"\n", k, pos)) ;
+		ASSERT (pos >= 0 && pos <= deg) ;
+		Pattern [deg++] = Pattern [pos] ;
+		Pattern [pos] = k ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* singletons */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = n1 - 1 ; k >= 0 ; k--)
+    {
+	deg = Uilen [k] ;
+	xk = X [k] ;
+	DEBUG4 (("Singleton k "ID"\n", k)) ;
+	if (deg > 0)
+	{
+	    up = Uip [k] ;
+	    Ui = (Int *) (Numeric->Memory + up) ;
+	    up += UNITS (Int, deg) ;
+	    Uval = (Entry *) (Numeric->Memory + up) ;
+	    for (j = 0 ; j < deg ; j++)
+	    {
+		DEBUG4 (("  k "ID" col "ID" value", k, Ui [j])) ;
+		EDEBUG4 (Uval [j]) ;
+		DEBUG4 (("\n")) ;
+		/* xk -= X [Ui [j]] * Uval [j] ; */
+		ASSERT (Ui [j] >= 0 && Ui [j] < n) ;
+		MULT_SUB (xk, X [Ui [j]], Uval [j]) ;
+	    }
+	}
+
+#ifndef NO_DIVIDE_BY_ZERO
+	/* Go ahead and divide by zero if D [k] is zero */
+	/* X [k] = xk / D [k] ; */
+	DIV (X [k], xk, D [k]) ;
+#else
+	/* Do not divide by zero */
+	if (IS_NONZERO (D [k]))
+	{
+	    /* X [k] = xk / D [k] ; */
+	    DIV (X [k], xk, D [k]) ;
+	}
+#endif
+
+    }
+
+#ifndef NDEBUG
+    for (j = 0 ; j < n ; j++)
+    {
+	DEBUG4 (("Usolve done "ID": ", j)) ;
+	EDEBUG4 (X [j]) ;
+	DEBUG4 (("\n")) ;
+    }
+    DEBUG4 (("Usolve done.\n")) ;
+#endif
+
+    return (DIV_FLOPS * ((double) n) + MULTSUB_FLOPS * ((double) Numeric->unz));
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_usolve.h b/src/C/SuiteSparse/UMFPACK/Source/umf_usolve.h
new file mode 100644
index 0000000..5055278
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_usolve.h
@@ -0,0 +1,12 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL double UMF_usolve
+(
+    NumericType *Numeric,
+    Entry X [ ],
+    Int Pattern [ ]
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_utsolve.c b/src/C/SuiteSparse/UMFPACK/Source/umf_utsolve.c
new file mode 100644
index 0000000..fb3f4a8
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_utsolve.c
@@ -0,0 +1,331 @@
+/* ========================================================================== */
+/* === UMF_utsolve ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*  solves U'x = b or U.'x=b, where U is the upper triangular factor of a */
+/*  matrix.  B is overwritten with the solution X. */
+/*  Returns the floating point operation count */
+
+#include "umf_internal.h"
+
+GLOBAL double
+#ifdef CONJUGATE_SOLVE
+UMF_uhsolve			/* solve U'x=b  (complex conjugate transpose) */
+#else
+UMF_utsolve			/* solve U.'x=b (array transpose) */
+#endif
+(
+    NumericType *Numeric,
+    Entry X [ ],		/* b on input, solution x on output */
+    Int Pattern [ ]		/* a work array of size n */
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Entry xk ;
+    Entry *xp, *D, *Uval ;
+    Int k, deg, j, *ip, col, *Upos, *Uilen, kstart, kend, up,
+	*Uip, n, uhead, ulen, pos, npiv, n1, *Ui ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    if (Numeric->n_row != Numeric->n_col) return (0.) ;
+    n = Numeric->n_row ;
+    npiv = Numeric->npiv ;
+    Upos = Numeric->Upos ;
+    Uilen = Numeric->Uilen ;
+    Uip = Numeric->Uip ;
+    D = Numeric->D ;
+    kend = 0 ;
+    n1 = Numeric->n1 ;
+
+#ifndef NDEBUG
+    DEBUG4 (("Utsolve start: npiv "ID" n "ID"\n", npiv, n)) ;
+    for (j = 0 ; j < n ; j++)
+    {
+	DEBUG4 (("Utsolve start "ID": ", j)) ;
+	EDEBUG4 (X [j]) ;
+	DEBUG4 (("\n")) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* singletons */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < n1 ; k++)
+    {
+	DEBUG4 (("Singleton k "ID"\n", k)) ;
+
+#ifndef NO_DIVIDE_BY_ZERO
+	/* Go ahead and divide by zero if D [k] is zero. */
+#ifdef CONJUGATE_SOLVE
+	/* xk = X [k] / conjugate (D [k]) ; */
+	DIV_CONJ (xk, X [k], D [k]) ;
+#else
+	/* xk = X [k] / D [k] ; */
+	DIV (xk, X [k], D [k]) ;
+#endif
+#else
+	/* Do not divide by zero */
+	if (IS_NONZERO (D [k]))
+	{
+#ifdef CONJUGATE_SOLVE
+	    /* xk = X [k] / conjugate (D [k]) ; */
+	    DIV_CONJ (xk, X [k], D [k]) ;
+#else
+	    /* xk = X [k] / D [k] ; */
+	    DIV (xk, X [k], D [k]) ;
+#endif
+	}
+#endif
+
+	X [k] = xk ;
+	deg = Uilen [k] ;
+	if (deg > 0 && IS_NONZERO (xk))
+	{
+	    up = Uip [k] ;
+	    Ui = (Int *) (Numeric->Memory + up) ;
+	    up += UNITS (Int, deg) ;
+	    Uval = (Entry *) (Numeric->Memory + up) ;
+	    for (j = 0 ; j < deg ; j++)
+	    {
+		DEBUG4 (("  k "ID" col "ID" value", k, Ui [j])) ;
+		EDEBUG4 (Uval [j]) ;
+		DEBUG4 (("\n")) ;
+#ifdef CONJUGATE_SOLVE
+		/* X [Ui [j]] -= xk * conjugate (Uval [j]) ; */
+		MULT_SUB_CONJ (X [Ui [j]], xk, Uval [j]) ;
+#else
+		/* X [Ui [j]] -= xk * Uval [j] ; */
+		MULT_SUB (X [Ui [j]], xk, Uval [j]) ;
+#endif
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* nonsingletons */
+    /* ---------------------------------------------------------------------- */
+
+    for (kstart = n1 ; kstart < npiv ; kstart = kend + 1)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* find the end of this Uchain */
+	/* ------------------------------------------------------------------ */
+
+	DEBUG4 (("kstart "ID" kend "ID"\n", kstart, kend)) ;
+	/* for (kend = kstart ; kend < npiv && Uip [kend+1] > 0 ; kend++) ; */
+	kend = kstart ;
+	while (kend < npiv && Uip [kend+1] > 0)
+	{
+	    kend++ ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* scan the whole Uchain to find the pattern of the first row of U */
+	/* ------------------------------------------------------------------ */
+
+	k = kend+1 ;
+	DEBUG4 (("\nKend "ID" K "ID"\n", kend, k)) ;
+
+	/* ------------------------------------------------------------------ */
+	/* start with last row in Uchain of U in Pattern [0..deg-1] */
+	/* ------------------------------------------------------------------ */
+
+	if (k == npiv)
+	{
+	    deg = Numeric->ulen ;
+	    if (deg > 0)
+	    {
+		/* :: make last pivot row of U (singular matrices only) :: */
+		for (j = 0 ; j < deg ; j++)
+		{
+		    Pattern [j] = Numeric->Upattern [j] ;
+		}
+	    }
+	}
+	else
+	{
+	    ASSERT (k >= 0 && k < npiv) ;
+	    up = -Uip [k] ;
+	    ASSERT (up > 0) ;
+	    deg = Uilen [k] ;
+	    DEBUG4 (("end of chain for row of U "ID" deg "ID"\n", k-1, deg)) ;
+	    ip = (Int *) (Numeric->Memory + up) ;
+	    for (j = 0 ; j < deg ; j++)
+	    {
+		col = *ip++ ;
+		DEBUG4 (("  k "ID" col "ID"\n", k-1, col)) ;
+		ASSERT (k <= col) ;
+		Pattern [j] = col ;
+	    }
+	}
+
+	/* empty the stack at the bottom of Pattern */
+	uhead = n ;
+
+	for (k = kend ; k > kstart ; k--)
+	{
+	    /* Pattern [0..deg-1] is the pattern of row k of U */
+
+	    /* -------------------------------------------------------------- */
+	    /* make row k-1 of U in Pattern [0..deg-1] */
+	    /* -------------------------------------------------------------- */
+
+	    ASSERT (k >= 0 && k < npiv) ;
+	    ulen = Uilen [k] ;
+	    /* delete, and push on the stack */
+	    for (j = 0 ; j < ulen ; j++)
+	    {
+		ASSERT (uhead >= deg) ;
+		Pattern [--uhead] = Pattern [--deg] ;
+	    }
+	    DEBUG4 (("middle of chain for row of U "ID" deg "ID"\n", k, deg)) ;
+	    ASSERT (deg >= 0) ;
+
+	    pos = Upos [k] ;
+	    if (pos != EMPTY)
+	    {
+		/* add the pivot column */
+		DEBUG4 (("k "ID" add pivot entry at position "ID"\n", k, pos)) ;
+		ASSERT (pos >= 0 && pos <= deg) ;
+		Pattern [deg++] = Pattern [pos] ;
+		Pattern [pos] = k ;
+	    }
+	}
+
+	/* Pattern [0..deg-1] is now the pattern of the first row in Uchain */
+
+	/* ------------------------------------------------------------------ */
+	/* solve using this Uchain, in reverse order */
+	/* ------------------------------------------------------------------ */
+
+	DEBUG4 (("Unwinding Uchain\n")) ;
+	for (k = kstart ; k <= kend ; k++)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* construct row k */
+	    /* -------------------------------------------------------------- */
+
+	    ASSERT (k >= 0 && k < npiv) ;
+	    pos = Upos [k] ;
+	    if (pos != EMPTY)
+	    {
+		/* remove the pivot column */
+		DEBUG4 (("k "ID" add pivot entry at position "ID"\n", k, pos)) ;
+		ASSERT (k > kstart) ;
+		ASSERT (pos >= 0 && pos < deg) ;
+		ASSERT (Pattern [pos] == k) ;
+		Pattern [pos] = Pattern [--deg] ;
+	    }
+
+	    up = Uip [k] ;
+	    ulen = Uilen [k] ;
+	    if (k > kstart)
+	    {
+		/* concatenate the deleted pattern; pop from the stack */
+		for (j = 0 ; j < ulen ; j++)
+		{
+		    ASSERT (deg <= uhead && uhead < n) ;
+		    Pattern [deg++] = Pattern [uhead++] ;
+		}
+		DEBUG4 (("middle of chain, row of U "ID" deg "ID"\n", k, deg)) ;
+		ASSERT (deg >= 0) ;
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* use row k of U */
+	    /* -------------------------------------------------------------- */
+
+#ifndef NO_DIVIDE_BY_ZERO
+	    /* Go ahead and divide by zero if D [k] is zero. */
+#ifdef CONJUGATE_SOLVE
+	    /* xk = X [k] / conjugate (D [k]) ; */
+	    DIV_CONJ (xk, X [k], D [k]) ;
+#else
+	    /* xk = X [k] / D [k] ; */
+	    DIV (xk, X [k], D [k]) ;
+#endif
+#else
+	    /* Do not divide by zero */
+	    if (IS_NONZERO (D [k]))
+	    {
+#ifdef CONJUGATE_SOLVE
+		/* xk = X [k] / conjugate (D [k]) ; */
+		DIV_CONJ (xk, X [k], D [k]) ;
+#else
+		/* xk = X [k] / D [k] ; */
+		DIV (xk, X [k], D [k]) ;
+#endif
+	    }
+#endif
+
+	    X [k] = xk ;
+	    if (IS_NONZERO (xk))
+	    {
+		if (k == kstart)
+		{
+		    up = -up ;
+		    xp = (Entry *) (Numeric->Memory + up + UNITS (Int, ulen)) ;
+		}
+		else
+		{
+		    xp = (Entry *) (Numeric->Memory + up) ;
+		}
+		for (j = 0 ; j < deg ; j++)
+		{
+		    DEBUG4 (("  k "ID" col "ID" value", k, Pattern [j])) ;
+		    EDEBUG4 (*xp) ;
+		    DEBUG4 (("\n")) ;
+#ifdef CONJUGATE_SOLVE
+		    /* X [Pattern [j]] -= xk * conjugate (*xp) ; */
+		    MULT_SUB_CONJ (X [Pattern [j]], xk, *xp) ;
+#else
+		    /* X [Pattern [j]] -= xk * (*xp) ; */
+		    MULT_SUB (X [Pattern [j]], xk, *xp) ;
+#endif
+		    xp++ ;
+		}
+	    }
+	}
+	ASSERT (uhead == n) ;
+    }
+
+#ifndef NO_DIVIDE_BY_ZERO
+    for (k = npiv ; k < n ; k++)
+    {
+	/* This is an *** intentional *** divide-by-zero, to get Inf or Nan,
+	 * as appropriate.  It is not a bug. */
+	ASSERT (IS_ZERO (D [k])) ;
+	/* For conjugate solve, D [k] == conjugate (D [k]), in this case */
+	/* xk = X [k] / D [k] ; */
+	DIV (xk, X [k], D [k]) ;
+	X [k] = xk ;
+    }
+#endif
+
+#ifndef NDEBUG
+    for (j = 0 ; j < n ; j++)
+    {
+	DEBUG4 (("Utsolve done "ID": ", j)) ;
+	EDEBUG4 (X [j]) ;
+	DEBUG4 (("\n")) ;
+    }
+    DEBUG4 (("Utsolve done.\n")) ;
+#endif
+
+    return (DIV_FLOPS * ((double) n) + MULTSUB_FLOPS * ((double) Numeric->unz));
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_utsolve.h b/src/C/SuiteSparse/UMFPACK/Source/umf_utsolve.h
new file mode 100644
index 0000000..59c0685
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_utsolve.h
@@ -0,0 +1,20 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL double UMF_utsolve
+(
+    NumericType *Numeric,
+    Entry X [ ],
+    Int Pattern [ ]
+) ;
+
+
+GLOBAL double UMF_uhsolve
+(
+    NumericType *Numeric,
+    Entry X [ ],
+    Int Pattern [ ]
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_valid_numeric.c b/src/C/SuiteSparse/UMFPACK/Source/umf_valid_numeric.c
new file mode 100644
index 0000000..e43ebab
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_valid_numeric.c
@@ -0,0 +1,46 @@
+/* ========================================================================== */
+/* === UMF_valid_numeric ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Returns TRUE if the Numeric object is valid, FALSE otherwise. */
+/* Does not check everything.  UMFPACK_report_numeric checks more. */
+
+#include "umf_internal.h"
+
+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) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_valid_numeric.h b/src/C/SuiteSparse/UMFPACK/Source/umf_valid_numeric.h
new file mode 100644
index 0000000..6d99218
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_valid_numeric.h
@@ -0,0 +1,10 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_valid_numeric
+(
+    NumericType *Numeric
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_valid_symbolic.c b/src/C/SuiteSparse/UMFPACK/Source/umf_valid_symbolic.c
new file mode 100644
index 0000000..396d548
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_valid_symbolic.c
@@ -0,0 +1,47 @@
+/* ========================================================================== */
+/* === UMF_valid_symbolic =================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_internal.h"
+
+/* 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) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_valid_symbolic.h b/src/C/SuiteSparse/UMFPACK/Source/umf_valid_symbolic.h
new file mode 100644
index 0000000..906f70c
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_valid_symbolic.h
@@ -0,0 +1,10 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_valid_symbolic
+(
+    SymbolicType *Symbolic
+) ;
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umf_version.h b/src/C/SuiteSparse/UMFPACK/Source/umf_version.h
new file mode 100644
index 0000000..d5fe456
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umf_version.h
@@ -0,0 +1,874 @@
+/* ========================================================================== */
+/* === umf_version.h ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+   Define routine names, depending on version being compiled.
+
+   DINT:	double precision, int's as integers
+   DLONG:	double precision, UF_long's as integers
+   ZLONG:	complex double precision, UF_long's as integers
+   ZINT:	complex double precision, int's as integers
+*/
+
+/* Set DINT as the default, if nothing is defined */
+#if !defined (DLONG) && !defined (DINT) && !defined (ZLONG) && !defined (ZINT)
+#define DINT
+#endif
+
+/* Determine if this is a real or complex version */
+#if defined (ZLONG) || defined (ZINT)
+#define COMPLEX
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* integer type (Int is int or UF_long) now defined in amd_internal.h */
+/* -------------------------------------------------------------------------- */
+
+#if defined (DLONG) || defined (ZLONG)
+#define LONG_INTEGER
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* Numerical relop macros for correctly handling the NaN case */
+/* -------------------------------------------------------------------------- */
+
+/*
+SCALAR_IS_NAN(x):
+    True if x is NaN.  False otherwise.  The commonly-existing isnan(x)
+    function could be used, but it's not in Kernighan & Ritchie 2nd edition
+    (ANSI C).  It may appear in <math.h>, but I'm not certain about
+    portability.  The expression x != x is true if and only if x is NaN,
+    according to the IEEE 754 floating-point standard.
+
+SCALAR_IS_ZERO(x):
+    True if x is zero.  False if x is nonzero, NaN, or +/- Inf.
+    This is (x == 0) if the compiler is IEEE 754 compliant.
+
+SCALAR_IS_NONZERO(x):
+    True if x is nonzero, NaN, or +/- Inf.  False if x zero.
+    This is (x != 0) if the compiler is IEEE 754 compliant.
+
+SCALAR_IS_LTZERO(x):
+    True if x is < zero or -Inf.  False if x is >= 0, NaN, or +Inf.
+    This is (x < 0) if the compiler is IEEE 754 compliant.
+*/
+
+#if defined (UMF_WINDOWS) && !defined (MATHWORKS)
+
+/* Yes, this is exceedingly ugly.  Blame Microsoft, which hopelessly */
+/* violates the IEEE 754 floating-point standard in a bizarre way. */
+/* If you're using an IEEE 754-compliant compiler, then x != x is true */
+/* iff x is NaN.  For Microsoft, (x < x) is true iff x is NaN. */
+/* So either way, this macro safely detects a NaN. */
+#define SCALAR_IS_NAN(x)	(((x) != (x)) || (((x) < (x))))
+#define SCALAR_IS_ZERO(x)	(((x) == 0.) && !SCALAR_IS_NAN(x))
+#define SCALAR_IS_NONZERO(x)	(((x) != 0.) || SCALAR_IS_NAN(x))
+#define SCALAR_IS_LTZERO(x)	(((x) < 0.) && !SCALAR_IS_NAN(x))
+
+#else
+
+/* These all work properly, according to the IEEE 754 standard ... except on */
+/* a PC with windows.  Works fine in Linux on the same PC... */
+#define SCALAR_IS_NAN(x)	((x) != (x))
+#define SCALAR_IS_ZERO(x)	((x) == 0.)
+#define SCALAR_IS_NONZERO(x)	((x) != 0.)
+#define SCALAR_IS_LTZERO(x)	((x) < 0.)
+
+#endif
+
+/* scalar absolute value macro. If x is NaN, the result is NaN: */
+#define SCALAR_ABS(x) ((SCALAR_IS_LTZERO (x)) ? -(x) : (x))
+
+/* true if an integer (stored in double x) would overflow (or if x is NaN) */
+#define INT_OVERFLOW(x) ((!((x) * (1.0+1e-8) <= (double) Int_MAX)) \
+			|| SCALAR_IS_NAN (x))
+
+/* print a scalar (avoid printing "-0" for negative zero).  */
+#define PRINT_SCALAR(a) \
+{ \
+    if (SCALAR_IS_NONZERO (a)) \
+    { \
+	PRINTF ((" (%g)", (a))) ; \
+    } \
+    else \
+    { \
+	PRINTF ((" (0)")) ; \
+    } \
+}
+
+/* -------------------------------------------------------------------------- */
+/* Real floating-point arithmetic */
+/* -------------------------------------------------------------------------- */
+
+#ifndef COMPLEX
+
+#define Entry double
+
+#define SPLIT(s)    		    (1)
+#define REAL_COMPONENT(c)	    (c)
+#define IMAG_COMPONENT(c)	    (0.)
+#define ASSIGN(c,s1,s2,p,split)	    { (c) = (s1)[p] ; }
+#define CLEAR(c)		    { (c) = 0. ; }
+#define CLEAR_AND_INCREMENT(p)	    { *p++ = 0. ; }
+#define IS_NAN(a)		    SCALAR_IS_NAN (a)
+#define IS_ZERO(a)		    SCALAR_IS_ZERO (a)
+#define IS_NONZERO(a)		    SCALAR_IS_NONZERO (a)
+#define SCALE_DIV(c,s)		    { (c) /= (s) ; }
+#define SCALE(c,s)		    { (c) *= (s) ; }
+#define ASSEMBLE(c,a)		    { (c) += (a) ; }
+#define ASSEMBLE_AND_INCREMENT(c,p) { (c) += *p++ ; }
+#define DECREMENT(c,a)		    { (c) -= (a) ; }
+#define MULT(c,a,b)		    { (c) = (a) * (b) ; }
+#define MULT_CONJ(c,a,b)	    { (c) = (a) * (b) ; }
+#define MULT_SUB(c,a,b)		    { (c) -= (a) * (b) ; }
+#define MULT_SUB_CONJ(c,a,b)	    { (c) -= (a) * (b) ; }
+#define DIV(c,a,b)		    { (c) = (a) / (b) ; }
+#define DIV_CONJ(c,a,b)		    { (c) = (a) / (b) ; }
+#define APPROX_ABS(s,a)		    { (s) = SCALAR_ABS (a) ; }
+#define ABS(s,a)		    { (s) = SCALAR_ABS (a) ; }
+#define PRINT_ENTRY(a)		    PRINT_SCALAR (a)
+
+/* for flop counts */
+#define MULTSUB_FLOPS	2.	/* c -= a*b */
+#define DIV_FLOPS	1.	/* c = a/b */
+#define ABS_FLOPS	0.	/* c = abs (a) */
+#define ASSEMBLE_FLOPS	1.	/* c += a */
+#define DECREMENT_FLOPS	1.	/* c -= a */
+#define MULT_FLOPS	1.	/* c = a*b */
+#define SCALE_FLOPS	1.	/* c = a/s */
+
+#else
+
+/* -------------------------------------------------------------------------- */
+/* Complex floating-point arithmetic */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Note:  An alternative to this DoubleComplex type would be to use a
+    struct { double r ; double i ; }.  The problem with that method
+    (used by the Sun Performance Library, for example) is that ANSI C provides
+    no guarantee about the layout of a struct.  It is possible that the sizeof
+    the struct above would be greater than 2 * sizeof (double).  This would
+    mean that the complex BLAS could not be used.  The method used here avoids
+    that possibility.  ANSI C *does* guarantee that an array of structs has
+    the same size as n times the size of one struct.
+
+    The ANSI C99 version of the C language includes a "double _Complex" type.
+    It should be possible in that case to do the following:
+
+    #define Entry double _Complex
+
+    and remove the DoubleComplex struct.  The macros, below, could then be
+    replaced with instrinsic operators.  Note that the #define Real and
+    #define Imag should also be removed (they only appear in this file).
+
+    For the MULT, MULT_SUB, MULT_SUB_CONJ, and MULT_CONJ macros,
+    the output argument c cannot be the same as any input argument.
+
+*/
+
+typedef struct
+{
+    double component [2] ;	/* real and imaginary parts */
+
+} DoubleComplex ;
+
+#define Entry DoubleComplex
+#define Real component [0]
+#define Imag component [1]
+
+/* for flop counts */
+#define MULTSUB_FLOPS	8.	/* c -= a*b */
+#define DIV_FLOPS	9.	/* c = a/b */
+#define ABS_FLOPS	6.	/* c = abs (a), count sqrt as one flop */
+#define ASSEMBLE_FLOPS	2.	/* c += a */
+#define DECREMENT_FLOPS	2.	/* c -= a */
+#define MULT_FLOPS	6.	/* c = a*b */
+#define SCALE_FLOPS	2.	/* c = a/s or c = a*s */
+
+/* -------------------------------------------------------------------------- */
+
+/* real part of c */
+#define REAL_COMPONENT(c) ((c).Real)
+
+/* -------------------------------------------------------------------------- */
+
+/* imag part of c */
+#define IMAG_COMPONENT(c) ((c).Imag)
+
+/* -------------------------------------------------------------------------- */
+
+/* Return TRUE if a complex number is in split form, FALSE if in packed form */
+#define SPLIT(sz) ((sz) != (double *) NULL)
+
+/* -------------------------------------------------------------------------- */
+
+/* c = (s1) + (s2)*i, if s2 is null, then X is in "packed" format (compatible
+ * with Entry and ANSI C99 double _Complex type).  */
+#define ASSIGN(c,s1,s2,p,split)	\
+{ \
+    if (split) \
+    { \
+        (c).Real = (s1)[p] ; \
+        (c).Imag = (s2)[p] ; \
+    }  \
+    else \
+    { \
+ 	(c) = ((Entry *)(s1))[p] ; \
+    }  \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c = 0 */
+#define CLEAR(c) \
+{ \
+    (c).Real = 0. ; \
+    (c).Imag = 0. ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* *p++ = 0 */
+#define CLEAR_AND_INCREMENT(p) \
+{ \
+    p->Real = 0. ; \
+    p->Imag = 0. ; \
+    p++ ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* True if a == 0 */
+#define IS_ZERO(a) \
+    (SCALAR_IS_ZERO ((a).Real) && SCALAR_IS_ZERO ((a).Imag))
+
+/* -------------------------------------------------------------------------- */
+
+/* True if a is NaN */
+#define IS_NAN(a) \
+    (SCALAR_IS_NAN ((a).Real) || SCALAR_IS_NAN ((a).Imag))
+
+/* -------------------------------------------------------------------------- */
+
+/* True if a != 0 */
+#define IS_NONZERO(a) \
+    (SCALAR_IS_NONZERO ((a).Real) || SCALAR_IS_NONZERO ((a).Imag))
+
+/* -------------------------------------------------------------------------- */
+
+/* c /= s */
+#define SCALE_DIV(c,s) \
+{ \
+    (c).Real /= (s) ; \
+    (c).Imag /= (s) ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c *= s */
+#define SCALE(c,s) \
+{ \
+    (c).Real *= (s) ; \
+    (c).Imag *= (s) ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c += a */
+#define ASSEMBLE(c,a) \
+{ \
+    (c).Real += (a).Real ; \
+    (c).Imag += (a).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c += *p++ */
+#define ASSEMBLE_AND_INCREMENT(c,p) \
+{ \
+    (c).Real += p->Real ; \
+    (c).Imag += p->Imag ; \
+    p++ ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c -= a */
+#define DECREMENT(c,a) \
+{ \
+    (c).Real -= (a).Real ; \
+    (c).Imag -= (a).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c = a*b, assert because c cannot be the same as a or b */
+#define MULT(c,a,b) \
+{ \
+    ASSERT (&(c) != &(a) && &(c) != &(b)) ; \
+    (c).Real = (a).Real * (b).Real - (a).Imag * (b).Imag ; \
+    (c).Imag = (a).Imag * (b).Real + (a).Real * (b).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c = a*conjugate(b), assert because c cannot be the same as a or b */
+#define MULT_CONJ(c,a,b) \
+{ \
+    ASSERT (&(c) != &(a) && &(c) != &(b)) ; \
+    (c).Real = (a).Real * (b).Real + (a).Imag * (b).Imag ; \
+    (c).Imag = (a).Imag * (b).Real - (a).Real * (b).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c -= a*b, assert because c cannot be the same as a or b */
+#define MULT_SUB(c,a,b) \
+{ \
+    ASSERT (&(c) != &(a) && &(c) != &(b)) ; \
+    (c).Real -= (a).Real * (b).Real - (a).Imag * (b).Imag ; \
+    (c).Imag -= (a).Imag * (b).Real + (a).Real * (b).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c -= a*conjugate(b), assert because c cannot be the same as a or b */
+#define MULT_SUB_CONJ(c,a,b) \
+{ \
+    ASSERT (&(c) != &(a) && &(c) != &(b)) ; \
+    (c).Real -= (a).Real * (b).Real + (a).Imag * (b).Imag ; \
+    (c).Imag -= (a).Imag * (b).Real - (a).Real * (b).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c = a/b, using function pointer */
+#define DIV(c,a,b) \
+{ \
+    (void) umfpack_divcomplex ((a).Real, (a).Imag, (b).Real, (b).Imag, \
+	&((c).Real), &((c).Imag)) ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c = a/conjugate(b), using function pointer */
+#define DIV_CONJ(c,a,b) \
+{ \
+    (void) umfpack_divcomplex ((a).Real, (a).Imag, (b).Real, (-(b).Imag), \
+	&((c).Real), &((c).Imag)) ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* approximate absolute value, s = |r|+|i| */
+#define APPROX_ABS(s,a) \
+{ \
+    (s) = SCALAR_ABS ((a).Real) + SCALAR_ABS ((a).Imag) ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* exact absolute value, s = sqrt (a.real^2 + a.imag^2) */
+#define ABS(s,a) \
+{ \
+    (s) = umfpack_hypot ((a).Real, (a).Imag) ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* print an entry (avoid printing "-0" for negative zero).  */
+#define PRINT_ENTRY(a) \
+{ \
+    if (SCALAR_IS_NONZERO ((a).Real)) \
+    { \
+	PRINTF ((" (%g", (a).Real)) ; \
+    } \
+    else \
+    { \
+	PRINTF ((" (0")) ; \
+    } \
+    if (SCALAR_IS_LTZERO ((a).Imag)) \
+    { \
+	PRINTF ((" - %gi)", -(a).Imag)) ; \
+    } \
+    else if (SCALAR_IS_ZERO ((a).Imag)) \
+    { \
+	PRINTF ((" + 0i)")) ; \
+    } \
+    else \
+    { \
+	PRINTF ((" + %gi)", (a).Imag)) ; \
+    } \
+}
+
+/* -------------------------------------------------------------------------- */
+
+#endif	/* #ifndef COMPLEX */
+
+/* -------------------------------------------------------------------------- */
+/* Double precision, with int's as integers */
+/* -------------------------------------------------------------------------- */
+
+#ifdef DINT
+
+#define UMF_analyze		 umf_i_analyze
+#define UMF_apply_order		 umf_i_apply_order
+#define UMF_assemble		 umfdi_assemble
+#define UMF_assemble_fixq	 umfdi_assemble_fixq
+#define UMF_blas3_update	 umfdi_blas3_update
+#define UMF_build_tuples	 umfdi_build_tuples
+#define UMF_build_tuples_usage	 umfdi_build_tuples_usage
+#define UMF_colamd		 umf_i_colamd
+#define UMF_colamd_set_defaults	 umf_i_colamd_set_defaults
+#define UMF_create_element	 umfdi_create_element
+#define UMF_extend_front	 umfdi_extend_front
+#define UMF_free		 umf_i_free
+#define UMF_fsize		 umf_i_fsize
+#define UMF_garbage_collection	 umfdi_garbage_collection
+#define UMF_get_memory		 umfdi_get_memory
+#define UMF_grow_front		 umfdi_grow_front
+#define UMF_init_front		 umfdi_init_front
+#define UMF_is_permutation	 umf_i_is_permutation
+#define UMF_kernel		 umfdi_kernel
+#define UMF_kernel_init		 umfdi_kernel_init
+#define UMF_kernel_init_usage	 umfdi_kernel_init_usage
+#define UMF_kernel_wrapup	 umfdi_kernel_wrapup
+#define UMF_local_search	 umfdi_local_search
+#define UMF_lsolve		 umfdi_lsolve
+#define UMF_ltsolve		 umfdi_ltsolve
+#define UMF_lhsolve		 umfdi_lhsolve
+#define UMF_malloc		 umf_i_malloc
+#define UMF_mem_alloc_element	 umfdi_mem_alloc_element
+#define UMF_mem_alloc_head_block umfdi_mem_alloc_head_block
+#define UMF_mem_alloc_tail_block umfdi_mem_alloc_tail_block
+#define UMF_mem_free_tail_block	 umfdi_mem_free_tail_block
+#define UMF_mem_init_memoryspace umfdi_mem_init_memoryspace
+#define UMF_realloc		 umf_i_realloc
+#define UMF_report_perm		 umf_i_report_perm
+#define UMF_report_vector	 umfdi_report_vector
+#define UMF_row_search		 umfdi_row_search
+#define UMF_scale		 umfdi_scale
+#define UMF_scale_column	 umfdi_scale_column
+#define UMF_set_stats		 umf_i_set_stats
+#define UMF_singletons		 umf_i_singletons
+#define UMF_solve		 umfdi_solve
+#define UMF_start_front		 umfdi_start_front
+#define UMF_store_lu		 umfdi_store_lu
+#define UMF_store_lu_drop	 umfdi_store_lu_drop
+#define UMF_symbolic_usage	 umfdi_symbolic_usage
+#define UMF_transpose		 umfdi_transpose
+#define UMF_tuple_lengths	 umfdi_tuple_lengths
+#define UMF_usolve		 umfdi_usolve
+#define UMF_utsolve		 umfdi_utsolve
+#define UMF_uhsolve		 umfdi_uhsolve
+#define UMF_valid_numeric	 umfdi_valid_numeric
+#define UMF_valid_symbolic	 umfdi_valid_symbolic
+#define UMF_triplet_map_x	 umfdi_triplet_map_x
+#define UMF_triplet_map_nox	 umfdi_triplet_map_nox
+#define UMF_triplet_nomap_x	 umfdi_triplet_nomap_x
+#define UMF_triplet_nomap_nox	 umfdi_triplet_nomap_nox
+#define UMF_2by2		 umfdi_2by2
+
+#define UMFPACK_col_to_triplet	 umfpack_di_col_to_triplet
+#define UMFPACK_defaults	 umfpack_di_defaults
+#define UMFPACK_free_numeric	 umfpack_di_free_numeric
+#define UMFPACK_free_symbolic	 umfpack_di_free_symbolic
+#define UMFPACK_get_lunz	 umfpack_di_get_lunz
+#define UMFPACK_get_numeric	 umfpack_di_get_numeric
+#define UMFPACK_get_symbolic	 umfpack_di_get_symbolic
+#define UMFPACK_get_determinant	 umfpack_di_get_determinant
+#define UMFPACK_numeric		 umfpack_di_numeric
+#define UMFPACK_qsymbolic	 umfpack_di_qsymbolic
+#define UMFPACK_report_control	 umfpack_di_report_control
+#define UMFPACK_report_info	 umfpack_di_report_info
+#define UMFPACK_report_matrix	 umfpack_di_report_matrix
+#define UMFPACK_report_numeric	 umfpack_di_report_numeric
+#define UMFPACK_report_perm	 umfpack_di_report_perm
+#define UMFPACK_report_status	 umfpack_di_report_status
+#define UMFPACK_report_symbolic	 umfpack_di_report_symbolic
+#define UMFPACK_report_triplet	 umfpack_di_report_triplet
+#define UMFPACK_report_vector	 umfpack_di_report_vector
+#define UMFPACK_save_numeric	 umfpack_di_save_numeric
+#define UMFPACK_save_symbolic	 umfpack_di_save_symbolic
+#define UMFPACK_load_numeric	 umfpack_di_load_numeric
+#define UMFPACK_load_symbolic	 umfpack_di_load_symbolic
+#define UMFPACK_scale		 umfpack_di_scale
+#define UMFPACK_solve		 umfpack_di_solve
+#define UMFPACK_symbolic	 umfpack_di_symbolic
+#define UMFPACK_transpose	 umfpack_di_transpose
+#define UMFPACK_triplet_to_col	 umfpack_di_triplet_to_col
+#define UMFPACK_wsolve		 umfpack_di_wsolve
+
+/* for debugging only: */
+#define UMF_malloc_count	 umf_i_malloc_count
+#define UMF_debug		 umfdi_debug
+#define UMF_allocfail		 umfdi_allocfail
+#define UMF_gprob		 umfdi_gprob
+#define UMF_dump_dense		 umfdi_dump_dense
+#define UMF_dump_element	 umfdi_dump_element
+#define UMF_dump_rowcol		 umfdi_dump_rowcol
+#define UMF_dump_matrix		 umfdi_dump_matrix
+#define UMF_dump_current_front	 umfdi_dump_current_front
+#define UMF_dump_lu		 umfdi_dump_lu
+#define UMF_dump_memory		 umfdi_dump_memory
+#define UMF_dump_packed_memory	 umfdi_dump_packed_memory
+#define UMF_dump_col_matrix	 umfdi_dump_col_matrix
+#define UMF_dump_chain		 umfdi_dump_chain
+#define UMF_dump_start		 umfdi_dump_start
+#define UMF_dump_rowmerge	 umfdi_dump_rowmerge
+#define UMF_dump_diagonal_map	 umfdi_dump_diagonal_map
+
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* Double precision, with UF_long's as integers */
+/* -------------------------------------------------------------------------- */
+
+#ifdef DLONG
+
+#define UMF_analyze		 umf_l_analyze
+#define UMF_apply_order		 umf_l_apply_order
+#define UMF_assemble		 umfdl_assemble
+#define UMF_assemble_fixq	 umfdl_assemble_fixq
+#define UMF_blas3_update	 umfdl_blas3_update
+#define UMF_build_tuples	 umfdl_build_tuples
+#define UMF_build_tuples_usage	 umfdl_build_tuples_usage
+#define UMF_colamd		 umf_l_colamd
+#define UMF_colamd_set_defaults	 umf_l_colamd_set_defaults
+#define UMF_create_element	 umfdl_create_element
+#define UMF_extend_front	 umfdl_extend_front
+#define UMF_free		 umf_l_free
+#define UMF_fsize		 umf_l_fsize
+#define UMF_garbage_collection	 umfdl_garbage_collection
+#define UMF_get_memory		 umfdl_get_memory
+#define UMF_grow_front		 umfdl_grow_front
+#define UMF_init_front		 umfdl_init_front
+#define UMF_is_permutation	 umf_l_is_permutation
+#define UMF_kernel		 umfdl_kernel
+#define UMF_kernel_init		 umfdl_kernel_init
+#define UMF_kernel_init_usage	 umfdl_kernel_init_usage
+#define UMF_kernel_wrapup	 umfdl_kernel_wrapup
+#define UMF_local_search	 umfdl_local_search
+#define UMF_lsolve		 umfdl_lsolve
+#define UMF_ltsolve		 umfdl_ltsolve
+#define UMF_lhsolve		 umfdl_lhsolve
+#define UMF_malloc		 umf_l_malloc
+#define UMF_mem_alloc_element	 umfdl_mem_alloc_element
+#define UMF_mem_alloc_head_block umfdl_mem_alloc_head_block
+#define UMF_mem_alloc_tail_block umfdl_mem_alloc_tail_block
+#define UMF_mem_free_tail_block	 umfdl_mem_free_tail_block
+#define UMF_mem_init_memoryspace umfdl_mem_init_memoryspace
+#define UMF_realloc		 umf_l_realloc
+#define UMF_report_perm		 umf_l_report_perm
+#define UMF_report_vector	 umfdl_report_vector
+#define UMF_row_search		 umfdl_row_search
+#define UMF_scale		 umfdl_scale
+#define UMF_scale_column	 umfdl_scale_column
+#define UMF_set_stats		 umf_l_set_stats
+#define UMF_singletons		 umf_l_singletons
+#define UMF_solve		 umfdl_solve
+#define UMF_start_front		 umfdl_start_front
+#define UMF_store_lu		 umfdl_store_lu
+#define UMF_store_lu_drop	 umfdl_store_lu_drop
+#define UMF_symbolic_usage	 umfdl_symbolic_usage
+#define UMF_transpose		 umfdl_transpose
+#define UMF_tuple_lengths	 umfdl_tuple_lengths
+#define UMF_usolve		 umfdl_usolve
+#define UMF_utsolve		 umfdl_utsolve
+#define UMF_uhsolve		 umfdl_uhsolve
+#define UMF_valid_numeric	 umfdl_valid_numeric
+#define UMF_valid_symbolic	 umfdl_valid_symbolic
+#define UMF_triplet_map_x	 umfdl_triplet_map_x
+#define UMF_triplet_map_nox	 umfdl_triplet_map_nox
+#define UMF_triplet_nomap_x	 umfdl_triplet_nomap_x
+#define UMF_triplet_nomap_nox	 umfdl_triplet_nomap_nox
+#define UMF_2by2		 umfdl_2by2
+
+#define UMFPACK_col_to_triplet	 umfpack_dl_col_to_triplet
+#define UMFPACK_defaults	 umfpack_dl_defaults
+#define UMFPACK_free_numeric	 umfpack_dl_free_numeric
+#define UMFPACK_free_symbolic	 umfpack_dl_free_symbolic
+#define UMFPACK_get_lunz	 umfpack_dl_get_lunz
+#define UMFPACK_get_numeric	 umfpack_dl_get_numeric
+#define UMFPACK_get_symbolic	 umfpack_dl_get_symbolic
+#define UMFPACK_get_determinant	 umfpack_dl_get_determinant
+#define UMFPACK_numeric		 umfpack_dl_numeric
+#define UMFPACK_qsymbolic	 umfpack_dl_qsymbolic
+#define UMFPACK_report_control	 umfpack_dl_report_control
+#define UMFPACK_report_info	 umfpack_dl_report_info
+#define UMFPACK_report_matrix	 umfpack_dl_report_matrix
+#define UMFPACK_report_numeric	 umfpack_dl_report_numeric
+#define UMFPACK_report_perm	 umfpack_dl_report_perm
+#define UMFPACK_report_status	 umfpack_dl_report_status
+#define UMFPACK_report_symbolic	 umfpack_dl_report_symbolic
+#define UMFPACK_report_triplet	 umfpack_dl_report_triplet
+#define UMFPACK_report_vector	 umfpack_dl_report_vector
+#define UMFPACK_save_numeric	 umfpack_dl_save_numeric
+#define UMFPACK_save_symbolic	 umfpack_dl_save_symbolic
+#define UMFPACK_load_numeric	 umfpack_dl_load_numeric
+#define UMFPACK_load_symbolic	 umfpack_dl_load_symbolic
+#define UMFPACK_scale		 umfpack_dl_scale
+#define UMFPACK_solve		 umfpack_dl_solve
+#define UMFPACK_symbolic	 umfpack_dl_symbolic
+#define UMFPACK_transpose	 umfpack_dl_transpose
+#define UMFPACK_triplet_to_col	 umfpack_dl_triplet_to_col
+#define UMFPACK_wsolve		 umfpack_dl_wsolve
+
+/* for debugging only: */
+#define UMF_malloc_count	 umf_l_malloc_count
+#define UMF_debug		 umfdl_debug
+#define UMF_allocfail		 umfdl_allocfail
+#define UMF_gprob		 umfdl_gprob
+#define UMF_dump_dense		 umfdl_dump_dense
+#define UMF_dump_element	 umfdl_dump_element
+#define UMF_dump_rowcol		 umfdl_dump_rowcol
+#define UMF_dump_matrix		 umfdl_dump_matrix
+#define UMF_dump_current_front	 umfdl_dump_current_front
+#define UMF_dump_lu		 umfdl_dump_lu
+#define UMF_dump_memory		 umfdl_dump_memory
+#define UMF_dump_packed_memory	 umfdl_dump_packed_memory
+#define UMF_dump_col_matrix	 umfdl_dump_col_matrix
+#define UMF_dump_chain		 umfdl_dump_chain
+#define UMF_dump_start		 umfdl_dump_start
+#define UMF_dump_rowmerge	 umfdl_dump_rowmerge
+#define UMF_dump_diagonal_map	 umfdl_dump_diagonal_map
+
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* Complex double precision, with int's as integers */
+/* -------------------------------------------------------------------------- */
+
+#ifdef ZINT
+
+#define UMF_analyze		 umf_i_analyze
+#define UMF_apply_order		 umf_i_apply_order
+#define UMF_assemble		 umfzi_assemble
+#define UMF_assemble_fixq	 umfzi_assemble_fixq
+#define UMF_blas3_update	 umfzi_blas3_update
+#define UMF_build_tuples	 umfzi_build_tuples
+#define UMF_build_tuples_usage	 umfzi_build_tuples_usage
+#define UMF_colamd		 umf_i_colamd
+#define UMF_colamd_set_defaults	 umf_i_colamd_set_defaults
+#define UMF_create_element	 umfzi_create_element
+#define UMF_extend_front	 umfzi_extend_front
+#define UMF_free		 umf_i_free
+#define UMF_fsize		 umf_i_fsize
+#define UMF_garbage_collection	 umfzi_garbage_collection
+#define UMF_get_memory		 umfzi_get_memory
+#define UMF_grow_front		 umfzi_grow_front
+#define UMF_init_front		 umfzi_init_front
+#define UMF_is_permutation	 umf_i_is_permutation
+#define UMF_kernel		 umfzi_kernel
+#define UMF_kernel_init		 umfzi_kernel_init
+#define UMF_kernel_init_usage	 umfzi_kernel_init_usage
+#define UMF_kernel_wrapup	 umfzi_kernel_wrapup
+#define UMF_local_search	 umfzi_local_search
+#define UMF_lsolve		 umfzi_lsolve
+#define UMF_ltsolve		 umfzi_ltsolve
+#define UMF_lhsolve		 umfzi_lhsolve
+#define UMF_malloc		 umf_i_malloc
+#define UMF_mem_alloc_element	 umfzi_mem_alloc_element
+#define UMF_mem_alloc_head_block umfzi_mem_alloc_head_block
+#define UMF_mem_alloc_tail_block umfzi_mem_alloc_tail_block
+#define UMF_mem_free_tail_block	 umfzi_mem_free_tail_block
+#define UMF_mem_init_memoryspace umfzi_mem_init_memoryspace
+#define UMF_realloc		 umf_i_realloc
+#define UMF_report_perm		 umf_i_report_perm
+#define UMF_report_vector	 umfzi_report_vector
+#define UMF_row_search		 umfzi_row_search
+#define UMF_scale		 umfzi_scale
+#define UMF_scale_column	 umfzi_scale_column
+#define UMF_set_stats		 umfzi_set_stats
+#define UMF_singletons		 umf_i_singletons
+#define UMF_solve		 umfzi_solve
+#define UMF_start_front		 umfzi_start_front
+#define UMF_store_lu		 umfzi_store_lu
+#define UMF_store_lu_drop	 umfzi_store_lu_drop
+#define UMF_symbolic_usage	 umfzi_symbolic_usage
+#define UMF_transpose		 umfzi_transpose
+#define UMF_tuple_lengths	 umfzi_tuple_lengths
+#define UMF_usolve		 umfzi_usolve
+#define UMF_utsolve		 umfzi_utsolve
+#define UMF_uhsolve		 umfzi_uhsolve
+#define UMF_valid_numeric	 umfzi_valid_numeric
+#define UMF_valid_symbolic	 umfzi_valid_symbolic
+#define UMF_triplet_map_x	 umfzi_triplet_map_x
+#define UMF_triplet_map_nox	 umfzi_triplet_map_nox
+#define UMF_triplet_nomap_x	 umfzi_triplet_nomap_x
+#define UMF_triplet_nomap_nox	 umfzi_triplet_nomap_nox
+#define UMF_2by2		 umfzi_2by2
+
+#define UMFPACK_col_to_triplet	 umfpack_zi_col_to_triplet
+#define UMFPACK_defaults	 umfpack_zi_defaults
+#define UMFPACK_free_numeric	 umfpack_zi_free_numeric
+#define UMFPACK_free_symbolic	 umfpack_zi_free_symbolic
+#define UMFPACK_get_lunz	 umfpack_zi_get_lunz
+#define UMFPACK_get_numeric	 umfpack_zi_get_numeric
+#define UMFPACK_get_symbolic	 umfpack_zi_get_symbolic
+#define UMFPACK_get_determinant	 umfpack_zi_get_determinant
+#define UMFPACK_numeric		 umfpack_zi_numeric
+#define UMFPACK_qsymbolic	 umfpack_zi_qsymbolic
+#define UMFPACK_report_control	 umfpack_zi_report_control
+#define UMFPACK_report_info	 umfpack_zi_report_info
+#define UMFPACK_report_matrix	 umfpack_zi_report_matrix
+#define UMFPACK_report_numeric	 umfpack_zi_report_numeric
+#define UMFPACK_report_perm	 umfpack_zi_report_perm
+#define UMFPACK_report_status	 umfpack_zi_report_status
+#define UMFPACK_report_symbolic	 umfpack_zi_report_symbolic
+#define UMFPACK_report_triplet	 umfpack_zi_report_triplet
+#define UMFPACK_report_vector	 umfpack_zi_report_vector
+#define UMFPACK_save_numeric	 umfpack_zi_save_numeric
+#define UMFPACK_save_symbolic	 umfpack_zi_save_symbolic
+#define UMFPACK_load_numeric	 umfpack_zi_load_numeric
+#define UMFPACK_load_symbolic	 umfpack_zi_load_symbolic
+#define UMFPACK_scale		 umfpack_zi_scale
+#define UMFPACK_solve		 umfpack_zi_solve
+#define UMFPACK_symbolic	 umfpack_zi_symbolic
+#define UMFPACK_transpose	 umfpack_zi_transpose
+#define UMFPACK_triplet_to_col	 umfpack_zi_triplet_to_col
+#define UMFPACK_wsolve		 umfpack_zi_wsolve
+
+/* for debugging only: */
+#define UMF_malloc_count	 umf_i_malloc_count
+#define UMF_debug		 umfzi_debug
+#define UMF_allocfail		 umfzi_allocfail
+#define UMF_gprob		 umfzi_gprob
+#define UMF_dump_dense		 umfzi_dump_dense
+#define UMF_dump_element	 umfzi_dump_element
+#define UMF_dump_rowcol		 umfzi_dump_rowcol
+#define UMF_dump_matrix		 umfzi_dump_matrix
+#define UMF_dump_current_front	 umfzi_dump_current_front
+#define UMF_dump_lu		 umfzi_dump_lu
+#define UMF_dump_memory		 umfzi_dump_memory
+#define UMF_dump_packed_memory	 umfzi_dump_packed_memory
+#define UMF_dump_col_matrix	 umfzi_dump_col_matrix
+#define UMF_dump_chain		 umfzi_dump_chain
+#define UMF_dump_start		 umfzi_dump_start
+#define UMF_dump_rowmerge	 umfzi_dump_rowmerge
+#define UMF_dump_diagonal_map	 umfzi_dump_diagonal_map
+
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* Complex double precision, with UF_long's as integers */
+/* -------------------------------------------------------------------------- */
+
+#ifdef ZLONG
+
+#define UMF_analyze		 umf_l_analyze
+#define UMF_apply_order		 umf_l_apply_order
+#define UMF_assemble		 umfzl_assemble
+#define UMF_assemble_fixq	 umfzl_assemble_fixq
+#define UMF_blas3_update	 umfzl_blas3_update
+#define UMF_build_tuples	 umfzl_build_tuples
+#define UMF_build_tuples_usage	 umfzl_build_tuples_usage
+#define UMF_colamd		 umf_l_colamd
+#define UMF_colamd_set_defaults	 umf_l_colamd_set_defaults
+#define UMF_create_element	 umfzl_create_element
+#define UMF_extend_front	 umfzl_extend_front
+#define UMF_free		 umf_l_free
+#define UMF_fsize		 umf_l_fsize
+#define UMF_garbage_collection	 umfzl_garbage_collection
+#define UMF_get_memory		 umfzl_get_memory
+#define UMF_grow_front		 umfzl_grow_front
+#define UMF_init_front		 umfzl_init_front
+#define UMF_is_permutation	 umf_l_is_permutation
+#define UMF_kernel		 umfzl_kernel
+#define UMF_kernel_init		 umfzl_kernel_init
+#define UMF_kernel_init_usage	 umfzl_kernel_init_usage
+#define UMF_kernel_wrapup	 umfzl_kernel_wrapup
+#define UMF_local_search	 umfzl_local_search
+#define UMF_lsolve		 umfzl_lsolve
+#define UMF_ltsolve		 umfzl_ltsolve
+#define UMF_lhsolve		 umfzl_lhsolve
+#define UMF_malloc		 umf_l_malloc
+#define UMF_mem_alloc_element	 umfzl_mem_alloc_element
+#define UMF_mem_alloc_head_block umfzl_mem_alloc_head_block
+#define UMF_mem_alloc_tail_block umfzl_mem_alloc_tail_block
+#define UMF_mem_free_tail_block	 umfzl_mem_free_tail_block
+#define UMF_mem_init_memoryspace umfzl_mem_init_memoryspace
+#define UMF_realloc		 umf_l_realloc
+#define UMF_report_perm		 umf_l_report_perm
+#define UMF_report_vector	 umfzl_report_vector
+#define UMF_row_search		 umfzl_row_search
+#define UMF_scale		 umfzl_scale
+#define UMF_scale_column	 umfzl_scale_column
+#define UMF_set_stats		 umfzl_set_stats
+#define UMF_singletons		 umf_l_singletons
+#define UMF_solve		 umfzl_solve
+#define UMF_start_front		 umfzl_start_front
+#define UMF_store_lu		 umfzl_store_lu
+#define UMF_store_lu_drop	 umfzl_store_lu_drop
+#define UMF_symbolic_usage	 umfzl_symbolic_usage
+#define UMF_transpose		 umfzl_transpose
+#define UMF_tuple_lengths	 umfzl_tuple_lengths
+#define UMF_usolve		 umfzl_usolve
+#define UMF_utsolve		 umfzl_utsolve
+#define UMF_uhsolve		 umfzl_uhsolve
+#define UMF_valid_numeric	 umfzl_valid_numeric
+#define UMF_valid_symbolic	 umfzl_valid_symbolic
+#define UMF_triplet_map_x	 umfzl_triplet_map_x
+#define UMF_triplet_map_nox	 umfzl_triplet_map_nox
+#define UMF_triplet_nomap_x	 umfzl_triplet_nomap_x
+#define UMF_triplet_nomap_nox	 umfzl_triplet_nomap_nox
+#define UMF_2by2		 umfzl_2by2
+
+#define UMFPACK_col_to_triplet	 umfpack_zl_col_to_triplet
+#define UMFPACK_defaults	 umfpack_zl_defaults
+#define UMFPACK_free_numeric	 umfpack_zl_free_numeric
+#define UMFPACK_free_symbolic	 umfpack_zl_free_symbolic
+#define UMFPACK_get_lunz	 umfpack_zl_get_lunz
+#define UMFPACK_get_numeric	 umfpack_zl_get_numeric
+#define UMFPACK_get_symbolic	 umfpack_zl_get_symbolic
+#define UMFPACK_get_determinant	 umfpack_zl_get_determinant
+#define UMFPACK_numeric		 umfpack_zl_numeric
+#define UMFPACK_qsymbolic	 umfpack_zl_qsymbolic
+#define UMFPACK_report_control	 umfpack_zl_report_control
+#define UMFPACK_report_info	 umfpack_zl_report_info
+#define UMFPACK_report_matrix	 umfpack_zl_report_matrix
+#define UMFPACK_report_numeric	 umfpack_zl_report_numeric
+#define UMFPACK_report_perm	 umfpack_zl_report_perm
+#define UMFPACK_report_status	 umfpack_zl_report_status
+#define UMFPACK_report_symbolic	 umfpack_zl_report_symbolic
+#define UMFPACK_report_triplet	 umfpack_zl_report_triplet
+#define UMFPACK_report_vector	 umfpack_zl_report_vector
+#define UMFPACK_save_numeric	 umfpack_zl_save_numeric
+#define UMFPACK_save_symbolic	 umfpack_zl_save_symbolic
+#define UMFPACK_load_numeric	 umfpack_zl_load_numeric
+#define UMFPACK_load_symbolic	 umfpack_zl_load_symbolic
+#define UMFPACK_scale		 umfpack_zl_scale
+#define UMFPACK_solve		 umfpack_zl_solve
+#define UMFPACK_symbolic	 umfpack_zl_symbolic
+#define UMFPACK_transpose	 umfpack_zl_transpose
+#define UMFPACK_triplet_to_col	 umfpack_zl_triplet_to_col
+#define UMFPACK_wsolve		 umfpack_zl_wsolve
+
+/* for debugging only: */
+#define UMF_malloc_count	 umf_l_malloc_count
+#define UMF_debug		 umfzl_debug
+#define UMF_allocfail		 umfzl_allocfail
+#define UMF_gprob		 umfzl_gprob
+#define UMF_dump_dense		 umfzl_dump_dense
+#define UMF_dump_element	 umfzl_dump_element
+#define UMF_dump_rowcol		 umfzl_dump_rowcol
+#define UMF_dump_matrix		 umfzl_dump_matrix
+#define UMF_dump_current_front	 umfzl_dump_current_front
+#define UMF_dump_lu		 umfzl_dump_lu
+#define UMF_dump_memory		 umfzl_dump_memory
+#define UMF_dump_packed_memory	 umfzl_dump_packed_memory
+#define UMF_dump_col_matrix	 umfzl_dump_col_matrix
+#define UMF_dump_chain		 umfzl_dump_chain
+#define UMF_dump_start		 umfzl_dump_start
+#define UMF_dump_rowmerge	 umfzl_dump_rowmerge
+#define UMF_dump_diagonal_map	 umfzl_dump_diagonal_map
+
+#endif
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_col_to_triplet.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_col_to_triplet.c
new file mode 100644
index 0000000..3075e2a
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_col_to_triplet.c
@@ -0,0 +1,72 @@
+/* ========================================================================== */
+/* === UMFPACK_col_to_triplet =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User callable.  Converts a column-oriented input matrix to triplet form by
+    constructing the column indices Tj from the column pointers Ap.  The matrix
+    may be singular.  See umfpack_col_to_triplet.h for details.
+
+*/
+
+#include "umf_internal.h"
+
+GLOBAL Int UMFPACK_col_to_triplet
+(
+    Int n_col,
+    const Int Ap [ ],
+    Int Tj [ ]
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int nz, j, p, p1, p2, length ;
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the column indices */
+    /* ---------------------------------------------------------------------- */
+
+    if (!Ap || !Tj)
+    {
+	return (UMFPACK_ERROR_argument_missing) ;
+    }
+    if (n_col <= 0)
+    {
+	return (UMFPACK_ERROR_n_nonpositive) ;
+    }
+    if (Ap [0] != 0)
+    {
+	return (UMFPACK_ERROR_invalid_matrix) ;
+    }
+    nz = Ap [n_col] ;
+    if (nz < 0)
+    {
+	return (UMFPACK_ERROR_invalid_matrix) ;
+    }
+
+    for (j = 0 ; j < n_col ; j++)
+    {
+	p1 = Ap [j] ;
+	p2 = Ap [j+1] ;
+	length = p2 - p1 ;
+	if (length < 0 || p2 > nz)
+	{
+	    return (UMFPACK_ERROR_invalid_matrix) ;
+	}
+	for (p = p1 ; p < p2 ; p++)
+	{
+	    Tj [p] = j ;
+	}
+    }
+
+    return (UMFPACK_OK) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_defaults.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_defaults.c
new file mode 100644
index 0000000..b8205b7
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_defaults.c
@@ -0,0 +1,114 @@
+/* ========================================================================== */
+/* === UMFPACK_defaults ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Sets default control parameters.  See umfpack_defaults.h
+    for details.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL void UMFPACK_defaults
+(
+    double Control [UMFPACK_CONTROL]
+)
+{
+    Int i ;
+
+    if (!Control)
+    {
+	/* silently return if no Control array */
+	return ;
+    }
+
+    for (i = 0 ; i < UMFPACK_CONTROL ; i++)
+    {
+	Control [i] = 0 ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* default control settings: can be modified at run-time */
+    /* ---------------------------------------------------------------------- */
+
+    /* used in UMFPACK_report_* routines: */
+    Control [UMFPACK_PRL] = UMFPACK_DEFAULT_PRL ;
+
+    /* used in UMFPACK_*symbolic: */
+    Control [UMFPACK_DENSE_ROW] = UMFPACK_DEFAULT_DENSE_ROW ;
+    Control [UMFPACK_DENSE_COL] = UMFPACK_DEFAULT_DENSE_COL ;
+    Control [UMFPACK_AMD_DENSE] = UMFPACK_DEFAULT_AMD_DENSE ;
+    Control [UMFPACK_STRATEGY] = UMFPACK_DEFAULT_STRATEGY ;
+    Control [UMFPACK_2BY2_TOLERANCE] = UMFPACK_DEFAULT_2BY2_TOLERANCE ;
+    Control [UMFPACK_AGGRESSIVE] = UMFPACK_DEFAULT_AGGRESSIVE ;
+
+    /* used in UMFPACK_numeric: */
+    Control [UMFPACK_PIVOT_TOLERANCE] = UMFPACK_DEFAULT_PIVOT_TOLERANCE ;
+    Control [UMFPACK_SYM_PIVOT_TOLERANCE] = UMFPACK_DEFAULT_SYM_PIVOT_TOLERANCE;
+    Control [UMFPACK_BLOCK_SIZE] = UMFPACK_DEFAULT_BLOCK_SIZE ;
+    Control [UMFPACK_ALLOC_INIT] = UMFPACK_DEFAULT_ALLOC_INIT ;
+    Control [UMFPACK_FRONT_ALLOC_INIT] = UMFPACK_DEFAULT_FRONT_ALLOC_INIT ;
+    Control [UMFPACK_SCALE] = UMFPACK_DEFAULT_SCALE ;
+
+    /* used in UMFPACK_*solve: */
+    Control [UMFPACK_IRSTEP] = UMFPACK_DEFAULT_IRSTEP ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compile-time settings: cannot be modified at run-time */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef NBLAS
+    /* do not use the BLAS - use in-line C code instead */
+    Control [UMFPACK_COMPILED_WITH_BLAS] = 0 ;
+#else
+    /* use externally-provided BLAS (dgemm, dger, dgemv, zgemm, zgeru, zgemv) */
+    Control [UMFPACK_COMPILED_WITH_BLAS] = 1 ;
+#endif
+
+#ifdef MATLAB_MEX_FILE
+    /* compiled as a MATLAB mexFunction */ 
+    Control [UMFPACK_COMPILED_FOR_MATLAB] = 1 ;
+#else
+#ifdef MATHWORKS
+    /* compiled for internal use in MATLAB */ 
+    Control [UMFPACK_COMPILED_FOR_MATLAB] = 2 ;
+#else
+    /* use ANSI C malloc, free, realloc, and printf */
+    Control [UMFPACK_COMPILED_FOR_MATLAB] = 0 ;
+#endif
+#endif
+
+#ifdef NO_TIMER
+    /* no timer used */
+    Control [UMFPACK_COMPILED_WITH_GETRUSAGE] = 3 ;
+#ifndef NPOSIX
+    /* uses the POSIX sysconf ( ) and times ( ) routines in UMFPACK_tic, toc */
+    Control [UMFPACK_COMPILED_WITH_GETRUSAGE] = 2 ;
+#else
+#ifdef GETRUSAGE
+    /* uses the non-standard getrusage to get CPU time (Solaris) */
+    Control [UMFPACK_COMPILED_WITH_GETRUSAGE] = 1 ;
+#else
+    /* uses the ANSI standard clock routine to get CPU time */
+    /* this may wrap around */
+    Control [UMFPACK_COMPILED_WITH_GETRUSAGE] = 0 ;
+#endif
+#endif
+#endif
+
+#ifndef NDEBUG
+    /* UMFPACK is compiled in debug mode. */
+    /* This is exceedingly slow. */
+    DEBUG0 (("UMFPACK is running in debug mode.  This is very slow!\n")) ;
+    Control [UMFPACK_COMPILED_IN_DEBUG_MODE] = 1 ;
+#else
+    /* UMFPACK is compiled in normal (non-debug) mode */
+    Control [UMFPACK_COMPILED_IN_DEBUG_MODE] = 0 ;
+#endif
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_free_numeric.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_free_numeric.c
new file mode 100644
index 0000000..36a6af1
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_free_numeric.c
@@ -0,0 +1,57 @@
+/* ========================================================================== */
+/* === UMFPACK_free_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*  User-callable.  Free the entire Numeric object (consists of 11 to 13
+ *  malloc'd objects.  See UMFPACK_free_numeric.h for details.
+ */
+
+#include "umf_internal.h"
+#include "umf_free.h"
+
+GLOBAL void UMFPACK_free_numeric
+(
+    void **NumericHandle
+)
+{
+
+    NumericType *Numeric ;
+    if (!NumericHandle)
+    {
+	return ;
+    }
+    Numeric = *((NumericType **) NumericHandle) ;
+    if (!Numeric)
+    {
+	return ;
+    }
+
+    /* these 9 objects always exist */
+    (void) UMF_free ((void *) Numeric->D) ;
+    (void) UMF_free ((void *) Numeric->Rperm) ;
+    (void) UMF_free ((void *) Numeric->Cperm) ;
+    (void) UMF_free ((void *) Numeric->Lpos) ;
+    (void) UMF_free ((void *) Numeric->Lilen) ;
+    (void) UMF_free ((void *) Numeric->Lip) ;
+    (void) UMF_free ((void *) Numeric->Upos) ;
+    (void) UMF_free ((void *) Numeric->Uilen) ;
+    (void) UMF_free ((void *) Numeric->Uip) ;
+
+    /* Rs does not exist if scaling was not performed */
+    (void) UMF_free ((void *) Numeric->Rs) ;
+
+    /* Upattern can only exist for singular or rectangular matrices */
+    (void) UMF_free ((void *) Numeric->Upattern) ;
+
+    /* these 2 objects always exist */
+    (void) UMF_free ((void *) Numeric->Memory) ;
+    (void) UMF_free ((void *) Numeric) ;
+
+    *NumericHandle = (void *) NULL ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_free_symbolic.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_free_symbolic.c
new file mode 100644
index 0000000..ccd4834
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_free_symbolic.c
@@ -0,0 +1,56 @@
+/* ========================================================================== */
+/* === UMFPACK_free_symbolic ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  See umfpack_free_symbolic.h for details.
+    All 10 objects comprising the Symbolic object are free'd via UMF_free.
+*/
+
+#include "umf_internal.h"
+#include "umf_free.h"
+
+GLOBAL void UMFPACK_free_symbolic
+(
+    void **SymbolicHandle
+)
+{
+
+    SymbolicType *Symbolic ;
+    if (!SymbolicHandle)
+    {
+	return ;
+    }
+    Symbolic = *((SymbolicType **) SymbolicHandle) ;
+    if (!Symbolic)
+    {
+	return ;
+    }
+
+    (void) UMF_free ((void *) Symbolic->Cperm_init) ;
+    (void) UMF_free ((void *) Symbolic->Rperm_init) ;
+    (void) UMF_free ((void *) Symbolic->Front_npivcol) ;
+    (void) UMF_free ((void *) Symbolic->Front_parent) ;
+    (void) UMF_free ((void *) Symbolic->Front_1strow) ;
+    (void) UMF_free ((void *) Symbolic->Front_leftmostdesc) ;
+    (void) UMF_free ((void *) Symbolic->Chain_start) ;
+    (void) UMF_free ((void *) Symbolic->Chain_maxrows) ;
+    (void) UMF_free ((void *) Symbolic->Chain_maxcols) ;
+    (void) UMF_free ((void *) Symbolic->Cdeg) ;
+    (void) UMF_free ((void *) Symbolic->Rdeg) ;
+
+    /* only when dense rows are present */
+    (void) UMF_free ((void *) Symbolic->Esize) ;
+
+    /* only when diagonal pivoting is prefered */
+    (void) UMF_free ((void *) Symbolic->Diagonal_map) ;
+
+    (void) UMF_free ((void *) Symbolic) ;
+    *SymbolicHandle = (void *) NULL ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_get_determinant.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_get_determinant.c
new file mode 100644
index 0000000..0f47e79
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_get_determinant.c
@@ -0,0 +1,308 @@
+/* ========================================================================== */
+/* === UMFPACK_get_determinant ============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* UMFPACK_get_determinant contributed by David Bateman, Motorola, Paris. */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  From the LU factors, scale factor, and permutation vectors
+    held in the Numeric object, calculates the determinant of the matrix A.
+    See umfpack_get_determinant.h for a more detailed description.
+
+    Dynamic memory usage:  calls UMF_malloc once, for a total space of
+    n integers, and then frees all of it via UMF_free when done.
+
+    Contributed by David Bateman, Motorola, Nov. 2004.
+    Modified for V4.4, Jan. 2005.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+/* ========================================================================== */
+/* === rescale_determinant ================================================== */
+/* ========================================================================== */
+
+/* If the mantissa is too big or too small, rescale it and change exponent */
+
+PRIVATE Int rescale_determinant
+(
+    Entry *d_mantissa,
+    double *d_exponent
+)
+{
+    double d_abs ;
+
+    ABS (d_abs, *d_mantissa) ;
+
+    if (SCALAR_IS_ZERO (d_abs))
+    {
+	/* the determinant is zero */
+	*d_exponent = 0 ;
+	return (FALSE) ;
+    }
+
+    if (SCALAR_IS_NAN (d_abs))
+    {
+	/* the determinant is NaN */
+	return (FALSE) ;
+    }
+
+    while (d_abs < 1.)
+    {
+	SCALE (*d_mantissa, 10.0) ;
+	*d_exponent = *d_exponent - 1.0 ;
+	ABS (d_abs, *d_mantissa) ;
+    }
+
+    while (d_abs >= 10.)
+    {
+	SCALE (*d_mantissa, 0.1) ;
+	*d_exponent = *d_exponent + 1.0 ;
+	ABS (d_abs, *d_mantissa) ;
+    }
+
+    return (TRUE) ;
+}
+
+/* ========================================================================== */
+/* === UMFPACK_get_determinant ============================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_get_determinant
+(
+    double *Mx,
+#ifdef COMPLEX
+    double *Mz,
+#endif
+    double *Ex,
+    void *NumericHandle,
+    double User_Info [UMFPACK_INFO]
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Entry d_mantissa, d_tmp ;
+    double d_exponent, Info2 [UMFPACK_INFO], one [2] = {1.0, 0.0}, d_sign ;
+    Entry *D ;
+    double *Info, *Rs ;
+    NumericType *Numeric ;
+    Int i, n, itmp, npiv, *Wi, *Rperm, *Cperm, do_scale ;
+
+#ifndef NRECIPROCAL
+    Int do_recip ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* check input parameters */
+    /* ---------------------------------------------------------------------- */
+
+    if (User_Info != (double *) NULL)
+    {
+	/* return Info in user's array */
+	Info = User_Info ;
+    }
+    else
+    {
+	/* no Info array passed - use local one instead */
+	Info = Info2 ;
+	for (i = 0 ; i < UMFPACK_INFO ; i++)
+	{
+	    Info [i] = EMPTY ;
+	}
+    }
+
+    Info [UMFPACK_STATUS] = UMFPACK_OK ;
+
+    Numeric = (NumericType *) NumericHandle ;
+    if (!UMF_valid_numeric (Numeric))
+    {
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_Numeric_object ;
+	return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    if (Numeric->n_row != Numeric->n_col)
+    {
+	/* only square systems can be handled */
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_system ;
+	return (UMFPACK_ERROR_invalid_system) ;
+    }
+
+    if (Mx == (double *) NULL)
+    {
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ;
+	return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    n = Numeric->n_row ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Wi = (Int *) UMF_malloc (n, sizeof (Int)) ;
+
+    if (!Wi)
+    {
+	DEBUGm4 (("out of memory: get determinant\n")) ;
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+	return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the determinant */
+    /* ---------------------------------------------------------------------- */
+
+    Rs = Numeric->Rs ;		/* row scale factors */
+    do_scale = (Rs != (double *) NULL) ;
+
+#ifndef NRECIPROCAL
+    do_recip = Numeric->do_recip ;
+#endif
+
+    d_mantissa = ((Entry *) one) [0] ;
+    d_exponent = 0.0 ;
+    D = Numeric->D ;
+
+    /* compute product of diagonal entries of U */
+    for (i = 0 ; i < n ; i++)
+    {
+	MULT (d_tmp, d_mantissa, D [i]) ;
+	d_mantissa = d_tmp ;
+
+	if (!rescale_determinant (&d_mantissa, &d_exponent))
+	{
+	    /* the determinant is zero or NaN */
+	    Info [UMFPACK_STATUS] = UMFPACK_WARNING_singular_matrix ;
+	    /* no need to compute the determinant of R */
+	    do_scale = FALSE ;
+	    break ;
+	}
+    }
+
+    /* compute product of diagonal entries of R (or its inverse) */
+    if (do_scale)
+    {
+	for (i = 0 ; i < n ; i++)
+	{
+#ifndef NRECIPROCAL
+	    if (do_recip)
+	    {
+		/* compute determinant of R inverse */
+		SCALE_DIV (d_mantissa, Rs [i]) ;
+	    }
+	    else
+#endif
+	    {
+		/* compute determinant of R */
+		SCALE (d_mantissa, Rs [i]) ;
+	    }
+	    if (!rescale_determinant (&d_mantissa, &d_exponent))
+	    {
+		/* the determinant is zero or NaN.  This is very unlikey to
+		 * occur here, since the scale factors for a tiny or zero row
+		 * are set to 1. */
+		Info [UMFPACK_STATUS] = UMFPACK_WARNING_singular_matrix ;
+		break ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* determine if P and Q are odd or even permutations */
+    /* ---------------------------------------------------------------------- */
+
+    npiv = 0 ;
+    Rperm = Numeric->Rperm ;
+
+    for (i = 0 ; i < n ; i++)
+    {
+	Wi [i] = Rperm [i] ;
+    }
+
+    for (i = 0 ; i < n ; i++)
+    {
+	while (Wi [i] != i)
+	{
+	    itmp = Wi [Wi [i]] ;
+	    Wi [Wi [i]] = Wi [i] ;
+	    Wi [i] = itmp ;
+	    npiv++ ;
+	}
+    }
+
+    Cperm = Numeric->Cperm ;
+
+    for (i = 0 ; i < n ; i++)
+    {
+	Wi [i] = Cperm [i] ;
+    }
+
+    for (i = 0 ; i < n ; i++)
+    {
+	while (Wi [i] != i)
+	{
+	    itmp = Wi [Wi [i]] ;
+	    Wi [Wi [i]] = Wi [i] ;
+	    Wi [i] = itmp ;
+	    npiv++ ;
+	}
+    }
+
+    /* if npiv is odd, the sign is -1.  if it is even, the sign is +1 */
+    d_sign = (npiv % 2) ? -1. : 1. ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free workspace */
+    /* ---------------------------------------------------------------------- */
+
+    (void) UMF_free ((void *) Wi) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the magnitude and exponent of the determinant */
+    /* ---------------------------------------------------------------------- */
+
+    if (Ex == (double *) NULL)
+    {
+	/* Ex is not provided, so return the entire determinant in d_mantissa */
+	SCALE (d_mantissa, pow (10.0, d_exponent)) ;
+    }
+    else
+    {
+	Ex [0] = d_exponent ;
+    }
+
+    Mx [0] = d_sign * REAL_COMPONENT (d_mantissa) ;
+
+#ifdef COMPLEX
+    if (SPLIT (Mz))
+    {
+	Mz [0] = d_sign * IMAG_COMPONENT (d_mantissa) ;
+    }
+    else
+    {
+	Mx [1] = d_sign * IMAG_COMPONENT (d_mantissa) ;
+    }
+#endif
+
+    /* determine if the determinant has (or will) overflow or underflow */
+    if (d_exponent + 1.0 > log10 (DBL_MAX))
+    {
+	Info [UMFPACK_STATUS] = UMFPACK_WARNING_determinant_overflow ;
+    }
+    else if (d_exponent - 1.0 < log10 (DBL_MIN))
+    {
+	Info [UMFPACK_STATUS] = UMFPACK_WARNING_determinant_underflow ;
+    }
+
+    return (UMFPACK_OK) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_get_lunz.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_get_lunz.c
new file mode 100644
index 0000000..2bfc714
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_get_lunz.c
@@ -0,0 +1,55 @@
+/* ========================================================================== */
+/* === UMFPACK_get_lunz ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Determines the number of nonzeros in L and U, and the size
+    of L and U.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+
+GLOBAL Int UMFPACK_get_lunz
+(
+    Int *lnz,
+    Int *unz,
+    Int *n_row,
+    Int *n_col,
+    Int *nz_udiag,
+    void *NumericHandle
+)
+{
+    NumericType *Numeric ;
+
+    Numeric = (NumericType *) NumericHandle ;
+
+    if (!UMF_valid_numeric (Numeric))
+    {
+	return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+    if (!lnz || !unz || !n_row || !n_col || !nz_udiag)
+    {
+	return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    *n_row = Numeric->n_row ;
+    *n_col = Numeric->n_col ;
+
+    /* number of nz's in L below diagonal, plus the unit diagonal of L */
+    *lnz = Numeric->lnz + MIN (Numeric->n_row, Numeric->n_col) ;
+
+    /* number of nz's in U above diagonal, plus nz's on diagaonal of U */
+    *unz = Numeric->unz + Numeric->nnzpiv ;
+
+    /* number of nz's on the diagonal */
+    *nz_udiag = Numeric->nnzpiv ;
+
+    return (UMFPACK_OK) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_get_numeric.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_get_numeric.c
new file mode 100644
index 0000000..8028a86
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_get_numeric.c
@@ -0,0 +1,1057 @@
+/* ========================================================================== */
+/* === UMFPACK_get_numeric ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Gets the LU factors and the permutation vectors held in the
+    Numeric object.  L is returned in sparse row form with sorted rows, U is
+    returned in sparse column form with sorted columns, and P and Q are
+    returned as permutation vectors.  See umfpack_get_numeric.h for a more
+    detailed description.
+
+    Returns TRUE if successful, FALSE if the Numeric object is invalid or
+    if out of memory.
+
+    Dynamic memory usage:  calls UMF_malloc twice, for a total space of
+    2*n integers, and then frees all of it via UMF_free when done.
+
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+
+PRIVATE void get_L
+(
+    Int Lp [ ],
+    Int Lj [ ],
+    double Lx [ ],
+#ifdef COMPLEX
+    double Lz [ ],
+#endif
+    NumericType *Numeric,
+    Int Pattern [ ],
+    Int Wi [ ]
+) ;
+
+PRIVATE void get_U
+(
+    Int Up [ ],
+    Int Ui [ ],
+    double Ux [ ],
+#ifdef COMPLEX
+    double Uz [ ],
+#endif
+    NumericType *Numeric,
+    Int Pattern [ ],
+    Int Wi [ ]
+) ;
+
+/* ========================================================================== */
+/* === UMFPACK_get_numeric ================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_get_numeric
+(
+    Int Lp [ ],
+    Int Lj [ ],
+    double Lx [ ],
+#ifdef COMPLEX
+    double Lz [ ],
+#endif
+    Int Up [ ],
+    Int Ui [ ],
+    double Ux [ ],
+#ifdef COMPLEX
+    double Uz [ ],
+#endif
+    Int P [ ],
+    Int Q [ ],
+    double Dx [ ],
+#ifdef COMPLEX
+    double Dz [ ],
+#endif
+    Int *p_do_recip,
+    double Rs [ ],
+    void *NumericHandle
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    NumericType *Numeric ;
+    Int getL, getU, *Rperm, *Cperm, k, nn, n_row, n_col, *Wi, *Pattern,
+	n_inner ;
+    double *Rs1 ;
+    Entry *D ;
+
+#ifndef NDEBUG
+    init_count = UMF_malloc_count ;
+#endif
+
+    Wi = (Int *) NULL ;
+    Pattern = (Int *) NULL ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check input parameters */
+    /* ---------------------------------------------------------------------- */
+
+    Numeric = (NumericType *) NumericHandle ;
+    if (!UMF_valid_numeric (Numeric))
+    {
+	return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    n_row = Numeric->n_row ;
+    n_col = Numeric->n_col ;
+    nn = MAX (n_row, n_col) ;
+    n_inner = MIN (n_row, n_col) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    getL = Lp && Lj && Lx ;
+    getU = Up && Ui && Ux ;
+
+    if (getL || getU)
+    {
+	Wi = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+	Pattern = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+	if (!Wi || !Pattern)
+	{
+	    (void) UMF_free ((void *) Wi) ;
+	    (void) UMF_free ((void *) Pattern) ;
+	    ASSERT (UMF_malloc_count == init_count) ;
+	    DEBUGm4 (("out of memory: get numeric\n")) ;
+	    return (UMFPACK_ERROR_out_of_memory) ;
+	}
+	ASSERT (UMF_malloc_count == init_count + 2) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get contents of Numeric */
+    /* ---------------------------------------------------------------------- */
+
+    if (P != (Int *) NULL)
+    {
+	Rperm = Numeric->Rperm ;
+	for (k = 0 ; k < n_row ; k++)
+	{
+	    P [k] = Rperm [k] ;
+	}
+    }
+
+    if (Q != (Int *) NULL)
+    {
+	Cperm = Numeric->Cperm ;
+	for (k = 0 ; k < n_col ; k++)
+	{
+	    Q [k] = Cperm [k] ;
+	}
+    }
+
+    if (getL)
+    {
+	get_L (Lp, Lj, Lx,
+#ifdef COMPLEX
+	    Lz,
+#endif
+	    Numeric, Pattern, Wi) ;
+    }
+
+    if (getU)
+    {
+	get_U (Up, Ui, Ux,
+#ifdef COMPLEX
+	    Uz,
+#endif
+	    Numeric, Pattern, Wi) ;
+    }
+
+    if (Dx != (double *) NULL)
+    {
+	D = Numeric->D ;
+#ifdef COMPLEX
+	if (SPLIT (Dz))
+	{
+	    for (k = 0 ; k < n_inner ; k++)
+	    {
+		Dx [k] = REAL_COMPONENT (D [k]) ;
+		Dz [k] = IMAG_COMPONENT (D [k]) ;
+	    }
+	}
+	else
+	{
+	    for (k = 0 ; k < n_inner ; k++)
+	    {
+	        Dx [2*k  ] =  REAL_COMPONENT (D [k]) ;
+	        Dx [2*k+1] =  IMAG_COMPONENT (D [k]) ;
+	    }
+	}
+#else
+	{
+	    D = Numeric->D ;
+	    for (k = 0 ; k < n_inner ; k++)
+	    {
+		Dx [k] = D [k] ;
+	    }
+	}
+#endif
+    }
+
+    /* return the flag stating whether the scale factors are to be multiplied,
+     * or divided.   If do_recip is TRUE, multiply.  Otherwise, divided.
+     * If NRECIPROCAL is defined at compile time, the scale factors are always
+     * to be used by dividing.
+     */
+    if (p_do_recip != (Int *) NULL)
+    {
+#ifndef NRECIPROCAL
+	*p_do_recip = Numeric->do_recip ;
+#else
+	*p_do_recip = FALSE ;
+#endif
+    }
+
+    if (Rs != (double *) NULL)
+    {
+	Rs1 = Numeric->Rs ;
+	if (Rs1 == (double *) NULL)
+	{
+	    /* R is the identity matrix.  */
+	    for (k = 0 ; k < n_row ; k++)
+	    {
+		Rs [k] = 1.0 ;
+	    }
+	}
+	else
+	{
+	    for (k = 0 ; k < n_row ; k++)
+	    {
+		Rs [k] = Rs1 [k] ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* free the workspace */
+    /* ---------------------------------------------------------------------- */
+
+    (void) UMF_free ((void *) Wi) ;
+    (void) UMF_free ((void *) Pattern) ;
+    ASSERT (UMF_malloc_count == init_count) ;
+
+    return (UMFPACK_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === get_L ================================================================ */
+/* ========================================================================== */
+
+/*
+    The matrix L is stored in the following arrays in the Numeric object:
+
+	Int Lpos [0..npiv]
+	Int Lip [0..npiv], index into Numeric->Memory
+	Int Lilen [0..npiv]
+	Unit *(Numeric->Memory), pointer to memory space holding row indices
+		and numerical values
+
+    where npiv is the number of pivot entries found.  If A is n_row-by-n_col,
+    then npiv <= MIN (n_row,n_col).
+
+    Let L_k denote the pattern of entries in column k of L (excluding the
+    diagonal).
+
+    An Lchain is a sequence of columns of L whose nonzero patterns are related.
+    The start of an Lchain is denoted by a negative value of Lip [k].
+
+    To obtain L_k:
+
+    (1)	If column k starts an Lchain, then L_k is stored in its entirety.
+	|Lip [k]| is an index into Numeric->Memory for the integer row indices
+	in L_k.  The number of entries in the column is |L_k| = Lilen [k].
+	This defines the pattern of the "leading" column of this chain.
+	Lpos [k] is not used for the first column in the chain.  Column zero
+	is always a leading column.
+
+    (2) If column k does not start an Lchain, then L_k is represented as a
+	superset of L_k-1.  Define Lnew_k such that (L_k-1 - {k} union Lnew_k)
+	= L_k, where Lnew_k and (L_k-1)-{k} are disjoint.  Lnew_k are the
+	entries in L_k that are not in L_k-1.  Lpos [k] holds the position of
+	pivot row index k in the prior pattern L_k-1 (if it is present), so
+	that the set subtraction (L_k-1)-{k} can be computed quickly, when
+	computing the pattern of L_k from L_k-1.  The number of new entries in
+	L_k is stored in Lilen [k] = |Lnew_k|.
+
+	Note that this means we must have the pattern L_k-1 to compute L_k.
+
+    In both cases (1) and (2), we obtain the pattern L_k.
+
+    The numerical values are stored in Numeric->Memory, starting at the index
+    |Lip [k]| + Lilen [k].  It is stored in the same order as the entries
+    in L_k, after L_k is obtained from cases (1) or (2), above.
+
+    The advantage of using this "packed" data structure is that it can
+    dramatically reduce the amount of storage needed for the pattern of L.
+    The disadvantage is that it can be difficult for the user to access,
+    and it does not match the sparse matrix data structure used in MATLAB.
+    Thus, this routine is provided to create a conventional sparse matrix
+    data structure for L, in sparse-row form.  A row-form of L appears to
+    MATLAB to be a column-oriented from of the transpose of L.  If you would
+    like a column-form of L, then use UMFPACK_transpose (an example of this
+    is in umfpackmex.c).
+
+*/
+/* ========================================================================== */
+
+PRIVATE void get_L
+(
+    Int Lp [ ],		/* of size n_row+1 */
+    Int Lj [ ],		/* of size lnz, where lnz = Lp [n_row] */
+    double Lx [ ],	/* of size lnz */
+#ifdef COMPLEX
+    double Lz [ ],	/* of size lnz */
+#endif
+    NumericType *Numeric,
+    Int Pattern [ ],	/* workspace of size n_row */
+    Int Wi [ ]		/* workspace of size n_row */
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Entry value ;
+    Entry *xp, *Lval ;
+    Int deg, *ip, j, row, n_row, n_col, n_inner, *Lpos, *Lilen, *Lip, p, llen,
+        lnz2, lp, newLchain, k, pos, npiv, *Li, n1 ;
+#ifdef COMPLEX
+    Int split = SPLIT (Lz) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG4 (("get_L start:\n")) ;
+    n_row = Numeric->n_row ;
+    n_col = Numeric->n_col ;
+    n_inner = MIN (n_row, n_col) ;
+    npiv = Numeric->npiv ;
+    n1 = Numeric->n1 ;
+    Lpos = Numeric->Lpos ;
+    Lilen = Numeric->Lilen ;
+    Lip = Numeric->Lip ;
+    deg = 0 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* count the nonzeros in each row of L */
+    /* ---------------------------------------------------------------------- */
+
+#pragma ivdep
+    for (row = 0 ; row < n_inner ; row++)
+    {
+	/* include the diagonal entry in the row counts */
+	Wi [row] = 1 ;
+    }
+#pragma ivdep
+    for (row = n_inner ; row < n_row ; row++)
+    {
+	Wi [row] = 0 ;
+    }
+
+    /* singletons */
+    for (k = 0 ; k < n1 ; k++)
+    {
+	DEBUG4 (("Singleton k "ID"\n", k)) ;
+	deg = Lilen [k] ;
+	if (deg > 0)
+	{
+	    lp = Lip [k] ;
+	    Li = (Int *) (Numeric->Memory + lp) ;
+	    lp += UNITS (Int, deg) ;
+	    Lval = (Entry *) (Numeric->Memory + lp) ;
+	    for (j = 0 ; j < deg ; j++)
+	    {
+		row = Li [j] ;
+		value = Lval [j] ;
+		DEBUG4 (("  row "ID"  k "ID" value", row, k)) ;
+		EDEBUG4 (value) ;
+		DEBUG4 (("\n")) ;
+		if (IS_NONZERO (value))
+		{
+		    Wi [row]++ ;
+		}
+	    }
+	}
+    }
+
+    /* non-singletons */
+    for (k = n1 ; k < npiv ; k++)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* make column of L in Pattern [0..deg-1] */
+	/* ------------------------------------------------------------------ */
+
+	lp = Lip [k] ;
+	newLchain = (lp < 0) ;
+	if (newLchain)
+	{
+	    lp = -lp ;
+	    deg = 0 ;
+	    DEBUG4 (("start of chain for column of L\n")) ;
+	}
+
+	/* remove pivot row */
+	pos = Lpos [k] ;
+	if (pos != EMPTY)
+	{
+	    DEBUG4 (("  k "ID" removing row "ID" at position "ID"\n",
+	    k, Pattern [pos], pos)) ;
+	    ASSERT (!newLchain) ;
+	    ASSERT (deg > 0) ;
+	    ASSERT (pos >= 0 && pos < deg) ;
+	    ASSERT (Pattern [pos] == k) ;
+	    Pattern [pos] = Pattern [--deg] ;
+	}
+
+	/* concatenate the pattern */
+	ip = (Int *) (Numeric->Memory + lp) ;
+	llen = Lilen [k] ;
+	for (j = 0 ; j < llen ; j++)
+	{
+	    row = *ip++ ;
+	    DEBUG4 (("  row "ID"  k "ID"\n", row, k)) ;
+	    ASSERT (row > k && row < n_row) ;
+	    Pattern [deg++] = row ;
+	}
+
+	xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ;
+
+	for (j = 0 ; j < deg ; j++)
+	{
+	    DEBUG4 (("  row "ID"  k "ID" value", Pattern [j], k)) ;
+	    row = Pattern [j] ;
+	    value = *xp++ ;
+	    EDEBUG4 (value) ;
+	    DEBUG4 (("\n")) ;
+	    if (IS_NONZERO (value))
+	    {
+		Wi [row]++ ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the final row form of L */
+    /* ---------------------------------------------------------------------- */
+
+    /* create the row pointers */
+    lnz2 = 0 ;
+    for (row = 0 ; row < n_row ; row++)
+    {
+	Lp [row] = lnz2 ;
+	lnz2 += Wi [row] ;
+	Wi [row] = Lp [row] ;
+    }
+    Lp [n_row] = lnz2 ;
+    ASSERT (Numeric->lnz + n_inner == lnz2) ;
+
+    /* add entries from the rows of L (singletons) */
+    for (k = 0 ; k < n1 ; k++)
+    {
+	DEBUG4 (("Singleton k "ID"\n", k)) ;
+	deg = Lilen [k] ;
+	if (deg > 0)
+	{
+	    lp = Lip [k] ;
+	    Li = (Int *) (Numeric->Memory + lp) ;
+	    lp += UNITS (Int, deg) ;
+	    Lval = (Entry *) (Numeric->Memory + lp) ;
+	    for (j = 0 ; j < deg ; j++)
+	    {
+		row = Li [j] ;
+		value = Lval [j] ;
+		DEBUG4 (("  row "ID"  k "ID" value", row, k)) ;
+		EDEBUG4 (value) ;
+		DEBUG4 (("\n")) ;
+		if (IS_NONZERO (value))
+		{
+		    p = Wi [row]++ ;
+		    Lj [p] = k ;
+#ifdef COMPLEX
+		    if (split)
+		    {
+
+		        Lx [p] = REAL_COMPONENT (value) ;
+			Lz [p] = IMAG_COMPONENT (value) ;
+		    }
+		    else
+		    {
+			Lx [2*p  ] = REAL_COMPONENT (value) ;
+			Lx [2*p+1] = IMAG_COMPONENT (value) ;
+		    }
+#else
+		    Lx [p] = value ;
+#endif
+		}
+	    }
+	}
+    }
+
+    /* add entries from the rows of L (non-singletons) */
+    for (k = n1 ; k < npiv ; k++)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* make column of L in Pattern [0..deg-1] */
+	/* ------------------------------------------------------------------ */
+
+	lp = Lip [k] ;
+	newLchain = (lp < 0) ;
+	if (newLchain)
+	{
+	    lp = -lp ;
+	    deg = 0 ;
+	    DEBUG4 (("start of chain for column of L\n")) ;
+	}
+
+	/* remove pivot row */
+	pos = Lpos [k] ;
+	if (pos != EMPTY)
+	{
+	    DEBUG4 (("  k "ID" removing row "ID" at position "ID"\n",
+	    k, Pattern [pos], pos)) ;
+	    ASSERT (!newLchain) ;
+	    ASSERT (deg > 0) ;
+	    ASSERT (pos >= 0 && pos < deg) ;
+	    ASSERT (Pattern [pos] == k) ;
+	    Pattern [pos] = Pattern [--deg] ;
+	}
+
+	/* concatenate the pattern */
+	ip = (Int *) (Numeric->Memory + lp) ;
+	llen = Lilen [k] ;
+	for (j = 0 ; j < llen ; j++)
+	{
+	    row = *ip++ ;
+	    DEBUG4 (("  row "ID"  k "ID"\n", row, k)) ;
+	    ASSERT (row > k) ;
+	    Pattern [deg++] = row ;
+	}
+
+	xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ;
+
+	for (j = 0 ; j < deg ; j++)
+	{
+	    DEBUG4 (("  row "ID"  k "ID" value", Pattern [j], k)) ;
+	    row = Pattern [j] ;
+	    value = *xp++ ;
+	    EDEBUG4 (value) ;
+	    DEBUG4 (("\n")) ;
+	    if (IS_NONZERO (value))
+	    {
+		p = Wi [row]++ ;
+		Lj [p] = k ;
+#ifdef COMPLEX
+		if (split)
+		{
+		    Lx [p] = REAL_COMPONENT (value) ;
+		    Lz [p] = IMAG_COMPONENT (value) ;
+		}
+		else
+		{
+		    Lx [2*p  ] = REAL_COMPONENT (value) ;
+		    Lx [2*p+1] = IMAG_COMPONENT (value) ;
+		}
+#else
+		Lx [p] = value ;
+#endif
+	    }
+	}
+    }
+
+    /* add all of the diagonal entries (L is unit diagonal) */
+    for (row = 0 ; row < n_inner ; row++)
+    {
+	p = Wi [row]++ ;
+	Lj [p] = row ;
+
+#ifdef COMPLEX
+	if (split)
+	{
+	    Lx [p] = 1. ;
+	    Lz [p] = 0. ;
+	}
+	else
+	{
+	    Lx [2*p  ] = 1. ;
+	    Lx [2*p+1] = 0. ;
+	}
+#else
+	Lx [p] = 1. ;
+#endif
+
+	ASSERT (Wi [row] == Lp [row+1]) ;
+    }
+
+#ifndef NDEBUG
+    DEBUG6 (("L matrix (stored by rows):")) ;
+    UMF_dump_col_matrix (Lx,
+#ifdef COMPLEX
+	Lz,
+#endif
+	Lj, Lp, n_inner, n_row, Numeric->lnz+n_inner) ;
+#endif
+
+    DEBUG4 (("get_L done:\n")) ;
+}
+
+
+/* ========================================================================== */
+/* === get_U ================================================================ */
+/* ========================================================================== */
+
+/*
+    The matrix U is stored in the following arrays in the Numeric object:
+
+	Int Upos [0..npiv]
+	Int Uip [0..npiv], index into Numeric->Memory
+	Int Uilen [0..npiv]
+	Unit *(Numeric->Memory), pointer to memory space holding column indices
+		and numerical values
+
+    where npiv is the number of pivot entries found.  If A is n_row-by-n_col,
+    then npiv <= MIN (n_row,n_col).
+
+    Let U_k denote the pattern of entries in row k of U (excluding the
+    diagonal).
+
+    A Uchain is a sequence of columns of U whose nonzero patterns are related.
+    The start of a Uchain is denoted by a negative value of Uip [k].
+
+    To obtain U_k-1:
+
+    (1) If row k is the start of a Uchain then Uip [k] is negative and |Uip [k]|
+	is an index into Numeric->Memory for the integer column indices in
+	U_k-1.  The number of entries in the row is |U_k-1| = Uilen [k].  This
+	defines the pattern of the "trailing" row of this chain that ends at
+	row k-1.
+
+
+    (2) If row k is not the start of a Uchain, then U_k-1 is a subset of U_k.
+	The indices in U_k are arranged so that last Uilen [k] entries of
+	U_k are those indices not in U_k-1.  Next, the pivot column index k is
+	added if it appears in row U_k-1 (it never appears in U_k).  Upos [k]
+	holds the position of pivot column index k in the pattern U_k-1 (if it
+	is present), so that the set union (U_k-1)+{k} can be computed quickly,
+	when computing the pattern of U_k-1 from U_k.
+
+	Note that this means we must have the pattern U_k to compute L_k-1.
+
+    In both cases (1) and (2), we obtain the pattern U_k.
+
+    The numerical values are stored in Numeric->Memory.  If k is the start of a
+    Uchain, then the offset is |Uip [k]| plus the size of the space needed to
+    store the pattern U_k-1.  Otherwise, Uip [k] is the offset itself of the
+    numerical values, since in this case no pattern is stored.
+    The numerical values are stored in the same order as the entries in U_k,
+    after U_k is obtained from cases (1) or (2), above.
+
+    The advantage of using this "packed" data structure is that it can
+    dramatically reduce the amount of storage needed for the pattern of U.
+    The disadvantage is that it can be difficult for the user to access,
+    and it does not match the sparse matrix data structure used in MATLAB.
+    Thus, this routine is provided to create a conventional sparse matrix
+    data structure for U, in sparse-column form.
+
+*/
+/* ========================================================================== */
+
+PRIVATE void get_U
+(
+    Int Up [ ],		/* of size n_col+1 */
+    Int Ui [ ],		/* of size unz, where unz = Up [n_col] */
+    double Ux [ ],	/* of size unz */
+#ifdef COMPLEX
+    double Uz [ ],	/* of size unz */
+#endif
+    NumericType *Numeric,
+    Int Pattern [ ],	/* workspace of size n_col */
+    Int Wi [ ]		/* workspace of size n_col */
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Entry value ;
+    Entry *xp, *D, *Uval ;
+    Int deg, j, *ip, col, *Upos, *Uilen, *Uip, n_col, ulen, *Usi,
+        unz2, p, k, up, newUchain, pos, npiv, n1 ;
+#ifdef COMPLEX
+    Int split = SPLIT (Uz) ;
+#endif
+#ifndef NDEBUG
+    Int nnzpiv = 0 ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG4 (("get_U start:\n")) ;
+    n_col = Numeric->n_col ;
+    n1 = Numeric->n1 ;
+    npiv = Numeric->npiv ;
+    Upos = Numeric->Upos ;
+    Uilen = Numeric->Uilen ;
+    Uip = Numeric->Uip ;
+    D = Numeric->D ;
+
+    /* ---------------------------------------------------------------------- */
+    /* count the nonzeros in each column of U */
+    /* ---------------------------------------------------------------------- */
+
+    for (col = 0 ; col < npiv ; col++)
+    {
+	/* include the diagonal entry in the column counts */
+	DEBUG4 (("D ["ID"] = ", col)) ;
+	EDEBUG4 (D [col]) ;
+	Wi [col] = IS_NONZERO (D [col]) ;
+	DEBUG4 ((" is nonzero: "ID"\n", Wi [col])) ;
+#ifndef NDEBUG
+	nnzpiv += IS_NONZERO (D [col]) ;
+#endif
+    }
+    DEBUG4 (("nnzpiv "ID" "ID"\n", nnzpiv, Numeric->nnzpiv)) ;
+    ASSERT (nnzpiv == Numeric->nnzpiv) ;
+    for (col = npiv ; col < n_col ; col++)
+    {
+	/* diagonal entries are zero for structurally singular part */
+	Wi [col] = 0 ;
+    }
+
+    deg = Numeric->ulen ;
+    if (deg > 0)
+    {
+	/* make last pivot row of U (singular matrices only) */
+	DEBUG0 (("Last pivot row of U: ulen "ID"\n", deg)) ;
+	for (j = 0 ; j < deg ; j++)
+	{
+	    Pattern [j] = Numeric->Upattern [j] ;
+	    DEBUG0 (("    column "ID"\n", Pattern [j])) ;
+	}
+    }
+
+    /* non-singletons */
+    for (k = npiv-1 ; k >= n1 ; k--)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* use row k of U */
+	/* ------------------------------------------------------------------ */
+
+	up = Uip [k] ;
+	ulen = Uilen [k] ;
+	newUchain = (up < 0) ;
+	if (newUchain)
+	{
+	    up = -up ;
+	    xp = (Entry *) (Numeric->Memory + up + UNITS (Int, ulen)) ;
+	}
+	else
+	{
+	    xp = (Entry *) (Numeric->Memory + up) ;
+	}
+
+	for (j = 0 ; j < deg ; j++)
+	{
+	    DEBUG4 (("  k "ID" col "ID" value\n", k, Pattern [j])) ;
+	    col = Pattern [j] ;
+	    ASSERT (col >= 0 && col < n_col) ;
+	    value = *xp++ ;
+	    EDEBUG4 (value) ;
+	    DEBUG4 (("\n")) ;
+	    if (IS_NONZERO (value))
+	    {
+		Wi [col]++ ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* make row k-1 of U in Pattern [0..deg-1] */
+	/* ------------------------------------------------------------------ */
+
+	if (k == n1) break ;
+
+	if (newUchain)
+	{
+	    /* next row is a new Uchain */
+	    deg = ulen ;
+	    DEBUG4 (("end of chain for row of U "ID" deg "ID"\n", k-1, deg)) ;
+	    ip = (Int *) (Numeric->Memory + up) ;
+	    for (j = 0 ; j < deg ; j++)
+	    {
+		col = *ip++ ;
+		DEBUG4 (("  k "ID" col "ID"\n", k-1, col)) ;
+		ASSERT (k <= col) ;
+		Pattern [j] = col ;
+	    }
+	}
+	else
+	{
+	    deg -= ulen ;
+	    DEBUG4 (("middle of chain for row of U "ID" deg "ID"\n", k-1, deg));
+	    ASSERT (deg >= 0) ;
+	    pos = Upos [k] ;
+	    if (pos != EMPTY)
+	    {
+		/* add the pivot column */
+		DEBUG4 (("k "ID" add pivot entry at position "ID"\n", k, pos)) ;
+		ASSERT (pos >= 0 && pos <= deg) ;
+		Pattern [deg++] = Pattern [pos] ;
+		Pattern [pos] = k ;
+	    }
+	}
+    }
+
+    /* singletons */
+    for (k = n1 - 1 ; k >= 0 ; k--)
+    {
+	deg = Uilen [k] ;
+	DEBUG4 (("Singleton k "ID"\n", k)) ;
+	if (deg > 0)
+	{
+	    up = Uip [k] ;
+	    Usi = (Int *) (Numeric->Memory + up) ;
+	    up += UNITS (Int, deg) ;
+	    Uval = (Entry *) (Numeric->Memory + up) ;
+	    for (j = 0 ; j < deg ; j++)
+	    {
+		col = Usi [j] ;
+		value = Uval [j] ;
+		DEBUG4 (("  k "ID" col "ID" value", k, col)) ;
+		EDEBUG4 (value) ;
+		DEBUG4 (("\n")) ;
+		if (IS_NONZERO (value))
+		{
+		    Wi [col]++ ;
+		}
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the final column form of U */
+    /* ---------------------------------------------------------------------- */
+
+    /* create the column pointers */
+    unz2 = 0 ;
+    for (col = 0 ; col < n_col ; col++)
+    {
+	Up [col] = unz2 ;
+	unz2 += Wi [col] ;
+    }
+    Up [n_col] = unz2 ;
+    DEBUG1 (("Numeric->unz "ID"  npiv "ID" nnzpiv "ID" unz2 "ID"\n",
+	Numeric->unz, npiv, Numeric->nnzpiv, unz2)) ;
+    ASSERT (Numeric->unz + Numeric->nnzpiv == unz2) ;
+
+    for (col = 0 ; col < n_col ; col++)
+    {
+	Wi [col] = Up [col+1] ;
+    }
+
+    /* add all of the diagonal entries */
+    for (col = 0 ; col < npiv ; col++)
+    {
+	if (IS_NONZERO (D [col]))
+	{
+	    p = --(Wi [col]) ;
+	    Ui [p] = col ;
+#ifdef COMPLEX
+	    if (split)
+	    {
+
+	        Ux [p] = REAL_COMPONENT (D [col]) ;
+		Uz [p] = IMAG_COMPONENT (D [col]) ;
+	    }
+	    else
+	    {
+		Ux [2*p  ] = REAL_COMPONENT (D [col]) ;
+		Ux [2*p+1] = IMAG_COMPONENT (D [col]) ;
+	    }
+#else
+	    Ux [p] = D [col] ;
+#endif
+	}
+    }
+
+    /* add all the entries from the rows of U */
+
+    deg = Numeric->ulen ;
+    if (deg > 0)
+    {
+	/* make last pivot row of U (singular matrices only) */
+	for (j = 0 ; j < deg ; j++)
+	{
+	    Pattern [j] = Numeric->Upattern [j] ;
+	}
+    }
+
+    /* non-singletons */
+    for (k = npiv-1 ; k >= n1 ; k--)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* use row k of U */
+	/* ------------------------------------------------------------------ */
+
+	up = Uip [k] ;
+	ulen = Uilen [k] ;
+	newUchain = (up < 0) ;
+	if (newUchain)
+	{
+	    up = -up ;
+	    xp = (Entry *) (Numeric->Memory + up + UNITS (Int, ulen)) ;
+	}
+	else
+	{
+	    xp = (Entry *) (Numeric->Memory + up) ;
+	}
+
+	xp += deg ;
+	for (j = deg-1 ; j >= 0 ; j--)
+	{
+	    DEBUG4 (("  k "ID" col "ID" value", k, Pattern [j])) ;
+	    col = Pattern [j] ;
+	    ASSERT (col >= 0 && col < n_col) ;
+	    value = *(--xp) ;
+	    EDEBUG4 (value) ;
+	    DEBUG4 (("\n")) ;
+	    if (IS_NONZERO (value))
+	    {
+		p = --(Wi [col]) ;
+		Ui [p] = k ;
+#ifdef COMPLEX
+		if (split)
+		{
+		    Ux [p] = REAL_COMPONENT (value) ;
+		    Uz [p] = IMAG_COMPONENT (value) ;
+		}
+		else
+		{
+		    Ux [2*p  ] = REAL_COMPONENT (value) ;
+		    Ux [2*p+1] = IMAG_COMPONENT (value) ;
+		}
+#else
+		Ux [p] = value ;
+#endif
+
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* make row k-1 of U in Pattern [0..deg-1] */
+	/* ------------------------------------------------------------------ */
+
+	if (newUchain)
+	{
+	    /* next row is a new Uchain */
+	    deg = ulen ;
+	    DEBUG4 (("end of chain for row of U "ID" deg "ID"\n", k-1, deg)) ;
+	    ip = (Int *) (Numeric->Memory + up) ;
+	    for (j = 0 ; j < deg ; j++)
+	    {
+		col = *ip++ ;
+		DEBUG4 (("  k "ID" col "ID"\n", k-1, col)) ;
+		ASSERT (k <= col) ;
+		Pattern [j] = col ;
+	    }
+	}
+	else
+	{
+	    deg -= ulen ;
+	    DEBUG4 (("middle of chain for row of U "ID" deg "ID"\n", k-1, deg));
+	    ASSERT (deg >= 0) ;
+	    pos = Upos [k] ;
+	    if (pos != EMPTY)
+	    {
+		/* add the pivot column */
+		DEBUG4 (("k "ID" add pivot entry at position "ID"\n", k, pos)) ;
+		ASSERT (pos >= 0 && pos <= deg) ;
+		Pattern [deg++] = Pattern [pos] ;
+		Pattern [pos] = k ;
+	    }
+	}
+    }
+
+    /* singletons */
+    for (k = n1 - 1 ; k >= 0 ; k--)
+    {
+	deg = Uilen [k] ;
+	DEBUG4 (("Singleton k "ID"\n", k)) ;
+	if (deg > 0)
+	{
+	    up = Uip [k] ;
+	    Usi = (Int *) (Numeric->Memory + up) ;
+	    up += UNITS (Int, deg) ;
+	    Uval = (Entry *) (Numeric->Memory + up) ;
+	    for (j = 0 ; j < deg ; j++)
+	    {
+		col = Usi [j] ;
+		value = Uval [j] ;
+		DEBUG4 (("  k "ID" col "ID" value", k, col)) ;
+		EDEBUG4 (value) ;
+		DEBUG4 (("\n")) ;
+		if (IS_NONZERO (value))
+		{
+		    p = --(Wi [col]) ;
+		    Ui [p] = k ;
+#ifdef COMPLEX
+		    if (split)
+		    {
+			Ux [p] = REAL_COMPONENT (value) ;
+			Uz [p] = IMAG_COMPONENT (value) ;
+		    }
+		    else
+		    {
+			Ux [2*p  ] = REAL_COMPONENT (value) ;
+			Ux [2*p+1] = IMAG_COMPONENT (value) ;
+		    }
+#else
+		    Ux [p] = value ;
+#endif
+		}
+	    }
+	}
+    }
+
+#ifndef NDEBUG
+    DEBUG6 (("U matrix:")) ;
+    UMF_dump_col_matrix (Ux,
+#ifdef COMPLEX
+	Uz,
+#endif
+	Ui, Up, Numeric->n_row, n_col, Numeric->unz + Numeric->nnzpiv) ;
+#endif
+
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_get_symbolic.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_get_symbolic.c
new file mode 100644
index 0000000..9363534
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_get_symbolic.c
@@ -0,0 +1,191 @@
+/* ========================================================================== */
+/* === UMFPACK_get_symbolic ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Gets the symbolic information held in the Symbolic object.
+    See umfpack_get_symbolic.h for a more detailed description.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_symbolic.h"
+
+GLOBAL Int UMFPACK_get_symbolic
+(
+    Int *p_n_row,
+    Int *p_n_col,
+    Int *p_n1,			/* number of singletons */
+    Int *p_nz,
+    Int *p_nfr,
+    Int *p_nchains,
+    Int P [ ],
+    Int Q [ ],
+    Int Front_npivcol [ ],
+    Int Front_parent [ ],
+    Int Front_1strow [ ],
+    Int Front_leftmostdesc [ ],
+    Int Chain_start [ ],
+    Int Chain_maxrows [ ],
+    Int Chain_maxcols [ ],
+    void *SymbolicHandle
+)
+{
+    SymbolicType *Symbolic ;
+    Int k, n_row, n_col, n1, nfr, nchains, *p ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Symbolic = (SymbolicType *) SymbolicHandle ;
+    if (!UMF_valid_symbolic (Symbolic))
+    {
+	return (UMFPACK_ERROR_invalid_Symbolic_object) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get contents of Symbolic */
+    /* ---------------------------------------------------------------------- */
+
+    n_row = Symbolic->n_row ;
+    n_col = Symbolic->n_col ;
+    n1 = Symbolic->n1 ;
+    nfr = Symbolic->nfr ;
+    nchains = Symbolic->nchains ;
+
+    if (p_n_row)
+    {
+	*p_n_row = n_row ;
+    }
+
+    if (p_n_col)
+    {
+	*p_n_col = n_col ;
+    }
+
+    if (p_n1)
+    {
+	*p_n1 = n1 ;
+    }
+
+    if (p_nz)
+    {
+	*p_nz = Symbolic->nz ;
+    }
+
+    if (p_nfr)
+    {
+	*p_nfr = nfr ;
+    }
+
+    if (p_nchains)
+    {
+	*p_nchains = nchains ;
+    }
+
+    if (P != (Int *) NULL)
+    {
+	Int *Rperm_init, *Diagonal_map ;
+	Rperm_init = Symbolic->Rperm_init ;
+	Diagonal_map = Symbolic->Diagonal_map ;
+	if (Diagonal_map != (Int *) NULL)
+	{
+	    ASSERT (n_row == n_col) ;
+	    /* next pivot rows are found in the diagonal map */
+	    for (k = 0 ; k < n_row ; k++)
+	    {
+		P [k] = Rperm_init [Diagonal_map [k]] ;
+	    }
+	}
+	else
+	{
+	    /* there is no diagonal map.  */
+	    for (k = 0 ; k < n_row ; k++)
+	    {
+		P [k] = Rperm_init [k] ;
+	    }
+	}
+    }
+
+    if (Q != (Int *) NULL)
+    {
+	p = Symbolic->Cperm_init ;
+	for (k = 0 ; k < n_col ; k++)
+	{
+	    Q [k] = p [k] ;
+	}
+    }
+
+    if (Front_npivcol != (Int *) NULL)
+    {
+	p = Symbolic->Front_npivcol ;
+	for (k = 0 ; k <= nfr ; k++)
+	{
+	    Front_npivcol [k] = p [k] ;
+	}
+    }
+
+    if (Front_parent != (Int *) NULL)
+    {
+	p = Symbolic->Front_parent ;
+	for (k = 0 ; k <= nfr ; k++)
+	{
+	    Front_parent [k] = p [k] ;
+	}
+    }
+
+    if (Front_1strow != (Int *) NULL)
+    {
+	p = Symbolic->Front_1strow ;
+	for (k = 0 ; k <= nfr ; k++)
+	{
+	    Front_1strow [k] = p [k] ;
+	}
+    }
+
+    if (Front_leftmostdesc != (Int *) NULL)
+    {
+	p = Symbolic->Front_leftmostdesc ;
+	for (k = 0 ; k <= nfr ; k++)
+	{
+	    Front_leftmostdesc [k] = p [k] ;
+	}
+    }
+
+    if (Chain_start != (Int *) NULL)
+    {
+	p = Symbolic->Chain_start ;
+	for (k = 0 ; k <= nchains ; k++)
+	{
+	    Chain_start [k] = p [k] ;
+	}
+    }
+
+    if (Chain_maxrows != (Int *) NULL)
+    {
+	p = Symbolic->Chain_maxrows ;
+	for (k = 0 ; k < nchains ; k++)
+	{
+	    Chain_maxrows [k] = p [k] ;
+	}
+	Chain_maxrows [nchains] = 0 ;
+    }
+
+    if (Chain_maxcols != (Int *) NULL)
+    {
+	p = Symbolic->Chain_maxcols ;
+	for (k = 0 ; k < nchains ; k++)
+	{
+	    Chain_maxcols [k] = p [k] ;
+	}
+	Chain_maxcols [nchains] = 0 ;
+    }
+
+    return (UMFPACK_OK) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_global.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_global.c
new file mode 100644
index 0000000..b612c1e
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_global.c
@@ -0,0 +1,130 @@
+/* ========================================================================== */
+/* === UMFPACK_global ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Global variables.  UMFPACK uses these function pointers for several
+    user-redefinable functions.   The amd_* functions are defined in
+    AMD/Source/amd_global.c.
+
+    Function pointer	    default	    for mexFunction
+					    (see MATLAB/umfpackmex.c)
+    ----------------	    -------	    ---------------
+    amd_malloc		    malloc	    mxMalloc
+    amd_free		    free	    mxFree
+    amd_realloc		    realloc	    mxRealloc
+    amd_calloc		    calloc	    mxCalloc
+    amd_printf		    printf	    mexPrintf
+
+    umfpack_hypot	    umf_hypot	    umf_hypot
+    umfpack_divcomplex	    umf_divcomplex  umf_divcomplex
+
+    This routine is compiled just once for all four versions of UMFPACK
+    (int/UF_long, double/complex).
+*/
+
+#include "umf_internal.h"
+
+double (*umfpack_hypot) (double, double) = umf_hypot ;
+int (*umfpack_divcomplex) (double, double, double, double, double *, double *)
+    = umf_divcomplex ;
+
+
+/* ========================================================================== */
+/* === umf_hypot ============================================================ */
+/* ========================================================================== */
+
+/* There is an equivalent routine called hypot in <math.h>, which conforms
+ * to ANSI C99.  However, UMFPACK does not assume that ANSI C99 is available.
+ * You can use the ANSI C99 hypot routine with:
+ *
+ *	#include <math.h>
+ *	umfpack_hypot = hypot ;
+ *
+ * prior to calling any UMFPACK routine.
+ *
+ * s = hypot (x,y) computes s = sqrt (x*x + y*y) but does so more accurately.
+ *
+ * The NaN case for the double relops x >= y and x+y == x is safely ignored.
+ */
+
+double umf_hypot (double x, double y)
+{
+    double s, r ;
+    x = SCALAR_ABS (x) ;
+    y = SCALAR_ABS (y) ;
+    if (x >= y)
+    {
+	if (x + y == x)
+	{
+	    s = x ;
+	}
+	else
+	{
+	    r = y / x ;
+	    s = x * sqrt (1.0 + r*r) ;
+	}
+    }
+    else
+    {
+	if (y + x == y)
+	{
+	    s = y ;
+	}
+	else
+	{
+	    r = x / y ;
+	    s = y * sqrt (1.0 + r*r) ;
+	}
+    } 
+    return (s) ;
+}
+
+
+/* ========================================================================== */
+/* === umf_divcomplex ======================================================= */
+/* ========================================================================== */
+
+/* c = a/b where c, a, and b are complex.  The real and imaginary parts are
+ * passed as separate arguments to this routine.  The NaN case is ignored
+ * for the double relop br >= bi.  Returns TRUE (1) if the denominator is
+ * zero, FALSE (0) otherwise.
+ *
+ * This uses ACM Algo 116, by R. L. Smith, 1962, which tries to avoid
+ * underflow and overflow.
+ *
+ * c can be the same variable as a or b.
+ */
+
+int umf_divcomplex
+(
+    double ar, double ai,	/* real and imaginary parts of a */
+    double br, double bi,	/* real and imaginary parts of b */
+    double *cr, double *ci	/* real and imaginary parts of c */
+)
+{
+    double tr, ti, r, den ;
+    if (SCALAR_ABS (br) >= SCALAR_ABS (bi))
+    {
+	r = bi / br ;
+	den = br + r * bi ;
+	tr = (ar + ai * r) / den ;
+	ti = (ai - ar * r) / den ;
+    }
+    else
+    {
+	r = br / bi ;
+	den = r * br + bi ;
+	tr = (ar * r + ai) / den ;
+	ti = (ai * r - ar) / den ;
+    }
+    *cr = tr ;
+    *ci = ti ;
+    return (SCALAR_IS_ZERO (den)) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_load_numeric.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_load_numeric.c
new file mode 100644
index 0000000..18dfcfe
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_load_numeric.c
@@ -0,0 +1,161 @@
+/* ========================================================================== */
+/* === UMFPACK_load_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Loads a Numeric object from a file created by
+    umfpack_*_save_numeric.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+#define READ(object,type,n) \
+{ \
+    object = (type *) UMF_malloc (n, sizeof (type)) ; \
+    if (object == (type *) NULL) \
+    { \
+	UMFPACK_free_numeric ((void **) &Numeric) ; \
+	fclose (f) ; \
+	return (UMFPACK_ERROR_out_of_memory) ; \
+    } \
+    if (fread (object, sizeof (type), n, f) != 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) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_load_symbolic.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_load_symbolic.c
new file mode 100644
index 0000000..6401645
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_load_symbolic.c
@@ -0,0 +1,165 @@
+/* ========================================================================== */
+/* === UMFPACK_load_symbolic ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Loads a Symbolic object from a file created by
+    umfpack_*_save_symbolic.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_symbolic.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+#define READ(object,type,n) \
+{ \
+    object = (type *) UMF_malloc (n, sizeof (type)) ; \
+    if (object == (type *) NULL) \
+    { \
+	UMFPACK_free_symbolic ((void **) &Symbolic) ; \
+	fclose (f) ; \
+	return (UMFPACK_ERROR_out_of_memory) ; \
+    } \
+    if (fread (object, sizeof (type), n, f) != 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) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_numeric.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_numeric.c
new file mode 100644
index 0000000..0a8d67f
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_numeric.c
@@ -0,0 +1,792 @@
+/* ========================================================================== */
+/* === UMFPACK_numeric ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Factorizes A into its LU factors, given a symbolic
+    pre-analysis computed by UMFPACK_symbolic.  See umfpack_numeric.h for a
+    description.
+
+    Dynamic memory allocation:  substantial.  See comments (1) through (7),
+    below.  If an error occurs, all allocated space is free'd by UMF_free.
+    If successful, the Numeric object contains 11 to 13 objects allocated by
+    UMF_malloc that hold the LU factors of the input matrix.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_symbolic.h"
+#include "umf_set_stats.h"
+#include "umf_kernel.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+#include "umf_realloc.h"
+
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+
+PRIVATE Int work_alloc
+(
+    WorkType *Work,
+    SymbolicType *Symbolic
+) ;
+
+PRIVATE void free_work
+(
+    WorkType *Work
+) ;
+
+PRIVATE Int numeric_alloc
+(
+    NumericType **NumericHandle,
+    SymbolicType *Symbolic,
+    double alloc_init,
+    Int scale
+) ;
+
+PRIVATE void error
+(
+    NumericType **Numeric,
+    WorkType *Work
+) ;
+
+
+/* ========================================================================== */
+/* === UMFPACK_numeric ====================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_numeric
+(
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    void *SymbolicHandle,
+    void **NumericHandle,
+    const double Control [UMFPACK_CONTROL],
+    double User_Info [UMFPACK_INFO]
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    double Info2 [UMFPACK_INFO], alloc_init, relpt, relpt2, droptol,
+	front_alloc_init, stats [2] ;
+    double *Info ;
+    WorkType WorkSpace, *Work ;
+    NumericType *Numeric ;
+    SymbolicType *Symbolic ;
+    Int n_row, n_col, n_inner, newsize, i, status, *inew, npiv, ulen, scale ;
+    Unit *mnew ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get the amount of time used by the process so far */
+    /* ---------------------------------------------------------------------- */
+
+    umfpack_tic (stats) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* initialize and check inputs */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    UMF_dump_start ( ) ;
+    init_count = UMF_malloc_count ;
+    DEBUGm4 (("\nUMFPACK numeric: U transpose version\n")) ;
+#endif
+
+    /* If front_alloc_init negative then allocate that size of front in
+     * UMF_start_front.  If alloc_init negative, then allocate that initial
+     * size of Numeric->Memory. */
+
+    relpt = GET_CONTROL (UMFPACK_PIVOT_TOLERANCE,
+	UMFPACK_DEFAULT_PIVOT_TOLERANCE) ;
+    relpt2 = GET_CONTROL (UMFPACK_SYM_PIVOT_TOLERANCE,
+	UMFPACK_DEFAULT_SYM_PIVOT_TOLERANCE) ;
+    alloc_init = GET_CONTROL (UMFPACK_ALLOC_INIT, UMFPACK_DEFAULT_ALLOC_INIT) ;
+    front_alloc_init = GET_CONTROL (UMFPACK_FRONT_ALLOC_INIT,
+	UMFPACK_DEFAULT_FRONT_ALLOC_INIT) ;
+    scale = GET_CONTROL (UMFPACK_SCALE, UMFPACK_DEFAULT_SCALE) ;
+    droptol = GET_CONTROL (UMFPACK_DROPTOL, UMFPACK_DEFAULT_DROPTOL) ;
+
+    relpt   = MAX (0.0, MIN (relpt,  1.0)) ;
+    relpt2  = MAX (0.0, MIN (relpt2, 1.0)) ;
+    droptol = MAX (0.0, droptol) ;
+    front_alloc_init = MIN (1.0, front_alloc_init) ;
+
+    if (scale != UMFPACK_SCALE_NONE && scale != UMFPACK_SCALE_MAX)
+    {
+	scale = UMFPACK_DEFAULT_SCALE ;
+    }
+
+    if (User_Info != (double *) NULL)
+    {
+	/* return Info in user's array */
+	Info = User_Info ;
+	/* clear the parts of Info that are set by UMFPACK_numeric */
+	for (i = UMFPACK_NUMERIC_SIZE ; i <= UMFPACK_MAX_FRONT_NCOLS ; i++)
+	{
+	    Info [i] = EMPTY ;
+	}
+	for (i = UMFPACK_NUMERIC_DEFRAG ; i < UMFPACK_IR_TAKEN ; i++)
+	{
+	    Info [i] = EMPTY ;
+	}
+    }
+    else
+    {
+	/* no Info array passed - use local one instead */
+	Info = Info2 ;
+	for (i = 0 ; i < UMFPACK_INFO ; i++)
+	{
+	    Info [i] = EMPTY ;
+	}
+    }
+
+    Symbolic = (SymbolicType *) SymbolicHandle ;
+    Numeric = (NumericType *) NULL ;
+    if (!UMF_valid_symbolic (Symbolic))
+    {
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_Symbolic_object ;
+	return (UMFPACK_ERROR_invalid_Symbolic_object) ;
+    }
+
+    /* compute alloc_init automatically for AMD ordering */
+    if (Symbolic->ordering == UMFPACK_ORDERING_AMD && alloc_init >= 0)
+    {
+	alloc_init = (Symbolic->nz + Symbolic->amd_lunz) / Symbolic->lunz_bound;
+	alloc_init = MIN (1.0, alloc_init) ;
+	alloc_init *= UMF_REALLOC_INCREASE ;
+    }
+
+    n_row = Symbolic->n_row ;
+    n_col = Symbolic->n_col ;
+    n_inner = MIN (n_row, n_col) ;
+
+    /* check for integer overflow in Numeric->Memory minimum size */
+    if (INT_OVERFLOW (Symbolic->dnum_mem_init_usage * sizeof (Unit)))
+    {
+	/* :: int overflow, initial Numeric->Memory size :: */
+	/* There's no hope to allocate a Numeric object big enough simply to
+	 * hold the initial matrix, so return an out-of-memory condition */
+	DEBUGm4 (("out of memory: numeric int overflow\n")) ;
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+	return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+    Info [UMFPACK_STATUS] = UMFPACK_OK ;
+    Info [UMFPACK_NROW] = n_row ;
+    Info [UMFPACK_NCOL] = n_col ;
+    Info [UMFPACK_SIZE_OF_UNIT] = (double) (sizeof (Unit)) ;
+
+    if (!Ap || !Ai || !Ax || !NumericHandle)
+    {
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ;
+	return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    Info [UMFPACK_NZ] = Ap [n_col] ;
+    *NumericHandle = (void *) NULL ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the Work object */
+    /* ---------------------------------------------------------------------- */
+
+    /* (1) calls UMF_malloc 15 or 17 times, to obtain temporary workspace of
+     * size c+1 Entry's and 2*(n_row+1) + 3*(n_col+1) + (n_col+n_inner+1) +
+     * (nn+1) + * 3*(c+1) + 2*(r+1) + max(r,c) + (nfr+1) integers plus 2*nn
+     * more integers if diagonal pivoting is to be done.  r is the maximum
+     * number of rows in any frontal matrix, c is the maximum number of columns
+     * in any frontal matrix, n_inner is min (n_row,n_col), nn is
+     * max (n_row,n_col), and nfr is the number of frontal matrices.  For a
+     * square matrix, this is c+1 Entry's and about 8n + 3c + 2r + max(r,c) +
+     * nfr integers, plus 2n more for diagonal pivoting.
+     */
+
+    Work = &WorkSpace ;
+    Work->n_row = n_row ;
+    Work->n_col = n_col ;
+    Work->nfr = Symbolic->nfr ;
+    Work->nb = Symbolic->nb ;
+    Work->n1 = Symbolic->n1 ;
+
+    if (!work_alloc (Work, Symbolic))
+    {
+	DEBUGm4 (("out of memory: numeric work\n")) ;
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+	error (&Numeric, Work) ;
+	return (UMFPACK_ERROR_out_of_memory) ;
+    }
+    ASSERT (UMF_malloc_count == init_count + 16 + 2*Symbolic->prefer_diagonal) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate Numeric object */
+    /* ---------------------------------------------------------------------- */
+
+    /* (2) calls UMF_malloc 10 or 11 times, for a total space of
+     * sizeof (NumericType) bytes, 4*(n_row+1) + 4*(n_row+1) integers, and
+     * (n_inner+1) Entry's, plus n_row Entry's if row scaling is to be done.
+     * sizeof (NumericType) is a small constant.  Next, it calls UMF_malloc
+     * once, for the variable-sized part of the Numeric object
+     * (Numeric->Memory).  The size of this object is the larger of
+     * (Control [UMFPACK_ALLOC_INIT]) *  (the approximate upper bound computed
+     * by UMFPACK_symbolic), and the minimum required to start the numerical
+     * factorization.  * This request is reduced if it fails.
+     */
+
+    if (!numeric_alloc (&Numeric, Symbolic, alloc_init, scale))
+    {
+	DEBUGm4 (("out of memory: initial numeric\n")) ;
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+	error (&Numeric, Work) ;
+	return (UMFPACK_ERROR_out_of_memory) ;
+    }
+    DEBUG0 (("malloc: init_count "ID" UMF_malloc_count "ID"\n",
+	init_count, UMF_malloc_count)) ;
+    ASSERT (UMF_malloc_count == init_count
+	+ (16 + 2*Symbolic->prefer_diagonal)
+	+ (11 + (scale != UMFPACK_SCALE_NONE))) ;
+
+    /* set control parameters */
+    Numeric->relpt = relpt ;
+    Numeric->relpt2 = relpt2 ;
+    Numeric->droptol = droptol ;
+    Numeric->alloc_init = alloc_init ;
+    Numeric->front_alloc_init = front_alloc_init ;
+    Numeric->scale = scale ;
+
+    DEBUG0 (("umf relpt %g %g init %g %g inc %g red %g\n",
+	relpt, relpt2, alloc_init, front_alloc_init,
+	UMF_REALLOC_INCREASE, UMF_REALLOC_REDUCTION)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* scale and factorize */
+    /* ---------------------------------------------------------------------- */
+
+    /* (3) During numerical factorization (inside UMF_kernel), the variable-size
+     * block of memory is increased in size via a call to UMF_realloc if it is
+     * found to be too small.  During factorization, this block holds the
+     * pattern and values of L and U at the top end, and the elements
+     * (contibution blocks) and the current frontal matrix (Work->F*) at the
+     * bottom end.  The peak size of the variable-sized object is estimated in
+     * UMFPACK_*symbolic (Info [UMFPACK_VARIABLE_PEAK_ESTIMATE]), although this
+     * upper bound can be very loose.  The size of the Symbolic object
+     * (which is currently allocated) is in Info [UMFPACK_SYMBOLIC_SIZE], and
+     * is between 2*n and 13*n integers.
+     */
+
+    DEBUG0 (("Calling umf_kernel\n")) ;
+    status = UMF_kernel (Ap, Ai, Ax,
+#ifdef COMPLEX
+	Az,
+#endif
+	Numeric, Work, Symbolic) ;
+
+    Info [UMFPACK_STATUS] = status ;
+    if (status < UMFPACK_OK)
+    {
+	/* out of memory, or pattern has changed */
+	error (&Numeric, Work) ;
+	return (status) ;
+    }
+
+    Info [UMFPACK_FORCED_UPDATES] = Work->nforced ;
+    Info [UMFPACK_VARIABLE_INIT] = Numeric->init_usage ;
+    if (Symbolic->prefer_diagonal)
+    {
+	Info [UMFPACK_NOFF_DIAG] = Work->noff_diagonal ;
+    }
+
+    DEBUG0 (("malloc: init_count "ID" UMF_malloc_count "ID"\n",
+	init_count, UMF_malloc_count)) ;
+
+    npiv = Numeric->npiv ;	/* = n_inner for nonsingular matrices */
+    ulen = Numeric->ulen ;	/* = 0 for square nonsingular matrices */
+
+    /* ---------------------------------------------------------------------- */
+    /* free Work object */
+    /* ---------------------------------------------------------------------- */
+
+    /* (4) After numerical factorization all of the objects allocated in step
+     * (1) are freed via UMF_free, except that one object of size n_col+1 is
+     * kept if there are off-diagonal nonzeros in the last pivot row (can only
+     * occur for singular or rectangular matrices).  This is Work->Upattern,
+     * which is transfered to Numeric->Upattern if ulen > 0.
+     */
+
+    DEBUG0 (("malloc: init_count "ID" UMF_malloc_count "ID"\n",
+	init_count, UMF_malloc_count)) ;
+
+    free_work (Work) ;
+
+    DEBUG0 (("malloc: init_count "ID" UMF_malloc_count "ID"\n",
+	init_count, UMF_malloc_count)) ;
+    DEBUG0 (("Numeric->ulen: "ID" scale: "ID"\n", ulen, scale)) ;
+    ASSERT (UMF_malloc_count == init_count + (ulen > 0) +
+	(11 + (scale != UMFPACK_SCALE_NONE))) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* reduce Lpos, Lilen, Lip, Upos, Uilen and Uip to size npiv+1 */
+    /* ---------------------------------------------------------------------- */
+
+    /* (5) Six components of the Numeric object are reduced in size if the
+     * matrix is singular or rectangular.   The original size is 3*(n_row+1) +
+     * 3*(n_col+1) integers.  The new size is 6*(npiv+1) integers.  For
+     * square non-singular matrices, these two sizes are the same.
+     */
+
+    if (npiv < n_row)
+    {
+	/* reduce Lpos, Uilen, and Uip from size n_row+1 to size npiv */
+	inew = (Int *) UMF_realloc (Numeric->Lpos, npiv+1, sizeof (Int)) ;
+	if (inew)
+	{
+	    Numeric->Lpos = inew ;
+	}
+	inew = (Int *) UMF_realloc (Numeric->Uilen, npiv+1, sizeof (Int)) ;
+	if (inew)
+	{
+	    Numeric->Uilen = inew ;
+	}
+	inew = (Int *) UMF_realloc (Numeric->Uip, npiv+1, sizeof (Int)) ;
+	if (inew)
+	{
+	    Numeric->Uip = inew ;
+	}
+    }
+
+    if (npiv < n_col)
+    {
+	/* reduce Upos, Lilen, and Lip from size n_col+1 to size npiv */
+	inew = (Int *) UMF_realloc (Numeric->Upos, npiv+1, sizeof (Int)) ;
+	if (inew)
+	{
+	    Numeric->Upos = inew ;
+	}
+	inew = (Int *) UMF_realloc (Numeric->Lilen, npiv+1, sizeof (Int)) ;
+	if (inew)
+	{
+	    Numeric->Lilen = inew ;
+	}
+	inew = (Int *) UMF_realloc (Numeric->Lip, npiv+1, sizeof (Int)) ;
+	if (inew)
+	{
+	    Numeric->Lip = inew ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* reduce Numeric->Upattern from size n_col+1 to size ulen+1 */
+    /* ---------------------------------------------------------------------- */
+
+    /* (6) The size of Numeric->Upattern (formerly Work->Upattern) is reduced
+     * from size n_col+1 to size ulen + 1.  If ulen is zero, the object does
+     * not exist. */
+
+    DEBUG4 (("ulen: "ID" Upattern "ID"\n", ulen, (Int) Numeric->Upattern)) ;
+    ASSERT (IMPLIES (ulen == 0, Numeric->Upattern == (Int *) NULL)) ;
+    if (ulen > 0 && ulen < n_col)
+    {
+	inew = (Int *) UMF_realloc (Numeric->Upattern, ulen+1, sizeof (Int)) ;
+	if (inew)
+	{
+	    Numeric->Upattern = inew ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* reduce Numeric->Memory to hold just the LU factors at the head */
+    /* ---------------------------------------------------------------------- */
+
+    /* (7) The variable-sized block (Numeric->Memory) is reduced to hold just L
+     * and U, via a call to UMF_realloc, since the frontal matrices are no
+     * longer needed.
+     */
+
+    newsize = Numeric->ihead ;
+    if (newsize < Numeric->size)
+    {
+	mnew = (Unit *) UMF_realloc (Numeric->Memory, newsize, sizeof (Unit)) ;
+	if (mnew)
+	{
+	    /* realloc succeeded (how can it fail since the size is reduced?) */
+	    Numeric->Memory = mnew ;
+	    Numeric->size = newsize ;
+	}
+    }
+    Numeric->ihead = Numeric->size ;
+    Numeric->itail = Numeric->ihead ;
+    Numeric->tail_usage = 0 ;
+    Numeric->ibig = EMPTY ;
+    /* UMF_mem_alloc_tail_block can no longer be called (no tail marker) */
+
+    /* ---------------------------------------------------------------------- */
+    /* report the results and return the Numeric object */
+    /* ---------------------------------------------------------------------- */
+
+    UMF_set_stats (
+	Info,
+	Symbolic,
+	(double) Numeric->max_usage,	/* actual peak Numeric->Memory */
+	(double) Numeric->size,		/* actual final Numeric->Memory */
+	Numeric->flops,			/* actual "true flops" */
+	(double) Numeric->lnz + n_inner,		/* actual nz in L */
+	(double) Numeric->unz + Numeric->nnzpiv,	/* actual nz in U */
+	(double) Numeric->maxfrsize,	/* actual largest front size */
+	(double) ulen,			/* actual Numeric->Upattern size */
+	(double) npiv,			/* actual # pivots found */
+	(double) Numeric->maxnrows,	/* actual largest #rows in front */
+	(double) Numeric->maxncols,	/* actual largest #cols in front */
+	scale != UMFPACK_SCALE_NONE,
+	Symbolic->prefer_diagonal,
+	ACTUAL) ;
+
+    Info [UMFPACK_ALLOC_INIT_USED] = Numeric->alloc_init ;
+    Info [UMFPACK_NUMERIC_DEFRAG] = Numeric->ngarbage ;
+    Info [UMFPACK_NUMERIC_REALLOC] = Numeric->nrealloc ;
+    Info [UMFPACK_NUMERIC_COSTLY_REALLOC] = Numeric->ncostly ;
+    Info [UMFPACK_COMPRESSED_PATTERN] = Numeric->isize ;
+    Info [UMFPACK_LU_ENTRIES] = Numeric->nLentries + Numeric->nUentries +
+	    Numeric->npiv ;
+    Info [UMFPACK_UDIAG_NZ] = Numeric->nnzpiv ;
+    Info [UMFPACK_RSMIN] = Numeric->rsmin ;
+    Info [UMFPACK_RSMAX] = Numeric->rsmax ;
+    Info [UMFPACK_WAS_SCALED] = Numeric->scale ;
+
+    /* nz in L and U with no dropping of small entries */
+    Info [UMFPACK_ALL_LNZ] = Numeric->all_lnz + n_inner ;
+    Info [UMFPACK_ALL_UNZ] = Numeric->all_unz + Numeric->nnzpiv ;
+    Info [UMFPACK_NZDROPPED] =
+	  (Numeric->all_lnz - Numeric->lnz)
+	+ (Numeric->all_unz - Numeric->unz) ;
+
+    /* estimate of the reciprocal of the condition number. */
+    if (SCALAR_IS_ZERO (Numeric->min_udiag)
+     || SCALAR_IS_ZERO (Numeric->max_udiag)
+     ||	SCALAR_IS_NAN (Numeric->min_udiag)
+     ||	SCALAR_IS_NAN (Numeric->max_udiag))
+    {
+	/* rcond is zero if there is any zero or NaN on the diagonal */
+	Numeric->rcond = 0.0 ;
+    }
+    else
+    {
+	/* estimate of the recipricol of the condition number. */
+	/* This is NaN if diagonal is zero-free, but has one or more NaN's. */
+	Numeric->rcond = Numeric->min_udiag / Numeric->max_udiag ;
+    }
+    Info [UMFPACK_UMIN]  = Numeric->min_udiag ;
+    Info [UMFPACK_UMAX]  = Numeric->max_udiag ;
+    Info [UMFPACK_RCOND] = Numeric->rcond ;
+
+    if (Numeric->nnzpiv < n_inner
+    || SCALAR_IS_ZERO (Numeric->rcond) || SCALAR_IS_NAN (Numeric->rcond))
+    {
+	/* there are zeros and/or NaN's on the diagonal of U */
+	DEBUG0 (("Warning, matrix is singular in umfpack_numeric\n")) ;
+	DEBUG0 (("nnzpiv "ID" n_inner "ID" rcond %g\n", Numeric->nnzpiv,
+	    n_inner, Numeric->rcond)) ;
+	status = UMFPACK_WARNING_singular_matrix ;
+	Info [UMFPACK_STATUS] = status ;
+    }
+
+    Numeric->valid = NUMERIC_VALID ;
+    *NumericHandle = (void *) Numeric ;
+
+    /* Numeric has 11 to 13 objects */
+    ASSERT (UMF_malloc_count == init_count + 11 +
+	+ (ulen > 0)			    /* Numeric->Upattern */
+	+ (scale != UMFPACK_SCALE_NONE)) ;  /* Numeric->Rs */
+
+    /* ---------------------------------------------------------------------- */
+    /* get the time used by UMFPACK_numeric */
+    /* ---------------------------------------------------------------------- */
+
+    umfpack_toc (stats) ;
+    Info [UMFPACK_NUMERIC_WALLTIME] = stats [0] ;
+    Info [UMFPACK_NUMERIC_TIME] = stats [1] ;
+
+    /* return UMFPACK_OK or UMFPACK_WARNING_singular_matrix */
+    return (status) ;
+
+}
+
+
+/* ========================================================================== */
+/* === numeric_alloc ======================================================== */
+/* ========================================================================== */
+
+/* Allocate the Numeric object */
+
+PRIVATE Int numeric_alloc
+(
+    NumericType **NumericHandle,
+    SymbolicType *Symbolic,
+    double alloc_init,
+    Int scale
+)
+{
+    double nsize, bsize ;
+    Int n_row, n_col, n_inner, min_usage, trying ;
+    NumericType *Numeric ;
+
+    DEBUG0 (("numeric alloc:\n")) ;
+
+    n_row = Symbolic->n_row ;
+    n_col = Symbolic->n_col ;
+    n_inner = MIN (n_row, n_col) ;
+    *NumericHandle = (NumericType *) NULL ;
+
+    /* 1 allocation:  accounted for in UMF_set_stats (num_On_size1),
+     * free'd in umfpack_free_numeric */
+    Numeric = (NumericType *) UMF_malloc (1, sizeof (NumericType)) ;
+
+    if (!Numeric)
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+    Numeric->valid = 0 ;
+    *NumericHandle = Numeric ;
+
+    /* 9 allocations:  accounted for in UMF_set_stats (num_On_size1),
+     * free'd in umfpack_free_numeric */
+    Numeric->D = (Entry *) UMF_malloc (n_inner+1, sizeof (Entry)) ;
+    Numeric->Rperm = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+    Numeric->Cperm = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+    Numeric->Lpos = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+    Numeric->Lilen = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+    Numeric->Lip = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+    Numeric->Upos = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+    Numeric->Uilen = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+    Numeric->Uip = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+
+    /* 1 allocation if scaling:  in UMF_set_stats (num_On_size1),
+     * free'd in umfpack_free_numeric */
+    if (scale != UMFPACK_SCALE_NONE)
+    {
+	DEBUG0 (("Allocating scale factors\n")) ;
+	Numeric->Rs = (double *) UMF_malloc (n_row, sizeof (double)) ;
+    }
+    else
+    {
+	DEBUG0 (("No scale factors allocated (R = I)\n")) ;
+	Numeric->Rs = (double *) NULL ;
+    }
+
+    Numeric->Memory = (Unit *) NULL ;
+
+    /* Upattern has already been allocated as part of the Work object.  If
+     * the matrix is singular or rectangular, and there are off-diagonal
+     * nonzeros in the last pivot row, then Work->Upattern is not free'd.
+     * Instead it is transfered to Numeric->Upattern.  If it exists,
+     * Numeric->Upattern is free'd in umfpack_free_numeric. */
+    Numeric->Upattern = (Int *) NULL ;	/* used for singular matrices only */
+
+    if (!Numeric->D || !Numeric->Rperm || !Numeric->Cperm || !Numeric->Upos ||
+	!Numeric->Lpos || !Numeric->Lilen || !Numeric->Uilen || !Numeric->Lip ||
+	!Numeric->Uip || (scale != UMFPACK_SCALE_NONE && !Numeric->Rs))
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate initial Numeric->Memory for LU factors and elements */
+    /* ---------------------------------------------------------------------- */
+
+    if (alloc_init < 0)
+    {
+	/* -alloc_init is the exact size to initially allocate */
+	nsize = -alloc_init ;
+    }
+    else
+    {
+	/* alloc_init is a ratio of the upper bound memory usage */
+	nsize = (alloc_init * Symbolic->num_mem_usage_est) + 1 ;
+    }
+    min_usage = Symbolic->num_mem_init_usage ;
+
+    /* Numeric->Memory must be large enough for UMF_kernel_init */
+    nsize = MAX (min_usage, nsize) ;
+
+    /* Numeric->Memory cannot be larger in size than Int_MAX / sizeof(Unit) */
+    /* For ILP32 mode:  2GB (nsize cannot be bigger than 256 Mwords) */
+    bsize = ((double) Int_MAX) / sizeof (Unit) - 1 ;
+    DEBUG0 (("bsize %g\n", bsize)) ;
+    nsize = MIN (nsize, bsize) ;
+
+    Numeric->size = (Int) nsize ;
+
+    DEBUG0 (("Num init %g usage_est %g numsize "ID" minusage "ID"\n",
+	alloc_init, Symbolic->num_mem_usage_est, Numeric->size, min_usage)) ;
+
+    /* allocates 1 object: */
+    /* keep trying until successful, or memory request is too small */
+    trying = TRUE ;
+    while (trying)
+    {
+	Numeric->Memory = (Unit *) UMF_malloc (Numeric->size, sizeof (Unit)) ;
+	if (Numeric->Memory)
+	{
+	    DEBUG0 (("Successful Numeric->size: "ID"\n", Numeric->size)) ;
+	    return (TRUE) ;
+	}
+	/* too much, reduce the request (but not below the minimum) */
+	/* and try again */
+	trying = Numeric->size > min_usage ;
+	Numeric->size = (Int)
+	    (UMF_REALLOC_REDUCTION * ((double) Numeric->size)) ;
+	Numeric->size = MAX (min_usage, Numeric->size) ;
+    }
+
+    return (FALSE) ;	/* we failed to allocate Numeric->Memory */
+}
+
+
+/* ========================================================================== */
+/* === work_alloc =========================================================== */
+/* ========================================================================== */
+
+/* Allocate the Work object.  Return TRUE if successful. */
+
+PRIVATE Int work_alloc
+(
+    WorkType *Work,
+    SymbolicType *Symbolic
+)
+{
+    Int n_row, n_col, nn, maxnrows, maxncols, nfr, ok, maxnrc, n1 ;
+
+    n_row = Work->n_row ;
+    n_col = Work->n_col ;
+    nn = MAX (n_row, n_col) ;
+    nfr = Work->nfr ;
+    n1 = Symbolic->n1 ;
+    ASSERT (n1 <= n_row && n1 <= n_col) ;
+
+    maxnrows = Symbolic->maxnrows + Symbolic->nb ;
+    maxnrows = MIN (n_row, maxnrows) ;
+    maxncols = Symbolic->maxncols + Symbolic->nb ;
+    maxncols = MIN (n_col, maxncols) ;
+    maxnrc = MAX (maxnrows, maxncols) ;
+
+    DEBUG0 (("work alloc:  maxnrows+nb "ID" maxncols+nb "ID"\n",
+	maxnrows, maxncols)) ;
+
+    /* 15 allocations, freed in free_work: */
+    /* accounted for in UMF_set_stats (work_usage) */
+    Work->Wx = (Entry *) UMF_malloc (maxnrows + 1, sizeof (Entry)) ;
+    Work->Wy = (Entry *) UMF_malloc (maxnrows + 1, sizeof (Entry)) ;
+    Work->Frpos    = (Int *) UMF_malloc (n_row + 1, sizeof (Int)) ;
+    Work->Lpattern = (Int *) UMF_malloc (n_row + 1, sizeof (Int)) ;
+    Work->Fcpos = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ;
+    Work->Wp = (Int *) UMF_malloc (nn + 1, sizeof (Int)) ;
+    Work->Wrp = (Int *) UMF_malloc (MAX (n_col,maxnrows) + 1, sizeof (Int)) ;
+    Work->Frows = (Int *) UMF_malloc (maxnrows + 1, sizeof (Int)) ;
+    Work->Wm    = (Int *) UMF_malloc (maxnrows + 1, sizeof (Int)) ;
+    Work->Fcols = (Int *) UMF_malloc (maxncols + 1, sizeof (Int)) ;
+    Work->Wio   = (Int *) UMF_malloc (maxncols + 1, sizeof (Int)) ;
+    Work->Woi   = (Int *) UMF_malloc (maxncols + 1, sizeof (Int)) ;
+    Work->Woo = (Int *) UMF_malloc (maxnrc + 1, sizeof (Int));
+    Work->elen = (n_col - n1) + (n_row - n1) + MIN (n_col-n1, n_row-n1) + 1 ;
+    Work->E = (Int *) UMF_malloc (Work->elen, sizeof (Int)) ;
+    Work->Front_new1strow = (Int *) UMF_malloc (nfr + 1, sizeof (Int)) ;
+
+    ok = (Work->Frpos && Work->Fcpos && Work->Lpattern
+	&& Work->Wp && Work->Wrp && Work->Frows && Work->Fcols
+	&& Work->Wio && Work->Woi && Work->Woo && Work->Wm
+	&& Work->E && Work->Front_new1strow && Work->Wx && Work->Wy) ;
+
+    /* 2 allocations: accounted for in UMF_set_stats (work_usage) */
+    if (Symbolic->prefer_diagonal)
+    {
+	Work->Diagonal_map  = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+	Work->Diagonal_imap = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+	ok = ok && Work->Diagonal_map && Work->Diagonal_imap ;
+    }
+    else
+    {
+	/* no diagonal map needed for rectangular matrices */
+	Work->Diagonal_map = (Int *) NULL ;
+	Work->Diagonal_imap = (Int *) NULL ;
+    }
+
+    /* 1 allocation, may become part of Numeric (if singular or rectangular): */
+    Work->Upattern = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ;
+    ok = ok && Work->Upattern ;
+
+    /* current frontal matrix does not yet exist */
+    Work->Flublock = (Entry *) NULL ;
+    Work->Flblock  = (Entry *) NULL ;
+    Work->Fublock  = (Entry *) NULL ;
+    Work->Fcblock  = (Entry *) NULL ;
+
+    DEBUG0 (("work alloc done.\n")) ;
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === free_work ============================================================ */
+/* ========================================================================== */
+
+PRIVATE void free_work
+(
+    WorkType *Work
+)
+{
+    DEBUG0 (("work free:\n")) ;
+    if (Work)
+    {
+	/* these 16 objects do exist */
+	Work->Wx = (Entry *) UMF_free ((void *) Work->Wx) ;
+	Work->Wy = (Entry *) UMF_free ((void *) Work->Wy) ;
+	Work->Frpos = (Int *) UMF_free ((void *) Work->Frpos) ;
+	Work->Fcpos = (Int *) UMF_free ((void *) Work->Fcpos) ;
+	Work->Lpattern = (Int *) UMF_free ((void *) Work->Lpattern) ;
+	Work->Upattern = (Int *) UMF_free ((void *) Work->Upattern) ;
+	Work->Wp = (Int *) UMF_free ((void *) Work->Wp) ;
+	Work->Wrp = (Int *) UMF_free ((void *) Work->Wrp) ;
+	Work->Frows = (Int *) UMF_free ((void *) Work->Frows) ;
+	Work->Fcols = (Int *) UMF_free ((void *) Work->Fcols) ;
+	Work->Wio = (Int *) UMF_free ((void *) Work->Wio) ;
+	Work->Woi = (Int *) UMF_free ((void *) Work->Woi) ;
+	Work->Woo = (Int *) UMF_free ((void *) Work->Woo) ;
+	Work->Wm = (Int *) UMF_free ((void *) Work->Wm) ;
+	Work->E = (Int *) UMF_free ((void *) Work->E) ;
+	Work->Front_new1strow =
+	    (Int *) UMF_free ((void *) Work->Front_new1strow) ;
+
+	/* these objects might not exist */
+	Work->Diagonal_map = (Int *) UMF_free ((void *) Work->Diagonal_map) ;
+	Work->Diagonal_imap = (Int *) UMF_free ((void *) Work->Diagonal_imap) ;
+    }
+    DEBUG0 (("work free done.\n")) ;
+}
+
+
+/* ========================================================================== */
+/* === error ================================================================ */
+/* ========================================================================== */
+
+/* Error return from UMFPACK_numeric.  Free all allocated memory. */
+
+PRIVATE void error
+(
+    NumericType **Numeric,
+    WorkType *Work
+)
+{
+    free_work (Work) ;
+    UMFPACK_free_numeric ((void **) Numeric) ;
+    ASSERT (UMF_malloc_count == init_count) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_qsymbolic.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_qsymbolic.c
new file mode 100644
index 0000000..fc7f267
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_qsymbolic.c
@@ -0,0 +1,2411 @@
+/* ========================================================================== */
+/* === UMFPACK_qsymbolic ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Performs a symbolic factorization.
+    See umfpack_qsymbolic.h and umfpack_symbolic.h for details.
+
+    Dynamic memory usage:  about (3.4nz + 8n + n) integers and n double's as
+    workspace (via UMF_malloc, for a square matrix).  All of it is free'd via
+    UMF_free if an error occurs.  If successful, the Symbolic object contains
+    12 to 14 objects allocated by UMF_malloc, with a total size of no more
+    than about 13*n integers.
+*/
+
+#include "umf_internal.h"
+#include "umf_symbolic_usage.h"
+#include "umf_colamd.h"
+#include "umf_set_stats.h"
+#include "umf_analyze.h"
+#include "umf_transpose.h"
+#include "umf_is_permutation.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+#include "umf_2by2.h"
+#include "umf_singletons.h"
+
+typedef struct	/* SWType */
+{
+    Int *Front_npivcol ;    /* size n_col + 1 */
+    Int *Front_nrows ;	    /* size n_col */
+    Int *Front_ncols ;	    /* size n_col */
+    Int *Front_parent ;	    /* size n_col */
+    Int *Front_cols ;	    /* size n_col */
+    Int *InFront ;	    /* size n_row */
+    Int *Ci ;		    /* size Clen */
+    Int *Cperm1 ;	    /* size n_col */
+    Int *Rperm1 ;	    /* size n_row */
+    Int *InvRperm1 ;	    /* size n_row */
+    Int *Si ;		    /* size nz */
+    Int *Sp ;		    /* size n_col + 1 */
+    double *Rs ;	    /* size n_row */
+    Int *Rperm_2by2 ;	    /* size n_row */
+
+} SWType ;
+
+PRIVATE void free_work
+(
+    SWType *SW
+) ;
+
+PRIVATE void error
+(
+    SymbolicType **Symbolic,
+    SWType *SW
+) ;
+
+/* worst-case usage for SW object */
+#define SYM_WORK_USAGE(n_col,n_row,Clen) \
+    (DUNITS (Int, Clen) + \
+     DUNITS (Int, nz) + \
+     4 * DUNITS (Int, n_row) + \
+     4 * DUNITS (Int, n_col) + \
+     2 * DUNITS (Int, n_col + 1) + \
+     DUNITS (double, n_row))
+
+/* required size of Ci for code that calls UMF_transpose and UMF_analyze below*/
+#define UMF_ANALYZE_CLEN(nz,n_row,n_col,nn) \
+    ((n_col) + MAX ((nz),(n_col)) + 3*(nn)+1 + (n_col))
+
+/* size of an element (in Units), including tuples */
+#define ELEMENT_SIZE(r,c) \
+    (DGET_ELEMENT_SIZE (r, c) + 1 + (r + c) * UNITS (Tuple, 1))
+
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+
+/* ========================================================================== */
+/* === do_amd =============================================================== */
+/* ========================================================================== */
+
+PRIVATE void do_amd
+(
+    Int n,
+    const Int Ap [ ],		/* size n+1 */
+    const Int Ai [ ],		/* size nz = Ap [n] */
+    Int Q [ ],			/* output permutation, j = Q [k] */
+    Int Qinv [ ],		/* output inverse permutation, Qinv [j] = k */
+    Int Sdeg [ ],		/* degree of A+A', from AMD_aat */
+    Int Clen,			/* size of Ci */
+    Int Ci [ ],			/* size Ci workspace */
+    double amd_Control [ ],	/* AMD control parameters */
+    double amd_Info [ ],	/* AMD info */
+    SymbolicType *Symbolic,	/* Symbolic object */
+    double Info [ ]		/* UMFPACK info */
+)
+{
+
+    if (n == 0)
+    {
+	Symbolic->amd_dmax = 0 ;
+	Symbolic->amd_lunz = 0 ;
+	Info [UMFPACK_SYMMETRIC_LUNZ] = 0 ;
+	Info [UMFPACK_SYMMETRIC_FLOPS] = 0 ;
+	Info [UMFPACK_SYMMETRIC_DMAX] = 0 ;
+	Info [UMFPACK_SYMMETRIC_NDENSE] = 0 ;
+    }
+    else
+    {
+	AMD_1 (n, Ap, Ai, Q, Qinv, Sdeg, Clen, Ci, amd_Control, amd_Info) ;
+
+	/* return estimates computed from AMD on PA+PA' */
+	Symbolic->amd_dmax = amd_Info [AMD_DMAX] ;
+	Symbolic->amd_lunz = 2 * amd_Info [AMD_LNZ] + n ;
+	Info [UMFPACK_SYMMETRIC_LUNZ] = Symbolic->amd_lunz ;
+	Info [UMFPACK_SYMMETRIC_FLOPS] = DIV_FLOPS * amd_Info [AMD_NDIV] +
+	    MULTSUB_FLOPS * amd_Info [AMD_NMULTSUBS_LU] ;
+	Info [UMFPACK_SYMMETRIC_DMAX] = Symbolic->amd_dmax ;
+	Info [UMFPACK_SYMMETRIC_NDENSE] = amd_Info [AMD_NDENSE] ;
+	Info [UMFPACK_SYMBOLIC_DEFRAG] += amd_Info [AMD_NCMPA] ;
+    }
+}
+
+/* ========================================================================== */
+/* === prune_singletons ===================================================== */
+/* ========================================================================== */
+
+/* Create the submatrix after removing the n1 singletons.  The matrix has
+ * row and column indices in the range 0 to n_row-n1 and 0 to n_col-n1,
+ * respectively.  */
+
+PRIVATE Int prune_singletons
+(
+    Int n1,
+    Int n_col,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    Int Cperm1 [ ],
+    Int InvRperm1 [ ],
+    Int Si [ ],
+    Int Sp [ ]
+#ifndef NDEBUG
+    , Int Rperm1 [ ]
+    , Int n_row
+#endif
+)
+{
+    Int row, k, pp, p, oldcol, newcol, newrow, nzdiag, do_nzdiag ;
+#ifdef COMPLEX
+    Int split = SPLIT (Az) ;
+#endif
+
+    nzdiag = 0 ;
+    do_nzdiag = (Ax != (double *) NULL) ;
+
+#ifndef NDEBUG
+    DEBUGm4 (("Prune : S = A (Cperm1 (n1+1:end), Rperm1 (n1+1:end))\n")) ;
+    for (k = 0 ; k < n_row ; k++)
+    {
+	ASSERT (Rperm1 [k] >= 0 && Rperm1 [k] < n_row) ;
+	ASSERT (InvRperm1 [Rperm1 [k]] == k) ;
+    }
+#endif
+
+    /* create the submatrix after removing singletons */
+
+    pp = 0 ;
+    for (k = n1 ; k < n_col ; k++)
+    {
+	oldcol = Cperm1 [k] ;
+	newcol = k - n1 ;
+	DEBUG5 (("Prune singletons k "ID" oldcol "ID" newcol "ID": "ID"\n",
+	    k, oldcol, newcol, pp)) ;
+	Sp [newcol] = pp ;  /* load column pointers */
+	for (p = Ap [oldcol] ; p < Ap [oldcol+1] ; p++)
+	{
+	    row = Ai [p] ;
+	    DEBUG5 (("  "ID":  row "ID, pp, row)) ;
+	    ASSERT (row >= 0 && row < n_row) ;
+	    newrow = InvRperm1 [row] - n1 ;
+	    ASSERT (newrow < n_row - n1) ;
+	    if (newrow >= 0)
+	    {
+		DEBUG5 (("  newrow "ID, newrow)) ;
+		Si [pp++] = newrow ;
+		if (do_nzdiag)
+		{
+		    /* count the number of truly nonzero entries on the
+		     * diagonal of S, excluding entries that are present,
+		     * but numerically zero */
+		    if (newrow == newcol)
+		    {
+			/* this is the diagonal entry */
+#ifdef COMPLEX
+		        if (split)
+			{
+			    if (SCALAR_IS_NONZERO (Ax [p]) ||
+				SCALAR_IS_NONZERO (Az [p]))
+			    {
+				nzdiag++ ;
+			    }
+			}
+			else
+			{
+			    if (SCALAR_IS_NONZERO (Ax [2*p  ]) ||
+				SCALAR_IS_NONZERO (Ax [2*p+1]))
+			    {
+				nzdiag++ ;
+			    }
+			}
+#else
+			if (SCALAR_IS_NONZERO (Ax [p]))
+			{
+			    nzdiag++ ;
+			}
+#endif
+		    }
+		}
+	    }
+	    DEBUG5 (("\n")) ;
+	}
+    }
+    Sp [n_col - n1] = pp ;
+
+    return (nzdiag) ;
+}
+
+/* ========================================================================== */
+/* === combine_ordering ===================================================== */
+/* ========================================================================== */
+
+PRIVATE void combine_ordering
+(
+    Int n1,
+    Int nempty_col,
+    Int n_col,
+    Int Cperm_init [ ],	    /* output permutation */
+    Int Cperm1 [ ],	    /* singleton and empty column ordering */
+    Int Qinv [ ]	    /* Qinv from AMD or COLAMD */
+)
+{
+    Int k, oldcol, newcol, knew ;
+
+    /* combine the singleton ordering with Qinv */
+#ifndef NDEBUG
+    for (k = 0 ; k < n_col ; k++)
+    {
+	Cperm_init [k] = EMPTY ;
+    }
+#endif
+    for (k = 0 ; k < n1 ; k++)
+    {
+	DEBUG1 ((ID" Initial singleton: "ID"\n", k, Cperm1 [k])) ;
+	Cperm_init [k] = Cperm1 [k] ;
+    }
+    for (k = n1 ; k < n_col - nempty_col ; k++)
+    {
+	/* this is a non-singleton column */
+	oldcol = Cperm1 [k] ;	/* user's name for this column */
+	newcol = k - n1 ;	/* Qinv's name for this column */
+	knew = Qinv [newcol] ;	/* Qinv's ordering for this column */
+	knew += n1 ;		/* shift order, after singletons */
+	DEBUG1 ((" k "ID" oldcol "ID" newcol "ID" knew "ID"\n",
+	    k, oldcol, newcol, knew)) ;
+	ASSERT (knew >= 0 && knew < n_col - nempty_col) ;
+	ASSERT (Cperm_init [knew] == EMPTY) ;
+	Cperm_init [knew] = oldcol ;
+    }
+    for (k = n_col - nempty_col ; k < n_col ; k++)
+    {
+	Cperm_init [k] = Cperm1 [k] ;
+    }
+#ifndef NDEBUG
+    {
+	Int *W = (Int *) malloc ((n_col + 1) * sizeof (Int)) ;
+	ASSERT (UMF_is_permutation (Cperm_init, W, n_col, n_col)) ;
+	free (W) ;
+    }
+#endif
+
+}
+
+/* ========================================================================== */
+/* === UMFPACK_qsymbolic ==================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_qsymbolic
+(
+    Int n_row,
+    Int n_col,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    const Int Quser [ ],
+    void **SymbolicHandle,
+    const double Control [UMFPACK_CONTROL],
+    double User_Info [UMFPACK_INFO]
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    double knobs [COLAMD_KNOBS], flops, f, r, c, force_fixQ,
+	Info2 [UMFPACK_INFO], drow, dcol, dtail_usage, dlf, duf, dmax_usage,
+	dhead_usage, dlnz, dunz, dmaxfrsize, dClen, dClen_analyze, sym,
+	amd_Info [AMD_INFO], dClen_amd, dr, dc, cr, cc, cp,
+	amd_Control [AMD_CONTROL], stats [2], tol ;
+    double *Info ;
+    Int i, nz, j, newj, status, f1, f2, maxnrows, maxncols, nfr, col,
+	nchains, maxrows, maxcols, p, nb, nn, *Chain_start, *Chain_maxrows,
+	*Chain_maxcols, *Front_npivcol, *Ci, Clen, colamd_stats [COLAMD_STATS],
+	fpiv, n_inner, child, parent, *Link, row, *Front_parent,
+	analyze_compactions, k, chain, is_sym, *Si, *Sp, n2, do_UMF_analyze,
+	fpivcol, fallrows, fallcols, *InFront, *F1, snz, *Front_1strow, f1rows,
+	kk, *Cperm_init, *Rperm_init, newrow, *InvRperm1, *Front_leftmostdesc,
+	Clen_analyze, strategy, Clen_amd, fixQ, prefer_diagonal, nzdiag, nzaat,
+	*Wq, *Sdeg, *Fr_npivcol, nempty, *Fr_nrows, *Fr_ncols, *Fr_parent,
+	*Fr_cols, nempty_row, nempty_col, user_auto_strategy, fail, max_rdeg,
+	head_usage, tail_usage, lnz, unz, esize, *Esize, rdeg, *Cdeg, *Rdeg,
+	*Cperm1, *Rperm1, n1, oldcol, newcol, n1c, n1r, *Rperm_2by2, oldrow,
+	dense_row_threshold, tlen, aggressive, scale, *Rp, *Ri ;
+
+    SymbolicType *Symbolic ;
+    SWType SWspace, *SW ;
+
+#ifndef NDEBUG
+    UMF_dump_start ( ) ;
+    init_count = UMF_malloc_count ;
+    PRINTF ((
+"**** Debugging enabled (UMFPACK will be exceedingly slow!) *****************\n"
+	)) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get the amount of time used by the process so far */
+    /* ---------------------------------------------------------------------- */
+
+    umfpack_tic (stats) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get control settings and check input parameters */
+    /* ---------------------------------------------------------------------- */
+
+    drow = GET_CONTROL (UMFPACK_DENSE_ROW, UMFPACK_DEFAULT_DENSE_ROW) ;
+    dcol = GET_CONTROL (UMFPACK_DENSE_COL, UMFPACK_DEFAULT_DENSE_COL) ;
+    nb = GET_CONTROL (UMFPACK_BLOCK_SIZE, UMFPACK_DEFAULT_BLOCK_SIZE) ;
+    strategy = GET_CONTROL (UMFPACK_STRATEGY, UMFPACK_DEFAULT_STRATEGY) ;
+    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 (UF_long)) ;
+    Info [UMFPACK_SIZE_OF_POINTER] = (double) (sizeof (void *)) ;
+    Info [UMFPACK_SIZE_OF_ENTRY] = (double) (sizeof (Entry)) ;
+    Info [UMFPACK_SYMBOLIC_DEFRAG] = 0 ;
+
+    if (!Ai || !Ap || !SymbolicHandle)
+    {
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ;
+	return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    *SymbolicHandle = (void *) NULL ;
+
+    if (n_row <= 0 || n_col <= 0)	/* n_row, n_col must be > 0 */
+    {
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_n_nonpositive ;
+	return (UMFPACK_ERROR_n_nonpositive) ;
+    }
+
+    nz = Ap [n_col] ;
+    DEBUG0 (("n_row "ID" n_col "ID" nz "ID"\n", n_row, n_col, nz)) ;
+    Info [UMFPACK_NZ] = nz ;
+    if (nz < 0)
+    {
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_matrix ;
+	return (UMFPACK_ERROR_invalid_matrix) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get the requested strategy */
+    /* ---------------------------------------------------------------------- */
+
+    if (n_row != n_col)
+    {
+	/* if the matrix is rectangular, the only available strategy is
+	 *  unsymmetric */
+	strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+	DEBUGm3 (("Rectangular: forcing unsymmetric strategy\n")) ;
+    }
+
+    if (strategy < UMFPACK_STRATEGY_AUTO
+     || strategy > UMFPACK_STRATEGY_SYMMETRIC)
+    {
+	/* unrecognized strategy */
+	strategy = UMFPACK_STRATEGY_AUTO ;
+    }
+
+    if (Quser != (Int *) NULL)
+    {
+	/* when the user provides Q, only symmetric and unsymmetric strategies
+	 * are available */
+	if (strategy == UMFPACK_STRATEGY_2BY2)
+	{
+	    strategy = UMFPACK_STRATEGY_SYMMETRIC ;
+	}
+	if (strategy != UMFPACK_STRATEGY_SYMMETRIC)
+	{
+	    strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+	}
+    }
+
+    user_auto_strategy = (strategy == UMFPACK_STRATEGY_AUTO) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* determine amount of memory required for UMFPACK_symbolic */
+    /* ---------------------------------------------------------------------- */
+
+    /* The size of Clen required for UMF_colamd is always larger than */
+    /* UMF_analyze, but the max is included here in case that changes in */
+    /* future versions. */
+
+    /* This is about 2.2*nz + 9*n_col + 6*n_row, or nz/5 + 13*n_col + 6*n_row,
+     * whichever is bigger.  For square matrices, it works out to
+     * 2.2nz + 15n, or nz/5 + 19n, whichever is bigger (typically 2.2nz+15n). */
+    dClen = UMF_COLAMD_RECOMMENDED ((double) nz, (double) n_row,
+	(double) n_col) ;
+
+    /* This is defined above, as max (nz,n_col) + 3*nn+1 + 2*n_col, where
+     * nn = max (n_row,n_col).  It is always smaller than the space required
+     * for colamd or amd. */
+    dClen_analyze = UMF_ANALYZE_CLEN ((double) nz, (double) n_row,
+	(double) n_col, (double) nn) ;
+    dClen = MAX (dClen, dClen_analyze) ;
+
+    /* The space for AMD can be larger than what's required for colamd: */
+    dClen_amd = 2.4 * (double) nz + 8 * (double) n_inner ;
+    /* additional space for the 2-by-2 strategy */
+    dClen_amd += (double) MAX (nn, nz) ;
+    dClen = MAX (dClen, dClen_amd) ;
+
+    /* worst case total memory usage for UMFPACK_symbolic (revised below) */
+    Info [UMFPACK_SYMBOLIC_PEAK_MEMORY] =
+	SYM_WORK_USAGE (n_col, n_row, dClen) +
+	UMF_symbolic_usage (n_row, n_col, n_col, n_col, n_col, TRUE) ;
+
+    if (INT_OVERFLOW (dClen * sizeof (Int)))
+    {
+	/* :: int overflow, Clen too large :: */
+	/* Problem is too large for array indexing (Ci [i]) with an Int i. */
+	/* Cannot even analyze the problem to determine upper bounds on */
+	/* memory usage. Need to use the UF_long version, umfpack_*l_*. */
+	DEBUGm4 (("out of memory: symbolic int overflow\n")) ;
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+	return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+    /* repeat the size calculations, in integers */
+    Clen = UMF_COLAMD_RECOMMENDED (nz, n_row, n_col) ;
+    Clen_analyze = UMF_ANALYZE_CLEN (nz, n_row, n_col, nn) ;
+    Clen = MAX (Clen, Clen_analyze) ;
+    Clen_amd = 2.4 * nz + 8 * n_inner ;
+    Clen_amd += MAX (nn, nz) ;			/* for Ri, in UMF_2by2 */
+    Clen = MAX (Clen, Clen_amd) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the first part of the Symbolic object (header and Cperm_init) */
+    /* ---------------------------------------------------------------------- */
+
+    /* (1) Five calls to UMF_malloc are made, for a total space of
+     * 2 * (n_row + n_col) + 4 integers + sizeof (SymbolicType).
+     * sizeof (SymbolicType) is a small constant.  This space is part of the
+     * Symbolic object and is not freed unless an error occurs.  If A is square
+     * then this is about 4*n integers.
+     */
+
+    Symbolic = (SymbolicType *) UMF_malloc (1, sizeof (SymbolicType)) ;
+
+    if (!Symbolic)
+    {
+	/* If we fail here, Symbolic is NULL and thus it won't be */
+	/* dereferenced by UMFPACK_free_symbolic, as called by error ( ). */
+	DEBUGm4 (("out of memory: symbolic object\n")) ;
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+	error (&Symbolic, (SWType *) NULL) ;
+	return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+    /* We now know that Symbolic has been allocated */
+    Symbolic->valid = 0 ;
+    Symbolic->Chain_start = (Int *) NULL ;
+    Symbolic->Chain_maxrows = (Int *) NULL ;
+    Symbolic->Chain_maxcols = (Int *) NULL ;
+    Symbolic->Front_npivcol = (Int *) NULL ;
+    Symbolic->Front_parent = (Int *) NULL ;
+    Symbolic->Front_1strow = (Int *) NULL ;
+    Symbolic->Front_leftmostdesc = (Int *) NULL ;
+    Symbolic->Esize = (Int *) NULL ;
+    Symbolic->esize = 0 ;
+
+    Symbolic->Cperm_init   = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+    Symbolic->Rperm_init   = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+    Symbolic->Cdeg	   = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+    Symbolic->Rdeg	   = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+    Symbolic->Diagonal_map = (Int *) NULL ;
+
+    Cperm_init = Symbolic->Cperm_init ;
+    Rperm_init = Symbolic->Rperm_init ;
+    Cdeg = Symbolic->Cdeg ;
+    Rdeg = Symbolic->Rdeg ;
+
+    if (!Cperm_init || !Rperm_init || !Cdeg || !Rdeg)
+    {
+	DEBUGm4 (("out of memory: symbolic perm\n")) ;
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+	error (&Symbolic, (SWType *) NULL) ;
+	return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+    Symbolic->n_row = n_row ;
+    Symbolic->n_col = n_col ;
+    Symbolic->nz = nz ;
+    Symbolic->nb = nb ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check user's input permutation */
+    /* ---------------------------------------------------------------------- */
+
+    if (Quser != (Int *) NULL)
+    {
+	/* use Cperm_init as workspace to check input permutation */
+	if (!UMF_is_permutation (Quser, Cperm_init, n_col, n_col))
+	{
+	    Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_permutation ;
+	    error (&Symbolic, (SWType *) NULL) ;
+	    return (UMFPACK_ERROR_invalid_permutation) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* (2) Eleven calls to UMF_malloc are made, for workspace of size
+     * Clen + nz + 7*n_col + 2*n_row + 2 integers.  Clen is the larger of
+     *     MAX (2*nz, 4*n_col) + 8*n_col + 6*n_row + n_col + nz/5 and
+     *     2.4*nz + 8 * MIN (n_row, n_col) + MAX (n_row, n_col, nz)
+     * If A is square and non-singular, then Clen is
+     *     MAX (MAX (2*nz, 4*n) + 7*n + nz/5,  3.4*nz) + 8*n
+     * If A has at least 4*n nonzeros then Clen is
+     *     MAX (2.2*nz + 7*n,  3.4*nz) + 8*n
+     * If A has at least (7/1.2)*n nonzeros, (about 5.8*n), then Clen is
+     *     3.4*nz + 8*n
+     * This space will be free'd when this routine finishes.
+     *
+     * Total space thus far is about 3.4nz + 12n integers.
+     * For the double precision, 32-bit integer version, the user's matrix
+     * requires an equivalent space of 3*nz + n integers.  So this space is just
+     * slightly larger than the user's input matrix (including the numerical
+     * values themselves).
+     */
+
+    SW = &SWspace ;	/* used for UMFPACK_symbolic only */
+
+    /* Note that SW->Front_* does not include the dummy placeholder front. */
+    /* This space is accounted for by the SYM_WORK_USAGE macro. */
+
+    /* this is free'd early */
+    SW->Si	      = (Int *) UMF_malloc (nz, sizeof (Int)) ;
+    SW->Sp	      = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ;
+    SW->InvRperm1     = (Int *) UMF_malloc (n_row, sizeof (Int)) ;
+    SW->Cperm1	      = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+
+    /* this is free'd late */
+    SW->Ci	      = (Int *) UMF_malloc (Clen, sizeof (Int)) ;
+    SW->Front_npivcol = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ;
+    SW->Front_nrows   = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+    SW->Front_ncols   = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+    SW->Front_parent  = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+    SW->Front_cols    = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+    SW->Rperm1	      = (Int *) UMF_malloc (n_row, sizeof (Int)) ;
+    SW->InFront	      = (Int *) UMF_malloc (n_row, sizeof (Int)) ;
+
+    /* this is allocated later, and free'd after Cperm1 but before Ci */
+    SW->Rperm_2by2    = (Int *) NULL ;   /* will be nn Int's */
+
+    /* this is allocated last, and free'd first */
+    SW->Rs	      = (double *) NULL ;	/* will be n_row double's */
+
+    Ci	       = SW->Ci ;
+    Fr_npivcol = SW->Front_npivcol ;
+    Fr_nrows   = SW->Front_nrows ;
+    Fr_ncols   = SW->Front_ncols ;
+    Fr_parent  = SW->Front_parent ;
+    Fr_cols    = SW->Front_cols ;
+    Cperm1     = SW->Cperm1 ;
+    Rperm1     = SW->Rperm1 ;
+    Si	       = SW->Si ;
+    Sp	       = SW->Sp ;
+    InvRperm1  = SW->InvRperm1 ;
+    Rperm_2by2 = (Int *) NULL ;
+    InFront    = SW->InFront ;
+
+    if (!Ci || !Fr_npivcol || !Fr_nrows || !Fr_ncols || !Fr_parent || !Fr_cols
+	|| !Cperm1 || !Rperm1 || !Si || !Sp || !InvRperm1 || !InFront)
+    {
+	DEBUGm4 (("out of memory: symbolic work\n")) ;
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+	error (&Symbolic, SW) ;
+	return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+    DEBUG0 (("Symbolic UMF_malloc_count - init_count = "ID"\n",
+	UMF_malloc_count - init_count)) ;
+    ASSERT (UMF_malloc_count == init_count + 17) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* find the row and column singletons */
+    /* ---------------------------------------------------------------------- */
+
+    /* [ use first nz + n_row + MAX (n_row, n_col) entries in Ci as workspace,
+     * and use Rperm_init as workspace */
+    ASSERT (Clen >= nz + n_row + MAX (n_row, n_col)) ;
+
+    status = UMF_singletons (n_row, n_col, Ap, Ai, Quser, strategy,
+	Cdeg, Cperm1, Rdeg,
+	Rperm1, InvRperm1, &n1, &n1c, &n1r, &nempty_col, &nempty_row, &is_sym,
+	&max_rdeg, /* workspace: */ Rperm_init, Ci, Ci + nz, Ci + nz + n_row) ;
+
+    /* ] done using Rperm_init and Ci as workspace */
+
+    /* InvRperm1 is now the inverse of Rperm1 */
+
+    if (status != UMFPACK_OK)
+    {
+	DEBUGm4 (("matrix invalid: UMF_singletons\n")) ;
+	Info [UMFPACK_STATUS] = status ;
+	error (&Symbolic, SW) ;
+	return (status) ;
+    }
+    Info [UMFPACK_NEMPTY_COL] = nempty_col ;
+    Info [UMFPACK_NEMPTY_ROW] = nempty_row ;
+    Info [UMFPACK_NDENSE_COL] = 0 ;	/* # dense rows/cols recomputed below */
+    Info [UMFPACK_NDENSE_ROW] = 0 ;
+    Info [UMFPACK_COL_SINGLETONS] = n1c ;
+    Info [UMFPACK_ROW_SINGLETONS] = n1r ;
+    Info [UMFPACK_S_SYMMETRIC] = is_sym ;
+
+    nempty = MIN (nempty_col, nempty_row) ;
+    Symbolic->nempty_row = nempty_row ;
+    Symbolic->nempty_col = nempty_col ;
+
+    /* UMF_singletons has verified that the user's input matrix is valid */
+    ASSERT (AMD_valid (n_row, n_col, Ap, Ai) == AMD_OK) ;
+
+    Symbolic->n1 = n1 ;
+    Symbolic->nempty = nempty ;
+    ASSERT (n1 <= n_inner) ;
+    n2 = nn - n1 - nempty ;
+
+    dense_row_threshold =
+	UMFPACK_DENSE_DEGREE_THRESHOLD (drow, n_col - n1 - nempty_col) ;
+    Symbolic->dense_row_threshold = dense_row_threshold ;
+
+    if (!is_sym)
+    {
+	/* either the pruned submatrix rectangular, or it is square and
+	 * Rperm [n1 .. n-nempty-1] is not the same as Cperm [n1 .. n-nempty-1].
+	 * Switch to the unsymmetric strategy, ignoring user-requested
+	 * strategy. */
+	strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+	DEBUGm4 (("Strategy: Unsymmetric singletons\n")) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* determine symmetry, nzdiag, and degrees of S+S' */
+    /* ---------------------------------------------------------------------- */
+
+    /* S is the matrix obtained after removing singletons
+     *   = A (Cperm1 [n1..n_col-nempty_col-1], Rperm1 [n1..n_row-nempty_row-1])
+     */
+
+    Wq = Rperm_init ;	    /* use Rperm_init as workspace for Wq [ */
+    Sdeg = Cperm_init ;	    /* use Cperm_init as workspace for Sdeg [ */
+    sym = EMPTY ;
+    nzaat = EMPTY ;
+    nzdiag = EMPTY ;
+    for (i = 0 ; i < AMD_INFO ; i++)
+    {
+	amd_Info [i] = EMPTY ;
+    }
+
+    if (strategy != UMFPACK_STRATEGY_UNSYMMETRIC)
+    {
+	/* This also determines the degree of each node in S+S' (Sdeg), which
+	 * is needed by the 2-by-2 strategy, the symmetry of S, and the number
+	 * of nonzeros on the diagonal of S. */
+	ASSERT (n_row == n_col) ;
+	ASSERT (nempty_row == nempty_col) ;
+
+	/* get the count of nonzeros on the diagonal of S, excluding explicitly
+	 * zero entries.  nzdiag = amd_Info [AMD_NZDIAG] counts the zero entries
+	 * in S. */
+
+	nzdiag = prune_singletons (n1, nn, Ap, Ai, Ax,
+#ifdef COMPLEX
+	    Az,
+#endif
+	    Cperm1, InvRperm1, Si, Sp
+#ifndef NDEBUG
+	    , Rperm1, nn
+#endif
+	    ) ;
+
+	/* use Ci as workspace to sort S into R, if needed [ */
+	if (Quser != (Int *) NULL)
+	{
+	    /* need to sort the columns of S first */
+	    Rp = Ci ;
+	    Ri = Ci + (n_row) + 1 ;
+	    (void) UMF_transpose (n2, n2, Sp, Si, (double *) NULL,
+		(Int *) NULL, (Int *) NULL, 0,
+		Rp, Ri, (double *) NULL, Wq, FALSE
+#ifdef COMPLEX
+		, (double *) NULL, (double *) NULL, FALSE
+#endif
+		) ;
+	}
+	else
+	{
+	    /* S already has sorted columns */
+	    Rp = Sp ;
+	    Ri = Si ;
+	}
+	ASSERT (AMD_valid (n2, n2, Rp, Ri) == AMD_OK) ;
+
+	nzaat = AMD_aat (n2, Rp, Ri, Sdeg, Wq, amd_Info) ;
+	sym = amd_Info [AMD_SYMMETRY] ;
+	Info [UMFPACK_N2] = n2 ;
+	/* nzdiag = amd_Info [AMD_NZDIAG] counts the zero entries of S too */
+
+	/* done using Ci as workspace to sort S into R ] */
+
+#ifndef NDEBUG
+	for (k = 0 ; k < n2 ; k++)
+	{
+	    ASSERT (Sdeg [k] >= 0 && Sdeg [k] < n2) ;
+	}
+	ASSERT (Sp [n2] - n2 <= nzaat && nzaat <= 2 * Sp [n2]) ;
+	DEBUG0 (("Explicit zeros: "ID" %g\n", nzdiag, amd_Info [AMD_NZDIAG])) ;
+#endif
+
+    }
+
+    /* get statistics from amd_aat, if computed */
+    Symbolic->sym = sym ;
+    Symbolic->nzaat = nzaat ;
+    Symbolic->nzdiag = nzdiag ;
+    Symbolic->amd_dmax = EMPTY ;
+
+    Info [UMFPACK_PATTERN_SYMMETRY] = sym ;
+    Info [UMFPACK_NZ_A_PLUS_AT] = nzaat ;
+    Info [UMFPACK_NZDIAG] = nzdiag ;
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the initial strategy based on symmetry and nnz (diag (S)) */
+    /* ---------------------------------------------------------------------- */
+
+    if (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)
+    {
+	double sym2 ;
+	Int *Blen, *W, nz_papat, nzd2, nweak, unmatched, Clen3 ;
+
+	/* ------------------------------------------------------------------ */
+	/* get workspace for UMF_2by2 */
+	/* ------------------------------------------------------------------ */
+
+	ASSERT (n_row == n_col && nn == n_row) ;
+
+#ifndef NDEBUG
+	for (k = 0 ; k < n2 ; k++)
+	{
+	    ASSERT (Sdeg [k] >= 0 && Sdeg [k] < n2) ;
+	}
+#endif
+
+	/* allocate Rperm_2by2 */
+	SW->Rperm_2by2 = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+	Rperm_2by2 = SW->Rperm_2by2 ;
+	if (Rperm_2by2 == (Int *) NULL)
+	{
+	    DEBUGm4 (("out of memory: Rperm_2by2\n")) ;
+	    Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+	    error (&Symbolic, SW) ;
+	    return (UMFPACK_ERROR_out_of_memory) ;
+	}
+
+	/* allocate Ri from the tail end of Ci [ */
+	Clen3 = Clen - (MAX (nn, nz) + 1) ;
+	Ri = Ci + Clen3 ;
+	ASSERT (Clen3 >= nz) ;	/* space required for UMF_2by2 */
+
+	/* use Fr_* as workspace for Rp, Blen, and W [ */
+	Rp = Fr_npivcol ;
+	Blen = Fr_ncols ;
+	W = Fr_cols ;
+
+	if (scale != UMFPACK_SCALE_NONE)
+	{
+	    SW->Rs = (double *) UMF_malloc (nn, sizeof (double)) ;
+	    if (SW->Rs == (double *) NULL)
+	    {
+		DEBUGm4 (("out of memory: scale factors for 2-by-2\n")) ;
+		Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+		error (&Symbolic, SW) ;
+		return (UMFPACK_ERROR_out_of_memory) ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* find the 2-by-2 row permutation */
+	/* ------------------------------------------------------------------ */
+
+	/* find a row permutation Rperm_2by2 such that S (Rperm_2by2, :)
+	 * has a healthy diagonal */
+
+	UMF_2by2 (nn, Ap, Ai, Ax,
+#ifdef COMPLEX
+		Az,
+#endif
+		tol, scale, Cperm1,
+#ifndef NDEBUG
+		Rperm1,
+#endif
+		InvRperm1, n1, nempty, Sdeg, Rperm_2by2, &nweak, &unmatched,
+		Ri, Rp, SW->Rs, Blen, W, Ci, Wq) ;
+	DEBUGm3 (("2by2: nweak "ID" unmatched "ID"\n", nweak, unmatched)) ;
+	Info [UMFPACK_2BY2_NWEAK] = nweak ;
+	Info [UMFPACK_2BY2_UNMATCHED] = unmatched ;
+
+	SW->Rs = (double *) UMF_free ((void *) SW->Rs) ;
+
+	/* R = S (Rperm_2by2,:)' */
+	(void) UMF_transpose (n2, n2, Sp, Si, (double *) NULL, Rperm_2by2,
+	    (Int *) NULL, 0, Rp, Ri, (double *) NULL, W, FALSE
+#ifdef COMPLEX
+	    , (double *) NULL, (double *) NULL, FALSE
+#endif
+	    ) ;
+	ASSERT (AMD_valid (n2, n2, Rp, Ri) == AMD_OK) ;
+
+	/* contents of Si and Sp no longer needed, but the space is
+	 * still needed */
+
+	/* ------------------------------------------------------------------ */
+	/* find symmetry of S (Rperm_2by2, :)', and prepare to order with AMD */
+	/* ------------------------------------------------------------------ */
+
+	for (i = 0 ; i < AMD_INFO ; i++)
+	{
+	    amd_Info [i] = EMPTY ;
+	}
+	nz_papat = AMD_aat (n2, Rp, Ri, Sdeg, Wq, amd_Info) ;
+	sym2 = amd_Info [AMD_SYMMETRY] ;
+	nzd2 = amd_Info [AMD_NZDIAG] ;
+
+	Info [UMFPACK_2BY2_PATTERN_SYMMETRY] = sym2 ;
+	Info [UMFPACK_2BY2_NZ_PA_PLUS_PAT] = nz_papat ;
+	Info [UMFPACK_2BY2_NZDIAG] = nzd2 ;
+
+	DEBUG0 (("2by2: sym2 %g nzd2 "ID" n2 "ID"\n", sym2, nzd2, n2)) ;
+
+	/* ------------------------------------------------------------------ */
+	/* evaluate the 2-by-2 results */
+	/* ------------------------------------------------------------------ */
+
+	if (user_auto_strategy)
+	{
+	    if ((sym2 > 1.1 * sym) && (nzd2 > 0.9 * n2))
+	    {
+		/* 2-by-2 made it much more symmetric */
+		DEBUGm4 (("eval Strategy 2by2: much more symmetric:  2by2\n")) ;
+		strategy = UMFPACK_STRATEGY_2BY2 ;
+	    }
+	    else if (sym2 < 0.7 * sym)
+	    {
+		/* 2-by-2 made it much more unsymmetric */
+		DEBUGm4 (("eval Strategy 2by2: much more UNsymmetric:unsym\n"));
+		strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+	    }
+	    else if (sym2 < 0.25)
+	    {
+		DEBUGm4 (("eval Strategy 2by2: is UNsymmetric: unsym\n"));
+		strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+	    }
+	    else if (sym2 >= 0.51)
+	    {
+		DEBUGm4 (("eval Strategy 2by2: sym2 >= 0.51: 2by2\n")) ;
+		strategy = UMFPACK_STRATEGY_2BY2 ;
+	    }
+	    else if (sym2 >= 0.999 * sym)
+	    {
+		/* 2-by-2 improved symmetry, or made it only slightly worse */
+		DEBUGm4 (("eval Strategy 2by2: sym2 >= 0.999 sym: 2by2\n")) ;
+		strategy = UMFPACK_STRATEGY_2BY2 ;
+	    }
+	    else
+	    {
+		/* can't decide what to do, so pick the unsymmetric strategy */
+		DEBUGm4 (("eval Strategy 2by2: punt: unsym\n"));
+		strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* if the 2-by-2 strategy is selected: */
+	/* ------------------------------------------------------------------ */
+
+	if (strategy == UMFPACK_STRATEGY_2BY2)
+	{
+	    if (Quser == (Int *) NULL)
+	    {
+		/* 2-by-2 strategy is successful */
+		/* compute amd (S) */
+		Int *Qinv = Fr_npivcol ;
+		ASSERT (Clen3 >= (nz_papat + nz_papat/5 + nn) + 7*nn) ;
+		do_amd (n2, Rp, Ri, Wq, Qinv, Sdeg, Clen3, Ci,
+		    amd_Control, amd_Info, Symbolic, Info) ;
+		/* combine the singleton ordering and the AMD ordering */
+		combine_ordering (n1, nempty, nn, Cperm_init, Cperm1, Qinv) ;
+	    }
+	    /* fix Rperm_2by2 to reflect A, not S */
+	    for (k = 0 ; k < n1 ; k++)
+	    {
+		oldcol = Cperm1 [k] ;
+		i = k ;
+		oldrow = Rperm1 [k] ;
+		W [oldcol] = oldrow ;
+	    }
+	    for (k = n1 ; k < nn - nempty ; k++)
+	    {
+		oldcol = Cperm1 [k] ;
+		i = Rperm_2by2 [k - n1] + n1 ;
+		oldrow = Rperm1 [i] ;
+		W [oldcol] = oldrow ;
+	    }
+	    for (k = nn - nempty ; k < nn ; k++)
+	    {
+		oldcol = Cperm1 [k] ;
+		i = k ;
+		oldrow = Rperm1 [k] ;
+		W [oldcol] = oldrow ;
+	    }
+	    for (k = 0 ; k < nn ; k++)
+	    {
+		Rperm_2by2 [k] = W [k] ;
+	    }
+
+	    /* Now, the "diagonal" entry in oldcol (where oldcol is the user's
+	     * name for a column, is the entry in row oldrow (where oldrow is
+	     * the user's name for a row, and oldrow = Rperm_2by2 [oldcol] */
+	}
+
+	/* Fr_* no longer needed for Rp, Blen, W ] */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* 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)) ;
+	}
+    }
+#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 ;
+		CLEAR (aij) ;
+		oldrow = Ai [p] ;
+		newrow = Ci [oldrow] ;
+		if (Ax != (double *) NULL)
+		{
+		    ASSIGN (aij, Ax, Az, p, SPLIT (Az)) ;
+		}
+		if (oldrow == oldcol)
+		{
+		    DEBUG2 (("     old diagonal : oldcol "ID" oldrow "ID" ",
+			    oldcol, oldrow)) ;
+		    EDEBUG2 (aij) ;
+		    DEBUG2 (("\n")) ;
+		}
+		if (newrow == Diagonal_map [newcol])
+		{
+		    DEBUG2 (("     MAP diagonal : newcol "ID" MAProw "ID" ",
+			    newcol, Diagonal_map [newrow])) ;
+		    EDEBUG2 (aij) ;
+		    DEBUG2 (("\n")) ;
+		}
+	    }
+	}
+#endif
+	/* done using Ci as workspace ] */
+
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* find the leftmost descendant of each front */
+    /* ---------------------------------------------------------------------- */
+
+    for (i = 0 ; i <= nfr ; i++)
+    {
+	Front_leftmostdesc [i] = EMPTY ;
+    }
+
+    for (i = 0 ; i < nfr ; i++)
+    {
+	/* start at i and walk up the tree */
+	DEBUG2 (("Walk up front tree from "ID"\n", i)) ;
+	j = i ;
+	while (j != EMPTY && Front_leftmostdesc [j] == EMPTY)
+	{
+	    DEBUG3 (("  Leftmost desc of "ID" is "ID"\n", j, i)) ;
+	    Front_leftmostdesc [j] = i ;
+	    j = Front_parent [j] ;
+	    DEBUG3 (("  go to j = "ID"\n", j)) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* find the frontal matrix chains and max frontal matrix sizes */
+    /* ---------------------------------------------------------------------- */
+
+    maxnrows = 1 ;		/* max # rows in any front */
+    maxncols = 1 ;		/* max # cols in any front */
+    dmaxfrsize = 1 ;		/* max frontal matrix size */
+
+    /* start the first chain */
+    nchains = 0 ;		/* number of chains */
+    Chain_start [0] = 0 ;	/* front 0 starts a new chain */
+    maxrows = 1 ;		/* max # rows for any front in current chain */
+    maxcols = 1 ;		/* max # cols for any front in current chain */
+    DEBUG1 (("Constructing chains:\n")) ;
+
+    for (i = 0 ; i < nfr ; i++)
+    {
+	/* get frontal matrix info */
+	fpivcol  = Front_npivcol [i] ;	    /* # candidate pivot columns */
+	fallrows = Fr_nrows [i] ;	    /* all rows (not just Schur comp) */
+	fallcols = Fr_ncols [i] ;	    /* all cols (not just Schur comp) */
+	parent = Front_parent [i] ;	    /* parent in column etree */
+	fpiv = MIN (fpivcol, fallrows) ;    /* # pivot rows and cols */
+	maxrows = MAX (maxrows, fallrows) ;
+	maxcols = MAX (maxcols, fallcols) ;
+
+	DEBUG1 (("Front: "ID", pivcol "ID", "ID"-by-"ID" parent "ID
+	    ", npiv "ID" Chain: maxrows "ID" maxcols "ID"\n", i, fpivcol,
+	    fallrows, fallcols, parent, fpiv, maxrows, maxcols)) ;
+
+	if (parent != i+1)
+	{
+	    /* this is the end of a chain */
+	    double s ;
+	    DEBUG1 (("\nEnd of chain "ID"\n", nchains)) ;
+
+	    /* make sure maxrows is an odd number */
+	    ASSERT (maxrows >= 0) ;
+	    if (maxrows % 2 == 0) maxrows++ ;
+
+	    DEBUG1 (("Chain maxrows "ID" maxcols "ID"\n", maxrows, maxcols)) ;
+
+	    Chain_maxrows [nchains] = maxrows ;
+	    Chain_maxcols [nchains] = maxcols ;
+
+	    /* keep track of the maximum front size for all chains */
+
+	    /* for Info only: */
+	    s = (double) maxrows * (double) maxcols ;
+	    dmaxfrsize = MAX (dmaxfrsize, s) ;
+
+	    /* for the subsequent numerical factorization */
+	    maxnrows = MAX (maxnrows, maxrows) ;
+	    maxncols = MAX (maxncols, maxcols) ;
+
+	    DEBUG1 (("Chain dmaxfrsize %g\n\n", dmaxfrsize)) ;
+
+	    /* start the next chain */
+	    nchains++ ;
+	    Chain_start [nchains] = i+1 ;
+	    maxrows = 1 ;
+	    maxcols = 1 ;
+	}
+    }
+
+    /* for Info only: */
+    dmaxfrsize = ceil (dmaxfrsize) ;
+    DEBUGm1 (("dmaxfrsize %30.20g Int_MAX "ID"\n", dmaxfrsize, Int_MAX)) ;
+    ASSERT (Symbolic->nchains == nchains) ;
+
+    /* For allocating objects in umfpack_numeric (does not include all possible
+     * pivots, particularly pivots from prior fronts in the chain.  Need to add
+     * nb to these to get the # of columns in the L block, for example.  This
+     * is the largest row dimension and largest column dimension of any frontal
+     * matrix.  maxnrows is always odd. */
+    Symbolic->maxnrows = maxnrows ;
+    Symbolic->maxncols = maxncols ;
+    DEBUGm3 (("maxnrows "ID" maxncols "ID"\n", maxnrows, maxncols)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* find the initial element sizes */
+    /* ---------------------------------------------------------------------- */
+
+    if (max_rdeg > dense_row_threshold)
+    {
+	/* there are one or more dense rows in the input matrix */
+	/* count the number of dense rows in each column */
+	/* use Ci as workspace for inverse of Rperm_init [ */
+	ASSERT (Esize != (Int *) NULL) ;
+	for (newrow = 0 ; newrow < n_row ; newrow++)
+	{
+	    oldrow = Rperm_init [newrow] ;
+	    ASSERT (oldrow >= 0 && oldrow < nn) ;
+	    Ci [oldrow] = newrow ;
+	}
+	for (col = n1 ; col < n_col - nempty_col ; col++)
+	{
+	    oldcol = Cperm_init [col] ;
+	    esize = Cdeg [oldcol] ;
+	    ASSERT (esize > 0) ;
+	    for (p = Ap [oldcol] ; p < Ap [oldcol+1] ; p++)
+	    {
+		oldrow = Ai [p] ;
+		newrow = Ci [oldrow] ;
+		if (newrow >= n1 && Rdeg [oldrow] > dense_row_threshold)
+		{
+		    esize-- ;
+		}
+	    }
+	    ASSERT (esize >= 0) ;
+	    Esize [col - n1] = esize ;
+	}
+	/* done using Ci as workspace ] */
+    }
+
+    /* If there are no dense rows, then Esize [col-n1] is identical to
+     * Cdeg [col], once Cdeg is permuted below */
+
+    /* ---------------------------------------------------------------------- */
+    /* permute Cdeg and Rdeg according to initial column and row permutation */
+    /* ---------------------------------------------------------------------- */
+
+    /* use Ci as workspace [ */
+    for (k = 0 ; k < n_col ; k++)
+    {
+	Ci [k] = Cdeg [Cperm_init [k]] ;
+    }
+    for (k = 0 ; k < n_col ; k++)
+    {
+	Cdeg [k] = Ci [k] ;
+    }
+    for (k = 0 ; k < n_row ; k++)
+    {
+	Ci [k] = Rdeg [Rperm_init [k]] ;
+    }
+    for (k = 0 ; k < n_row ; k++)
+    {
+	Rdeg [k] = Ci [k] ;
+    }
+    /* done using Ci as workspace ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* simulate UMF_kernel_init */
+    /* ---------------------------------------------------------------------- */
+
+    /* count elements and tuples at tail, LU factors of singletons, and
+     * head and tail markers */
+
+    dlnz = n_inner ;	/* upper limit of nz in L (incl diag) */
+    dunz = dlnz ;	/* upper limit of nz in U (incl diag) */
+
+    /* head marker */
+    head_usage  = 1 ;
+    dhead_usage = 1 ;
+
+    /* tail markers: */
+    tail_usage  = 2 ;
+    dtail_usage = 2 ;
+
+    /* allocate the Rpi and Rpx workspace for UMF_kernel_init (incl. headers) */
+    tail_usage  +=  UNITS (Int *, n_row+1) +  UNITS (Entry *, n_row+1) + 2 ;
+    dtail_usage += DUNITS (Int *, n_row+1) + DUNITS (Entry *, n_row+1) + 2 ;
+    DEBUG1 (("Symbolic usage after Rpi/Rpx allocation: head "ID" tail "ID"\n",
+	head_usage, tail_usage)) ;
+
+    /* LU factors for singletons, at the head of memory */
+    for (k = 0 ; k < n1 ; k++)
+    {
+	lnz = Cdeg [k] - 1 ;
+	unz = Rdeg [k] - 1 ;
+	dlnz += lnz ;
+	dunz += unz ;
+	DEBUG1 (("singleton k "ID" pivrow "ID" pivcol "ID" lnz "ID" unz "ID"\n",
+	    k, Rperm_init [k], Cperm_init [k], lnz, unz)) ;
+	head_usage  +=  UNITS (Int, lnz) +  UNITS (Entry, lnz)
+		    +   UNITS (Int, unz) +  UNITS (Entry, unz) ;
+	dhead_usage += DUNITS (Int, lnz) + DUNITS (Entry, lnz)
+		    +  DUNITS (Int, unz) + DUNITS (Entry, unz) ;
+    }
+    DEBUG1 (("Symbolic init head usage: "ID" for LU singletons\n",head_usage)) ;
+
+    /* column elements: */
+    for (k = n1 ; k < n_col - nempty_col; k++)
+    {
+	esize = Esize ? Esize [k-n1] : Cdeg [k] ;
+	DEBUG2 (("   esize: "ID"\n", esize)) ;
+	ASSERT (esize >= 0) ;
+	if (esize > 0)
+	{
+	    tail_usage  +=  GET_ELEMENT_SIZE (esize, 1) + 1 ;
+	    dtail_usage += DGET_ELEMENT_SIZE (esize, 1) + 1 ;
+	}
+    }
+
+    /* dense row elements */
+    if (Esize)
+    {
+	Int nrow_elements = 0 ;
+	for (k = n1 ; k < n_row - nempty_row ; k++)
+	{
+	    rdeg = Rdeg [k] ;
+	    if (rdeg > dense_row_threshold)
+	    {
+		tail_usage  += GET_ELEMENT_SIZE (1, rdeg) + 1 ;
+		dtail_usage += GET_ELEMENT_SIZE (1, rdeg) + 1 ;
+		nrow_elements++ ;
+	    }
+	}
+	Info [UMFPACK_NDENSE_ROW] = nrow_elements ;
+    }
+
+    DEBUG1 (("Symbolic usage: "ID" = head "ID" + tail "ID" after els\n",
+	head_usage + tail_usage, head_usage, tail_usage)) ;
+
+    /* compute the tuple lengths */
+    if (Esize)
+    {
+	/* row tuples */
+	for (row = n1 ; row < n_row ; row++)
+	{
+	    rdeg = Rdeg [row] ;
+	    tlen = (rdeg > dense_row_threshold) ? 1 : rdeg ;
+	    tail_usage  += 1 +  UNITS (Tuple, TUPLES (tlen)) ;
+	    dtail_usage += 1 + DUNITS (Tuple, TUPLES (tlen)) ;
+	}
+	/* column tuples */
+	for (col = n1 ; col < n_col - nempty_col ; col++)
+	{
+	    /* tlen is 1 plus the number of dense rows in this column */
+	    esize = Esize [col - n1] ;
+	    tlen = (esize > 0) + (Cdeg [col] - esize) ;
+	    tail_usage  += 1 +  UNITS (Tuple, TUPLES (tlen)) ;
+	    dtail_usage += 1 + DUNITS (Tuple, TUPLES (tlen)) ;
+	}
+	for ( ; col < n_col ; col++)
+	{
+	    tail_usage  += 1 +  UNITS (Tuple, TUPLES (0)) ;
+	    dtail_usage += 1 + DUNITS (Tuple, TUPLES (0)) ;
+	}
+    }
+    else
+    {
+	/* row tuples */
+	for (row = n1 ; row < n_row ; row++)
+	{
+	    tlen = Rdeg [row] ;
+	    tail_usage  += 1 +  UNITS (Tuple, TUPLES (tlen)) ;
+	    dtail_usage += 1 + DUNITS (Tuple, TUPLES (tlen)) ;
+	}
+	/* column tuples */
+	for (col = n1 ; col < n_col ; col++)
+	{
+	    tail_usage  += 1 +  UNITS (Tuple, TUPLES (1)) ;
+	    dtail_usage += 1 + DUNITS (Tuple, TUPLES (1)) ;
+	}
+    }
+
+    Symbolic->num_mem_init_usage = head_usage + tail_usage ;
+    DEBUG1 (("Symbolic usage: "ID" = head "ID" + tail "ID" final\n",
+	Symbolic->num_mem_init_usage, head_usage, tail_usage)) ;
+
+    ASSERT (UMF_is_permutation (Rperm_init, Ci, n_row, n_row)) ;
+
+    /* initial head and tail usage in Numeric->Memory */
+    dmax_usage = dhead_usage + dtail_usage ;
+    dmax_usage = MAX (Symbolic->num_mem_init_usage, ceil (dmax_usage)) ;
+    Info [UMFPACK_VARIABLE_INIT_ESTIMATE] = dmax_usage ;
+
+    /* In case Symbolic->num_mem_init_usage overflows, keep as a double, too */
+    Symbolic->dnum_mem_init_usage = dmax_usage ;
+
+    /* free the Rpi and Rpx workspace */
+    tail_usage  -=  UNITS (Int *, n_row+1) +  UNITS (Entry *, n_row+1) ;
+    dtail_usage -= DUNITS (Int *, n_row+1) + DUNITS (Entry *, n_row+1) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* simulate UMF_kernel, assuming unsymmetric pivoting */
+    /* ---------------------------------------------------------------------- */
+
+    /* Use Ci as temporary workspace for link lists [ */
+    Link = Ci ;
+    for (i = 0 ; i < nfr ; i++)
+    {
+	Link [i] = EMPTY ;
+    }
+
+    flops = 0 ;			/* flop count upper bound */
+
+    for (chain = 0 ; chain < nchains ; chain++)
+    {
+	double fsize ;
+	f1 = Chain_start [chain] ;
+	f2 = Chain_start [chain+1] - 1 ;
+
+	/* allocate frontal matrix working array (C, L, and U) */
+	dr = Chain_maxrows [chain] ;
+	dc = Chain_maxcols [chain] ;
+	fsize =
+	      nb*nb	    /* LU is nb-by-nb */
+	    + dr*nb	    /* L is dr-by-nb */
+	    + nb*dc	    /* U is nb-by-dc, stored by rows */
+	    + dr*dc ;	    /* C is dr by dc */
+	dtail_usage += DUNITS (Entry, fsize) ;
+	dmax_usage = MAX (dmax_usage, dhead_usage + dtail_usage) ;
+
+	for (i = f1 ; i <= f2 ; i++)
+	{
+
+	    /* get frontal matrix info */
+	    fpivcol  = Front_npivcol [i] ; /* # candidate pivot columns */
+	    fallrows = Fr_nrows [i] ;   /* all rows (not just Schur comp*/
+	    fallcols = Fr_ncols [i] ;   /* all cols (not just Schur comp*/
+	    parent = Front_parent [i] ; /* parent in column etree */
+	    fpiv = MIN (fpivcol, fallrows) ;	/* # pivot rows and cols */
+	    f = (double) fpiv ;
+	    r = fallrows - fpiv ;		/* # rows in Schur comp. */
+	    c = fallcols - fpiv ;		/* # cols in Schur comp. */
+
+	    /* assemble all children of front i in column etree */
+	    for (child = Link [i] ; child != EMPTY ; child = Link [child])
+	    {
+		ASSERT (child >= 0 && child < i) ;
+		ASSERT (Front_parent [child] == i) ;
+		/* free the child element and remove it from tuple lists */
+		cp = MIN (Front_npivcol [child], Fr_nrows [child]) ;
+		cr = Fr_nrows [child] - cp ;
+		cc = Fr_ncols [child] - cp ;
+		ASSERT (cp >= 0 && cr >= 0 && cc >= 0) ;
+		dtail_usage -= ELEMENT_SIZE (cr, cc) ;
+
+	    }
+
+	    /* The flop count computed here is "canonical". */
+
+	    /* factorize the frontal matrix */
+	    flops += DIV_FLOPS * (f*r + (f-1)*f/2)  /* scale pivot columns */
+		/* f outer products: */
+		+ MULTSUB_FLOPS * (f*r*c + (r+c)*(f-1)*f/2 + (f-1)*f*(2*f-1)/6);
+
+	    /* count nonzeros and memory usage in double precision */
+	    dlf = (f*f-f)/2 + f*r ;		/* nz in L below diagonal */
+	    duf = (f*f-f)/2 + f*c ;		/* nz in U above diagonal */
+	    dlnz += dlf ;
+	    dunz += duf ;
+
+	    /* store f columns of L and f rows of U */
+	    dhead_usage +=
+		DUNITS (Entry, dlf + duf)   /* numerical values (excl diag) */
+		+ DUNITS (Int, r + c + f) ; /* indices (compressed) */
+
+	    if (parent != EMPTY)
+	    {
+		/* create new element and place in tuple lists */
+		dtail_usage += ELEMENT_SIZE (r, c) ;
+
+		/* place in link list of parent */
+		Link [i] = Link [parent] ;
+		Link [parent] = i ;
+	    }
+
+	    /* keep track of peak Numeric->Memory usage */
+	    dmax_usage = MAX (dmax_usage, dhead_usage + dtail_usage) ;
+
+	}
+
+	/* free the current frontal matrix */
+	dtail_usage -= DUNITS (Entry, fsize) ;
+    }
+
+    dhead_usage = ceil (dhead_usage) ;
+    dmax_usage = ceil (dmax_usage) ;
+    Symbolic->num_mem_size_est = dhead_usage ;
+    Symbolic->num_mem_usage_est = dmax_usage ;
+    Symbolic->lunz_bound = dlnz + dunz - n_inner ;
+
+    /* ] done using Ci as workspace for Link array */
+
+    /* ---------------------------------------------------------------------- */
+    /* estimate total memory usage in UMFPACK_numeric */
+    /* ---------------------------------------------------------------------- */
+
+    UMF_set_stats (
+	Info,
+	Symbolic,
+	dmax_usage,		/* estimated peak size of Numeric->Memory */
+	dhead_usage,		/* estimated final size of Numeric->Memory */
+	flops,			/* estimated "true flops" */
+	dlnz,			/* estimated nz in L */
+	dunz,			/* estimated nz in U */
+	dmaxfrsize,		/* estimated largest front size */
+	(double) n_col,		/* worst case Numeric->Upattern size */
+	(double) n_inner,	/* max possible pivots to be found */
+	(double) maxnrows,	/* estimated largest #rows in front */
+	(double) maxncols,	/* estimated largest #cols in front */
+	TRUE,			/* assume scaling is to be performed */
+	prefer_diagonal,
+	ESTIMATE) ;
+
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    for (i = 0 ; i < nchains ; i++)
+    {
+	DEBUG2 (("Chain "ID" start "ID" end "ID" maxrows "ID" maxcols "ID"\n",
+		i, Chain_start [i], Chain_start [i+1] - 1,
+		Chain_maxrows [i], Chain_maxcols [i])) ;
+	UMF_dump_chain (Chain_start [i], Fr_parent, Fr_npivcol, Fr_nrows,
+	    Fr_ncols, nfr) ;
+    }
+    fpivcol = 0 ;
+    for (i = 0 ; i < nfr ; i++)
+    {
+	fpivcol = MAX (fpivcol, Front_npivcol [i]) ;
+    }
+    DEBUG0 (("Max pivot cols in any front: "ID"\n", fpivcol)) ;
+    DEBUG1 (("Largest front: maxnrows "ID" maxncols "ID" dmaxfrsize %g\n",
+	maxnrows, maxncols, dmaxfrsize)) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* UMFPACK_symbolic was successful, return the object handle */
+    /* ---------------------------------------------------------------------- */
+
+    Symbolic->valid = SYMBOLIC_VALID ;
+    *SymbolicHandle = (void *) Symbolic ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* (6) The last of the workspace is free'd.  The final Symbolic object
+     * consists of 12 to 14 allocated objects.  Its final total size is lies
+     * roughly between 4*n and 13*n for a square matrix, which is all that is
+     * left of the memory allocated by this routine.  If an error occurs, the
+     * entire Symbolic object is free'd when this routine returns (the error
+     * return routine, below).
+     */
+
+    free_work (SW) ;
+
+    DEBUG0 (("(3)Symbolic UMF_malloc_count - init_count = "ID"\n",
+	UMF_malloc_count - init_count)) ;
+    ASSERT (UMF_malloc_count == init_count + 12
+	+ (Symbolic->Esize != (Int *) NULL)
+	+ (Symbolic->Diagonal_map != (Int *) NULL)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get the time used by UMFPACK_*symbolic */
+    /* ---------------------------------------------------------------------- */
+
+    umfpack_toc (stats) ;
+    Info [UMFPACK_SYMBOLIC_WALLTIME] = stats [0] ;
+    Info [UMFPACK_SYMBOLIC_TIME] = stats [1] ;
+
+    return (UMFPACK_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === free_work ============================================================ */
+/* ========================================================================== */
+
+PRIVATE void free_work
+(
+    SWType *SW
+)
+{
+    if (SW)
+    {
+	SW->Rperm_2by2 = (Int *) UMF_free ((void *) SW->Rperm_2by2) ;
+	SW->InvRperm1 = (Int *) UMF_free ((void *) SW->InvRperm1) ;
+	SW->Rs = (double *) UMF_free ((void *) SW->Rs) ;
+	SW->Si = (Int *) UMF_free ((void *) SW->Si) ;
+	SW->Sp = (Int *) UMF_free ((void *) SW->Sp) ;
+	SW->Ci = (Int *) UMF_free ((void *) SW->Ci) ;
+	SW->Front_npivcol = (Int *) UMF_free ((void *) SW->Front_npivcol);
+	SW->Front_nrows = (Int *) UMF_free ((void *) SW->Front_nrows) ;
+	SW->Front_ncols = (Int *) UMF_free ((void *) SW->Front_ncols) ;
+	SW->Front_parent = (Int *) UMF_free ((void *) SW->Front_parent) ;
+	SW->Front_cols = (Int *) UMF_free ((void *) SW->Front_cols) ;
+	SW->Cperm1 = (Int *) UMF_free ((void *) SW->Cperm1) ;
+	SW->Rperm1 = (Int *) UMF_free ((void *) SW->Rperm1) ;
+	SW->InFront = (Int *) UMF_free ((void *) SW->InFront) ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === error ================================================================ */
+/* ========================================================================== */
+
+/* Error return from UMFPACK_symbolic.  Free all allocated memory. */
+
+PRIVATE void error
+(
+    SymbolicType **Symbolic,
+    SWType *SW
+)
+{
+
+    free_work (SW) ;
+    UMFPACK_free_symbolic ((void **) Symbolic) ;
+    ASSERT (UMF_malloc_count == init_count) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_control.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_control.c
new file mode 100644
index 0000000..74a2ed7
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_control.c
@@ -0,0 +1,361 @@
+/* ========================================================================== */
+/* === UMFPACK_report_control =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints the control settings.  See umfpack_report_control.h
+    for details.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL void UMFPACK_report_control
+(
+    const double Control [UMFPACK_CONTROL]
+)
+{
+    double drow, dcol, relpt, relpt2, alloc_init, front_alloc_init, amd_alpha,
+	tol, force_fixQ, droptol, aggr ;
+    Int prl, nb, irstep, strategy, scale, s ;
+
+    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+    if (prl < 2)
+    {
+	/* default is to print nothing */
+	return ;
+    }
+
+    PRINTF  (("UMFPACK V%d.%d.%d (%s), Control:\n", UMFPACK_MAIN_VERSION,
+	UMFPACK_SUB_VERSION, UMFPACK_SUBSUB_VERSION, UMFPACK_DATE)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* run-time options */
+    /* ---------------------------------------------------------------------- */
+
+    /* This is a "run-time" option because all four umfpack_* versions */
+    /* compiled into the UMFPACK library. */
+
+#ifdef DINT
+    PRINTF (("    Matrix entry defined as: double\n")) ;
+    PRINTF (("    Int (generic integer) defined as: int\n")) ;
+#endif
+#ifdef DLONG
+    PRINTF (("    Matrix entry defined as: double\n")) ;
+    PRINTF (("    Int (generic integer) defined as: UF_long\n")) ;
+#endif
+#ifdef ZINT
+    PRINTF (("    Matrix entry defined as: double complex\n")) ;
+    PRINTF (("    Int (generic integer) defined as: int\n")) ;
+#endif
+#ifdef ZLONG
+    PRINTF (("    Matrix entry defined as: double complex\n")) ;
+    PRINTF (("    Int (generic integer) defined as: UF_long\n")) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* printing level */
+    /* ---------------------------------------------------------------------- */
+
+    PRINTF (("\n    "ID": print level: "ID"\n",
+	(Int) INDEX (UMFPACK_PRL), prl)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* dense row/col parameters */
+    /* ---------------------------------------------------------------------- */
+
+    drow = GET_CONTROL (UMFPACK_DENSE_ROW, UMFPACK_DEFAULT_DENSE_ROW) ;
+    dcol = GET_CONTROL (UMFPACK_DENSE_COL, UMFPACK_DEFAULT_DENSE_COL) ;
+
+    PRINTF (("    "ID": dense row parameter:    %g\n",
+	(Int) INDEX (UMFPACK_DENSE_ROW), drow)) ;
+    PRINTF (("        \"dense\" rows have    > max (16, (%g)*16*sqrt(n_col)"
+	" entries)\n", drow)) ;
+    PRINTF (("    "ID": dense column parameter: %g\n",
+	(Int) INDEX (UMFPACK_DENSE_COL), dcol)) ;
+    PRINTF (("        \"dense\" columns have > max (16, (%g)*16*sqrt(n_row)"
+	" entries)\n", dcol)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* pivot tolerance */
+    /* ---------------------------------------------------------------------- */
+
+    relpt = GET_CONTROL (UMFPACK_PIVOT_TOLERANCE,
+	UMFPACK_DEFAULT_PIVOT_TOLERANCE) ;
+    relpt = MAX (0.0, MIN (relpt, 1.0)) ;
+    PRINTF (("    "ID": pivot tolerance: %g\n",
+	(Int) INDEX (UMFPACK_PIVOT_TOLERANCE), relpt)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* block size */
+    /* ---------------------------------------------------------------------- */
+
+    nb = GET_CONTROL (UMFPACK_BLOCK_SIZE, UMFPACK_DEFAULT_BLOCK_SIZE) ;
+    nb = MAX (1, nb) ;
+    PRINTF (("    "ID": block size for dense matrix kernels: "ID"\n",
+	(Int) INDEX (UMFPACK_BLOCK_SIZE), nb)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* strategy */
+    /* ---------------------------------------------------------------------- */
+
+    strategy = GET_CONTROL (UMFPACK_STRATEGY, UMFPACK_DEFAULT_STRATEGY) ;
+    if (strategy < UMFPACK_STRATEGY_AUTO
+     || strategy > UMFPACK_STRATEGY_SYMMETRIC)
+    {
+	strategy = UMFPACK_STRATEGY_AUTO ;
+    }
+
+    PRINTF (("    "ID": strategy: "ID,
+	(Int) INDEX (UMFPACK_STRATEGY), strategy)) ;
+
+    if (strategy == UMFPACK_STRATEGY_SYMMETRIC)
+    {
+	PRINTF ((" (symmetric)\n"
+	"        Q = AMD (A+A'), Q not refined during numerical\n"
+	"        factorization, and diagonal pivoting (P=Q') attempted.\n")) ;
+    }
+    else if (strategy == UMFPACK_STRATEGY_UNSYMMETRIC)
+    {
+	PRINTF ((" (unsymmetric)\n"
+	"        Q = COLAMD (A), Q refined during numerical\n"
+	"        factorization, and no attempt at diagonal pivoting.\n")) ;
+    }
+    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)) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* drop tolerance */
+    /* ---------------------------------------------------------------------- */
+
+    droptol = GET_CONTROL (UMFPACK_DROPTOL, UMFPACK_DEFAULT_DROPTOL) ;
+    PRINTF (("    "ID": drop tolerance: %g\n",
+	(Int) INDEX (UMFPACK_DROPTOL), droptol)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* aggressive absorption */
+    /* ---------------------------------------------------------------------- */
+
+    aggr = GET_CONTROL (UMFPACK_AGGRESSIVE, UMFPACK_DEFAULT_AGGRESSIVE) ;
+    PRINTF (("    "ID": AMD and COLAMD aggressive absorption: %g",
+	(Int) INDEX (UMFPACK_AGGRESSIVE), aggr)) ;
+    if (aggr != 0.0)
+    {
+	PRINTF ((" (yes)\n")) ;
+    }
+    else
+    {
+	PRINTF ((" (no)\n")) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compile-time options */
+    /* ---------------------------------------------------------------------- */
+
+    PRINTF ((
+	"\n    The following options can only be changed at compile-time:\n")) ;
+
+    PRINTF (("    "ID": BLAS library used:  ",
+	(Int) INDEX (UMFPACK_COMPILED_WITH_BLAS))) ;
+
+#ifdef NBLAS
+    PRINTF (("none.  UMFPACK will be slow.\n")) ;
+#else
+    PRINTF (("Fortran BLAS.  size of BLAS integer: "ID"\n",
+	(Int) (sizeof (BLAS_INT)))) ;
+#endif
+
+#ifdef MATLAB_MEX_FILE
+    PRINTF (("    "ID": compiled for MATLAB\n",
+	(Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ;
+#else
+#ifdef MATHWORKS
+    PRINTF (("    "ID": compiled for MATLAB\n",
+	(Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ;
+#else
+    PRINTF (("    "ID": compiled for ANSI C\n",
+	(Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ;
+#endif
+#endif
+
+#ifdef NO_TIMER
+    PRINTF (("    "ID": no CPU timer \n",
+	(Int) INDEX (UMFPACK_COMPILED_WITH_GETRUSAGE))) ;
+#else
+#ifndef NPOSIX
+    PRINTF (("    "ID": CPU timer is POSIX times ( ) routine.\n",
+	(Int) INDEX (UMFPACK_COMPILED_WITH_GETRUSAGE))) ;
+#else
+#ifdef GETRUSAGE
+    PRINTF (("    "ID": CPU timer is getrusage.\n",
+	(Int) INDEX (UMFPACK_COMPILED_WITH_GETRUSAGE))) ;
+#else
+    PRINTF (("    "ID": CPU timer is ANSI C clock (may wrap around).\n",
+	(Int) INDEX (UMFPACK_COMPILED_WITH_GETRUSAGE))) ;
+#endif
+#endif
+#endif
+
+#ifndef NDEBUG
+    PRINTF ((
+"**** Debugging enabled (UMFPACK will be exceedingly slow!) *****************\n"
+"    "ID": compiled with debugging enabled. ",
+	(Int) INDEX (UMFPACK_COMPILED_IN_DEBUG_MODE))) ;
+#else
+    PRINTF (("    "ID": compiled for normal operation (debugging disabled)\n",
+	(Int) INDEX (UMFPACK_COMPILED_IN_DEBUG_MODE))) ;
+#endif
+
+    PRINTF (("    computer/operating system: %s\n", UMFPACK_ARCHITECTURE)) ;
+    PRINTF (("    size of int: %g UF_long: %g Int: %g pointer: %g"
+	" double: %g Entry: %g (in bytes)\n\n", (double) sizeof (int),
+	(double) sizeof (UF_long), (double) sizeof (Int),
+	(double) sizeof (void *), (double) sizeof (double),
+	(double) sizeof (Entry))) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_info.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_info.c
new file mode 100644
index 0000000..ff7818b
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_info.c
@@ -0,0 +1,611 @@
+/* ========================================================================== */
+/* === UMFPACK_report_info ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints the Info array.  See umfpack_report_info.h for
+    details.
+*/
+
+#include "umf_internal.h"
+
+#define PRINT_INFO(format,x) \
+{ \
+    if (SCALAR_IS_NAN (x) || (!SCALAR_IS_LTZERO (x))) \
+    { \
+	PRINTF ((format, x)) ; \
+    } \
+}
+
+/* RATIO macro uses a double relop, but ignore NaN case: */
+#define RATIO(a,b,c) (((b) == 0) ? (c) : (((double) a)/((double) b)))
+
+/* ========================================================================== */
+/* === print_ratio ========================================================== */
+/* ========================================================================== */
+
+PRIVATE void print_ratio
+(
+    char *what,
+    char *format,
+    double estimate,
+    double actual
+)
+{
+    if (estimate < 0 && actual < 0)	/* double relop, but ignore Nan case */
+    {
+	return ;
+    }
+    PRINTF (("    %-27s", what)) ;
+    if (estimate >= 0)			/* double relop, but ignore Nan case */
+    {
+	PRINTF ((format, estimate)) ;
+    }
+    else
+    {
+	PRINTF (("                    -")) ;
+    }
+    if (actual >= 0)			/* double relop, but ignore Nan case */
+    {
+	PRINTF ((format, actual)) ;
+    }
+    else
+    {
+	PRINTF (("                    -")) ;
+    }
+    if (estimate >= 0 && actual >= 0)	/* double relop, but ignore Nan case */
+    {
+	PRINTF ((" %5.0f%%\n", 100 * RATIO (actual, estimate, 1))) ;
+    }
+    else
+    {
+	PRINTF (("      -\n")) ;
+    }
+}
+
+/* ========================================================================== */
+/* === UMFPACK_report_info ================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMFPACK_report_info
+(
+    const double Control [UMFPACK_CONTROL],
+    const double Info [UMFPACK_INFO]
+)
+{
+
+    double lnz_est, unz_est, lunz_est, lnz, unz, lunz, tsym, tnum, fnum, tsolve,
+	fsolve, ttot, ftot, twsym, twnum, twsolve, twtot, n2 ;
+    Int n_row, n_col, n_inner, prl, is_sym ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get control settings and status to determine what to print */
+    /* ---------------------------------------------------------------------- */
+
+    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+    if (!Info || prl < 2)
+    {
+	/* no output generated if Info is (double *) NULL */
+	/* or if prl is less than 2 */
+	return ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* print umfpack version */
+    /* ---------------------------------------------------------------------- */
+
+    PRINTF  (("UMFPACK V%d.%d.%d (%s), Info:\n", UMFPACK_MAIN_VERSION,
+	UMFPACK_SUB_VERSION, UMFPACK_SUBSUB_VERSION, UMFPACK_DATE)) ;
+
+#ifndef NDEBUG
+    PRINTF ((
+"**** Debugging enabled (UMFPACK will be exceedingly slow!) *****************\n"
+    )) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* print run-time options */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef DINT
+    PRINTF (("    matrix entry defined as:          double\n")) ;
+    PRINTF (("    Int (generic integer) defined as: int\n")) ;
+#endif
+#ifdef DLONG
+    PRINTF (("    matrix entry defined as:          double\n")) ;
+    PRINTF (("    Int (generic integer) defined as: UF_long\n")) ;
+#endif
+#ifdef ZINT
+    PRINTF (("    matrix entry defined as:          double complex\n")) ;
+    PRINTF (("    Int (generic integer) defined as: int\n")) ;
+#endif
+#ifdef ZLONG
+    PRINTF (("    matrix entry defined as:          double complex\n")) ;
+    PRINTF (("    Int (generic integer) defined as: UF_long\n")) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* print compile-time options */
+    /* ---------------------------------------------------------------------- */
+
+    PRINTF (("    BLAS library used: ")) ;
+
+#ifdef NBLAS
+    PRINTF (("none.  UMFPACK will be slow.\n")) ;
+#else
+    PRINTF (("Fortran BLAS.  size of BLAS integer: "ID"\n",
+	(Int) (sizeof (BLAS_INT)))) ;
+#endif
+
+    PRINTF (("    MATLAB:                           ")) ;
+#ifdef MATLAB_MEX_FILE
+    PRINTF (("yes.\n")) ;
+#else
+#ifdef MATHWORKS
+    PRINTF (("yes.\n")) ;
+#else
+    PRINTF (("no.\n")) ;
+#endif
+#endif
+
+    PRINTF (("    CPU timer:                        ")) ;
+#ifdef NO_TIMER
+    PRINTF (("none.\n")) ;
+#else
+#ifndef NPOSIX
+    PRINTF (("POSIX times ( ) routine.\n")) ;
+#else
+#ifdef GETRUSAGE
+    PRINTF (("getrusage ( ) routine.\n")) ;
+#else
+    PRINTF (("ANSI clock ( ) routine.\n")) ;
+#endif
+#endif
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* print n and nz */
+    /* ---------------------------------------------------------------------- */
+
+    n_row = (Int) Info [UMFPACK_NROW] ;
+    n_col = (Int) Info [UMFPACK_NCOL] ;
+    n_inner = MIN (n_row, n_col) ;
+
+    PRINT_INFO ("    number of rows in matrix A:       "ID"\n", n_row) ;
+    PRINT_INFO ("    number of columns in matrix A:    "ID"\n", n_col) ;
+    PRINT_INFO ("    entries in matrix A:              "ID"\n",
+	(Int) Info [UMFPACK_NZ]) ;
+    PRINT_INFO ("    memory usage reported in:         "ID"-byte Units\n",
+	(Int) Info [UMFPACK_SIZE_OF_UNIT]) ;
+
+    PRINT_INFO ("    size of int:                      "ID" bytes\n",
+	(Int) Info [UMFPACK_SIZE_OF_INT]) ;
+    PRINT_INFO ("    size of UF_long:                  "ID" bytes\n",
+	(Int) Info [UMFPACK_SIZE_OF_LONG]) ;
+    PRINT_INFO ("    size of pointer:                  "ID" bytes\n",
+	(Int) Info [UMFPACK_SIZE_OF_POINTER]) ;
+    PRINT_INFO ("    size of numerical entry:          "ID" bytes\n",
+	(Int) Info [UMFPACK_SIZE_OF_ENTRY]) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* symbolic parameters */
+    /* ---------------------------------------------------------------------- */
+
+    if (Info [UMFPACK_STRATEGY_USED] == UMFPACK_STRATEGY_SYMMETRIC)
+    {
+	PRINTF (("\n    strategy used:                    symmetric\n")) ;
+    }
+    else if (Info [UMFPACK_STRATEGY_USED] == UMFPACK_STRATEGY_UNSYMMETRIC)
+    {
+	PRINTF (("\n    strategy used:                    unsymmetric\n")) ;
+    }
+    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 ("    nz in L (incl diagonal), if none dropped       %.0f\n",
+	Info [UMFPACK_ALL_LNZ]) ;
+    PRINT_INFO ("    nz in U (incl diagonal), if none dropped       %.0f\n",
+	Info [UMFPACK_ALL_UNZ]) ;
+    PRINT_INFO ("    number of small entries dropped                %.0f\n",
+	Info [UMFPACK_NZDROPPED]) ;
+    PRINT_INFO ("    nonzeros on diagonal of U:                     %.0f\n",
+	Info [UMFPACK_UDIAG_NZ]) ;
+    PRINT_INFO ("    min abs. value on diagonal of U:               %.2e\n",
+	Info [UMFPACK_UMIN]) ;
+    PRINT_INFO ("    max abs. value on diagonal of U:               %.2e\n",
+	Info [UMFPACK_UMAX]) ;
+    PRINT_INFO ("    estimate of reciprocal of condition number:    %.2e\n",
+	Info [UMFPACK_RCOND]) ;
+    PRINT_INFO ("    indices in compressed pattern:                 %.0f\n",
+	Info [UMFPACK_COMPRESSED_PATTERN]) ;
+    PRINT_INFO ("    numerical values stored in Numeric object:     %.0f\n",
+	Info [UMFPACK_LU_ENTRIES]) ;
+    PRINT_INFO ("    numeric factorization defragmentations:        %.0f\n",
+	Info [UMFPACK_NUMERIC_DEFRAG]) ;
+    PRINT_INFO ("    numeric factorization reallocations:           %.0f\n",
+	Info [UMFPACK_NUMERIC_REALLOC]) ;
+    PRINT_INFO ("    costly numeric factorization reallocations:    %.0f\n",
+	Info [UMFPACK_NUMERIC_COSTLY_REALLOC]) ;
+    PRINT_INFO ("    numeric factorization CPU time (sec):          %.2f\n",
+	tnum) ;
+    PRINT_INFO ("    numeric factorization wallclock time (sec):    %.2f\n",
+	twnum) ;
+
+#define TMIN 0.001
+
+    if (tnum > TMIN && fnum > 0)
+    {
+	PRINT_INFO (
+	   "    numeric factorization mflops (CPU time):       %.2f\n",
+	   1e-6 * fnum / tnum) ;
+    }
+    if (twnum > TMIN && fnum > 0)
+    {
+	PRINT_INFO (
+	   "    numeric factorization mflops (wallclock):      %.2f\n",
+	   1e-6 * fnum / twnum) ;
+    }
+
+    ttot = EMPTY ;
+    ftot = fnum ;
+    if (tsym >= TMIN && tnum >= 0)
+    {
+	ttot = tsym + tnum ;
+	PRINT_INFO ("    symbolic + numeric CPU time (sec):             %.2f\n",
+	    ttot) ;
+	if (ftot > 0 && ttot > TMIN)
+	{
+	    PRINT_INFO (
+		"    symbolic + numeric mflops (CPU time):          %.2f\n",
+		1e-6 * ftot / ttot) ;
+	}
+    }
+
+    twtot = EMPTY ;
+    if (twsym >= TMIN && twnum >= TMIN)
+    {
+	twtot = twsym + twnum ;
+	PRINT_INFO ("    symbolic + numeric wall clock time (sec):      %.2f\n",
+	    twtot) ;
+	if (ftot > 0 && twtot > TMIN)
+	{
+	    PRINT_INFO (
+		"    symbolic + numeric mflops (wall clock):        %.2f\n",
+		1e-6 * ftot / twtot) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* solve */
+    /* ---------------------------------------------------------------------- */
+
+    tsolve = Info [UMFPACK_SOLVE_TIME] ;
+    twsolve = Info [UMFPACK_SOLVE_WALLTIME] ;
+    fsolve = Info [UMFPACK_SOLVE_FLOPS] ;
+
+    PRINT_INFO ("\n    solve flops:                                   %.5e\n",
+	fsolve) ;
+    PRINT_INFO ("    iterative refinement steps taken:              %.0f\n",
+	Info [UMFPACK_IR_TAKEN]) ;
+    PRINT_INFO ("    iterative refinement steps attempted:          %.0f\n",
+	Info [UMFPACK_IR_ATTEMPTED]) ;
+    PRINT_INFO ("    sparse backward error omega1:                  %.2e\n",
+	Info [UMFPACK_OMEGA1]) ;
+    PRINT_INFO ("    sparse backward error omega2:                  %.2e\n",
+	Info [UMFPACK_OMEGA2]) ;
+    PRINT_INFO ("    solve CPU time (sec):                          %.2f\n",
+	tsolve) ;
+    PRINT_INFO ("    solve wall clock time (sec):                   %.2f\n",
+	twsolve) ;
+    if (fsolve > 0 && tsolve > TMIN)
+    {
+	PRINT_INFO (
+	    "    solve mflops (CPU time):                       %.2f\n",
+	    1e-6 * fsolve / tsolve) ;
+    }
+    if (fsolve > 0 && twsolve > TMIN)
+    {
+	PRINT_INFO (
+	    "    solve mflops (wall clock time):                %.2f\n",
+	    1e-6 * fsolve / twsolve) ;
+    }
+
+    if (ftot >= 0 && fsolve >= 0)
+    {
+	ftot += fsolve ;
+	PRINT_INFO (
+	"\n    total symbolic + numeric + solve flops:        %.5e\n", ftot) ;
+    }
+
+    if (tsolve >= TMIN)
+    {
+	if (ttot >= TMIN && ftot >= 0)
+	{
+	    ttot += tsolve ;
+	    PRINT_INFO (
+		"    total symbolic + numeric + solve CPU time:     %.2f\n",
+		ttot) ;
+	    if (ftot > 0 && ttot > TMIN)
+	    {
+		PRINT_INFO (
+		"    total symbolic + numeric + solve mflops (CPU): %.2f\n",
+		1e-6 * ftot / ttot) ;
+	    }
+	}
+    }
+
+    if (twsolve >= TMIN)
+    {
+	if (twtot >= TMIN && ftot >= 0)
+	{
+	    twtot += tsolve ;
+	    PRINT_INFO (
+		"    total symbolic+numeric+solve wall clock time:  %.2f\n",
+		twtot) ;
+	    if (ftot > 0 && twtot > TMIN)
+	    {
+		PRINT_INFO (
+		"    total symbolic+numeric+solve mflops(wallclock) %.2f\n",
+		1e-6 * ftot / twtot) ;
+	    }
+	}
+    }
+    PRINTF (("\n")) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_matrix.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_matrix.c
new file mode 100644
index 0000000..6add888
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_matrix.c
@@ -0,0 +1,201 @@
+/* ========================================================================== */
+/* === UMFPACK_report_matrix ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints a column or row-oriented matrix.  See
+    umfpack_report_matrix.h for details.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL Int UMFPACK_report_matrix
+(
+    Int n_row,
+    Int n_col,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    Int col_form,		/* 1: column form, 0: row form */
+    const double Control [UMFPACK_CONTROL]
+)
+{
+    Entry a ;
+    Int prl, i, k, length, ilast, p, nz, prl1, p1, p2, n, n_i, do_values ;
+    char *vector, *index ;
+#ifdef COMPLEX
+    Int split = SPLIT (Az) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the form, and check if inputs exist */
+    /* ---------------------------------------------------------------------- */
+
+    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+    if (prl <= 2)
+    {
+	return (UMFPACK_OK) ;
+    }
+
+    if (col_form)
+    {
+	vector = "column" ;	/* column vectors */
+	index = "row" ;		/* with row indices */
+	n = n_col ;
+	n_i = n_row ;
+    }
+    else
+    {
+	vector = "row" ;	/* row vectors */
+	index = "column" ;	/* with column indices */
+	n = n_row ;
+	n_i = n_col ;
+    }
+
+    PRINTF (("%s-form matrix, n_row "ID" n_col "ID", ", vector, n_row, n_col)) ;
+
+    if (n_row <= 0 || n_col <= 0)
+    {
+	PRINTF (("ERROR: n_row <= 0 or n_col <= 0\n\n")) ;
+	return (UMFPACK_ERROR_n_nonpositive) ;
+    }
+
+    if (!Ap)
+    {
+	PRINTF (("ERROR: Ap missing\n\n")) ;
+	return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    nz = Ap [n] ;
+    PRINTF (("nz = "ID". ", nz)) ;
+    if (nz < 0)
+    {
+	PRINTF (("ERROR: number of entries < 0\n\n")) ;
+	return (UMFPACK_ERROR_invalid_matrix) ;
+    }
+
+    if (Ap [0] != 0)
+    {
+	PRINTF (("ERROR: Ap ["ID"] = "ID" must be "ID"\n\n",
+	    (Int) INDEX (0), INDEX (Ap [0]), (Int) INDEX (0))) ;
+	return (UMFPACK_ERROR_invalid_matrix) ;
+    }
+
+    if (!Ai)
+    {
+	PRINTF (("ERROR: Ai missing\n\n")) ;
+	return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    do_values = Ax != (double *) NULL ;
+
+    PRINTF4 (("\n")) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check the row/column pointers, Ap */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < n ; k++)
+    {
+	if (Ap [k] < 0)
+	{
+	    PRINTF (("ERROR: Ap ["ID"] < 0\n\n", INDEX (k))) ;
+	    return (UMFPACK_ERROR_invalid_matrix) ;
+	}
+	if (Ap [k] > nz)
+	{
+	    PRINTF (("ERROR: Ap ["ID"] > size of Ai\n\n", INDEX (k))) ;
+	    return (UMFPACK_ERROR_invalid_matrix) ;
+	}
+    }
+
+    for (k = 0 ; k < n ; k++)
+    {
+	length = Ap [k+1] - Ap [k] ;
+	if (length < 0)
+	{
+	    PRINTF (("ERROR: # entries in %s "ID" is < 0\n\n",
+		vector, INDEX (k))) ;
+	    return (UMFPACK_ERROR_invalid_matrix) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* print each vector */
+    /* ---------------------------------------------------------------------- */
+
+    prl1 = prl ;
+
+    for (k = 0 ; k < n ; k++)
+    {
+	/* if prl is 4, print the first 10 entries of the first 10 vectors */
+	if (k < 10)
+	{
+	    prl = prl1 ;
+	}
+	/* get the vector pointers */
+	p1 = Ap [k] ;
+	p2 = Ap [k+1] ;
+	length = p2 - p1 ;
+	PRINTF4 (("\n    %s "ID": start: "ID" end: "ID" entries: "ID"\n",
+	    vector, INDEX (k), p1, p2-1, length)) ;
+	ilast = EMPTY ;
+	for (p = p1 ; p < p2 ; p++)
+	{
+	    i = Ai [p] ;
+	    PRINTF4 (("\t%s "ID" ", index, INDEX (i))) ;
+	    if (do_values && prl >= 4)
+	    {
+		PRINTF ((":")) ;
+		ASSIGN (a, Ax, Az, p, split) ;
+		PRINT_ENTRY (a) ;
+	    }
+	    if (i < 0 || i >= n_i)
+	    {
+		PRINTF ((" ERROR: %s index "ID" out of range in %s "ID"\n\n",
+		    index, INDEX (i), vector, INDEX (k))) ;
+		return (UMFPACK_ERROR_invalid_matrix) ;
+	    }
+	    if (i <= ilast)
+	    {
+		PRINTF ((" ERROR: %s index "ID" out of order (or duplicate) in "
+		    "%s "ID"\n\n", index, INDEX (i), vector, INDEX (k))) ;
+		return (UMFPACK_ERROR_invalid_matrix) ;
+	    }
+	    PRINTF4 (("\n")) ;
+	    /* truncate printout, but continue to check matrix */
+	    if (prl == 4 && (p - p1) == 9 && length > 10)
+	    {
+		PRINTF4 (("\t...\n")) ;
+		prl-- ;
+	    }
+	    ilast = i ;
+	}
+	/* truncate printout, but continue to check matrix */
+	if (prl == 4 && k == 9 && n > 10)
+	{
+	    PRINTF4 (("\n    ...\n")) ;
+	    prl-- ;
+	}
+    }
+    prl = prl1 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* return the status of the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    PRINTF4 (("    %s-form matrix ", vector)) ;
+    PRINTF (("OK\n\n")) ;
+
+    return (UMFPACK_OK) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_numeric.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_numeric.c
new file mode 100644
index 0000000..73a5d24
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_numeric.c
@@ -0,0 +1,663 @@
+/* ========================================================================== */
+/* === UMFPACK_report_numeric =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints the Numeric object.
+    See umfpack_report_numeric.h for details.
+
+    Dynamic memory usage:  Allocates a size n*sizeof(Int) workspace via a single
+    call to UMF_malloc and then frees all of it via UMF_free on return.  The
+    workspace is not allocated if an early error return occurs before the
+    workspace is needed.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+#include "umf_report_perm.h"
+#include "umf_report_vector.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+
+PRIVATE Int report_L
+(
+    NumericType *Numeric,
+    Int Pattern [ ],
+    Int prl
+) ;
+
+
+PRIVATE Int report_U
+(
+    NumericType *Numeric,
+    Int Pattern [ ],
+    Int prl
+) ;
+
+/* ========================================================================== */
+/* === UMFPACK_report_numeric =============================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_report_numeric
+(
+    void *NumericHandle,
+    const double Control [UMFPACK_CONTROL]
+)
+{
+    Int prl, *W, nn, n_row, n_col, n_inner, num_fixed_size, numeric_size,
+	npiv ;
+    NumericType *Numeric ;
+
+    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+    if (prl <= 2)
+    {
+	return (UMFPACK_OK) ;
+    }
+
+    PRINTF (("Numeric object:  ")) ;
+
+    Numeric = (NumericType *) NumericHandle ;
+    if (!UMF_valid_numeric (Numeric))
+    {
+	PRINTF (("ERROR: LU factors invalid\n\n")) ;
+	return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    n_row = Numeric->n_row ;
+    n_col = Numeric->n_col ;
+    nn = MAX (n_row, n_col) ;
+    n_inner = MIN (n_row, n_col) ;
+    npiv = Numeric->npiv ;
+
+    DEBUG1 (("n_row "ID" n_col "ID" nn "ID" n_inner "ID" npiv "ID"\n",
+	n_row, n_col, nn, n_inner, npiv)) ;
+
+    /* size of Numeric object, except Numeric->Memory and Numeric->Upattern */
+    /* see also UMF_set_stats */
+    num_fixed_size =
+	UNITS (NumericType, 1)		/* Numeric structure */
+	+ UNITS (Entry, n_inner+1)	/* D */
+	+ UNITS (Int, n_row+1)		/* Rperm */
+	+ UNITS (Int, n_col+1)		/* Cperm */
+	+ 6 * UNITS (Int, npiv+1)	/* Lpos, Uilen, Uip, Upos, Lilen, Lip */
+	+ ((Numeric->scale != UMFPACK_SCALE_NONE) ?
+		UNITS (Entry, n_row) : 0) ; /* Rs */
+
+    DEBUG1 (("num fixed size: "ID"\n", num_fixed_size)) ;
+    DEBUG1 (("Numeric->size "ID"\n", Numeric->size)) ;
+    DEBUG1 (("ulen units "ID"\n", UNITS (Int, Numeric->ulen))) ;
+
+    /* size of Numeric->Memory is Numeric->size */
+    /* size of Numeric->Upattern is Numeric->ulen */
+    numeric_size = num_fixed_size + Numeric->size
+	+ UNITS (Int, Numeric->ulen) ;
+
+    DEBUG1 (("numeric total size "ID"\n", numeric_size)) ;
+
+    if (prl >= 4)
+    {
+	PRINTF (("\n    n_row: "ID"  n_col: "ID"\n", n_row, n_col)) ;
+
+	PRINTF (("    relative pivot tolerance used:              %g\n",
+	    Numeric->relpt)) ;
+	PRINTF (("    relative symmetric pivot tolerance used:    %g\n",
+	    Numeric->relpt2)) ;
+
+	PRINTF (("    matrix scaled: ")) ;
+	if (Numeric->scale == UMFPACK_SCALE_NONE)
+	{
+	    PRINTF (("no")) ;
+	}
+	else if (Numeric->scale == UMFPACK_SCALE_SUM)
+	{
+	    PRINTF (("yes (divided each row by sum abs value in each row)\n")) ;
+	    PRINTF (("    minimum sum (abs (rows of A)):              %.5e\n",
+		Numeric->rsmin)) ;
+	    PRINTF (("    maximum sum (abs (rows of A)):              %.5e",
+		Numeric->rsmax)) ;
+	}
+	else if (Numeric->scale == UMFPACK_SCALE_MAX)
+	{
+	    PRINTF (("yes (divided each row by max abs value in each row)\n")) ;
+	    PRINTF (("    minimum max (abs (rows of A)):              %.5e\n",
+		Numeric->rsmin)) ;
+	    PRINTF (("    maximum max (abs (rows of A)):              %.5e",
+		Numeric->rsmax)) ;
+	}
+	PRINTF (("\n")) ;
+
+	PRINTF (("    initial allocation parameter used:          %g\n",
+	    Numeric->alloc_init)) ;
+	PRINTF (("    frontal matrix allocation parameter used:   %g\n",
+	    Numeric->front_alloc_init)) ;
+	PRINTF (("    final total size of Numeric object (Units): "ID"\n",
+	    numeric_size)) ;
+	PRINTF (("    final total size of Numeric object (MBytes): %.1f\n",
+	    MBYTES (numeric_size))) ;
+	PRINTF (("    peak size of variable-size part (Units):    "ID"\n",
+	    Numeric->max_usage)) ;
+	PRINTF (("    peak size of variable-size part (MBytes):   %.1f\n",
+	    MBYTES (Numeric->max_usage))) ;
+	PRINTF (("    largest actual frontal matrix size:         "ID"\n",
+	    Numeric->maxfrsize)) ;
+	PRINTF (("    memory defragmentations:                    "ID"\n",
+	    Numeric->ngarbage)) ;
+	PRINTF (("    memory reallocations:                       "ID"\n",
+	    Numeric->nrealloc)) ;
+	PRINTF (("    costly memory reallocations:                "ID"\n",
+	    Numeric->ncostly)) ;
+	PRINTF (("    entries in compressed pattern (L and U):    "ID"\n",
+	    Numeric->isize)) ;
+	PRINTF (("    number of nonzeros in L (excl diag):        "ID"\n",
+	    Numeric->lnz)) ;
+	PRINTF (("    number of entries stored in L (excl diag):  "ID"\n",
+	    Numeric->nLentries)) ;
+	PRINTF (("    number of nonzeros in U (excl diag):        "ID"\n",
+	    Numeric->unz)) ;
+	PRINTF (("    number of entries stored in U (excl diag):  "ID"\n",
+	    Numeric->nUentries)) ;
+	PRINTF (("    factorization floating-point operations:    %g\n",
+	    Numeric->flops)) ;
+	PRINTF (("    number of nonzeros on diagonal of U:        "ID"\n",
+	    Numeric->nnzpiv)) ;
+	PRINTF (("    min abs. value on diagonal of U:            %.5e\n",
+	    Numeric->min_udiag)) ;
+	PRINTF (("    max abs. value on diagonal of U:            %.5e\n",
+	    Numeric->max_udiag)) ;
+	PRINTF (("    reciprocal condition number estimate:       %.2e\n",
+	    Numeric->rcond)) ;
+    }
+
+    W = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+    if (!W)
+    {
+	PRINTF ((" ERROR: out of memory to check Numeric object\n\n")) ;
+	return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+    if (Numeric->Rs)
+    {
+#ifndef NRECIPROCAL
+	if (Numeric->do_recip)
+	{
+	    PRINTF4 (("\nScale factors applied via multiplication\n")) ;
+	}
+	else
+#endif
+	{
+	    PRINTF4 (("\nScale factors applied via division\n")) ;
+	}
+	PRINTF4 (("Scale factors, Rs: ")) ;
+	(void) UMF_report_vector (n_row, Numeric->Rs, (double *) NULL,
+	    prl, FALSE, TRUE) ;
+    }
+    else
+    {
+	PRINTF4 (("Scale factors, Rs: (not present)\n")) ;
+    }
+
+    PRINTF4 (("\nP: row ")) ;
+    if (UMF_report_perm (n_row, Numeric->Rperm, W, prl, 0) != UMFPACK_OK)
+    {
+	(void) UMF_free ((void *) W) ;
+	return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    PRINTF4 (("\nQ: column ")) ;
+    if (UMF_report_perm (n_col, Numeric->Cperm, W, prl, 0) != UMFPACK_OK)
+    {
+	(void) UMF_free ((void *) W) ;
+	return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    if (!report_L (Numeric, W, prl))
+    {
+	(void) UMF_free ((void *) W) ;
+	PRINTF ((" ERROR: L factor invalid\n\n")) ;
+	return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    if (!report_U (Numeric, W, prl))
+    {
+	(void) UMF_free ((void *) W) ;
+	PRINTF ((" ERROR: U factor invalid\n\n")) ;
+	return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    /* The diagonal of U is in "merged" (Entry) form, not "split" form. */
+    PRINTF4 (("\ndiagonal of U: ")) ;
+    (void) UMF_report_vector (n_inner, (double *) Numeric->D, (double *) NULL,
+	prl, FALSE, FALSE) ;
+
+    (void) UMF_free ((void *) W) ;
+
+    PRINTF4 (("    Numeric object:  ")) ;
+    PRINTF (("OK\n\n")) ;
+    return (UMFPACK_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === report_L ============================================================= */
+/* ========================================================================== */
+
+PRIVATE Int report_L
+(
+    NumericType *Numeric,
+    Int Pattern [ ],
+    Int prl
+)
+{
+    Int k, deg, *ip, j, row, n_row, *Lpos, *Lilen, valid, k1,
+	*Lip, newLchain, llen, prl1, pos, lp, p, npiv, n1, *Li ;
+    Entry *xp, *Lval ;
+
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (prl >= 3) ;
+
+    n_row = Numeric->n_row ;
+    npiv = Numeric->npiv ;
+    n1 = Numeric->n1 ;
+    Lpos = Numeric->Lpos ;
+    Lilen = Numeric->Lilen ;
+    Lip = Numeric->Lip ;
+    prl1 = prl ;
+    deg = 0 ;
+
+    PRINTF4 ((
+    "\nL in Numeric object, in column-oriented compressed-pattern form:\n"
+    "    Diagonal entries are all equal to 1.0 (not stored)\n")) ;
+
+    ASSERT (Pattern != (Int *) NULL) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print L */
+    /* ---------------------------------------------------------------------- */
+
+    k1 = 12 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print the singleton columns of L */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < n1 ; k++)
+    {
+	if (k1 > 0)
+	{
+	    prl = prl1 ;
+	}
+	lp = Lip [k] ;
+	deg = Lilen [k] ;
+	Li = (Int *) (Numeric->Memory + lp) ;
+	lp += UNITS (Int, deg) ;
+	Lval = (Entry *) (Numeric->Memory + lp) ;
+	if (k1-- > 0)
+	{
+	    prl = prl1 ;
+	}
+	else if (prl == 4)
+	{
+	    PRINTF (("    ...\n")) ;
+	    prl-- ;
+	}
+	PRINTF4 (("\n    column "ID":", INDEX (k))) ;
+	PRINTF4 (("  length "ID".\n", deg)) ;
+	for (j = 0 ; j < deg ; j++)
+	{
+	    row = Li [j] ;
+	    PRINTF4 (("\trow "ID" : ", INDEX (row))) ;
+	    if (prl >= 4) PRINT_ENTRY (Lval [j]) ;
+	    if (row <= k || row >= n_row)
+	    {
+		return (FALSE) ;
+	    }
+	    PRINTF4 (("\n")) ;
+	    /* truncate printout, but continue to check L */
+	    if (prl == 4 && j == 9 && deg > 10)
+	    {
+		PRINTF (("\t...\n")) ;
+		prl-- ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* print the regular columns of L */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = n1 ; k < npiv ; k++)
+    {
+	/* if prl is 4, print the first 10 entries of the first 10 columns */
+	if (k1 > 0)
+	{
+	    prl = prl1 ;
+	}
+
+	lp = Lip [k] ;
+	newLchain = (lp < 0) ;
+	if (newLchain)
+	{
+	    lp = -lp ;
+	    deg = 0 ;
+	}
+
+	if (k1-- > 0)
+	{
+	    prl = prl1 ;
+	}
+	else if (prl == 4)
+	{
+	    PRINTF (("    ...\n")) ;
+	    prl-- ;
+	}
+
+	PRINTF4 (("\n    column "ID":", INDEX (k))) ;
+
+	/* ------------------------------------------------------------------ */
+	/* make column of L in Pattern [0..deg-1] */
+	/* ------------------------------------------------------------------ */
+
+	/* remove pivot row */
+	pos = Lpos [k] ;
+	if (pos != EMPTY)
+	{
+	    PRINTF4 (("  remove row "ID" at position "ID".",
+		INDEX (Pattern [pos]), INDEX (pos))) ;
+	    valid = (!newLchain) && (deg > 0) && (pos < deg) && (pos >= 0)
+		&& (Pattern [pos] == k) ;
+	    if (!valid)
+	    {
+		return (FALSE) ;
+	    }
+	    Pattern [pos] = Pattern [--deg] ;
+	}
+
+	/* concatenate the pattern */
+	llen = Lilen [k] ;
+	if (llen < 0)
+	{
+	    return (FALSE) ;
+	}
+	p = lp + UNITS (Int, llen) ;
+	xp = (Entry *) (Numeric->Memory + p) ;
+	if ((llen > 0 || deg > 0)
+	    && (p + (Int) UNITS (Entry, deg) > Numeric->size))
+	{
+	    return (FALSE) ;
+	}
+	if (llen > 0)
+	{
+	    PRINTF4 (("  add "ID" entries.", llen)) ;
+	    ip = (Int *) (Numeric->Memory + lp) ;
+	    for (j = 0 ; j < llen ; j++)
+	    {
+		Pattern [deg++] = *ip++ ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* print column k of L */
+	/* ------------------------------------------------------------------ */
+
+	PRINTF4 (("  length "ID".", deg)) ;
+	if (newLchain)
+	{
+	    PRINTF4 (("  Start of Lchain.")) ;
+	}
+	PRINTF4 (("\n")) ;
+
+	for (j = 0 ; j < deg ; j++)
+	{
+	    row = Pattern [j] ;
+	    PRINTF4 (("\trow "ID" : ", INDEX (row))) ;
+	    if (prl >= 4) PRINT_ENTRY (*xp) ;
+	    if (row <= k || row >= n_row)
+	    {
+		return (FALSE) ;
+	    }
+	    PRINTF4 (("\n")) ;
+	    xp++ ;
+	    /* truncate printout, but continue to check L */
+	    if (prl == 4 && j == 9 && deg > 10)
+	    {
+		PRINTF (("\t...\n")) ;
+		prl-- ;
+	    }
+	}
+    }
+
+    PRINTF4 (("\n")) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === report_U ============================================================= */
+/* ========================================================================== */
+
+PRIVATE Int report_U
+(
+    NumericType *Numeric,
+    Int Pattern [ ],
+    Int prl
+)
+{
+    /* ---------------------------------------------------------------------- */
+
+    Int k, deg, j, *ip, col, *Upos, *Uilen, k1, prl1, pos,
+	*Uip, n_col, ulen, p, newUchain, up, npiv, n1, *Ui ;
+    Entry *xp, *Uval ;
+
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (prl >= 3) ;
+
+    n_col = Numeric->n_col ;
+    npiv = Numeric->npiv ;
+    n1 = Numeric->n1 ;
+    Upos = Numeric->Upos ;
+    Uilen = Numeric->Uilen ;
+    Uip = Numeric->Uip ;
+    prl1 = prl ;
+
+    PRINTF4 ((
+    "\nU in Numeric object, in row-oriented compressed-pattern form:\n"
+    "    Diagonal is stored separately.\n")) ;
+
+    ASSERT (Pattern != (Int *) NULL) ;
+
+    k1 = 12 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print the sparse part of U */
+    /* ---------------------------------------------------------------------- */
+
+    deg = Numeric->ulen ;
+    if (deg > 0)
+    {
+	/* make last pivot row of U (singular matrices only) */
+	for (j = 0 ; j < deg ; j++)
+	{
+	    Pattern [j] = Numeric->Upattern [j] ;
+	}
+    }
+
+    PRINTF4 (("\n    row "ID":  length "ID".  End of Uchain.\n", INDEX (npiv-1),
+	deg)) ;
+
+    for (k = npiv-1 ; k >= n1 ; k--)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* print row k of U */
+	/* ------------------------------------------------------------------ */
+
+	/* if prl is 3, print the first 10 entries of the first 10 columns */
+	if (k1 > 0)
+	{
+	    prl = prl1 ;
+	}
+
+	up = Uip [k] ;
+	ulen = Uilen [k] ;
+	if (ulen < 0)
+	{
+	    return (FALSE) ;
+	}
+	newUchain = (up < 0) ;
+	if (newUchain)
+	{
+	    up = -up ;
+	    p = up + UNITS (Int, ulen) ;
+	}
+	else
+	{
+	    p = up ;
+	}
+	xp = (Entry *) (Numeric->Memory + p) ;
+	if (deg > 0 && (p + (Int) UNITS (Entry, deg) > Numeric->size))
+	{
+	    return (FALSE) ;
+	}
+	for (j = 0 ; j < deg ; j++)
+	{
+	    col = Pattern [j] ;
+	    PRINTF4 (("\tcol "ID" :", INDEX (col))) ;
+	    if (prl >= 4) PRINT_ENTRY (*xp) ;
+	    if (col <= k || col >= n_col)
+	    {
+		return (FALSE) ;
+	    }
+	    PRINTF4 (("\n")) ;
+	    xp++ ;
+	    /* truncate printout, but continue to check U */
+	    if (prl == 4 && j == 9 && deg > 10)
+	    {
+		PRINTF (("\t...\n")) ;
+		prl-- ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* make row k-1 of U in Pattern [0..deg-1] */
+	/* ------------------------------------------------------------------ */
+
+	if (k1-- > 0)
+	{
+	    prl = prl1 ;
+	}
+	else if (prl == 4)
+	{
+	    PRINTF (("    ...\n")) ;
+	    prl-- ;
+	}
+
+	if (k > 0)
+	{
+	    PRINTF4 (("\n    row "ID":  ", INDEX (k-1))) ;
+	}
+
+	if (newUchain)
+	{
+	    /* next row is a new Uchain */
+	    if (k > 0)
+	    {
+		deg = ulen ;
+		PRINTF4 (("length "ID".  End of Uchain.\n", deg)) ;
+		if (up + (Int) UNITS (Int, ulen) > Numeric->size)
+		{
+		    return (FALSE) ;
+		}
+		ip = (Int *) (Numeric->Memory + up) ;
+		for (j = 0 ; j < deg ; j++)
+		{
+		    Pattern [j] = *ip++ ;
+		}
+	    }
+	}
+	else
+	{
+	    if (ulen > 0)
+	    {
+		PRINTF4 (("remove "ID" entries.  ", ulen)) ;
+	    }
+	    deg -= ulen ;
+	    if (deg < 0)
+	    {
+		return (FALSE) ;
+	    }
+	    pos = Upos [k] ;
+	    if (pos != EMPTY)
+	    {
+		/* add the pivot column */
+		PRINTF4 (("add column "ID" at position "ID".  ",
+		    INDEX (k), INDEX (pos))) ;
+		if (pos < 0 || pos > deg)
+		{
+		    return (FALSE) ;
+		}
+		Pattern [deg++] = Pattern [pos] ;
+		Pattern [pos] = k ;
+	    }
+	    PRINTF4 (("length "ID".\n", deg)) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* print the singleton rows of U */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = n1 - 1 ; k >= 0 ; k--)
+    {
+	if (k1 > 0)
+	{
+	    prl = prl1 ;
+	}
+	up = Uip [k] ;
+	deg = Uilen [k] ;
+	Ui = (Int *) (Numeric->Memory + up) ;
+	up += UNITS (Int, deg) ;
+	Uval = (Entry *) (Numeric->Memory + up) ;
+	if (k1-- > 0)
+	{
+	    prl = prl1 ;
+	}
+	else if (prl == 4)
+	{
+	    PRINTF (("    ...\n")) ;
+	    prl-- ;
+	}
+	PRINTF4 (("\n    row "ID":", INDEX (k))) ;
+	PRINTF4 (("  length "ID".\n", deg)) ;
+	for (j = 0 ; j < deg ; j++)
+	{
+	    col = Ui [j] ;
+	    PRINTF4 (("\tcol "ID" : ", INDEX (col))) ;
+	    if (prl >= 4) PRINT_ENTRY (Uval [j]) ;
+	    if (col <= k || col >= n_col)
+	    {
+		return (FALSE) ;
+	    }
+	    PRINTF4 (("\n")) ;
+	    /* truncate printout, but continue to check U */
+	    if (prl == 4 && j == 9 && deg > 10)
+	    {
+		PRINTF (("\t...\n")) ;
+		prl-- ;
+	    }
+	}
+    }
+
+    prl = prl1 ;
+    PRINTF4 (("\n")) ;
+    return (TRUE) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_perm.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_perm.c
new file mode 100644
index 0000000..591122b
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_perm.c
@@ -0,0 +1,44 @@
+/* ========================================================================== */
+/* === UMFPACK_report_perm ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints a permutation vector.  See umfpack_report_perm.h
+    for details.
+
+    Dynamic memory usage:  Allocates a size max(np,1)*sizeof(Int) workspace via
+    a single call to UMF_malloc and then frees all of it via UMF_free on return.
+*/
+
+#include "umf_internal.h"
+#include "umf_report_perm.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+GLOBAL Int UMFPACK_report_perm
+(
+    Int np,
+    const Int Perm [ ],
+    const double Control [UMFPACK_CONTROL]
+)
+{
+    Int prl, *W, status ;
+
+    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+    if (prl <= 2)
+    {
+	return (UMFPACK_OK) ;
+    }
+
+    W = (Int *) UMF_malloc (MAX (np,1), sizeof (Int)) ;
+    status = UMF_report_perm (np, Perm, W, prl, 1) ;
+    (void) UMF_free ((void *) W) ;
+    return (status) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_status.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_status.c
new file mode 100644
index 0000000..068bb7c
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_status.c
@@ -0,0 +1,119 @@
+/* ========================================================================== */
+/* === UMFPACK_report_status ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints the return value from other UMFPACK_* routines.
+    See umfpack_report_status.h for details.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL void UMFPACK_report_status
+(
+    const double Control [UMFPACK_CONTROL],
+    Int status
+)
+{
+    Int prl ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get control settings and status to determine what to print */
+    /* ---------------------------------------------------------------------- */
+
+    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+    if (prl < 1)
+    {
+	/* no output generated if prl is less than 1 */
+	return ;
+    }
+
+    if (status == UMFPACK_OK && prl <= 1)
+    {
+	/* no output generated if prl is 1 or less and no error occurred. */
+	/* note that the default printing level is 1. */
+	return ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* print umfpack license, copyright, version, and status condition */
+    /* ---------------------------------------------------------------------- */
+
+    PRINTF  (("\n")) ;
+    PRINTF4 (("%s\n", UMFPACK_COPYRIGHT)) ;
+    PRINTF6 (("%s", UMFPACK_LICENSE_PART1)) ;
+    PRINTF6 (("%s", UMFPACK_LICENSE_PART2)) ;
+    PRINTF6 (("%s", UMFPACK_LICENSE_PART3)) ;
+    PRINTF  (("UMFPACK V%d.%d.%d (%s): ", UMFPACK_MAIN_VERSION,
+	UMFPACK_SUB_VERSION, UMFPACK_SUBSUB_VERSION, UMFPACK_DATE)) ;
+
+    switch (status)
+    {
+	case UMFPACK_OK:
+	    PRINTF (("OK\n")) ;
+	    break ;
+
+	case UMFPACK_WARNING_singular_matrix:
+	    PRINTF (("WARNING: matrix is singular\n")) ;
+	    break ;
+
+	case UMFPACK_ERROR_out_of_memory:
+	    PRINTF (("ERROR: out of memory\n")) ;
+	    break ;
+
+	case UMFPACK_ERROR_invalid_Numeric_object:
+	    PRINTF (("ERROR: Numeric object is invalid\n")) ;
+	    break ;
+
+	case UMFPACK_ERROR_invalid_Symbolic_object:
+	    PRINTF (("ERROR: Symbolic object is invalid\n")) ;
+	    break ;
+
+	case UMFPACK_ERROR_argument_missing:
+	    PRINTF (("ERROR: required argument(s) missing\n")) ;
+	    break ;
+
+	case UMFPACK_ERROR_n_nonpositive:
+	    PRINTF (("ERROR: dimension (n_row or n_col) must be > 0\n")) ;
+	    break ;
+
+	case UMFPACK_ERROR_invalid_matrix:
+	    PRINTF (("ERROR: input matrix is invalid\n")) ;
+	    break ;
+
+	case UMFPACK_ERROR_invalid_system:
+	    PRINTF (("ERROR: system argument invalid\n")) ;
+	    break ;
+
+	case UMFPACK_ERROR_invalid_permutation:
+	    PRINTF (("ERROR: invalid permutation\n")) ;
+	    break ;
+
+	case UMFPACK_ERROR_different_pattern:
+	    PRINTF (("ERROR: pattern of matrix (Ap and/or Ai) has changed\n")) ;
+	    break ;
+
+	case UMFPACK_ERROR_internal_error:
+	    PRINTF (("INTERNAL ERROR!\n"
+	    "Input arguments might be corrupted or aliased, or an internal\n"
+	    "error has occurred.  Check your input arguments with the\n"
+	    "umfpack_*_report_* routines before calling the umfpack_*\n"
+	    "computational routines.  Recompile UMFPACK with debugging\n"
+	    "enabled, and look for failed assertions.  If all else fails\n"
+	    "please report this error to Tim Davis (davis at cise.ufl.edu).\n"
+	    )) ;
+	    break ;
+
+	default:
+	    PRINTF (("ERROR: Unrecognized error code: "ID"\n", status)) ;
+
+    }
+    PRINTF  (("\n")) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_symbolic.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_symbolic.c
new file mode 100644
index 0000000..4142834
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_symbolic.c
@@ -0,0 +1,228 @@
+/* ========================================================================== */
+/* === UMFPACK_report_symbolic ============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints the Symbolic object. See umfpack_report_symbolic.h
+    for details.  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) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_triplet.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_triplet.c
new file mode 100644
index 0000000..6bb6fb8
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_triplet.c
@@ -0,0 +1,99 @@
+/* ========================================================================== */
+/* === UMFPACK_report_triplet =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints a matrix in triplet form.  See
+    umfpack_report_triplet.h for details.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL Int UMFPACK_report_triplet
+(
+    Int n_row,
+    Int n_col,
+    Int nz,
+    const Int Ti [ ],
+    const Int Tj [ ],
+    const double Tx [ ],
+#ifdef COMPLEX
+    const double Tz [ ],
+#endif
+    const double Control [UMFPACK_CONTROL]
+)
+{
+    Entry t ;
+    Int prl, prl1, k, i, j, do_values ;
+#ifdef COMPLEX
+    Int split = SPLIT (Tz) ;
+#endif
+
+    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+    if (prl <= 2)
+    {
+	return (UMFPACK_OK) ;
+    }
+
+    PRINTF (("triplet-form matrix, n_row = "ID", n_col = "ID" nz = "ID". ",
+	n_row, n_col, nz)) ;
+
+    if (!Ti || !Tj)
+    {
+	PRINTF (("ERROR: indices not present\n\n")) ;
+	return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    if (n_row <= 0 || n_col <= 0)
+    {
+	PRINTF (("ERROR: n_row or n_col is <= 0\n\n")) ;
+	return (UMFPACK_ERROR_n_nonpositive) ;
+    }
+
+    if (nz < 0)
+    {
+	PRINTF (("ERROR: nz is < 0\n\n")) ;
+	return (UMFPACK_ERROR_invalid_matrix) ;
+    }
+
+    PRINTF4 (("\n")) ;
+
+    do_values = Tx != (double *) NULL ;
+
+    prl1 = prl ;
+    for (k = 0 ; k < nz ; k++)
+    {
+	i = Ti [k] ;
+	j = Tj [k] ;
+	PRINTF4 (("    "ID" : "ID" "ID" ", INDEX (k), INDEX (i), INDEX (j))) ;
+	if (do_values && prl >= 4)
+	{
+	    ASSIGN (t, Tx, Tz, k, split) ;
+	    PRINT_ENTRY (t) ;
+	}
+	PRINTF4 (("\n")) ;
+	if (i < 0 || i >= n_row || j < 0 || j >= n_col)
+	{
+	    /* invalid triplet */
+	    PRINTF (("ERROR: invalid triplet\n\n")) ;
+	    return (UMFPACK_ERROR_invalid_matrix) ;
+	}
+	if (prl == 4 && k == 9 && nz > 10)
+	{
+	    PRINTF (("    ...\n")) ;
+	    prl-- ;
+	}
+    }
+    prl = prl1 ;
+
+    PRINTF4 (("    triplet-form matrix ")) ;
+    PRINTF (("OK\n\n")) ;
+    return (UMFPACK_OK) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_vector.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_vector.c
new file mode 100644
index 0000000..3b27d3f
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_vector.c
@@ -0,0 +1,43 @@
+/* ========================================================================== */
+/* === UMFPACK_report_vector ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints a real or complex vector.
+    See umfpack_report_vector.h for details.
+*/
+
+#include "umf_internal.h"
+#include "umf_report_vector.h"
+
+GLOBAL Int UMFPACK_report_vector
+(
+    Int n,
+    const double Xx [ ],
+#ifdef COMPLEX
+    const double Xz [ ],
+#endif
+    const double Control [UMFPACK_CONTROL]
+)
+{
+    Int prl ;
+
+#ifndef COMPLEX
+    double *Xz = (double *) NULL ;
+#endif
+
+    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+    if (prl <= 2)
+    {
+	return (UMFPACK_OK) ;
+    }
+
+    return (UMF_report_vector (n, Xx, Xz, prl, TRUE, FALSE)) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_save_numeric.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_save_numeric.c
new file mode 100644
index 0000000..2d8a73f
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_save_numeric.c
@@ -0,0 +1,92 @@
+/* ========================================================================== */
+/* === UMFPACK_save_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Saves a Numeric object to a file.  It can later be read back
+    in via a call to umfpack_*_load_numeric.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+
+#define WRITE(object,type,n) \
+{ \
+    ASSERT (object != (type *) NULL) ; \
+    if (fwrite (object, sizeof (type), n, f) != 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) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_save_symbolic.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_save_symbolic.c
new file mode 100644
index 0000000..c326b28
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_save_symbolic.c
@@ -0,0 +1,95 @@
+/* ========================================================================== */
+/* === UMFPACK_save_symbolic ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Saves a Symbolic object to a file.  It can later be read
+    back in via a call to umfpack_*_load_symbolic.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_symbolic.h"
+
+#define WRITE(object,type,n) \
+{ \
+    ASSERT (object != (type *) NULL) ; \
+    if (fwrite (object, sizeof (type), n, f) != 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) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_scale.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_scale.c
new file mode 100644
index 0000000..5a08616
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_scale.c
@@ -0,0 +1,158 @@
+/* ========================================================================== */
+/* === UMFPACK_scale ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Applies the scale factors computed during numerical
+    factorization to a vector. See umfpack_scale.h for more details.
+
+    The LU factorization is L*U = P*R*A*Q, where P and Q are permutation
+    matrices, and R is diagonal.  This routine computes X = R * B using the
+    matrix R stored in the Numeric object.
+
+    Returns FALSE if any argument is invalid, TRUE otherwise.
+
+    If R not present in the Numeric object, then R = I and no floating-point
+    work is done.  B is simply copied into X.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+
+GLOBAL Int UMFPACK_scale
+(
+    double Xx [ ],
+#ifdef COMPLEX
+    double Xz [ ],
+#endif
+    const double Bx [ ],
+#ifdef COMPLEX
+    const double Bz [ ],
+#endif
+    void *NumericHandle
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    NumericType *Numeric ;
+    Int n, i ;
+    double *Rs ;
+#ifdef COMPLEX
+    Int split = SPLIT (Xz) && SPLIT (Bz) ;
+#endif
+
+    Numeric = (NumericType *) NumericHandle ;
+    if (!UMF_valid_numeric (Numeric))
+    {
+	return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    n = Numeric->n_row ;
+    Rs = Numeric->Rs ;
+
+    if (!Xx || !Bx)
+    {
+	return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* X = R*B or R\B */
+    /* ---------------------------------------------------------------------- */
+
+    if (Rs != (double *) NULL)
+    {
+#ifndef NRECIPROCAL
+	if (Numeric->do_recip)
+	{
+	    /* multiply by the scale factors */
+#ifdef COMPLEX
+	    if (split)
+	    {
+		for (i = 0 ; i < n ; i++)
+		{
+		    Xx [i] = Bx [i] * Rs [i] ;
+		    Xz [i] = Bz [i] * Rs [i] ;
+		}
+	    }
+	    else
+	    {
+		for (i = 0 ; i < n ; i++)
+		{
+		    Xx [2*i  ] = Bx [2*i  ] * Rs [i] ;
+		    Xx [2*i+1] = Bx [2*i+1] * Rs [i] ;
+		}
+	    }
+#else
+	    for (i = 0 ; i < n ; i++)
+	    {
+		Xx [i] = Bx [i] * Rs [i] ;
+	    }
+#endif
+	}
+	else
+#endif
+	{
+	    /* divide by the scale factors */
+#ifdef COMPLEX
+	    if (split)
+	    {
+		for (i = 0 ; i < n ; i++)
+		{
+		    Xx [i] = Bx [i] / Rs [i] ;
+		    Xz [i] = Bz [i] / Rs [i] ;
+		}
+	    }
+	    else
+	    {
+		for (i = 0 ; i < n ; i++)
+		{
+		    Xx [2*i  ] = Bx [2*i  ] / Rs [i] ;
+		    Xx [2*i+1] = Bx [2*i+1] / Rs [i] ;
+		}
+	    }
+#else
+	    for (i = 0 ; i < n ; i++)
+	    {
+		Xx [i] = Bx [i] / Rs [i] ;
+	    }
+#endif
+	}
+    }
+    else
+    {
+	/* no scale factors, just copy B into X */
+#ifdef COMPLEX
+        if (split)
+	{
+	    for (i = 0 ; i < n ; i++)
+	    {
+		Xx [i] = Bx [i] ;
+		Xz [i] = Bz [i] ;
+	    }
+	}
+	else
+	{
+	    for (i = 0 ; i < n ; i++)
+	    {
+		Xx [2*i  ] = Bx [2*i  ] ;
+		Xx [2*i+1] = Bx [2*i+1] ;
+	    }
+	}
+#else
+	for (i = 0 ; i < n ; i++)
+	{
+	    Xx [i] = Bx [i] ;
+	}
+#endif
+    }
+
+    return (UMFPACK_OK) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_solve.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_solve.c
new file mode 100644
index 0000000..fcdebe2
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_solve.c
@@ -0,0 +1,245 @@
+/* ========================================================================== */
+/* === UMFPACK_solve ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Solves a linear system using the numerical factorization
+    computed by UMFPACK_numeric.  See umfpack_solve.h for more details.
+
+    For umfpack_*_solve:
+	Dynamic memory usage:  UMFPACK_solve calls UMF_malloc twice, for
+	workspace of size c*n*sizeof(double) + n*sizeof(Int), where c is
+	defined below.  On return, all of this workspace is free'd via UMF_free.
+
+    For umfpack_*_wsolve:
+	No dynamic memory usage.  Input arrays are used for workspace instead.
+	Pattern is a workspace of size n Integers.  The double array W must be
+	at least of size c*n, where c is defined below.
+
+    If iterative refinement is requested, and Ax=b, A'x=b or A.'x=b is being
+    solved, and the matrix A is not singular, then c is 5 for the real version
+    and 10 for the complex version.  Otherwise, c is 1 for the real version and
+    4 for the complex version.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+#include "umf_solve.h"
+
+#ifndef WSOLVE
+#include "umf_malloc.h"
+#include "umf_free.h"
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+#endif
+
+GLOBAL Int
+#ifdef WSOLVE
+UMFPACK_wsolve
+#else
+UMFPACK_solve
+#endif
+(
+    Int sys,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    double Xx [ ],
+#ifdef COMPLEX
+    double Xz [ ],
+#endif
+    const double Bx [ ],
+#ifdef COMPLEX
+    const double Bz [ ],
+#endif
+    void *NumericHandle,
+    const double Control [UMFPACK_CONTROL],
+    double User_Info [UMFPACK_INFO]
+#ifdef WSOLVE
+    , Int Pattern [ ],
+    double W [ ]
+#endif
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    double Info2 [UMFPACK_INFO], stats [2] ;
+    double *Info ;
+    NumericType *Numeric ;
+    Int n, i, irstep, status ;
+#ifndef WSOLVE
+    Int *Pattern, wsize ;
+    double *W ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get the amount of time used by the process so far */
+    /* ---------------------------------------------------------------------- */
+
+    umfpack_tic (stats) ;
+
+#ifndef WSOLVE
+#ifndef NDEBUG
+    init_count = UMF_malloc_count ;
+#endif
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    irstep = GET_CONTROL (UMFPACK_IRSTEP, UMFPACK_DEFAULT_IRSTEP) ;
+
+    if (User_Info != (double *) NULL)
+    {
+	/* return Info in user's array */
+	Info = User_Info ;
+	/* clear the parts of Info that are set by UMFPACK_solve */
+	for (i = UMFPACK_IR_TAKEN ; i <= UMFPACK_SOLVE_TIME ; i++)
+	{
+	    Info [i] = EMPTY ;
+	}
+    }
+    else
+    {
+	/* no Info array passed - use local one instead */
+	Info = Info2 ;
+	for (i = 0 ; i < UMFPACK_INFO ; i++)
+	{
+	    Info [i] = EMPTY ;
+	}
+    }
+
+    Info [UMFPACK_STATUS] = UMFPACK_OK ;
+    Info [UMFPACK_SOLVE_FLOPS] = 0 ;
+
+    Numeric = (NumericType *) NumericHandle ;
+    if (!UMF_valid_numeric (Numeric))
+    {
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_Numeric_object ;
+	return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    Info [UMFPACK_NROW] = Numeric->n_row ;
+    Info [UMFPACK_NCOL] = Numeric->n_col ;
+
+    if (Numeric->n_row != Numeric->n_col)
+    {
+	/* only square systems can be handled */
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_system ;
+	return (UMFPACK_ERROR_invalid_system) ;
+    }
+    n = Numeric->n_row ;
+    if (Numeric->nnzpiv < n
+	|| SCALAR_IS_ZERO (Numeric->rcond) || SCALAR_IS_NAN (Numeric->rcond))
+    {
+	/* turn off iterative refinement if A is singular */
+	/* or if U has NaN's on the diagonal. */
+	irstep = 0 ;
+    }
+
+    if (!Xx || !Bx)
+    {
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ;
+	return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    if (sys >= UMFPACK_Pt_L)
+    {
+	/* no iterative refinement except for nonsingular Ax=b, A'x=b, A.'x=b */
+	irstep = 0 ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate or check the workspace */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef WSOLVE
+
+    if (!W || !Pattern)
+    {
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ;
+	return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+#else
+
+#ifdef COMPLEX
+    if (irstep > 0)
+    {
+	wsize = 10*n ;		/* W, X, Z, S, Y, B2 */
+    }
+    else
+    {
+	wsize = 4*n ;		/* W, X */
+    }
+#else
+    if (irstep > 0)
+    {
+	wsize = 5*n ;		/* W, Z, S, Y, B2 */
+    }
+    else
+    {
+	wsize = n ;		/* W */
+    }
+#endif
+
+    Pattern = (Int *) UMF_malloc (n, sizeof (Int)) ;
+    W = (double *) UMF_malloc (wsize, sizeof (double)) ;
+    if (!W || !Pattern)
+    {
+	DEBUGm4 (("out of memory: solve work\n")) ;
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+	(void) UMF_free ((void *) W) ;
+	(void) UMF_free ((void *) Pattern) ;
+	return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+#endif	/* WSOLVE */
+
+    /* ---------------------------------------------------------------------- */
+    /* solve the system */
+    /* ---------------------------------------------------------------------- */
+
+    status = UMF_solve (sys, Ap, Ai, Ax, Xx, Bx,
+#ifdef COMPLEX
+	Az, Xz, Bz,
+#endif
+	Numeric, irstep, Info, Pattern, W) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free the workspace (if allocated) */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef WSOLVE
+    (void) UMF_free ((void *) W) ;
+    (void) UMF_free ((void *) Pattern) ;
+    ASSERT (UMF_malloc_count == init_count) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get the time used by UMFPACK_*solve */
+    /* ---------------------------------------------------------------------- */
+
+    Info [UMFPACK_STATUS] = status ;
+    if (status >= 0)
+    {
+	umfpack_toc (stats) ;
+	Info [UMFPACK_SOLVE_WALLTIME] = stats [0] ;
+	Info [UMFPACK_SOLVE_TIME] = stats [1] ;
+    }
+
+    return (status) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_symbolic.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_symbolic.c
new file mode 100644
index 0000000..39ee106
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_symbolic.c
@@ -0,0 +1,39 @@
+/* ========================================================================== */
+/* === UMFPACK_symbolic ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Performs a symbolic factorization.
+    See umfpack_symbolic.h for details.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL Int UMFPACK_symbolic
+(
+    Int n_row,
+    Int n_col,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    void **SymbolicHandle,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+)
+{
+    Int *Qinit = (Int *) NULL ;
+    return (UMFPACK_qsymbolic (n_row, n_col, Ap, Ai, Ax,
+#ifdef COMPLEX
+	Az,
+#endif
+	Qinit, SymbolicHandle, Control, Info)) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_tictoc.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_tictoc.c
new file mode 100644
index 0000000..605f789
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_tictoc.c
@@ -0,0 +1,106 @@
+/* ========================================================================== */
+/* === umfpack_tictoc ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Returns the time in seconds used by the process, and
+    the current wall clock time.  BE CAREFUL:  if you compare the run time of
+    UMFPACK with other sparse matrix packages, be sure to use the same timer.
+    See umfpack_tictoc.h for details.
+
+    These routines conform to the POSIX standard.  See umf_config.h for
+    more details.
+*/
+
+#include "umf_internal.h"
+
+#ifdef NO_TIMER
+
+/* -------------------------------------------------------------------------- */
+/* no timer used if -DNO_TIMER is defined at compile time */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_tic (double stats [2])
+{
+    stats [0] = 0 ;
+    stats [1] = 0 ;
+}
+
+void umfpack_toc (double stats [2])
+{
+    stats [0] = 0 ;
+    stats [1] = 0 ;
+}
+
+#else
+
+/* -------------------------------------------------------------------------- */
+/* timer routines, using either times() or clock() */
+/* -------------------------------------------------------------------------- */
+
+#define TINY_TIME 1e-4
+
+#ifndef NPOSIX
+
+#include <unistd.h>
+#include <sys/times.h>
+
+void umfpack_tic (double stats [2])
+{
+    /* Return the current time */
+    /* stats [0]: current wallclock time, in seconds */
+    /* stats [1]: user + system time for the process, in seconds */
+
+    double ticks ;
+    struct tms t ;
+
+    ticks = (double) sysconf (_SC_CLK_TCK) ;
+    stats [0] = (double) times (&t) / ticks ;
+    stats [1] = (double) (t.tms_utime + t.tms_stime) / ticks ;
+
+    /* if time is tiny, just return zero */
+    if (stats [0] < TINY_TIME) stats [0] = 0 ;
+    if (stats [1] < TINY_TIME) stats [1] = 0 ;
+}
+
+#else
+
+/* Generic ANSI C: use the ANSI clock function.  No wallclock time. */
+
+#include <time.h>
+
+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 ;
+
+}
+
+#endif
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_timer.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_timer.c
new file mode 100644
index 0000000..7e8d20b
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_timer.c
@@ -0,0 +1,83 @@
+/* ========================================================================== */
+/* === umfpack_timer ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Returns the time in seconds used by the process.  BE
+    CAREFUL:  if you compare the run time of UMFPACK with other sparse matrix
+    packages, be sure to use the same timer.  See umfpack_timer.h for details.
+    See umfpack_tictoc.h, which is the timer used internally by UMFPACK.
+*/
+
+#ifdef NO_TIMER
+
+/* -------------------------------------------------------------------------- */
+/* no timer used if -DNO_TIMER is defined at compile time */
+/* -------------------------------------------------------------------------- */
+
+double umfpack_timer ( void )
+{
+    return (0) ;
+}
+
+#else
+
+#ifdef GETRUSAGE
+
+/* -------------------------------------------------------------------------- */
+/* use getrusage for accurate process times (and no overflow) */
+/* -------------------------------------------------------------------------- */
+
+/*
+    This works under Solaris, SGI Irix, Linux, IBM RS 6000 (AIX), and Compaq
+    Alpha.  It might work on other Unix systems, too.  Includes both the "user
+    time" and the "system time".  The system time is the time spent by the
+    operating system on behalf of the process, and thus should be charged to
+    the process.
+*/
+
+#include <sys/time.h>
+#include <sys/resource.h>
+
+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 <time.h>
+
+double umfpack_timer ( void )
+{
+    return (((double) (clock ( ))) / ((double) (CLOCKS_PER_SEC))) ;
+}
+
+#endif
+#endif
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_transpose.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_transpose.c
new file mode 100644
index 0000000..4a6b9ba
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_transpose.c
@@ -0,0 +1,108 @@
+/* ========================================================================== */
+/* === UMFPACK_transpose ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User callable.  Computes a permuted transpose, R = (A (P,Q))' in MATLAB
+    notation.  See umfpack_transpose.h for details.  A and R can be rectangular.
+    The matrix A may be singular.
+    The complex version can do transpose (') or array transpose (.').
+
+    Dynamic memory usage: A single call to UMF_malloc is made, for a workspace
+    of size max (n_row,n_col,1) * sizeof(Int).  This is then free'd on return,
+    via UMF_free.
+*/
+
+#include "umf_internal.h"
+#include "umf_transpose.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_transpose
+(
+    Int n_row,
+    Int n_col,
+    const Int Ap [ ],	/* size n_col+1 */
+    const Int Ai [ ],	/* size nz = Ap [n_col] */
+    const double Ax [ ], /* size nz, if present */
+#ifdef COMPLEX
+    const double Az [ ], /* size nz, if present */
+#endif
+
+    const Int P [ ],	/* P [k] = i means original row i is kth row in A(P,Q)*/
+			/* P is identity if not present */
+			/* size n_row, if present */
+
+    const Int Q [ ],	/* Q [k] = j means original col j is kth col in A(P,Q)*/
+			/* Q is identity if not present */
+			/* size n_col, if present */
+
+    Int Rp [ ],		/* size n_row+1 */
+    Int Ri [ ],		/* size nz */
+    double Rx [ ]	/* size nz, if present */
+#ifdef COMPLEX
+    , double Rz [ ]	/* size nz, if present */
+    , Int do_conjugate	/* if true, then to conjugate transpose */
+			/* otherwise, do array transpose */
+#endif
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int status, *W, nn ;
+
+#ifndef NDEBUG
+    init_count = UMF_malloc_count ;
+    UMF_dump_start ( ) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    nn = MAX (n_row, n_col) ;
+    nn = MAX (nn, 1) ;
+    W = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+    if (!W)
+    {
+	DEBUGm4 (("out of memory: transpose work\n")) ;
+	ASSERT (UMF_malloc_count == init_count) ;
+	return (UMFPACK_ERROR_out_of_memory) ;
+    }
+    ASSERT (UMF_malloc_count == init_count + 1) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* C = (A (P,Q))' or (A (P,Q)).' */
+    /* ---------------------------------------------------------------------- */
+
+    status = UMF_transpose (n_row, n_col, Ap, Ai, Ax, P, Q, n_col, Rp, Ri, Rx,
+	W, TRUE
+#ifdef COMPLEX
+	, Az, Rz, do_conjugate
+#endif
+	) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free the workspace */
+    /* ---------------------------------------------------------------------- */
+
+    (void) UMF_free ((void *) W) ;
+    ASSERT (UMF_malloc_count == init_count) ;
+
+    return (status) ;
+}
diff --git a/src/C/SuiteSparse/UMFPACK/Source/umfpack_triplet_to_col.c b/src/C/SuiteSparse/UMFPACK/Source/umfpack_triplet_to_col.c
new file mode 100644
index 0000000..92f5a8d
--- /dev/null
+++ b/src/C/SuiteSparse/UMFPACK/Source/umfpack_triplet_to_col.c
@@ -0,0 +1,225 @@
+/* ========================================================================== */
+/* === UMFPACK_triplet_to_col =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 5.0, Copyright (c) 1995-2006 by Timothy A. Davis.  CISE,   */
+/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User callable.  Converts triplet input to column-oriented form.  Duplicate
+    entries may exist (they are summed in the output).  The columns of the
+    column-oriented form are in sorted order.  The input is not modified.
+    Returns 1 if OK, 0 if an error occurred.  See umfpack_triplet_to_col.h for
+    details.
+
+    If Map is present (a non-NULL pointer to an Int array of size nz), then on
+    output it holds the position of the triplets in the column-form matrix.
+    That is, suppose p = Map [k], and the k-th triplet is i=Ti[k], j=Tj[k], and
+    aij=Tx[k].  Then i=Ai[p], and aij will have been summed into Ax[p].  Also,
+    Ap[j] <= p < Ap[j+1].  The Map array is not computed if it is (Int *) NULL.
+
+    Dynamic memory usage:
+
+	If numerical values are present, then one (two for complex version)
+	workspace of size (nz+1)*sizeof(double) is allocated via UMF_malloc.
+	Next, 4 calls to UMF_malloc are made to obtain workspace of size
+	((nz+1) + (n_row+1) + n_row + MAX (n_row,n_col)) * sizeof(Int).  All of
+	this workspace (4 to 6 objects) are free'd via UMF_free on return.
+
+	For the complex version, additional space is allocated.
+
+	An extra array of size nz*sizeof(Int) is allocated if Map is present.
+*/
+
+#include "umf_internal.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+#include "umf_triplet.h"
+
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_triplet_to_col
+(
+    Int n_row,
+    Int n_col,
+    Int nz,
+    const Int Ti [ ],		/* size nz */
+    const Int Tj [ ],		/* size nz */
+    const double Tx [ ],	/* size nz */
+#ifdef COMPLEX
+    const double Tz [ ],	/* size nz */
+#endif
+    Int Ap [ ],			/* size n_col + 1 */
+    Int Ai [ ],			/* size nz */
+    double Ax [ ]		/* size nz */
+#ifdef COMPLEX
+    , double Az [ ]		/* size nz */
+#endif
+    , Int Map [ ]		/* size nz */
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int *RowCount, *Rp, *Rj, *W, nn, do_values, do_map, *Map2, status ;
+    double *Rx ;
+#ifdef COMPLEX
+    double *Rz ;
+    Int split ;
+#endif
+
+#ifndef NDEBUG
+    UMF_dump_start ( ) ;
+    init_count = UMF_malloc_count ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    if (!Ai || !Ap || !Ti || !Tj)
+    {
+	return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    if (n_row <= 0 || n_col <= 0)		/* must be > 0 */
+    {
+	return (UMFPACK_ERROR_n_nonpositive) ;
+    }
+
+    if (nz < 0)		/* nz must be >= 0 (singular matrices are OK) */
+    {
+	return (UMFPACK_ERROR_invalid_matrix) ;
+    }
+
+    nn = MAX (n_row, n_col) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Rx = (double *) NULL ;
+
+    do_values = Ax && Tx ;
+
+    if (do_values)
+    {
+#ifdef COMPLEX
+	Rx = (double *) UMF_malloc (2*nz+2, sizeof (double)) ;
+	split = SPLIT (Tz) && SPLIT (Az) ;
+	if (split)
+	{
+	    Rz = Rx + nz ;
+	}
+	else
+	{
+	    Rz = (double *) NULL ;
+	}
+#else
+	Rx = (double *) UMF_malloc (nz+1, sizeof (double)) ;
+#endif
+	if (!Rx)
+	{
+	    DEBUGm4 (("out of memory: triplet work \n")) ;
+	    ASSERT (UMF_malloc_count == init_count) ;
+	    return (UMFPACK_ERROR_out_of_memory) ;
+	}
+    }
+
+    do_map = (Map != (Int *) NULL) ;
+    Map2 = (Int *) NULL ;
+    if (do_map)
+    {
+	DEBUG0 (("Do map:\n")) ;
+	Map2 = (Int *) UMF_malloc (nz+1, sizeof (Int)) ;
+	if (!Map2)
+	{
+	    DEBUGm4 (("out of memory: triplet map\n")) ;
+	    (void) UMF_free ((void *) Rx) ;
+	    ASSERT (UMF_malloc_count == init_count) ;
+	    return (UMFPACK_ERROR_out_of_memory) ;
+	}
+    }
+
+    Rj = (Int *) UMF_malloc (nz+1, sizeof (Int)) ;
+    Rp = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+    RowCount = (Int *) UMF_malloc (n_row, sizeof (Int)) ;
+    W = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+    if (!Rj || !Rp || !RowCount || !W)
+    {
+	DEBUGm4 (("out of memory: triplet work (int)\n")) ;
+	(void) UMF_free ((void *) Rx) ;
+	(void) UMF_free ((void *) Map2) ;
+	(void) UMF_free ((void *) Rp) ;
+	(void) UMF_free ((void *) Rj) ;
+	(void) UMF_free ((void *) RowCount) ;
+	(void) UMF_free ((void *) W) ;
+	ASSERT (UMF_malloc_count == init_count) ;
+	return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+    ASSERT (UMF_malloc_count == init_count + 4 +
+	(Rx != (double *) NULL) + do_map) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert from triplet to column form */
+    /* ---------------------------------------------------------------------- */
+
+    if (do_map)
+    {
+	if (do_values)
+	{
+	    status = UMF_triplet_map_x (n_row, n_col, nz, Ti, Tj, Ap, Ai, Rp,
+		Rj, W, RowCount, Tx, Ax, Rx
+#ifdef COMPLEX
+		, Tz, Az, Rz
+#endif
+		, Map, Map2) ;
+	}
+	else
+	{
+	    status = UMF_triplet_map_nox (n_row, n_col, nz, Ti, Tj, Ap, Ai, Rp,
+		Rj, W, RowCount, Map, Map2) ;
+	}
+    }
+    else
+    {
+	if (do_values)
+	{
+	    status = UMF_triplet_nomap_x (n_row, n_col, nz, Ti, Tj, Ap, Ai, Rp,
+		Rj, W, RowCount , Tx, Ax, Rx
+#ifdef COMPLEX
+		, Tz, Az, Rz
+#endif
+		) ;
+	}
+	else
+	{
+	    status = UMF_triplet_nomap_nox (n_row, n_col, nz, Ti, Tj, Ap, Ai,
+		Rp, Rj, W, RowCount) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* free the workspace */
+    /* ---------------------------------------------------------------------- */
+
+    (void) UMF_free ((void *) Rx) ;
+    (void) UMF_free ((void *) Map2) ;
+    (void) UMF_free ((void *) Rp) ;
+    (void) UMF_free ((void *) Rj) ;
+    (void) UMF_free ((void *) RowCount) ;
+    (void) UMF_free ((void *) W) ;
+    ASSERT (UMF_malloc_count == init_count) ;
+
+    return (status) ;
+}
diff --git a/src/C/SuiteSparse_cvxopt_extra/README b/src/C/SuiteSparse_cvxopt_extra/README
new file mode 100644
index 0000000..952cf9e
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/README
@@ -0,0 +1,7 @@
+This directory contains CVXOPT specific modifications to the libraries 
+in SuiteSparse necessary to build them with CVXOPT using distutils.
+
+The additions are very minor; the directory contains a number of
+files for different numerical types (int, long, single and double
+precision floating point etc.) that would normally be automatically
+generated by the C preprocessor.  
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_global.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_global.c
new file mode 100644
index 0000000..e8c9e8e
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_global.c
@@ -0,0 +1 @@
+#include "../../SuiteSparse/AMD/Source/amd_global.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_1.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_1.c
new file mode 100644
index 0000000..4353630
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_1.c
@@ -0,0 +1,3 @@
+#define DINT
+
+#include "../../SuiteSparse/AMD/Source/amd_1.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_2.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_2.c
new file mode 100644
index 0000000..75d8670
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_2.c
@@ -0,0 +1,3 @@
+#define DINT
+
+#include "../../SuiteSparse/AMD/Source/amd_2.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_aat.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_aat.c
new file mode 100644
index 0000000..16042e2
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_aat.c
@@ -0,0 +1,3 @@
+#define DINT
+
+#include "../../SuiteSparse/AMD/Source/amd_aat.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_defaults.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_defaults.c
new file mode 100644
index 0000000..9ec8227
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_defaults.c
@@ -0,0 +1,3 @@
+#define DINT
+
+#include "../../SuiteSparse/AMD/Source/amd_defaults.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_dump.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_dump.c
new file mode 100644
index 0000000..ba46149
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_dump.c
@@ -0,0 +1,3 @@
+#define DINT
+
+#include "../../SuiteSparse/AMD/Source/amd_dump.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_order.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_order.c
new file mode 100644
index 0000000..9a396e5
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_order.c
@@ -0,0 +1,3 @@
+#define DINT
+
+#include "../../SuiteSparse/AMD/Source/amd_order.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_post_tree.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_post_tree.c
new file mode 100644
index 0000000..bfbf2ce
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_post_tree.c
@@ -0,0 +1,3 @@
+#define DINT
+
+#include "../../SuiteSparse/AMD/Source/amd_post_tree.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_postorder.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_postorder.c
new file mode 100644
index 0000000..6f51bad
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_postorder.c
@@ -0,0 +1,3 @@
+#define DINT
+
+#include "../../SuiteSparse/AMD/Source/amd_postorder.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_preprocess.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_preprocess.c
new file mode 100644
index 0000000..b5fb2c3
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_preprocess.c
@@ -0,0 +1,3 @@
+#define DINT
+
+#include "../../SuiteSparse/AMD/Source/amd_preprocess.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_valid.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_valid.c
new file mode 100644
index 0000000..18f02d9
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_valid.c
@@ -0,0 +1,3 @@
+#define DINT
+
+#include "../../SuiteSparse/AMD/Source/amd_valid.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_1.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_1.c
new file mode 100644
index 0000000..d5ecba0
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_1.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/AMD/Source/amd_1.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_2.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_2.c
new file mode 100644
index 0000000..5a18aca
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_2.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/AMD/Source/amd_2.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_aat.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_aat.c
new file mode 100644
index 0000000..77f7ac8
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_aat.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/AMD/Source/amd_aat.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_defaults.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_defaults.c
new file mode 100644
index 0000000..5c8c865
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_defaults.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/AMD/Source/amd_defaults.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_dump.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_dump.c
new file mode 100644
index 0000000..c598601
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_dump.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/AMD/Source/amd_dump.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_order.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_order.c
new file mode 100644
index 0000000..4003f6d
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_order.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/AMD/Source/amd_order.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_post_tree.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_post_tree.c
new file mode 100644
index 0000000..cb4851c
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_post_tree.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/AMD/Source/amd_post_tree.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_postorder.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_postorder.c
new file mode 100644
index 0000000..db6e9d7
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_postorder.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/AMD/Source/amd_postorder.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_preprocess.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_preprocess.c
new file mode 100644
index 0000000..a7c9c30
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_preprocess.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/AMD/Source/amd_preprocess.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_valid.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_valid.c
new file mode 100644
index 0000000..3804def
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_valid.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/AMD/Source/amd_valid.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_2by2.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_2by2.c
new file mode 100644
index 0000000..c27a474
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_2by2.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_2by2.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_assemble.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_assemble.c
new file mode 100644
index 0000000..84212ac
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_assemble.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_assemble.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_assemble_fixq.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_assemble_fixq.c
new file mode 100644
index 0000000..d5eeb60
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_assemble_fixq.c
@@ -0,0 +1,3 @@
+#define DINT
+#define FIXQ
+#include "../../SuiteSparse/UMFPACK/Source/umf_assemble.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_blas3_update.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_blas3_update.c
new file mode 100644
index 0000000..f8dc40d
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_blas3_update.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_blas3_update.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_build_tuples.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_build_tuples.c
new file mode 100644
index 0000000..1b7fcda
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_build_tuples.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_build_tuples.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_create_element.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_create_element.c
new file mode 100644
index 0000000..026507f
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_create_element.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_create_element.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_extend_front.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_extend_front.c
new file mode 100644
index 0000000..97583a0
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_extend_front.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_extend_front.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_garbage_collection.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_garbage_collection.c
new file mode 100644
index 0000000..5a8f268
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_garbage_collection.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_garbage_collection.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_get_memory.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_get_memory.c
new file mode 100644
index 0000000..fedad1e
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_get_memory.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_get_memory.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_grow_front.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_grow_front.c
new file mode 100644
index 0000000..c11fb7a
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_grow_front.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_grow_front.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_init_front.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_init_front.c
new file mode 100644
index 0000000..1952f39
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_init_front.c
@@ -0,0 +1,3 @@
+#define DINT
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_init_front.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_kernel.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_kernel.c
new file mode 100644
index 0000000..f1837ba
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_kernel.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_kernel.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_kernel_init.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_kernel_init.c
new file mode 100644
index 0000000..46bf880
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_kernel_init.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_kernel_init.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_kernel_wrapup.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_kernel_wrapup.c
new file mode 100644
index 0000000..a09a080
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_kernel_wrapup.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_lhsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_lhsolve.c
new file mode 100644
index 0000000..49c9547
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_lhsolve.c
@@ -0,0 +1,3 @@
+#define DINT
+#define CONJUGATE_SOLVE
+#include "../../SuiteSparse/UMFPACK/Source/umf_ltsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_local_search.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_local_search.c
new file mode 100644
index 0000000..fcbbdb8
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_local_search.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_local_search.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_lsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_lsolve.c
new file mode 100644
index 0000000..b6c592f
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_lsolve.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_lsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_ltsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_ltsolve.c
new file mode 100644
index 0000000..a4b7882
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_ltsolve.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_ltsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_alloc_element.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_alloc_element.c
new file mode 100644
index 0000000..044733d
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_alloc_element.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_element.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_alloc_head_block.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_alloc_head_block.c
new file mode 100644
index 0000000..7ff901e
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_alloc_head_block.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_head_block.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_alloc_tail_block.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_alloc_tail_block.c
new file mode 100644
index 0000000..32afac8
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_alloc_tail_block.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_tail_block.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_free_tail_block.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_free_tail_block.c
new file mode 100644
index 0000000..e0ac11b
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_free_tail_block.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_free_tail_block.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_init_memoryspace.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_init_memoryspace.c
new file mode 100644
index 0000000..2faaf74
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_init_memoryspace.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_init_memoryspace.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_row_search.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_row_search.c
new file mode 100644
index 0000000..50e4cab
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_row_search.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_row_search.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_scale.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_scale.c
new file mode 100644
index 0000000..a89fe95
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_scale.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_scale.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_scale_column.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_scale_column.c
new file mode 100644
index 0000000..f86b9f8
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_scale_column.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_scale_column.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_set_stats.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_set_stats.c
new file mode 100644
index 0000000..339c537
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_set_stats.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_set_stats.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_solve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_solve.c
new file mode 100644
index 0000000..2a1f680
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_solve.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_solve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_start_front.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_start_front.c
new file mode 100644
index 0000000..3f6ead3
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_start_front.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_start_front.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_store_lu.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_store_lu.c
new file mode 100644
index 0000000..b38ea09
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_store_lu.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_store_lu.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_store_lu_drop.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_store_lu_drop.c
new file mode 100644
index 0000000..7cb0fce
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_store_lu_drop.c
@@ -0,0 +1,3 @@
+#define DINT
+#define DROP
+#include "../../SuiteSparse/UMFPACK/Source/umf_store_lu.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_symbolic_usage.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_symbolic_usage.c
new file mode 100644
index 0000000..3e72467
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_symbolic_usage.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_symbolic_usage.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_transpose.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_transpose.c
new file mode 100644
index 0000000..2401dfe
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_transpose.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_transpose.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_tuple_lengths.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_tuple_lengths.c
new file mode 100644
index 0000000..1f80970
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_tuple_lengths.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_tuple_lengths.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_uhsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_uhsolve.c
new file mode 100644
index 0000000..441f34f
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_uhsolve.c
@@ -0,0 +1,3 @@
+#define DINT
+#define CONJUGATE_SOLVE
+#include "../../SuiteSparse/UMFPACK/Source/umf_utsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_usolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_usolve.c
new file mode 100644
index 0000000..c0cd333
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_usolve.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_usolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_utsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_utsolve.c
new file mode 100644
index 0000000..70de72b
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_utsolve.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_utsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_valid_numeric.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_valid_numeric.c
new file mode 100644
index 0000000..81ade90
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_valid_numeric.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_valid_numeric.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_valid_symbolic.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_valid_symbolic.c
new file mode 100644
index 0000000..4b5f446
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_valid_symbolic.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_valid_symbolic.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_2by2.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_2by2.c
new file mode 100644
index 0000000..12b54c4
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_2by2.c
@@ -0,0 +1,3 @@
+#define DLONG
+ 
+#include "../../SuiteSparse/UMFPACK/Source/umf_2by2.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_assemble.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_assemble.c
new file mode 100644
index 0000000..f49c736
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_assemble.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_assemble.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_assemble_fixq.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_assemble_fixq.c
new file mode 100644
index 0000000..1796089
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_assemble_fixq.c
@@ -0,0 +1,3 @@
+#define DLONG
+#define FIXQ
+#include "../../SuiteSparse/UMFPACK/Source/umf_assemble.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_blas3_update.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_blas3_update.c
new file mode 100644
index 0000000..b73b37d
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_blas3_update.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_blas3_update.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_build_tuples.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_build_tuples.c
new file mode 100644
index 0000000..dc8b4fc
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_build_tuples.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_build_tuples.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_create_elememt.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_create_elememt.c
new file mode 100644
index 0000000..dcf93a3
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_create_elememt.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_create_element.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_extend_front.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_extend_front.c
new file mode 100644
index 0000000..25e91aa
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_extend_front.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_extend_front.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_garbage_collection.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_garbage_collection.c
new file mode 100644
index 0000000..3cf1c70
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_garbage_collection.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_garbage_collection.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_get_memory.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_get_memory.c
new file mode 100644
index 0000000..760a8e4
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_get_memory.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_get_memory.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_grow_front.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_grow_front.c
new file mode 100644
index 0000000..e15ed69
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_grow_front.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_grow_front.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_init_front.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_init_front.c
new file mode 100644
index 0000000..5a13725
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_init_front.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_init_front.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_kernel.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_kernel.c
new file mode 100644
index 0000000..83b565f
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_kernel.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_kernel.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_kernel_init.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_kernel_init.c
new file mode 100644
index 0000000..a20b9c0
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_kernel_init.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_kernel_init.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_kernel_wrapup.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_kernel_wrapup.c
new file mode 100644
index 0000000..ab63c41
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_kernel_wrapup.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_lhsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_lhsolve.c
new file mode 100644
index 0000000..135efdd
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_lhsolve.c
@@ -0,0 +1,4 @@
+#define DLONG
+
+#define CONJUGATE_SOLVE
+#include "../../SuiteSparse/UMFPACK/Source/umf_ltsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_local_search.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_local_search.c
new file mode 100644
index 0000000..cd14206
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_local_search.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_local_search.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_lsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_lsolve.c
new file mode 100644
index 0000000..a3a912c
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_lsolve.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_lsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_ltsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_ltsolve.c
new file mode 100644
index 0000000..3a40f06
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_ltsolve.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_ltsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_alloc_element.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_alloc_element.c
new file mode 100644
index 0000000..4557361
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_alloc_element.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_element.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_alloc_head_block.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_alloc_head_block.c
new file mode 100644
index 0000000..7553478
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_alloc_head_block.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_head_block.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_alloc_tail_block.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_alloc_tail_block.c
new file mode 100644
index 0000000..00e7617
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_alloc_tail_block.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_tail_block.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_free_tail_block.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_free_tail_block.c
new file mode 100644
index 0000000..cce27ae
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_free_tail_block.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_free_tail_block.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_init_memoryspace.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_init_memoryspace.c
new file mode 100644
index 0000000..db0ce68
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_init_memoryspace.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_init_memoryspace.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_row_search.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_row_search.c
new file mode 100644
index 0000000..ca116ac
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_row_search.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_row_search.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_scale.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_scale.c
new file mode 100644
index 0000000..3843545
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_scale.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_scale.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_scale_column.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_scale_column.c
new file mode 100644
index 0000000..3fc1fa7
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_scale_column.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_scale_column.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_set_stats.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_set_stats.c
new file mode 100644
index 0000000..b79cd00
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_set_stats.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_set_stats.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_solve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_solve.c
new file mode 100644
index 0000000..58ec5e6
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_solve.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_solve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_start_front.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_start_front.c
new file mode 100644
index 0000000..9724290
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_start_front.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_start_front.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_store_lu.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_store_lu.c
new file mode 100644
index 0000000..cf7d91e
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_store_lu.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_store_lu.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_store_lu_drop.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_store_lu_drop.c
new file mode 100644
index 0000000..de8fcfc
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_store_lu_drop.c
@@ -0,0 +1,3 @@
+#define DLONG
+#define DROP
+#include "../../SuiteSparse/UMFPACK/Source/umf_store_lu.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_symbolic_usage.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_symbolic_usage.c
new file mode 100644
index 0000000..e86dba6
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_symbolic_usage.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_symbolic_usage.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_transpose.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_transpose.c
new file mode 100644
index 0000000..4283da4
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_transpose.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_transpose.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_tuple_lengths.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_tuple_lengths.c
new file mode 100644
index 0000000..0c15b26
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_tuple_lengths.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_tuple_lengths.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_uhsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_uhsolve.c
new file mode 100644
index 0000000..c966c08
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_uhsolve.c
@@ -0,0 +1,4 @@
+#define DLONG
+
+#define CONJUGATE_SOLVE
+#include "../../SuiteSparse/UMFPACK/Source/umf_utsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_usolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_usolve.c
new file mode 100644
index 0000000..e17eb16
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_usolve.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_usolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_utsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_utsolve.c
new file mode 100644
index 0000000..a9c3e99
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_utsolve.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_utsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_valid_numeric.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_valid_numeric.c
new file mode 100644
index 0000000..55cc2f7
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_valid_numeric.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_valid_numeric.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_valid_symbolic.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_valid_symbolic.c
new file mode 100644
index 0000000..0979643
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_valid_symbolic.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_valid_symbolic.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_analyze.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_analyze.c
new file mode 100644
index 0000000..76e3f5d
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_analyze.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_analyze.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_apply_order.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_apply_order.c
new file mode 100644
index 0000000..3d2ad76
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_apply_order.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_apply_order.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_colamd.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_colamd.c
new file mode 100644
index 0000000..aa018f1
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_colamd.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_colamd.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_free.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_free.c
new file mode 100644
index 0000000..0600fb5
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_free.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_free.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_fsize.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_fsize.c
new file mode 100644
index 0000000..27191c0
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_fsize.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_fsize.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_is_permutation.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_is_permutation.c
new file mode 100644
index 0000000..c874291
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_is_permutation.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_is_permutation.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_malloc.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_malloc.c
new file mode 100644
index 0000000..b9026e3
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_malloc.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_malloc.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_realloc.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_realloc.c
new file mode 100644
index 0000000..1f32b99
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_realloc.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_realloc.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_singletons.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_singletons.c
new file mode 100644
index 0000000..57c713d
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_singletons.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_singletons.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_analyze.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_analyze.c
new file mode 100644
index 0000000..df42f24
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_analyze.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_analyze.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_apply_order.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_apply_order.c
new file mode 100644
index 0000000..91a3027
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_apply_order.c
@@ -0,0 +1,2 @@
+#define DLONG
+#include "../../SuiteSparse/UMFPACK/Source/umf_apply_order.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_colamd.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_colamd.c
new file mode 100644
index 0000000..a974488
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_colamd.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_colamd.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_free.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_free.c
new file mode 100644
index 0000000..7ce0a3a
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_free.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_free.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_fsize.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_fsize.c
new file mode 100644
index 0000000..359c9b3
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_fsize.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_fsize.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_is_permutation.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_is_permutation.c
new file mode 100644
index 0000000..bc2846c
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_is_permutation.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_is_permutation.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_malloc.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_malloc.c
new file mode 100644
index 0000000..bfc2e26
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_malloc.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_malloc.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_realloc.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_realloc.c
new file mode 100644
index 0000000..410060f
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_realloc.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_realloc.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_singletons.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_singletons.c
new file mode 100644
index 0000000..c991f08
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_singletons.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_singletons.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_2by2.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_2by2.c
new file mode 100644
index 0000000..7ab8cfa
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_2by2.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_2by2.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_assemble.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_assemble.c
new file mode 100644
index 0000000..d1717bd
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_assemble.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_assemble.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_assemble_fixq.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_assemble_fixq.c
new file mode 100644
index 0000000..9eeccc1
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_assemble_fixq.c
@@ -0,0 +1,3 @@
+#define ZINT
+#define FIXQ
+#include "../../SuiteSparse/UMFPACK/Source/umf_assemble.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_blas3_update.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_blas3_update.c
new file mode 100644
index 0000000..297ed18
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_blas3_update.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_blas3_update.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_build_tuples.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_build_tuples.c
new file mode 100644
index 0000000..c22f9c6
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_build_tuples.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_build_tuples.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_create_element.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_create_element.c
new file mode 100644
index 0000000..12be344
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_create_element.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_create_element.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_extend_front.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_extend_front.c
new file mode 100644
index 0000000..92eb622
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_extend_front.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_extend_front.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_garbage_collection.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_garbage_collection.c
new file mode 100644
index 0000000..98f9cf7
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_garbage_collection.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_garbage_collection.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_get_memory.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_get_memory.c
new file mode 100644
index 0000000..d3a35d9
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_get_memory.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_get_memory.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_grow_front.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_grow_front.c
new file mode 100644
index 0000000..e5c10f2
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_grow_front.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_grow_front.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_init_front.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_init_front.c
new file mode 100644
index 0000000..b90e7fe
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_init_front.c
@@ -0,0 +1,3 @@
+#define ZINT
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_init_front.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_kernel.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_kernel.c
new file mode 100644
index 0000000..dbdfde4
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_kernel.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_kernel.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_kernel_init.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_kernel_init.c
new file mode 100644
index 0000000..3c55c35
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_kernel_init.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_kernel_init.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_kernel_wrapup.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_kernel_wrapup.c
new file mode 100644
index 0000000..0dae817
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_kernel_wrapup.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_lhsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_lhsolve.c
new file mode 100644
index 0000000..1cdbad9
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_lhsolve.c
@@ -0,0 +1,3 @@
+#define ZINT
+#define CONJUGATE_SOLVE
+#include "../../SuiteSparse/UMFPACK/Source/umf_ltsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_local_search.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_local_search.c
new file mode 100644
index 0000000..751cf5c
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_local_search.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_local_search.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_lsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_lsolve.c
new file mode 100644
index 0000000..9260f15
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_lsolve.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_lsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_ltsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_ltsolve.c
new file mode 100644
index 0000000..6a19361
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_ltsolve.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_ltsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_alloc_element.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_alloc_element.c
new file mode 100644
index 0000000..b4e411f
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_alloc_element.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_element.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_alloc_head_block.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_alloc_head_block.c
new file mode 100644
index 0000000..180a21a
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_alloc_head_block.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_head_block.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_alloc_tail_block.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_alloc_tail_block.c
new file mode 100644
index 0000000..b00850a
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_alloc_tail_block.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_tail_block.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_free_tail_block.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_free_tail_block.c
new file mode 100644
index 0000000..1579e4e
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_free_tail_block.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_free_tail_block.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_init_memoryspace.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_init_memoryspace.c
new file mode 100644
index 0000000..5b8cbbb
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_init_memoryspace.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_init_memoryspace.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_row_search.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_row_search.c
new file mode 100644
index 0000000..82218a9
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_row_search.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_row_search.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_scale.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_scale.c
new file mode 100644
index 0000000..0f24eaa
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_scale.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_scale.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_scale_column.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_scale_column.c
new file mode 100644
index 0000000..dd71747
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_scale_column.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_scale_column.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_set_stats.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_set_stats.c
new file mode 100644
index 0000000..b2fccdd
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_set_stats.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_set_stats.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_solve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_solve.c
new file mode 100644
index 0000000..05774ed
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_solve.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_solve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_start_front.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_start_front.c
new file mode 100644
index 0000000..578992d
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_start_front.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_start_front.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_store_lu.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_store_lu.c
new file mode 100644
index 0000000..2d5f40d
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_store_lu.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_store_lu.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_store_lu_drop.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_store_lu_drop.c
new file mode 100644
index 0000000..123ec11
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_store_lu_drop.c
@@ -0,0 +1,3 @@
+#define ZINT
+#define DROP
+#include "../../SuiteSparse/UMFPACK/Source/umf_store_lu.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_symbolic_usage.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_symbolic_usage.c
new file mode 100644
index 0000000..3b7bc05
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_symbolic_usage.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_symbolic_usage.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_transpose.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_transpose.c
new file mode 100644
index 0000000..152e783
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_transpose.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_transpose.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_tuple_lengths.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_tuple_lengths.c
new file mode 100644
index 0000000..3a23016
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_tuple_lengths.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_tuple_lengths.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_uhsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_uhsolve.c
new file mode 100644
index 0000000..e6d78d8
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_uhsolve.c
@@ -0,0 +1,3 @@
+#define ZINT
+#define CONJUGATE_SOLVE
+#include "../../SuiteSparse/UMFPACK/Source/umf_utsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_usolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_usolve.c
new file mode 100644
index 0000000..3aa1c43
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_usolve.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_usolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_utsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_utsolve.c
new file mode 100644
index 0000000..56c47b5
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_utsolve.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_utsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_valid_numeric.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_valid_numeric.c
new file mode 100644
index 0000000..206be5b
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_valid_numeric.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_valid_numeric.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_valid_symbolic.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_valid_symbolic.c
new file mode 100644
index 0000000..d3aa54d
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_valid_symbolic.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umf_valid_symbolic.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_2by2.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_2by2.c
new file mode 100644
index 0000000..2d3d097
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_2by2.c
@@ -0,0 +1,3 @@
+#define ZLONG
+ 
+#include "../../SuiteSparse/UMFPACK/Source/umf_2by2.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_assemble.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_assemble.c
new file mode 100644
index 0000000..c5f9f0f
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_assemble.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_assemble.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_assemble_fixq.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_assemble_fixq.c
new file mode 100644
index 0000000..b94d2da
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_assemble_fixq.c
@@ -0,0 +1,3 @@
+#define ZLONG
+#define FIXQ
+#include "../../SuiteSparse/UMFPACK/Source/umf_assemble.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_blas3_update.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_blas3_update.c
new file mode 100644
index 0000000..d7827ab
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_blas3_update.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_blas3_update.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_build_tuples.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_build_tuples.c
new file mode 100644
index 0000000..00845e4
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_build_tuples.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_build_tuples.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_create_elememt.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_create_elememt.c
new file mode 100644
index 0000000..ffd7567
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_create_elememt.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_create_element.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_extend_front.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_extend_front.c
new file mode 100644
index 0000000..b149b7d
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_extend_front.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_extend_front.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_garbage_collection.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_garbage_collection.c
new file mode 100644
index 0000000..b7edc57
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_garbage_collection.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_garbage_collection.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_get_memory.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_get_memory.c
new file mode 100644
index 0000000..eff5a54
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_get_memory.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_get_memory.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_grow_front.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_grow_front.c
new file mode 100644
index 0000000..52a23f8
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_grow_front.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_grow_front.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_init_front.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_init_front.c
new file mode 100644
index 0000000..902f850
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_init_front.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_init_front.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_kernel.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_kernel.c
new file mode 100644
index 0000000..3387f55
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_kernel.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_kernel.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_kernel_init.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_kernel_init.c
new file mode 100644
index 0000000..eeee308
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_kernel_init.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_kernel_init.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_kernel_wrapup.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_kernel_wrapup.c
new file mode 100644
index 0000000..5a2cdd4
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_kernel_wrapup.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_lhsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_lhsolve.c
new file mode 100644
index 0000000..fa34f01
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_lhsolve.c
@@ -0,0 +1,4 @@
+#define ZLONG
+
+#define CONJUGATE_SOLVE
+#include "../../SuiteSparse/UMFPACK/Source/umf_ltsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_local_search.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_local_search.c
new file mode 100644
index 0000000..8f89985
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_local_search.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_local_search.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_lsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_lsolve.c
new file mode 100644
index 0000000..59ea2a8
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_lsolve.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_lsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_ltsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_ltsolve.c
new file mode 100644
index 0000000..39a4a88
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_ltsolve.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_ltsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_alloc_element.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_alloc_element.c
new file mode 100644
index 0000000..96c27a2
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_alloc_element.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_element.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_alloc_head_block.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_alloc_head_block.c
new file mode 100644
index 0000000..1683bb6
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_alloc_head_block.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_head_block.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_alloc_tail_block.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_alloc_tail_block.c
new file mode 100644
index 0000000..d85c8a5
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_alloc_tail_block.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_tail_block.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_free_tail_block.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_free_tail_block.c
new file mode 100644
index 0000000..65fd652
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_free_tail_block.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_free_tail_block.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_init_memoryspace.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_init_memoryspace.c
new file mode 100644
index 0000000..e535032
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_init_memoryspace.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_mem_init_memoryspace.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_row_search.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_row_search.c
new file mode 100644
index 0000000..ed44055
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_row_search.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_row_search.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_scale.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_scale.c
new file mode 100644
index 0000000..af82c54
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_scale.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_scale.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_scale_column.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_scale_column.c
new file mode 100644
index 0000000..a6097d1
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_scale_column.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_scale_column.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_set_stats.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_set_stats.c
new file mode 100644
index 0000000..80af787
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_set_stats.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_set_stats.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_solve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_solve.c
new file mode 100644
index 0000000..76a3c0f
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_solve.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_solve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_start_front.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_start_front.c
new file mode 100644
index 0000000..f0e4a41
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_start_front.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_start_front.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_store_lu.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_store_lu.c
new file mode 100644
index 0000000..b5b9c27
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_store_lu.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_store_lu.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_store_lu_drop.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_store_lu_drop.c
new file mode 100644
index 0000000..b817454
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_store_lu_drop.c
@@ -0,0 +1,3 @@
+#define ZLONG
+#define DROP
+#include "../../SuiteSparse/UMFPACK/Source/umf_store_lu.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_symbolic_usage.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_symbolic_usage.c
new file mode 100644
index 0000000..fe745bb
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_symbolic_usage.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_symbolic_usage.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_transpose.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_transpose.c
new file mode 100644
index 0000000..a8cf3ed
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_transpose.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_transpose.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_tuple_lengths.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_tuple_lengths.c
new file mode 100644
index 0000000..3c21f97
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_tuple_lengths.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_tuple_lengths.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_uhsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_uhsolve.c
new file mode 100644
index 0000000..e5eb0ad
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_uhsolve.c
@@ -0,0 +1,4 @@
+#define ZLONG
+
+#define CONJUGATE_SOLVE
+#include "../../SuiteSparse/UMFPACK/Source/umf_utsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_usolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_usolve.c
new file mode 100644
index 0000000..2cca779
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_usolve.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_usolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_utsolve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_utsolve.c
new file mode 100644
index 0000000..4794601
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_utsolve.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_utsolve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_valid_numeric.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_valid_numeric.c
new file mode 100644
index 0000000..5c220b0
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_valid_numeric.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_valid_numeric.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_valid_symbolic.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_valid_symbolic.c
new file mode 100644
index 0000000..d286f11
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_valid_symbolic.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umf_valid_symbolic.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_free_numeric.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_free_numeric.c
new file mode 100644
index 0000000..7a28cf4
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_free_numeric.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_free_numeric.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_free_symbolic.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_free_symbolic.c
new file mode 100644
index 0000000..207c715
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_free_symbolic.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_free_symbolic.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_numeric.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_numeric.c
new file mode 100644
index 0000000..63dcda5
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_numeric.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_numeric.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_qsymbolic.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_qsymbolic.c
new file mode 100644
index 0000000..7039606
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_qsymbolic.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_qsymbolic.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_solve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_solve.c
new file mode 100644
index 0000000..bb764dc
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_solve.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_solve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_symbolic.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_symbolic.c
new file mode 100644
index 0000000..3d947c0
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_symbolic.c
@@ -0,0 +1,2 @@
+#define DINT
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_symbolic.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_free_numeric.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_free_numeric.c
new file mode 100644
index 0000000..20ed153
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_free_numeric.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_free_numeric.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_free_symbolic.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_free_symbolic.c
new file mode 100644
index 0000000..0b108a1
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_free_symbolic.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_free_symbolic.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_numeric.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_numeric.c
new file mode 100644
index 0000000..0d1e3aa
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_numeric.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_numeric.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_qsymbolic.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_qsymbolic.c
new file mode 100644
index 0000000..946c59e
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_qsymbolic.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_qsymbolic.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_solve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_solve.c
new file mode 100644
index 0000000..137d9f1
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_solve.c
@@ -0,0 +1,3 @@
+#define DLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_solve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_symbolic.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_symbolic.c
new file mode 100644
index 0000000..464d39d
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_symbolic.c
@@ -0,0 +1,2 @@
+#define DLONG
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_symbolic.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_free_numeric.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_free_numeric.c
new file mode 100644
index 0000000..bd507da
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_free_numeric.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_free_numeric.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_free_symbolic.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_free_symbolic.c
new file mode 100644
index 0000000..9c4cdb5
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_free_symbolic.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_free_symbolic.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_numeric.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_numeric.c
new file mode 100644
index 0000000..364afe7
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_numeric.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_numeric.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_qsymbolic.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_qsymbolic.c
new file mode 100644
index 0000000..d748f9d
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_qsymbolic.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_qsymbolic.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_solve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_solve.c
new file mode 100644
index 0000000..de050f7
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_solve.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_solve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_symbolic.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_symbolic.c
new file mode 100644
index 0000000..559c7d1
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_symbolic.c
@@ -0,0 +1,2 @@
+#define ZINT
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_symbolic.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_free_numeric.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_free_numeric.c
new file mode 100644
index 0000000..2c9bb10
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_free_numeric.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_free_numeric.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_free_symbolic.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_free_symbolic.c
new file mode 100644
index 0000000..8f30367
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_free_symbolic.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_free_symbolic.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_numeric.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_numeric.c
new file mode 100644
index 0000000..da89bc8
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_numeric.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_numeric.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_qsymbolic.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_qsymbolic.c
new file mode 100644
index 0000000..a630f6c
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_qsymbolic.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_qsymbolic.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_solve.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_solve.c
new file mode 100644
index 0000000..1c23ab1
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_solve.c
@@ -0,0 +1,3 @@
+#define ZLONG
+
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_solve.c"
diff --git a/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_symbolic.c b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_symbolic.c
new file mode 100644
index 0000000..0f23a02
--- /dev/null
+++ b/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_symbolic.c
@@ -0,0 +1,2 @@
+#define ZLONG
+#include "../../SuiteSparse/UMFPACK/Source/umfpack_symbolic.c"
diff --git a/src/C/amd.c b/src/C/amd.c
new file mode 100644
index 0000000..3d1f41d
--- /dev/null
+++ b/src/C/amd.c
@@ -0,0 +1,198 @@
+/*
+ * This file is part of CVXOPT version 0.8.2.
+ * Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+ */
+
+#include "cvxopt.h"
+#include "amd.h"
+#include "misc.h"
+
+/* defined in pyconfig.h */
+#if (SIZEOF_INT < SIZEOF_LONG)
+#define amd_order amd_l_order
+#define amd_defaults amd_l_defaults
+#endif
+
+
+PyDoc_STRVAR(amd__doc__,"Interface to the AMD library.\n\n"
+"Approximate minimum degree ordering of sparse matrices.\n\n"
+"The default values of the control parameterse in the AMD 'Control' "
+"array\n"
+"described in the AMD User Guide are used.  The values can be modified "
+"by\n"
+"making an entry in the dictionary amd.options, with possible key "
+"values\n"
+"'AMD_DENSE' and 'AMD_AGGRESSIVE'.\n\n"
+"AMD is available from http://www.cise.ufl.edu/research/sparse/amd.");
+
+
+static  PyObject *amd_module;
+
+typedef struct {
+    char  name[20];
+    int   idx;
+}   param_tuple;
+
+static const param_tuple AMD_PARAM_LIST[] = {
+    {"AMD_DENSE", AMD_DENSE},
+    {"AMD_AGGRESSIVE", AMD_AGGRESSIVE}
+}; /* 2 parameters */
+
+static int get_param_idx(char *str, int *idx) 
+{
+    int i;
+
+    for (i=0; i<2; i++) if (!strcmp(AMD_PARAM_LIST[i].name, str)) {
+        *idx =  AMD_PARAM_LIST[i].idx; 
+        return 1;
+    }
+    return 0;  
+}
+
+static int set_defaults(double *control)
+{
+    int_compat pos=0; 
+    int param_id; 
+    PyObject *param, *key, *value;
+    char *keystr, err_str[100];
+
+    amd_defaults(control);
+
+    if (!(param = PyObject_GetAttrString(amd_module, "options")) ||
+        !PyDict_Check(param)){
+        PyErr_SetString(PyExc_AttributeError, "missing amd.options"
+            "dictionary");
+        return 0;
+    }
+    while (PyDict_Next(param, &pos, &key, &value)) 
+        if ((keystr = PyString_AsString(key)) && get_param_idx(keystr, 
+            &param_id)) {
+            if (!PyInt_Check(value) && !PyFloat_Check(value)){
+                sprintf(err_str, "invalid value for AMD parameter: "
+                    "%-.20s", keystr);
+                PyErr_SetString(PyExc_ValueError, err_str); 
+                Py_DECREF(param);
+                return 0;
+            }
+            control[param_id] = PyFloat_AsDouble(value);
+    }
+    Py_DECREF(param);
+    return 1;
+}
+
+
+static char doc_order[] = 
+    "Computes the approximate minimum degree ordering of a square "
+    "matrix.\n\n"
+    "p = order(A, uplo='L')\n\n"
+    "PURPOSE\n"
+    "Computes a permutation p that reduces fill-in in the Cholesky\n"
+    "factorization of A[p,p].\n\n"
+    "ARGUMENTS\n"
+    "A         square sparse matrix\n\n"
+    "uplo      'L' or 'U'.  If uplo is 'L', the lower triangular part\n"
+    "          of A is used and the upper triangular is ignored.  If\n"
+    "          uplo is 'U', the upper triangular part is used and the\n"
+    "          lower triangular part is ignored.\n\n"
+    "p         'i' matrix of length equal to the order of A";  
+
+
+static PyObject* order_c(PyObject *self, PyObject *args, 
+    PyObject *kwrds)
+{
+    spmatrix *A;
+    matrix *perm;
+    char uplo='L';
+    int j, k, n, nnz, alloc=0, info;
+    int_t *rowind=NULL, *colptr=NULL;
+    double control[AMD_CONTROL];
+    char *kwlist[] = {"A", "uplo", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|c", kwlist, &A, 
+        &uplo)) return NULL;
+    if (!set_defaults(control)) return NULL;
+    if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A)){
+        PyErr_SetString(PyExc_TypeError, "A must be a square sparse "
+            "matrix");
+        return NULL;
+    }
+    if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'");
+    if (!(perm = (matrix *) Matrix_New(SP_NROWS(A),1,INT)))    
+        return PyErr_NoMemory();
+    n = SP_NROWS(A);
+    for (nnz=0, j=0; j<n; j++) {
+	if (uplo == 'L'){
+            for (k=SP_COL(A)[j]; k<SP_COL(A)[j+1] && SP_ROW(A)[k]<j; 
+                k++); 
+            nnz += SP_COL(A)[j+1] - k;
+	}
+	else {
+            for (k=SP_COL(A)[j]; k<SP_COL(A)[j+1] && SP_ROW(A)[k] <= j; 
+                k++); 
+            nnz += k - SP_COL(A)[j];
+        }
+    }
+    if (nnz == SP_NNZ(A)){
+        colptr = (int_t *) SP_COL(A);
+        rowind = (int_t *) SP_ROW(A);
+    }
+    else {
+	alloc = 1;
+        colptr = (int_t *) calloc(n+1, sizeof(int_t));
+        rowind = (int_t *) calloc(nnz, sizeof(int_t));
+	if (!colptr || !rowind) {
+            Py_XDECREF(perm);  free(colptr);  free(rowind);
+	    return PyErr_NoMemory();
+	}
+	colptr[0] = 0;
+        for (j=0; j<n; j++) {
+	    if (uplo == 'L'){
+                for (k=SP_COL(A)[j]; k<SP_COL(A)[j+1] && 
+                    SP_ROW(A)[k] < j; k++);
+		nnz = SP_COL(A)[j+1] - k;
+                colptr[j+1] = colptr[j] + nnz;
+		memcpy(rowind + colptr[j], (int_t *) SP_ROW(A) + k, 
+                    nnz*sizeof(int_t));
+	    }
+	    else {
+                for (k=SP_COL(A)[j]; k<SP_COL(A)[j+1] && 
+                    SP_ROW(A)[k] <= j; k++);
+                nnz = k - SP_COL(A)[j];
+                colptr[j+1] = colptr[j] + nnz;
+		memcpy(rowind + colptr[j], (int_t *) (SP_ROW(A) + 
+                    SP_COL(A)[j]), nnz*sizeof(int_t));
+	    }
+        }
+    }
+    info = amd_order(n, colptr, rowind, MAT_BUFI(perm), control, NULL);
+    if (alloc){
+        free(colptr);  
+        free(rowind);
+    }
+    switch (info) { 
+        case AMD_OUT_OF_MEMORY:
+            Py_XDECREF(perm);
+            return PyErr_NoMemory();
+
+        case AMD_INVALID:
+            Py_XDECREF(perm);
+            return Py_BuildValue("");
+
+        case AMD_OK:
+            return (PyObject *) perm;
+    }
+    return Py_BuildValue("");
+}
+
+static PyMethodDef amd_functions[] = {
+{"order", (PyCFunction) order_c, METH_VARARGS|METH_KEYWORDS, doc_order},
+{NULL}  /* Sentinel */
+};
+
+PyMODINIT_FUNC initamd(void)
+{
+    amd_module = Py_InitModule3("cvxopt.amd", amd_functions, 
+        amd__doc__);
+    PyModule_AddObject(amd_module, "options", PyDict_New());
+    if (import_cvxopt() < 0) return;
+}
diff --git a/src/C/base.c b/src/C/base.c
new file mode 100644
index 0000000..7834906
--- /dev/null
+++ b/src/C/base.c
@@ -0,0 +1,950 @@
+/*
+ * This file is part of CVXOPT version 0.8.2.
+ * Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+ */
+
+#define BASE_MODULE
+
+#include "Python.h"
+#include "cvxopt.h"
+#include "misc.h" 
+
+#include <complexobject.h>
+
+PyDoc_STRVAR(base__doc__,"Convex optimization package");
+
+PyTypeObject matrix_tp ;
+matrix * Matrix_New(int, int, int) ;
+matrix * Matrix_NewFromMatrix(matrix *, int) ;
+matrix * Matrix_NewFromSequence(PyObject *, int) ; 
+matrix * Matrix_NewFromArrayStruct(PyObject *, int, int *) ;
+
+PyTypeObject spmatrix_tp ;
+spmatrix * SpMatrix_New(int_t, int_t, int, int ) ;
+spmatrix * SpMatrix_NewFromMatrix(matrix *, int) ;
+spmatrix * SpMatrix_NewFromSpMatrix(spmatrix *, int, int) ; 
+spmatrix * SpMatrix_NewFromIJV(matrix *, matrix *, matrix *, 
+    int_t, int_t, int, int) ;
+void free_ccs(ccs *) ;
+
+extern int (*sp_axpy[])(number, void *, void *, int, int, int, void **) ;
+
+extern int (*sp_gemm[])(char, char, number, void *, void *, number, void *, 
+    int, int, int, int, void **, int, int, int);
+
+extern int (*sp_gemv[])(char, int, int, number, void *, int, void *, int,  
+    number, void *, int) ;
+
+extern int (*sp_symv[])(char, int, number, ccs *, int, void *, int,
+    number, void *, int) ;
+
+extern int (*sp_syrk[])(char, char, number, void *, number, 
+    void *, int, int, int, int, void **) ;
+
+const int  E_SIZE[] = { sizeof(int_t), sizeof(double), sizeof(complex) };
+const char TC_CHAR[][2] = {"i","d","z"} ;
+const char PRINTOPT[][15] = {"iformat","dformat","zformat"} ;
+
+PyObject *base_mod;
+
+/* 
+ *  Helper routines and definitions to implement type transparency.
+ */
+
+number One[3], MinusOne[3], Zero[3];
+
+static void write_inum(void *dest, int i, void *src, int j) {
+  ((int_t *)dest)[i]  = ((int_t *)src)[j];
+}
+
+static void write_dnum(void *dest, int i, void *src, int j) {
+  ((double *)dest)[i]  = ((double *)src)[j];
+}
+
+static void write_znum(void *dest, int i, void *src, int j) {
+  ((complex *)dest)[i]  = ((complex *)src)[j];
+}
+
+void (*write_num[])(void *, int, void *, int) = {
+  write_inum, write_dnum, write_znum };
+
+static PyObject * inum2PyObject(void *src, int i) {
+  return Py_BuildValue("l", ((int_t *)src)[i]);
+}
+
+static PyObject * dnum2PyObject(void *src, int i) {
+  return Py_BuildValue("d", ((double *)src)[i]);
+}
+
+static PyObject * znum2PyObject(void *src, int i) {
+  Py_complex z;
+  z.real = creal (((complex *)src)[i]);
+  z.imag = cimag (((complex *)src)[i]);
+  return Py_BuildValue("D", &z);
+}
+
+PyObject * (*num2PyObject[])(void *, int) = {
+  inum2PyObject, dnum2PyObject, znum2PyObject };
+
+/* val_id: 0 = matrix, 1 = PyNumber */
+static int 
+convert_inum(void *dest, void *val, int val_id, int offset) 
+{
+  if (val_id==0) { /* 1x1 matrix */
+    switch (MAT_ID(val)) {
+    case INT: 
+      *(int_t *)dest = MAT_BUFI(val)[offset]; return 0; 
+      //case DOUBLE: 
+      //*(int_t *)dest = (int_t)round(MAT_BUFD(val)[offset]); return 0; 
+    default: PY_ERR_INT(PyExc_TypeError,"cannot cast argument as integer");
+    }
+  } else { /* PyNumber */
+    if (PyInt_Check((PyObject *)val)) {
+      *(int_t *)dest = PyInt_AS_LONG((PyObject *)val); return 0; 
+    } 
+    //else if (PyFloat_Check((PyObject *)val)) {
+    //  *(int_t *)dest = roundl(PyFloat_AS_DOUBLE((PyObject *)val)); return 0; 
+    //}
+    else PY_ERR_INT(PyExc_TypeError,"cannot cast argument as integer");
+  }    
+}
+
+static int 
+convert_dnum(void *dest, void *val, int val_id, int offset) 
+{
+  if (val_id==0) { /* matrix */
+    switch (MAT_ID(val)) {
+    case INT:    *(double *)dest = MAT_BUFI(val)[offset]; return 0;
+    case DOUBLE: *(double *)dest = MAT_BUFD(val)[offset]; return 0;
+    default: PY_ERR_INT(PyExc_TypeError, "cannot cast argument as double");
+    }
+  } else { /* PyNumber */
+    if (PyInt_Check((PyObject *)val) || PyFloat_Check((PyObject *)val)) {
+      *(double *)dest = PyFloat_AsDouble((PyObject *)val); 
+      return 0;
+    }
+    else PY_ERR_INT(PyExc_TypeError,"cannot cast argument as double");
+  } 
+}
+
+static int 
+convert_znum(void *dest, void *val, int val_id, int offset) 
+{  
+  if (val_id==0) { /* 1x1 matrix */
+    switch (MAT_ID(val)) {
+    case INT:     
+      *(complex *)dest = MAT_BUFI(val)[offset]; return 0;
+    case DOUBLE:  
+      *(complex *)dest = MAT_BUFD(val)[offset]; return 0;
+    case COMPLEX:
+      *(complex *)dest = MAT_BUFZ(val)[offset]; return 0;
+    default: return -1; 
+    }
+  } else { /* PyNumber */
+    Py_complex c = PyComplex_AsCComplex((PyObject *)val);
+    *(complex *)dest = c.real + I*c.imag;
+    return 0;
+  }    
+}
+
+int (*convert_num[])(void *, void *, int, int) = { 
+  convert_inum, convert_dnum, convert_znum };
+
+extern void daxpy_(int *, void *, void *, int *, void *, int *) ;
+extern void zaxpy_(int *, void *, void *, int *, void *, int *) ;
+
+static void i_axpy(int *n, void *a, void *x, int *incx, void *y, int *incy) {
+  int i;
+  for (i=0; i < *n; i++) {
+    ((int_t *)y)[i*(*incy)] += *((int_t *)a)*((int_t *)x)[i*(*incx)];
+  }
+}
+
+void (*axpy[])(int *, void *, void *, int *, void *, int *) = { 
+  i_axpy, daxpy_, zaxpy_ };
+
+extern void dscal_(int *, void *, void *, int *) ;
+extern void zscal_(int *, void *, void *, int *) ;
+
+/* we dont implement a BLAS iscal */
+static void i_scal(int *n, void *a, void *x, int *incx) {
+  int i;
+  for (i=0; i < *n; i++) {
+    ((int_t *)x)[i*(*incx)] *= *((int_t *)a);
+  }
+}
+
+void (*scal[])(int *, void *, void *, int *) = { i_scal, dscal_, zscal_ };
+
+extern void dgemm_(char *, char *, int *, int *, int *, void *, void *,
+    int *, void *, int *, void *, void *, int *) ;
+extern void zgemm_(char *, char *, int *, int *, int *, void *, void *,
+    int *, void *, int *, void *, void *, int *) ;
+
+/* we dont implement a BLAS igemm */
+static void i_gemm(char *transA, char *transB, int *m, int *n, int *k, 
+    void *alpha, void *A, int *ldA, void *B, int *ldB, void *beta, 
+    void *C, int *ldC) 
+{
+  int i, j, l;
+  for (j=0; j<*n; j++) {   
+    for (i=0; i<*m; i++) {      
+      ((int_t *)C)[i+j*(*m)] = 0;
+      for (l=0; l<*k; l++)
+	((int_t *)C)[i+j*(*m)]+=((int_t *)A)[i+l*(*m)]*((int_t *)B)[j*(*k)+l];
+    }    
+  }  
+}
+
+void (*gemm[])(char *, char *, int *, int *, int *, void *, void *, int *, 
+    void *, int *, void *, void *, int *) = { i_gemm, dgemm_, zgemm_ };
+
+extern void dgemv_(char *, int *, int *, void *, void *, int *, void *, 
+    int *, void *, void *, int *);
+extern void zgemv_(char *, int *, int *, void *, void *, int *, void *, 
+    int *, void *, void *, int *);
+static void (*gemv[])(char *, int *, int *, void *, void *, int *, void *, 
+    int *, void *, void *, int *) = { NULL, dgemv_, zgemv_ };
+
+extern void dsyrk_(char *, char *, int *, int *, void *, void *,
+    int *, void *, void *, int *);
+extern void zsyrk_(char *, char *, int *, int *, void *, void *,
+    int *, void *, void *, int *);
+void (*syrk[])(char *, char *, int *, int *, void *, void *,
+    int *, void *, void *, int *) = { NULL, dsyrk_, zsyrk_ };
+
+extern void dsymv_(char *, int *, void *, void *, int *, void *, int *, 
+    void *, void *, int *);
+extern void zsymv_(char *, int *, void *, void *, int *, void *, int *, 
+    void *, void *, int *);
+void (*symv[])(char *, int *, void *, void *, int *, void *, int *, 
+    void *, void *, int *) = { NULL, dsymv_, zsymv_ };
+
+static void mtx_iabs(void *src, void *dest, int n) {
+  int i;
+  for (i=0; i<n; i++)
+    ((int_t *)dest)[i] = labs(((int_t *)src)[i]);
+}
+
+static void mtx_dabs(void *src, void *dest, int n) {
+  int i;
+  for (i=0; i<n; i++)
+    ((double *)dest)[i] = fabs(((double *)src)[i]);
+}
+
+static void mtx_zabs(void *src, void *dest, int n) {
+  int i;
+  for (i=0; i<n; i++) 
+    ((double *)dest)[i] = cabs(((complex *)src)[i]);
+}
+
+void (*mtx_abs[])(void *, void *, int) = { mtx_iabs, mtx_dabs, mtx_zabs };
+
+static int idiv(void *dest, number a, int n) {
+  if (a.i==0) PY_ERR_INT(PyExc_ZeroDivisionError, "division by zero");
+  int i;
+  for (i=0; i<n; i++)
+    ((int_t *)dest)[i] /= a.i;
+
+  return 0;
+}
+
+static int ddiv(void *dest, number a, int n) {
+  if (a.d==0.0) PY_ERR_INT(PyExc_ZeroDivisionError, "division by zero");
+  int _n = n, int1 = 1;
+  double _a = 1/a.d;
+  dscal_(&_n, (void *)&_a, dest, &int1);
+  return 0;
+}
+
+static int zdiv(void *dest, number a, int n) {
+  if (cabs(a.z) == 0.0)
+    PY_ERR_INT(PyExc_ZeroDivisionError, "division by zero");
+
+  int _n = n, int1 = 1;
+  complex _a = 1.0/a.z; 
+  zscal_(&_n, (void *)&_a, dest, &int1);
+  return 0;  
+}
+
+int (*div_array[])(void *, number, int) = { idiv, ddiv, zdiv };
+
+static int mtx_irem(void *dest, number a, int n) {
+  if (a.i==0) PY_ERR_INT(PyExc_ZeroDivisionError, "division by zero");
+  int i;
+  for (i=0; i<n; i++)
+    ((int_t *)dest)[i] %= a.i;
+
+  return 0;
+}
+
+static int mtx_drem(void *dest, number a, int n) {
+  if (a.d==0.0) PY_ERR_INT(PyExc_ZeroDivisionError, "division by zero");
+  int i;
+  for (i=0; i<n; i++) 
+    ((double *)dest)[i] -= floor(((double *)dest)[i]/a.d)*a.d;
+
+  return 0;
+}
+
+int (*mtx_rem[])(void *, number, int) = { mtx_irem, mtx_drem };
+
+/* val_type = 0: (sp)matrix if type = 0, PY_NUMBER if type = 1 */
+int get_id(void *val, int val_type) {
+  if (!val_type) {
+    if Matrix_Check((PyObject *)val)
+      return MAT_ID((matrix *)val);
+    else 
+      return SP_ID((spmatrix *)val);
+  }
+  else if (PyInt_Check((PyObject *)val)) 
+    return INT;
+  else if (PyFloat_Check((PyObject *)val))
+    return DOUBLE;
+  else 
+    return COMPLEX;
+}
+
+
+
+static int Matrix_Check_func(void *o) {
+  return Matrix_Check((PyObject*)o);
+}
+
+static int SpMatrix_Check_func(void *o) {
+  return SpMatrix_Check((PyObject *)o);
+}
+
+
+static char doc_axpy[] =
+    "Constant times a vector plus a vector (y := alpha*x+y).\n\n"
+    "axpy(x, y, n=None, alpha=1.0)\n\n"
+    "ARGUMENTS\n"
+    "x         'd' or 'z' (sp)matrix\n\n"
+    "y         'd' or 'z' (sp)matrix.  Must have the same type as x.\n\n"
+    "n         integer.  If n<0, the default value of n is used.\n"
+    "          The default value is equal to\n"
+    "          (len(x)>=offsetx+1) ? 1+(len(x)-offsetx-1)/incx : 0.\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if x is complex";
+
+PyObject * base_axpy(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+  PyObject *x, *y, *partial = NULL; 
+  PyObject *ao=NULL;
+  number a;
+  char *kwlist[] = {"x", "y", "alpha", "partial", NULL};
+  
+  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|OO", kwlist, 
+	  &x, &y, &ao, &partial)) return NULL;
+  
+  if (!Matrix_Check(x) && !SpMatrix_Check(x)) err_mtrx("x");
+  if (!Matrix_Check(y) && !SpMatrix_Check(y)) err_mtrx("y");
+  if (partial && !PyBool_Check(partial)) err_bool("partial");
+
+  if (X_ID(x) != X_ID(y)) err_conflicting_ids;
+  int id = X_ID(x);
+
+  if (X_NROWS(x) != X_NROWS(y) || X_NCOLS(x) != X_NCOLS(y))
+    PY_ERR_TYPE("dimensions of x and y do not match");
+  
+  if (ao && convert_num[id](&a, ao, 1, 0)) err_type("alpha");
+  
+  if (Matrix_Check(x) && Matrix_Check(y)) {
+    int n = X_NROWS(x)*X_NCOLS(x);
+    axpy[id](&n, (ao ? &a : &One[id]), MAT_BUF(x), (int *)&One[INT], 
+	MAT_BUF(y), (int *)&One[INT]);
+  }
+  else {
+    
+    void *z = NULL;
+    if (sp_axpy[id]((ao ? a : One[id]), 
+	    Matrix_Check(x) ? MAT_BUF(x): ((spmatrix *)x)->obj,  
+	    Matrix_Check(y) ? MAT_BUF(y): ((spmatrix *)y)->obj,  
+	    SpMatrix_Check(x), SpMatrix_Check(y), 
+	    partial ? PyInt_AS_LONG(partial) : 0, &z))
+      return PyErr_NoMemory(); 
+
+    if (z) { 
+      free_ccs( ((spmatrix *)y)->obj );
+      ((spmatrix *)y)->obj = z;
+    }
+  } 
+
+  return Py_BuildValue("");
+}
+
+static char doc_gemm[] =
+    "General matrix-matrix product.\n\n"
+    "gemm(A, B, C, transA='N', transB='N', alpha=1.0, beta=0.0, \n"
+    "     partial=False) \n\n"
+    "PURPOSE\n"   
+    "Computes \n"
+    "C := alpha*A*B + beta*C     if transA = 'N' and transB = 'N'.\n"
+    "C := alpha*A^T*B + beta*C   if transA = 'T' and transB = 'N'.\n"
+    "C := alpha*A^H*B + beta*C   if transA = 'C' and transB = 'N'.\n"
+    "C := alpha*A*B^T + beta*C   if transA = 'N' and transB = 'T'.\n"
+    "C := alpha*A^T*B^T + beta*C if transA = 'T' and transB = 'T'.\n"
+    "C := alpha*A^H*B^T + beta*C if transA = 'C' and transB = 'T'.\n"
+    "C := alpha*A*B^H + beta*C   if transA = 'N' and transB = 'C'.\n"
+    "C := alpha*A^T*B^H + beta*C if transA = 'T' and transB = 'C'.\n"
+    "C := alpha*A^H*B^H + beta*C if transA = 'C' and transB = 'C'.\n"
+    "If k=0, this reduces to C := beta*C.\n\n"
+    "ARGUMENTS\n\n" 
+    "A         'd' or 'z' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "C         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "transA    'N', 'T' or 'C'\n\n"
+    "transB    'N', 'T' or 'C'\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "beta      number (int, float or complex).  Complex beta is only\n"
+    "          allowed if A is complex.\n\n"
+    "partial   boolean. If C is sparse and partial is True, then only the\n"
+    "          nonzero elements of C are updated irrespective of the\n"
+    "          sparsity patterns of A and B.";
+
+PyObject* base_gemm(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+  PyObject *A, *B, *C, *partial=NULL;
+  PyObject *ao=NULL, *bo=NULL;
+  number a, b;
+  int m, n, k;
+  char transA='N', transB='N';
+  char *kwlist[] = {"A", "B", "C", "transA", "transB", "alpha", "beta",
+		    "partial", NULL};
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ccOOO", 
+	  kwlist, &A, &B, &C, &transA, &transB, &ao, &bo, &partial))
+    return NULL;
+
+  if (!(Matrix_Check(A) || SpMatrix_Check(A)))
+    PY_ERR_TYPE("A must a matrix or spmatrix");
+  if (!(Matrix_Check(B) || SpMatrix_Check(B)))
+    PY_ERR_TYPE("B must a matrix or spmatrix");
+  if (!(Matrix_Check(C) || SpMatrix_Check(C)))
+    PY_ERR_TYPE("C must a matrix or spmatrix");
+  if (partial && !PyBool_Check(partial)) err_bool("partial");
+
+  if (X_ID(A) != X_ID(B) || X_ID(A) != X_ID(C) ||
+      X_ID(B) != X_ID(C)) err_conflicting_ids;
+
+  if (transA != 'N' && transA != 'T' && transA != 'C') 
+    err_char("transA", "'N', 'T', 'C'");
+  if (transB != 'N' && transB != 'T' && transB != 'C')
+    err_char("transB", "'N', 'T', 'C'");
+
+  m = (transA == 'N') ? X_NROWS(A) : X_NCOLS(A);
+  n = (transB == 'N') ? X_NCOLS(B) : X_NROWS(B);
+  k = (transA == 'N') ? X_NCOLS(A) : X_NROWS(A);
+  if (k != ((transB == 'N') ? X_NROWS(B) : X_NCOLS(B)))  
+    PY_ERR_TYPE("dimensions of A and B do not match");
+
+  if (m == 0 || n == 0) return Py_BuildValue("");
+
+  if (ao && convert_num[X_ID(A)](&a, ao, 1, 0)) err_type("alpha");
+  if (bo && convert_num[X_ID(A)](&b, bo, 1, 0)) err_type("beta");
+
+  int id = X_ID(A);
+  if (Matrix_Check(A) && Matrix_Check(B) && Matrix_Check(C)) {
+
+    int ldA = MAX(1,MAT_NROWS(A));
+    int ldB = MAX(1,MAT_NROWS(B));
+    int ldC = MAX(1,MAT_NROWS(C));  
+    if (id == INT) err_invalid_id;
+    gemm[id](&transA, &transB, &m, &n, &k, (ao ? &a : &One[id]),
+	MAT_BUF(A), &ldA, MAT_BUF(B), &ldB, (bo ? &b : &Zero[id]), 
+	MAT_BUF(C), &ldC);
+  } else {
+
+    void *z = NULL;
+    if (sp_gemm[id](transA, transB, (ao ? a : One[id]), 
+	    Matrix_Check(A) ? MAT_BUF(A) : ((spmatrix *)A)->obj, 
+	    Matrix_Check(B) ? MAT_BUF(B) : ((spmatrix *)B)->obj,  
+	    (bo ? b : Zero[id]),
+	    Matrix_Check(C) ? MAT_BUF(C) : ((spmatrix *)C)->obj, 
+	    SpMatrix_Check(A), SpMatrix_Check(B), SpMatrix_Check(C), 
+	    partial ? PyInt_AS_LONG(partial) : 0, &z, m, n, k))
+      return PyErr_NoMemory(); 
+
+    if (z) { 
+      free_ccs( ((spmatrix *)C)->obj );
+      ((spmatrix *)C)->obj = z;
+    }    
+  }
+
+  return Py_BuildValue("");
+}
+
+static char doc_gemv[] =
+    "General matrix-vector product for sparse and dense matrices. \n\n"
+    "gemv(A, x, y, trans='N', alpha=1.0, beta=0.0, m=A.size[0],\n"
+    "     n=A.size[1], incx=1, incy=1, offsetA=0, offsetx=0, offsety=0)\n\n"
+    "PURPOSE\n"
+    "If trans is 'N', computes y := alpha*A*x + beta*y.\n"
+    "If trans is 'T', computes y := alpha*A^T*x + beta*y.\n"
+    "If trans is 'C', computes y := alpha*A^H*x + beta*y.\n"
+    "The matrix A is m by n.\n"
+    "Returns immediately if n=0 and trans is 'T' or 'C', or if m=0 \n"
+    "and trans is 'N'.\n"
+    "Computes y := beta*y if n=0, m>0 and trans is 'N', or if m=0, \n"
+    "n>0 and trans is 'T' or 'C'.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' (sp)matrix\n\n"
+    "x         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "y         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "trans     'N', 'T' or 'C'\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "beta      number (int, float or complex).  Complex beta is only\n"
+    "          allowed if A is complex.\n\n"
+    "m         integer.  If negative, the default value is used.\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "          If zero, the default value is used.\n\n"
+    "incx      nonzero integer\n\n"
+    "incy      nonzero integer\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetx   nonnegative integer\n\n"
+    "offsety   nonnegative integer\n\n"
+    "This sparse version of GEMV requires that\n"
+    "  m <= A.size[0] - (offsetA % A.size[0])";
+
+static PyObject* base_gemv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+  matrix *x, *y;
+  PyObject *A;
+  PyObject *ao=NULL, *bo=NULL;
+  number a, b;
+  int m=-1, n=-1, ix=1, iy=1, oA=0, ox=0, oy=0; 
+  char trans='N'; 
+  char *kwlist[] = {"A", "x", "y", "trans", "alpha", "beta", "m", "n", 
+		    "incx", "incy", "offsetA", "offsetx",
+		    "offsety", NULL};
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOOiiiiiii", 
+	  kwlist, &A, &x, &y, &trans, &ao, &bo, &m, &n, &ix, &iy, 
+	  &oA, &ox, &oy))
+    return NULL;
+  
+  if (!Matrix_Check(A) && !SpMatrix_Check(A))
+    PY_ERR(PyExc_TypeError, "A must be a dense or sparse matrix");
+  if (!Matrix_Check(x)) err_mtrx("x");
+  if (!Matrix_Check(y)) err_mtrx("y");
+
+  if (MAT_ID(x) == INT || MAT_ID(y) == INT || X_ID(A) == INT) 
+    PY_ERR_TYPE("invalid matrix types");
+
+  if (X_ID(A) != MAT_ID(x) || X_ID(A) != MAT_ID(y))
+    err_conflicting_ids;
+  
+  if (trans != 'N' && trans != 'T' && trans != 'C') 
+    err_char("trans", "'N','T','C'");
+
+  if (ix == 0) err_nz_int("incx");
+  if (iy == 0) err_nz_int("incy");
+  
+  int id = MAT_ID(x);
+  if (m < 0) m = X_NROWS(A);
+  if (n < 0) n = X_NCOLS(A);
+  if ((!m && trans == 'N') || (!n && (trans == 'T' || trans == 'C')))
+    return Py_BuildValue("");
+
+  if (oA < 0) err_nn_int("offsetA");
+  if (n > 0 && m > 0 && oA + (n-1)*MAX(1,X_NROWS(A)) + m > 
+      X_NROWS(A)*X_NCOLS(A))
+    err_buf_len("A");
+  
+  if (ox < 0) err_nn_int("offsetx");
+  if ((trans == 'N' && n > 0 && ox + (n-1)*abs(ix) + 1 > MAT_LGT(x)) || 
+      ((trans == 'T' || trans == 'C') && m > 0 && 
+	  ox + (m-1)*abs(ix) + 1 > MAT_LGT(x))) err_buf_len("x");
+  
+  if (oy < 0) err_nn_int("offsety");
+  if ((trans == 'N' && oy + (m-1)*abs(iy) + 1 > MAT_LGT(y)) || 
+      ((trans == 'T' || trans == 'C') && 
+	  oy + (n-1)*abs(iy) + 1 > MAT_LGT(y))) err_buf_len("y");
+
+  if (ao && convert_num[MAT_ID(x)](&a, ao, 1, 0)) err_type("alpha");
+  if (bo && convert_num[MAT_ID(x)](&b, bo, 1, 0)) err_type("beta");
+  
+  if (Matrix_Check(A)) {
+    int ldA = MAX(1,X_NROWS(A));
+    if (trans == 'N' && n == 0)
+      scal[id](&m, (bo ? &b : &Zero[id]), MAT_BUF(y)+oy*E_SIZE[id], &iy);
+    else if ((trans == 'T' || trans == 'C') && m == 0)
+      scal[id](&n, (bo ? &b : &Zero[id]), MAT_BUF(y)+oy*E_SIZE[id], &iy);
+    else 
+      gemv[id](&trans, &m, &n, (ao ? &a : &One[id]), 
+	  MAT_BUF(A) + oA*E_SIZE[id], &ldA, 
+	  MAT_BUF(x) + ox*E_SIZE[id], &ix, (bo ? &b : &Zero[id]), 
+	  MAT_BUF(y) + oy*E_SIZE[id], &iy);
+  } else {
+    if (sp_gemv[id](trans, m, n, (ao ? a : One[id]), ((spmatrix *)A)->obj, 
+	    oA, MAT_BUF(x) + ox*E_SIZE[id], ix, (bo ? b : Zero[id]), 
+	    MAT_BUF(y) + oy*E_SIZE[id], iy))
+      return PyErr_NoMemory();      
+  }
+  
+  return Py_BuildValue("");
+}
+
+static char doc_syrk[] =
+    "Rank-k update of symmetric sparse or dense matrix.\n\n"
+    "syrk(A, C, uplo='L', trans='N', alpha=1.0, beta=0.0, partial=False)\n\n"
+    "PURPOSE   \n"
+    "If trans is 'N', computes C := alpha*A*A^T + beta*C.\n"
+    "If trans is 'T', computes C := alpha*A^T*A + beta*C.\n"
+    "C is symmetric (real or complex) of order n. \n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' (sp)matrix\n\n"
+    "C         'd' or 'z' (sp)matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "trans     'N' or 'T'\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "beta      number (int, float or complex).  Complex beta is only\n"
+    "          allowed if A is complex.\n\n"
+    "partial   boolean. If C is sparse and partial is True, then only the\n"
+    "          nonzero elements of C are updated irrespective of the\n"
+    "          sparsity patterns of A.";
+
+static PyObject* base_syrk(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+  PyObject *A, *C, *partial=NULL, *ao=NULL, *bo=NULL;
+  number a, b; 
+  char trans='N', uplo='L';
+  char *kwlist[] = {"A", "C", "uplo", "trans", "alpha", "beta", "partial",
+		    NULL};
+  
+  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccOOO", kwlist, 
+	  &A, &C, &uplo, &trans, &ao, &bo, &partial))
+    return NULL;
+  
+  if (!(Matrix_Check(A) || SpMatrix_Check(A)))
+    PY_ERR_TYPE("A must be a dense or sparse matrix");
+  if (!(Matrix_Check(C) || SpMatrix_Check(C)))
+    PY_ERR_TYPE("C must be a dense or sparse matrix");
+
+  int id = X_ID(A);
+  if (id == INT) PY_ERR_TYPE("invalid matrix types");
+  if (id != X_ID(C)) err_conflicting_ids;
+  
+  if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+  if (id == DOUBLE && trans != 'N' && trans != 'T' &&
+      trans != 'C') err_char("trans", "'N', 'T', 'C'");
+  if (id == COMPLEX && trans != 'N' && trans != 'T') 
+    err_char("trans", "'N', 'T'");
+
+  if (partial && !PyBool_Check(partial)) err_bool("partial");
+  
+  int n = (trans == 'N') ? X_NROWS(A) : X_NCOLS(A);
+  int k = (trans == 'N') ? X_NCOLS(A) : X_NROWS(A);
+  if (n == 0) return Py_BuildValue("");
+  
+  if (ao && convert_num[id](&a, ao, 1, 0)) err_type("alpha");
+  if (bo && convert_num[id](&b, bo, 1, 0)) err_type("beta");
+
+  if (Matrix_Check(A) && Matrix_Check(C)) {
+
+    int ldA = MAX(1,MAT_NROWS(A));
+    int ldC = MAX(1,MAT_NROWS(C));
+
+    syrk[id](&uplo, &trans, &n, &k, (ao ? &a : &One[id]), 
+	MAT_BUF(A), &ldA, (bo ? &b : &Zero[id]), MAT_BUF(C), &ldC);
+  } else {
+
+    void *z = NULL;
+    if (sp_syrk[id](uplo, trans, 
+	    (ao ? a : One[id]), 
+	    Matrix_Check(A) ? MAT_BUF(A) : ((spmatrix *)A)->obj, 
+	    (bo ? b : Zero[id]),
+	    Matrix_Check(C) ? MAT_BUF(C) : ((spmatrix *)C)->obj, 
+	    SpMatrix_Check(A), SpMatrix_Check(C), 
+	    partial ? PyInt_AS_LONG(partial) : 0, 
+	    (trans == 'N' ? X_NCOLS(A) : X_NROWS(A)), &z))
+      return PyErr_NoMemory(); 
+
+    if (z) { 
+      free_ccs( ((spmatrix *)C)->obj );
+      ((spmatrix *)C)->obj = z;
+    }    
+  }
+  
+  return Py_BuildValue("");
+}
+
+static char doc_symv[] =
+    "Matrix-vector product with a real symmetric dense or sparse matrix.\n\n"
+    "symv(A, x, y, uplo='L', alpha=1.0, beta=0.0, n=A.size[0], \n"
+    "     ldA=max(1,A.size[0]), incx=1, incy=1, offsetA=0, offsetx=0,\n"
+    "     offsety=0)\n\n"
+    "PURPOSE\n"
+    "Computes y := alpha*A*x + beta*y with A real symmetric of order n."
+    "n\n"
+    "ARGUMENTS\n"
+    "A         'd' (sp)matrix\n\n"
+    "x         'd' matrix\n\n"
+    "y         'd' matrix\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "alpha     real number (int or float)\n\n"
+    "beta      real number (int or float)\n\n"
+    "n         integer.  If negative, the default value is used.\n"
+    "          If the default value is used, we require that\n"
+    "          A.size[0]=A.size[1].\n\n"
+    "incx      nonzero integer\n\n"
+    "incy      nonzero integer\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetx   nonnegative integer\n\n"
+    "offsety   nonnegative integer\n\n"
+    "This sparse version of SYMV requires that\n"
+    "  m <= A.size[0] - (offsetA % A.size[0])";
+
+static PyObject* base_symv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+  PyObject *A, *ao=NULL, *bo=NULL;
+  matrix *x, *y;
+  number a, b;
+  int n=-1, ix=1, iy=1, oA=0, ox=0, oy=0, ldA; 
+  char uplo='L'; 
+  char *kwlist[] = {"A", "x", "y", "uplo", "alpha", "beta", "n",
+		    "incx", "incy", "offsetA", "offsetx", "offsety", NULL};
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOOiiiiii", kwlist, &A, 
+	  &x, &y, &uplo, &ao, &bo, &n, &ix, &iy, &oA, &ox, &oy))
+    return NULL;
+
+  if (!Matrix_Check(A) && !SpMatrix_Check(A)) 
+    PY_ERR_TYPE("A must be a dense or sparse matrix");
+
+  ldA = MAX(1,X_NROWS(A));
+
+  if (!Matrix_Check(x)) err_mtrx("x");
+  if (!Matrix_Check(y)) err_mtrx("y");
+  if (X_ID(A) != MAT_ID(x) || X_ID(A) != MAT_ID(y) ||
+      MAT_ID(x) != MAT_ID(y)) err_conflicting_ids;
+
+  int id = X_ID(A);
+  if (id == INT) PY_ERR_TYPE("invalid matrix types");
+  
+  if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+
+  if (ix == 0) err_nz_int("incx");
+  if (iy == 0) err_nz_int("incy");
+
+  if (n < 0) { 
+    if (X_NROWS(A) != X_NCOLS(A)) {
+      PyErr_SetString(PyExc_ValueError, "A is not square");
+      return NULL;
+    }
+    n = X_NROWS(A);
+  }
+  if (n == 0) return Py_BuildValue("");
+
+  if (oA < 0) err_nn_int("offsetA");
+  if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+  if (ox < 0) err_nn_int("offsetx");
+  if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x");
+  if (oy < 0) err_nn_int("offsety");
+  if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y");
+    
+  if (ao && convert_num[id](&a, ao, 1, 0)) err_type("alpha");
+  if (bo && convert_num[id](&b, bo, 1, 0)) err_type("beta");
+
+  if (Matrix_Check(A)) {
+    
+    symv[id](&uplo, &n, (ao ? &a : &One[id]), 
+	MAT_BUF(A) + oA*E_SIZE[id], &ldA, MAT_BUF(x) + ox*E_SIZE[id], 
+	&ix, (bo ? &b : &Zero[id]), MAT_BUF(y) + oy*E_SIZE[id], &iy);    
+  }
+  else {
+    
+    if (sp_symv[id](uplo, n, (ao ? a : One[id]), ((spmatrix *)A)->obj, 
+	    oA, MAT_BUF(x) + ox*E_SIZE[id], ix, 
+	    (bo ? b : Zero[id]), MAT_BUF(y) + oy*E_SIZE[id], iy))
+      return PyErr_NoMemory();      
+  }
+  
+  return Py_BuildValue("");
+}
+
+spmatrix * sparse_concat(PyObject *L, int id_arg) ;
+
+static PyObject *
+sparse(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+  PyObject *Objx = NULL;
+  static char *kwlist[] = { "x", "tc", NULL};
+   char tc = 0;
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|c:matrix", kwlist, 
+	  &Objx, &tc))
+    return NULL;
+
+  if (tc && !(VALID_TC_SP(tc))) PY_ERR_TYPE("tc must be 'd' or 'z'");  
+  int id = (tc ? TC2ID(tc) : -1);
+
+  spmatrix *ret = NULL;
+  /* a matrix */
+  if (Matrix_Check(Objx)) {
+
+    int m = MAT_NROWS(Objx), n = MAT_NCOLS(Objx);    
+    ret = SpMatrix_NewFromMatrix((matrix *)Objx, 
+	(id == -1 ? MAX(DOUBLE,MAT_ID(Objx)) : id)); 
+
+    MAT_NROWS(Objx) = m; MAT_NCOLS(Objx) = n;    
+  }
+
+  /* sparse matrix */
+  else if (SpMatrix_Check(Objx)) {
+
+    int nnz=0, ik, jk;
+
+    for (jk=0; jk<SP_NCOLS(Objx); jk++) {
+      for (ik=SP_COL(Objx)[jk]; ik<SP_COL(Objx)[jk+1]; ik++) {
+	if (((SP_ID(Objx) == DOUBLE) && (SP_VALD(Objx)[ik] != 0.0)) ||
+	    ((SP_ID(Objx) == COMPLEX) && (SP_VALZ(Objx)[ik] != 0.0)))
+	  nnz++;	
+      }
+    }
+
+    ret = SpMatrix_New(SP_NROWS(Objx), SP_NCOLS(Objx), nnz, SP_ID(Objx));
+    if (!ret) return PyErr_NoMemory();
+
+    nnz = 0;
+    for (jk=0; jk<SP_NCOLS(Objx); jk++) {
+      for (ik=SP_COL(Objx)[jk]; ik<SP_COL(Objx)[jk+1]; ik++) {
+	if ((SP_ID(Objx) == DOUBLE) && (SP_VALD(Objx)[ik] != 0.0)) {
+	  SP_VALD(ret)[nnz] = SP_VALD(Objx)[ik];
+	  SP_ROW(ret)[nnz++] = SP_ROW(Objx)[ik];
+	  SP_COL(ret)[jk+1]++;	
+	}
+	else if ((SP_ID(Objx) == COMPLEX) && (SP_VALZ(Objx)[ik] != 0.0)) {
+	  SP_VALZ(ret)[nnz] = SP_VALZ(Objx)[ik];
+	  SP_ROW(ret)[nnz++] = SP_ROW(Objx)[ik];
+	  SP_COL(ret)[jk+1]++;	
+	}
+      }
+    }
+    
+    for (jk=0; jk<SP_NCOLS(Objx); jk++) 
+      SP_COL(ret)[jk+1] += SP_COL(ret)[jk];
+    
+    /*
+    ret = SpMatrix_NewFromSpMatrix((spmatrix *)Objx, 0, 
+	(id == -1 ? SP_ID(Objx) : id));
+    */
+  }
+
+  /* x is a list of lists */
+  else if (PyList_Check(Objx)) 
+    ret = sparse_concat(Objx, id);
+  
+  else PY_ERR_TYPE("invalid matrix initialization");
+
+  return (PyObject *)ret;
+}
+
+extern PyObject * matrix_exp(matrix *, PyObject *, PyObject *) ;
+extern PyObject * matrix_log(matrix *, PyObject *, PyObject *) ;
+extern PyObject * matrix_sqrt(matrix *, PyObject *, PyObject *) ;
+extern PyObject * matrix_cos(matrix *, PyObject *, PyObject *) ;
+extern PyObject * matrix_sin(matrix *, PyObject *, PyObject *) ;
+extern PyObject * matrix_elem_mul(matrix *, PyObject *, PyObject *) ;
+extern PyObject * matrix_elem_div(matrix *, PyObject *, PyObject *) ;
+
+static PyMethodDef base_functions[] = {
+  {"exp", (PyCFunction)matrix_exp, METH_VARARGS|METH_KEYWORDS, 
+  "Computes the element-wise expontial of a matrix"},
+  {"log", (PyCFunction)matrix_log, METH_VARARGS|METH_KEYWORDS, 
+  "Computes the element-wise logarithm of a matrix"},
+  {"sqrt", (PyCFunction)matrix_sqrt, METH_VARARGS|METH_KEYWORDS, 
+  "Computes the element-wise square-root of a matrix"},
+  {"cos", (PyCFunction)matrix_cos, METH_VARARGS|METH_KEYWORDS, 
+  "Computes the element-wise cosine of a matrix"},
+  {"sin", (PyCFunction)matrix_sin, METH_VARARGS|METH_KEYWORDS, 
+  "Computes the element-wise sine of a matrix"},
+  {"axpy", (PyCFunction)base_axpy, METH_VARARGS|METH_KEYWORDS, doc_axpy},
+  {"gemm", (PyCFunction)base_gemm, METH_VARARGS|METH_KEYWORDS, doc_gemm},
+  {"gemv", (PyCFunction)base_gemv, METH_VARARGS|METH_KEYWORDS, doc_gemv},
+  {"syrk", (PyCFunction)base_syrk, METH_VARARGS|METH_KEYWORDS, doc_syrk},
+  {"symv", (PyCFunction)base_symv, METH_VARARGS|METH_KEYWORDS, doc_symv},
+  {"mul", (PyCFunction)matrix_elem_mul, METH_VARARGS|METH_KEYWORDS, 
+   "elementwise product of two matrices"},
+  {"div", (PyCFunction)matrix_elem_div, METH_VARARGS|METH_KEYWORDS, 
+   "elementwise division between two matrices"},
+  {"sparse", (PyCFunction)sparse, METH_VARARGS|METH_KEYWORDS, 
+   "convenience function for creating sparse matrices"},
+  {NULL}		/* sentinel */
+};
+
+PyMODINIT_FUNC
+initbase(void)
+{  
+  static void *base_API[8];
+  PyObject *c_api_object;
+  
+  if (!(base_mod = Py_InitModule3("base", base_functions, base__doc__)))
+    return;
+
+  /* for MS VC++ compatibility */
+  matrix_tp.tp_alloc = PyType_GenericAlloc;
+  matrix_tp.tp_free = PyObject_Del;
+  if (PyType_Ready(&matrix_tp) < 0)
+    return;
+  
+  if (PyType_Ready(&matrix_tp) < 0)
+    return;
+    
+  Py_INCREF(&matrix_tp);
+  if (PyModule_AddObject(base_mod, "matrix", (PyObject *) &matrix_tp) < 0)
+    return;   
+
+  spmatrix_tp.tp_alloc = PyType_GenericAlloc;
+  spmatrix_tp.tp_free = PyObject_Del;
+  if (PyType_Ready(&spmatrix_tp) < 0)
+    return;
+    
+  Py_INCREF(&spmatrix_tp);
+  if (PyModule_AddObject(base_mod, "spmatrix", (PyObject *) &spmatrix_tp) < 0)
+    return;   
+
+  /* Create the print_options dictionary */
+  PyObject *printopt = PyDict_New();
+  PyObject *dstr = PyString_FromString("5.4e");
+  PyObject *istr = PyString_FromString("5li");
+  PyObject *zstr = PyString_FromString("5.4e");
+  if (PyDict_SetItemString(printopt, "dformat", dstr) ||
+      PyDict_SetItemString(printopt, "iformat", istr) ||
+      PyDict_SetItemString(printopt, "zformat", zstr)) 
+  {
+    Py_XDECREF(printopt); 
+    Py_XDECREF(dstr); Py_XDECREF(istr); Py_XDECREF(zstr);
+    return;
+  }
+  Py_DECREF(dstr); Py_DECREF(istr); Py_DECREF(zstr);
+
+  if (PyModule_AddObject(base_mod, "print_options", printopt) < 0)
+    return;   
+
+  One[INT].i = 1; One[DOUBLE].d = 1.0; One[COMPLEX].z = 1.0;
+
+  MinusOne[INT].i = -1; MinusOne[DOUBLE].d = -1.0; MinusOne[COMPLEX].z = -1.0;
+
+  Zero[INT].i = 0; Zero[DOUBLE].d = 0.0; Zero[COMPLEX].z = 0.0;
+
+  /* initialize the C API object */
+  base_API[0] = (void *)Matrix_New;
+  base_API[1] = (void *)Matrix_NewFromMatrix;
+  base_API[2] = (void *)Matrix_NewFromSequence;
+  base_API[3] = (void *)Matrix_Check_func;
+  base_API[4] = (void *)SpMatrix_New;
+  base_API[5] = (void *)SpMatrix_NewFromSpMatrix;
+  base_API[6] = (void *)SpMatrix_NewFromIJV;
+  base_API[7] = (void *)SpMatrix_Check_func;
+
+  /* Create a CObject containing the API pointer array's address */
+  c_api_object = PyCObject_FromVoidPtr((void *)base_API, NULL);
+
+  if (c_api_object != NULL)
+    PyModule_AddObject(base_mod, "_C_API", c_api_object);
+}
diff --git a/src/C/blas.c b/src/C/blas.c
new file mode 100644
index 0000000..825b48c
--- /dev/null
+++ b/src/C/blas.c
@@ -0,0 +1,3316 @@
+/*
+ * This file is part of CVXOPT version 0.8.2.
+ * Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+ */
+
+#include "Python.h"
+#include "cvxopt.h"
+#include "misc.h"
+
+#define USE_CBLAS_ZDOT 0
+
+PyDoc_STRVAR(blas__doc__,"Interface to the double-precision real and "
+    "complex BLAS.\n\n"
+    "Double and complex matrices and vectors are stored in CVXOPT \n"
+    "matrices using the conventional BLAS storage schemes, with the\n"
+    "CVXOPT matrix buffers interpreted as one-dimensional arrays.\n"
+    "For each matrix argument X, an additional integer argument\n"
+    "offsetX specifies the start of the array, i.e., the pointer\n"
+    "X->buffer + offsetX is passed to the BLAS function.  The other \n"
+    "arguments (dimensions and options) have the same meaning as in\n"
+    "the BLAS definition.  Default values of the dimension arguments\n"
+    "are derived from the CVXOPT matrix sizes.");
+
+
+/* BLAS 1 prototypes */
+extern void dswap_(int *n, double *x, int *incx, double *y, int *incy);
+extern void zswap_(int *n, complex *x, int *incx, complex *y, 
+    int *incy);
+extern void dscal_(int *n, double *alpha, double *x, int *incx);
+extern void zscal_(int *n, complex *alpha, complex *x, int *incx);
+extern void zdscal_(int *n, double *alpha, complex *x, int *incx);
+extern void dcopy_(int *n, double *x, int *incx, double *y, int *incy);
+extern void zcopy_(int *n, complex *x, int *incx, complex *y, 
+    int *incy);
+extern void daxpy_(int *n, double *alpha, double *x, int *incx, 
+    double *y, int *incy);
+extern void zaxpy_(int *n, complex *alpha, complex *x, int *incx, 
+    complex *y, int *incy);
+extern double ddot_(int *n, double *x, int *incx, double *y, int *incy);
+#if USE_CBLAS_ZDOT
+extern void cblas_zdotc_sub(int n, void *x, int incx, void *y, 
+    int incy, void *result);
+extern void cblas_zdotu_sub(int n, void *x, int incx, void *y, int incy,
+    void *result);
+#endif
+extern double dnrm2_(int *n, double *x, int *incx);
+extern double dznrm2_(int *n, complex *x, int *incx);
+extern double dasum_(int *n, double *x, int *incx);
+extern double dzasum_(int *n, complex *x, int *incx);
+extern int idamax_(int *n, double *x, int *incx);
+extern int izamax_(int *n, complex *x, int *incx);
+
+
+/* BLAS 2 prototypes */
+extern void dgemv_(char* trans, int *m, int *n, double *alpha, 
+    double *A, int *lda, double *x, int *incx, double *beta, double *y,
+    int *incy);
+extern void zgemv_(char* trans, int *m, int *n, complex *alpha, 
+    complex *A, int *lda, complex *x, int *incx, complex *beta, 
+    complex *y, int *incy);
+extern void dgbmv_(char* trans, int *m, int *n, int *kl, int *ku, 
+    double *alpha, double *A, int *lda, double *x, int *incx, 
+    double *beta, double *y,  int *incy); 
+extern void zgbmv_(char* trans, int *m, int *n, int *kl, int *ku, 
+    complex *alpha, complex *A, int *lda, complex *x, int *incx, 
+    complex *beta, complex *y,  int *incy); 
+extern void dsymv_(char *uplo, int *n, double *alpha, double *A, 
+    int *lda, double *x, int *incx, double *beta, double *y, int *incy);
+extern void zhemv_(char *uplo, int *n, complex *alpha, complex *A, 
+    int *lda, complex *x, int *incx, complex *beta, complex *y, 
+    int *incy);
+extern void dsbmv_(char *uplo, int *n, int *k, double *alpha, double *A,
+    int *lda, double *x, int *incx, double *beta, double *y, int *incy);
+extern void zhbmv_(char *uplo, int *n, int *k, complex *alpha, 
+    complex *A, int *lda, complex *x, int *incx, complex *beta, 
+    complex *y, int *incy);
+extern void dtrmv_(char *uplo, char *trans, char *diag, int *n, 
+    double *A, int *lda, double *x, int *incx);
+extern void ztrmv_(char *uplo, char *trans, char *diag, int *n, 
+    complex *A, int *lda, complex *x, int *incx);
+extern void dtbmv_(char *uplo, char *trans, char *diag, int *n, int *k, 
+    double *A, int *lda, double *x, int *incx);
+extern void ztbmv_(char *uplo, char *trans, char *diag, int *n, int *k, 
+    complex *A, int *lda, complex *x, int *incx);
+extern void dtrsv_(char *uplo, char *trans, char *diag, int *n, 
+    double *A, int *lda, double *x, int *incx);
+extern void ztrsv_(char *uplo, char *trans, char *diag, int *n, 
+    complex *A, int *lda, complex *x, int *incx);
+extern void dtbsv_(char *uplo, char *trans, char *diag, int *n, int *k, 
+    double *A, int *lda, double *x, int *incx);
+extern void ztbsv_(char *uplo, char *trans, char *diag, int *n, int *k, 
+    complex *A, int *lda, complex *x, int *incx);
+extern void dger_(int *m, int *n, double *alpha, double *x, int *incx, 
+    double *y, int *incy, double *A, int *lda);
+extern void zgerc_(int *m, int *n, complex *alpha, complex *x, 
+    int *incx, complex *y, int *incy, complex *A, int *lda);
+extern void zgeru_(int *m, int *n, complex *alpha, complex *x, 
+    int *incx, complex *y, int *incy, complex *A, int *lda);
+extern void dsyr_(char *uplo, int *n, double *alpha, double *x, 
+    int *incx, double *A, int *lda);
+extern void zher_(char *uplo, int *n, double *alpha, complex *x, 
+    int *incx, complex *A, int *lda);
+extern void dsyr2_(char *uplo, int *n, double *alpha, double *x, 
+    int *incx, double *y, int *incy, double *A, int *lda);
+extern void zher2_(char *uplo, int *n, complex *alpha, complex *x, 
+    int *incx, complex *y, int *incy, complex *A, int *lda);
+
+
+/* BLAS 3 prototypes */
+extern void dgemm_(char *transa, char *transb, int *m, int *n, int *k, 
+    double *alpha, double *A, int *lda, double *B, int *ldb, 
+    double *beta, double *C, int *ldc);
+extern void zgemm_(char *transa, char *transb, int *m, int *n, int *k, 
+    complex *alpha, complex *A, int *lda, complex *B, int *ldb, 
+    complex *beta, complex *C, int *ldc);
+extern void dsymm_(char *side, char *uplo, int *m, int *n, 
+    double *alpha, double *A, int *lda, double *B, int *ldb, 
+    double *beta, double *C, int *ldc);
+extern void zsymm_(char *side, char *uplo, int *m, int *n, 
+    complex *alpha, complex *A, int *lda, complex *B, int *ldb, 
+    complex *beta, complex *C, int *ldc);
+extern void zhemm_(char *side, char *uplo, int *m, int *n, 
+    complex *alpha, complex *A, int *lda, complex *B, int *ldb, 
+    complex *beta, complex *C, int *ldc);
+extern void dsyrk_(char *uplo, char *trans, int *n, int *k, 
+    double *alpha, double *A, int *lda, double *beta, double *B, 
+    int *ldb);
+extern void zsyrk_(char *uplo, char *trans, int *n, int *k, 
+    complex *alpha, complex *A, int *lda, complex *beta, complex *B, 
+    int *ldb);
+extern void zherk_(char *uplo, char *trans, int *n, int *k, 
+    double *alpha, complex *A, int *lda, double *beta, complex *B, 
+    int *ldb);
+extern void dsyr2k_(char *uplo, char *trans, int *n, int *k, 
+    double *alpha, double *A, int *lda, double *B, int *ldb, 
+    double *beta, double *C, int *ldc);
+extern void zsyr2k_(char *uplo, char *trans, int *n, int *k, 
+    complex *alpha, complex *A, int *lda, complex *B, int *ldb, 
+    complex *beta, complex *C, int *ldc);
+extern void zher2k_(char *uplo, char *trans, int *n, int *k, 
+    complex *alpha, complex *A, int *lda, complex *B, int *ldb, 
+    double *beta, complex *C, int *ldc);
+extern void dtrmm_(char *side, char *uplo, char *transa, char *diag, 
+    int *m, int *n, double *alpha, double *A, int *lda, double *B, 
+    int *ldb);
+extern void ztrmm_(char *side, char *uplo, char *transa, char *diag, 
+    int *m, int *n, complex *alpha, complex *A, int *lda, complex *B, 
+    int *ldb);
+extern void dtrsm_(char *side, char *uplo, char *transa, char *diag, 
+    int *m, int *n, double *alpha, double *A, int *lda, double *B, 
+    int *ldb);
+extern void ztrsm_(char *side, char *uplo, char *transa, char *diag, 
+    int *m, int *n, complex *alpha, complex *A, int *lda, complex *B, 
+    int *ldb);
+
+
+static int number_from_pyobject(PyObject *o, number *a, int id)
+{
+    switch (id){
+        case DOUBLE:
+            if (!PyInt_Check(o) && !PyLong_Check(o) && 
+                !PyFloat_Check(o)) return -1;
+            (*a).d = PyFloat_AsDouble(o);
+            return 0;
+
+        case COMPLEX:
+            if (!PyInt_Check(o) && !PyLong_Check(o) && 
+                !PyFloat_Check(o) && !PyComplex_Check(o)) return -1;
+            (*a).z = PyComplex_RealAsDouble(o) + 
+                I*PyComplex_ImagAsDouble(o);
+            return 0;
+    }
+    return -1;
+}
+
+
+static char doc_swap[] =
+    "Interchanges two vectors (x <-> y).\n\n"
+    "swap(x, y, n=None, incx=1, incy=1, offsetx=0, offsety=0)\n\n"
+    "ARGUMENTS\n"
+    "x         'd' or 'z' matrix\n\n"
+    "y         'd' or 'z' matrix.  Must have the same type as x.\n\n"
+    "n         integer.  If n<0, the default value of n is used.\n"
+    "          The default value is equal to\n"
+    "          len(x)>=offsetx+1 ? 1+(len(x)-offsetx-1)/|incx| : 0.\n"
+    "          If the default value is used, it must be equal to\n"
+    "          len(y)>=offsety+1 ? 1+(len(y)-offsetx-1)/|incy| : 0.\n\n"
+    "incx      nonzero integer\n\n" 
+    "incy      nonzero integer\n\n" 
+    "offsetx   nonnegative integer\n\n"
+    "offsety   nonnegative integer";
+
+static PyObject* swap(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *x, *y; 
+    int n=-1, ix=1, iy=1, ox=0, oy=0; 
+    char *kwlist[] = {"x", "y", "n", "incx", "incy", "offsetx", 
+        "offsety", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiiii", kwlist, 
+        &x, &y, &n, &ix, &iy, &ox, &oy)) return NULL;
+
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (!Matrix_Check(y)) err_mtrx("y");
+    if (MAT_ID(x) != MAT_ID(y)) err_conflicting_ids;
+
+    if (ix == 0) err_nz_int("incx");
+    if (iy == 0) err_nz_int("incy");
+
+    if (ox < 0) err_nn_int("offsetx");
+    if (oy < 0) err_nn_int("offsety");
+
+    if (n<0){
+        n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/abs(ix) : 0;
+        if (n != ((len(y) >= oy+1) ? 1+(len(y)-oy-1)/abs(iy) : 0)){
+            PyErr_SetString(PyExc_ValueError, "arrays have unequal "
+                "default lengths");
+            return NULL;
+        }
+    }
+    if (n == 0) return Py_BuildValue("");
+
+    if (len(x) < ox+1+(n-1)*abs(ix)) err_buf_len("x");
+    if (len(y) < oy+1+(n-1)*abs(iy)) err_buf_len("y");
+
+    switch (MAT_ID(x)){
+        case DOUBLE: 
+            dswap_(&n, MAT_BUFD(x)+ox, &ix, MAT_BUFD(y)+oy, &iy);
+            break;
+
+        case COMPLEX:
+            zswap_(&n, MAT_BUFZ(x)+ox, &ix, MAT_BUFZ(y)+oy, &iy);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_scal[] =
+    "Scales a vector by a constant (x := alpha*x).\n\n"
+    "scal(alpha, x, n=None, inc=1, offset=0)\n\n"
+    "ARGUMENTS\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if x is complex.\n\n"
+    "x         'd' or 'z' matrix\n\n"
+    "n         integer.  If n<0, the default value of n is used.\n"
+    "          The default value is equal to\n"
+    "          (len(x)>=offset+1) ? 1+(len-offset-1)/inc : 0.\n\n"
+    "inc       positive integer\n\n" 
+    "offset    nonnegative integer";
+
+static PyObject* scal(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *x; 
+    PyObject *ao;
+    number a; 
+    int n=-1, ix=1, ox=0;
+    char *kwlist[] = {"alpha", "x", "n", "inc", "offset", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iii", kwlist, 
+        &ao, &x, &n, &ix, &ox)) return NULL;
+
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (ix <= 0) err_p_int("inc");
+    if (ox < 0) err_nn_int("offset");
+    if (n < 0) n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/ix : 0;
+    if (n == 0) return Py_BuildValue("");
+    if (len(x) < ox+1+(n-1)*ix) err_buf_len("x");
+
+    switch (MAT_ID(x)){
+        case DOUBLE: 
+            if (number_from_pyobject(ao, &a, MAT_ID(x))) 
+                err_type("alpha");
+            dscal_(&n, &a.d, MAT_BUFD(x)+ox, &ix);
+	    break;
+
+        case COMPLEX:
+            if (!number_from_pyobject(ao, &a, DOUBLE)) 
+                zdscal_(&n, &a.d, MAT_BUFZ(x)+ox, &ix);
+            else if (!number_from_pyobject(ao, &a, COMPLEX)) 
+                zscal_(&n, &a.z, MAT_BUFZ(x)+ox, &ix);
+            else
+                err_type("alpha");
+	    break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue(""); 
+}
+
+
+static char doc_copy[] =
+    "Copies a vector x to a vector y (y := x).\n\n"
+    "copy(x, y, n=None, incx=1, incy=1, offsetx=0, offsety=0)\n\n"
+    "ARGUMENTS\n"
+    "x         'd' or 'z' matrix\n\n"
+    "y         'd' or 'z' matrix.  Must have the same type as x.\n\n"
+    "n         integer.  If n<0, the default value of n is used.\n"
+    "          The default value is given by\n" 
+    "          (len(x)>=offsetx+1) ? 1+(len(x)-offsetx-1)/incx : 0\n\n"
+    "incx      nonzero integer\n\n" 
+    "incy      nonzero integer\n\n" 
+    "offsetx   nonnegative integer\n\n"
+    "offsety   nonnegative integer";
+
+static PyObject* copy(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *x, *y; 
+    int n=-1, ix=1, iy=1, ox=0, oy=0;
+    char *kwlist[] = {"x", "y", "n", "incx", "incy", "offsetx",
+        "offsety", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiiii", kwlist, 
+        &x, &y, &n, &ix, &iy, &ox, &oy))
+        return NULL;
+
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (!Matrix_Check(y)) err_mtrx("y");
+    if (MAT_ID(x) != MAT_ID(y)) err_conflicting_ids;
+
+    if (ix == 0) err_nz_int("incx");
+    if (iy == 0) err_nz_int("incy");
+
+    if (ox < 0 ) err_nn_int("offsetx");
+    if (oy < 0 ) err_nn_int("offsety");
+
+    if (n < 0) n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/abs(ix) : 0;
+    if (n == 0) return Py_BuildValue("");
+
+    if (len(x) < ox+1+(n-1)*abs(ix)) err_buf_len("x");
+    if (len(y) < oy+1+(n-1)*abs(iy)) err_buf_len("y");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            dcopy_(&n, MAT_BUFD(x)+ox, &ix, MAT_BUFD(y)+oy, &iy);
+            break;
+
+        case COMPLEX:
+            zcopy_(&n, MAT_BUFZ(x)+ox, &ix, MAT_BUFZ(y)+oy, &iy);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_axpy[] =
+    "Constant times a vector plus a vector (y := alpha*x+y).\n\n"
+    "axpy(x, y, alpha=1.0, n=None, incx=1, incy=1, offsetx=0, "
+    "offsety=0)\n\n"
+    "ARGUMENTS\n"
+    "x         'd' or 'z' matrix\n\n"
+    "y         'd' or 'z' matrix.  Must have the same type as x.\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if x is complex.\n\n"
+    "n         integer.  If n<0, the default value of n is used.\n"
+    "          The default value is equal to\n"
+    "          (len(x)>=offsetx+1) ? 1+(len(x)-offsetx-1)/incx : 0.\n\n"
+    "incx      nonzero integer\n\n" 
+    "incy      nonzero integer\n\n" 
+    "offsetx   nonnegative integer\n\n"
+    "offsety   nonnegative integer";
+
+static PyObject* axpy(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *x, *y; 
+    PyObject *ao=NULL;
+    number a;
+    int n=-1, ix=1, iy=1, ox=0, oy=0;
+    char *kwlist[] = {"x", "y", "alpha", "n", "incx", "incy", "offsetx",
+        "offsety", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Oiiiii", kwlist, 
+        &x, &y, &ao, &n, &ix, &iy, &ox, &oy)) return NULL;
+
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (!Matrix_Check(y)) err_mtrx("y");
+    if (MAT_ID(x) != MAT_ID(y)) err_conflicting_ids;
+
+    if (ix == 0) err_nz_int("incx");
+    if (iy == 0) err_nz_int("incy");
+
+    if (ox < 0) err_nn_int("offsetx");
+    if (oy < 0) err_nn_int("offsety");
+
+    if (n < 0) n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/abs(ix) : 0;
+    if (n == 0) return Py_BuildValue("");
+
+    if (len(x) < ox + 1+(n-1)*abs(ix)) err_buf_len("x");
+    if (len(y) < oy + 1+(n-1)*abs(iy)) err_buf_len("y");
+
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) 
+        err_type("alpha");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            if (!ao) a.d=1.0; 
+            daxpy_(&n, &a.d, MAT_BUFD(x)+ox, &ix, MAT_BUFD(y)+oy, &iy);
+            break;
+
+        case COMPLEX:
+            if (!ao) a.z=1.0; 
+            zaxpy_(&n, &a.z, MAT_BUFZ(x)+ox, &ix, MAT_BUFZ(y)+oy, &iy);
+            break;
+
+        default: 
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_dot[] =
+    "Returns x^H*y for real or complex x, y.\n\n"
+    "dot(x, y, n=None, incx=1, incy=1, offsetx=0, offsety=0)\n\n"
+    "ARGUMENTS\n"
+    "x         'd' or 'z' matrix\n\n"
+    "y         'd' or 'z' matrix.  Must have the same type as x.\n\n"
+    "n         integer.  If n<0, the default value of n is used.\n"
+    "          The default value is equal to\n"
+    "          (len(x)>=offsetx+1) ? 1+(len(x)-offsetx-1)/incx : 0.\n"
+    "          If the default value is used, it must be equal to\n"
+    "          len(y)>=offsety+1 ? 1+(len(y)-offsetx-1)/|incy| : 0.\n\n"
+    "incx      nonzero integer\n\n" 
+    "incy      nonzero integer\n\n" 
+    "offsetx   nonnegative integer\n\n"
+    "offsety   nonnegative integer\n\n"
+    "Returns 0 if n=0.";  
+
+static PyObject* dot(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *x, *y; 
+    number val;
+    int n=-1, ix=1, iy=1, ox=0, oy=0; 
+    char *kwlist[] = {"x", "y", "n", "incx", "incy", "offsetx",
+        "offsety", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiiii", kwlist, 
+        &x, &y, &n, &ix, &iy, &ox, &oy)) 
+        return NULL;
+
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (!Matrix_Check(y)) err_mtrx("y");
+    if (MAT_ID(x) != MAT_ID(y)) err_conflicting_ids;
+
+    if (ix == 0) err_nz_int("incx");
+    if (iy == 0) err_nz_int("incy");
+
+    if (ox < 0) err_nn_int("offsetx");
+    if (oy < 0) err_nn_int("offsety");
+
+    if (n<0){
+        n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/abs(ix) : 0;
+        if (n != ((len(y) >= oy+1) ? 1+(len(y)-oy-1)/abs(iy) : 0)){
+            PyErr_SetString(PyExc_ValueError, "arrays have unequal "
+                "default lengths");
+            return NULL;
+        }
+    }
+
+    if (n && len(x) < ox + 1 + (n-1)*abs(ix)) err_buf_len("x");
+    if (n && len(y) < oy + 1 + (n-1)*abs(iy)) err_buf_len("y");
+
+    switch (MAT_ID(x)){
+        case DOUBLE: 
+            val.d = (n==0) ? 0.0 : ddot_(&n, MAT_BUFD(x)+ox, &ix, 
+                MAT_BUFD(y)+oy, &iy);
+            return Py_BuildValue("d", val.d);
+
+        case COMPLEX: 
+	    if (n==0) val.z = 0.0;
+	    else
+#if USE_CBLAS_ZDOT
+                cblas_zdotc_sub(n, MAT_BUFZ(x)+ox, ix, MAT_BUFZ(y)+oy, 
+                    iy, &val.z);
+#else
+                ix *= 2;
+                iy *= 2;
+                val.z = (ddot_(&n, MAT_BUFD(x)+2*ox, &ix,
+                    MAT_BUFD(y)+2*oy, &iy) + 
+                    ddot_(&n, MAT_BUFD(x)+2*ox + 1, &ix, 
+                    MAT_BUFD(y)+2*oy + 1, &iy)) +
+                    I*(ddot_(&n, MAT_BUFD(x)+2*ox, &ix,
+                    MAT_BUFD(y)+2*oy + 1, &iy) - 
+                    ddot_(&n, MAT_BUFD(x)+2*ox + 1, &ix, 
+                    MAT_BUFD(y)+2*oy, &iy));
+#endif
+	    return PyComplex_FromDoubles(creal(val.z),cimag(val.z));
+
+        default:
+            err_invalid_id;
+    }
+}
+
+
+static char doc_dotu[] =
+    "Returns x^T*y for real or complex x, y.\n\n"
+    "dotu(x, y, n=None, incx=1, incy=1, offsetx=0, offsety=0)\n\n"
+    "ARGUMENTS\n"
+    "x         'd' or 'z' matrix\n\n"
+    "y         'd' or 'z' matrix.  Must have the same type as x.\n\n"
+    "n         integer.  If n<0, the default value of n is used.\n"
+    "          The default value is equal to\n"
+    "          (len(x)>=offsetx+1) ? 1+(len(x)-offsetx-1)/incx : 0.\n"
+    "          If the default value is used, it must be equal to\n"
+    "          len(y)>=offsety+1 ? 1+(len(y)-offsetx-1)/|incy| : 0.\n\n"
+    "incx      nonzero integer\n\n" 
+    "incy      nonzero integer\n\n" 
+    "offsetx   nonnegative integer\n\n"
+    "offsety   nonnegative integer\n\n"
+    "Returns 0 if n=0.";  
+
+static PyObject* dotu(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *x, *y; 
+    number val;
+    int n=-1, ix=1, iy=1, ox=0, oy=0; 
+    char *kwlist[] = {"x", "y", "n", "incx", "incy", "offsetx",
+        "offsety", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiiii", kwlist, 
+        &x, &y, &n, &ix, &iy, &ox, &oy)) 
+        return NULL;
+
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (!Matrix_Check(y)) err_mtrx("y");
+    if (MAT_ID(x) != MAT_ID(y)) err_conflicting_ids;
+
+    if (ix == 0) err_nz_int("incx");
+    if (iy == 0) err_nz_int("incy");
+
+    if (ox < 0) err_nn_int("offsetx");
+    if (oy < 0) err_nn_int("offsety");
+
+    if (n<0){
+        n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/abs(ix) : 0;
+        if (n != ((len(y) >= oy+1) ? 1+(len(y)-oy-1)/abs(iy) : 0)){
+            PyErr_SetString(PyExc_ValueError, "arrays have unequal "
+                "default lengths");
+            return NULL;
+        }
+    }
+
+    if (n && len(x) < ox + 1 + (n-1)*abs(ix)) err_buf_len("x");
+    if (n && len(y) < oy + 1 + (n-1)*abs(iy)) err_buf_len("y");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            val.d = (n==0) ? 0.0 : ddot_(&n, MAT_BUFD(x)+ox, &ix, 
+                MAT_BUFD(y)+oy, &iy);
+            return Py_BuildValue("d", val.d);
+
+        case COMPLEX:
+	    if (n==0) val.z = 0.0;
+	    else
+#if USE_CBLAS_ZDOT
+                cblas_zdotu_sub(n, MAT_BUFZ(x)+ox, ix, MAT_BUFZ(y)+oy, 
+                    iy, &val.z);
+#else
+                ix *= 2;
+                iy *= 2;
+                val.z = (ddot_(&n, MAT_BUFD(x)+2*ox, &ix,
+                    MAT_BUFD(y)+2*oy, &iy) - 
+                    ddot_(&n, MAT_BUFD(x)+2*ox + 1, &ix, 
+                    MAT_BUFD(y)+2*oy + 1, &iy)) +
+                    I*(ddot_(&n, MAT_BUFD(x)+2*ox, &ix,
+                    MAT_BUFD(y)+2*oy + 1, &iy) + 
+                    ddot_(&n, MAT_BUFD(x)+2*ox + 1, &ix, 
+                    MAT_BUFD(y)+2*oy, &iy));
+#endif
+	    return PyComplex_FromDoubles(creal(val.z),cimag(val.z));
+
+        default:
+            err_invalid_id;
+    }
+}
+
+
+static char doc_nrm2[] =
+    "Returns the Euclidean norm of a vector (returns ||x||_2).\n\n"
+    "nrm2(x, n=None, inc=1, offset=0)\n\n"
+    "ARGUMENTS\n"
+    "x         'd' or 'z' matrix\n\n"
+    "n         integer.  If n<0, the default value of n is used.\n"
+    "          The default value is equal to\n"
+    "          (len(x)>=offsetx+1) ? 1+(len(x)-offsetx-1)/incx : 0.\n\n"
+    "inc       positive integer\n\n" 
+    "offset    nonnegative integer\n\n"
+    "Returns 0 if n=0.";
+
+static PyObject* nrm2(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *x;
+    int n=-1, ix=1, ox=0;
+    char *kwlist[] = {"x", "n", "inc", "offset", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|iii", kwlist, &x, 
+        &n, &ix, &ox)) return NULL;
+
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (ix <= 0) err_p_int("incx");
+    if (ox < 0) err_nn_int("offsetx");
+    if (n < 0) n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/ix : 0;
+    if (n == 0) return Py_BuildValue("d", 0.0);
+    if (len(x) < ox + 1+(n-1)*ix) err_buf_len("x");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            return Py_BuildValue("d", dnrm2_(&n, MAT_BUFD(x)+ox, &ix)); 
+
+        case COMPLEX:
+            return Py_BuildValue("d", dznrm2_(&n, MAT_BUFZ(x)+ox, &ix));
+
+        default:
+            err_invalid_id;
+    }
+}
+
+
+static char doc_asum[] =
+    "Returns ||Re x||_1 + ||Im x||_1.\n\n"
+    "asum(x, n=None, inc=1, offset=0)\n\n"
+    "ARGUMENTS\n"
+    "x         'd' or 'z' matrix\n\n"
+    "n         integer.  If n<0, the default value of n is used.\n"
+    "          The default value is equal to\n"
+    "          n = (len(x)>=offset+1) ? 1+(len(x)-offset-1)/inc : 0.\n"
+    "\n"
+    "inc       positive integer\n\n" 
+    "offset    nonnegative integer\n\n"
+    "Returns 0 if n=0.";
+
+static PyObject* asum(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *x;
+    int n=-1, ix=1, ox=0; 
+    char *kwlist[] = {"x", "n", "inc", "offset", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|iii", kwlist, 
+        &x, &n, &ix, &ox)) 
+        return NULL;
+
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (ix <= 0) err_p_int("inc");
+    if (ox < 0) err_nn_int("offset");
+    if (n < 0) n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/ix : 0;
+    if (n == 0) return Py_BuildValue("d", 0.0);
+    if (len(x) < ox + 1+(n-1)*ix) err_buf_len("x");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            return Py_BuildValue("d", dasum_(&n, MAT_BUFD(x)+ox, &ix));
+
+        case COMPLEX:
+            return Py_BuildValue("d", dzasum_(&n, MAT_BUFZ(x)+ox, &ix));
+
+        default:
+            err_invalid_id;
+    }
+}
+
+
+static char doc_iamax[] =
+    "Returns the index (in {0,...,n-1}) of the coefficient with \n"
+    "maximum value of |Re x_k| + |Im x_k|.\n\n"
+    "iamax(x, n=None, inc=1, offset=0)\n\n"
+    "ARGUMENTS\n"
+    "x         'd' or 'z' matrix\n\n"
+    "n         integer.  If n<0, the default value of n is used.\n"
+    "          The default value is equal to\n"
+    "          (len(x)>=offset+1) ? 1+(len(x)-offset-1)/inc : 0.\n\n"
+    "inc       positive integer\n\n" 
+    "offset    nonnegative integer\n\n"
+    "In the case of ties, the index of the first maximizer is \n"
+    "returned.  If n=0, iamax returns 0."; 
+
+static PyObject* iamax(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *x;
+    int n=-1, ix=1, ox=0; 
+    char *kwlist[] = {"x", "n", "inc", "offset", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|iii", kwlist, 
+        &x, &n, &ix, &ox)) 
+        return NULL;
+
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (ix <= 0) err_p_int("inc");
+    if (ox < 0) err_nn_int("offset");
+    if (n < 0) n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/ix : 0;
+    if (n == 0) return Py_BuildValue("i", 0);
+    if (len(x) < ox + 1+(n-1)*ix) err_buf_len("x");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            return Py_BuildValue("i", 
+                idamax_(&n, MAT_BUFD(x)+ox, &ix)-1);
+
+        case COMPLEX:
+            return Py_BuildValue("i", 
+                izamax_(&n, MAT_BUFZ(x)+ox, &ix)-1);
+
+        default:
+            err_invalid_id;
+    }
+}
+
+
+static char doc_gemv[] =
+    "General matrix-vector product. \n\n"
+    "gemv(A, x, y, trans='N', alpha=1.0, beta=0.0, m=A.size[0],\n"
+    "     n=A.size[1], ldA=max(1,A.size[0]), incx=1, incy=1, \n"
+    "     offsetA=0, offsetx=0, offsety=0)\n\n"
+    "PURPOSE\n"
+    "If trans is 'N', computes y := alpha*A*x + beta*y.\n"
+    "If trans is 'T', computes y := alpha*A^T*x + beta*y.\n"
+    "If trans is 'C', computes y := alpha*A^H*x + beta*y.\n"
+    "The matrix A is m by n.\n"
+    "Returns immediately if n=0 and trans is 'T' or 'C', or if m=0 \n"
+    "and trans is 'N'.\n"
+    "Computes y := beta*y if n=0, m>0 and trans is 'N', or if m=0, \n"
+    "n>0 and trans is 'T' or 'C'.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "x         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "y         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "trans     'N', 'T' or 'C'\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "beta      number (int, float or complex).  Complex beta is only\n"
+    "          allowed if A is complex.\n\n"
+    "m         integer.  If negative, the default value is used.\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,m).\n"
+    "          If zero, the default value is used.\n\n"
+    "incx      nonzero integer\n\n"
+    "incy      nonzero integer\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetx   nonnegative integer\n\n"
+    "offsety   nonnegative integer";
+
+static PyObject* gemv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *x, *y;
+    PyObject *ao=NULL, *bo=NULL;
+    number a, b;
+    int m=-1, n=-1, ldA=0, ix=1, iy=1, oA=0, ox=0, oy=0; 
+    char trans='N'; 
+    char *kwlist[] = {"A", "x", "y", "trans", "alpha", "beta", "m", "n",
+        "ldA", "incx", "incy", "offsetA", "offsetx", "offsety", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOOiiiiiiii", 
+        kwlist, &A, &x, &y, &trans, &ao, &bo, &m, &n, &ldA, &ix, &iy, 
+        &oA, &ox, &oy))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (!Matrix_Check(y)) err_mtrx("y");
+    if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) ||
+        MAT_ID(x) != MAT_ID(y)) err_conflicting_ids;
+
+    if (trans != 'N' && trans != 'T' && trans != 'C') 
+        err_char("trans", "'N','T','C'");
+
+    if (ix == 0) err_nz_int("incx");
+    if (iy == 0) err_nz_int("incy");
+
+    if (m < 0) m = A->nrows;
+    if (n < 0) n = A->ncols;
+    if ((!m && trans == 'N') || (!n && (trans == 'T' || trans == 'C')))
+        return Py_BuildValue("");
+
+    if (ldA == 0) ldA = MAX(1,A->nrows); 
+    if (ldA < MAX(1,m)) err_ld("ldA"); 
+
+    if (oA < 0) err_nn_int("offsetA");
+    if (n > 0 && m > 0 && oA + (n-1)*ldA + m > len(A)) err_buf_len("A");
+
+    if (ox < 0) err_nn_int("offsetx");
+    if ((trans == 'N' && n > 0 && ox + (n-1)*abs(ix) + 1 > len(x)) || 
+	((trans == 'T' || trans == 'C') && m > 0 && 
+        ox + (m-1)*abs(ix) + 1 > len(x))) err_buf_len("x");
+
+    if (oy < 0) err_nn_int("offsety");
+    if ((trans == 'N' && oy + (m-1)*abs(iy) + 1 > len(y)) || 
+        ((trans == 'T' || trans == 'C') && 
+        oy + (n-1)*abs(iy) + 1 > len(y))) err_buf_len("y");
+
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) 
+        err_type("alpha");
+    if (bo && number_from_pyobject(bo, &b, MAT_ID(x))) 
+        err_type("beta");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            if (!ao) a.d=1.0; 
+            if (!bo) b.d=0.0;
+            if (trans == 'N' && n == 0)
+                dscal_(&m, &b.d, MAT_BUFD(y)+oy, &iy);
+            else if ((trans == 'T' || trans == 'C') && m == 0)
+                dscal_(&n, &b.d, MAT_BUFD(y)+oy, &iy);
+            else 
+                dgemv_(&trans, &m, &n, &a.d, MAT_BUFD(A)+oA, &ldA, 
+                    MAT_BUFD(x)+ox, &ix, &b.d, MAT_BUFD(y)+oy, &iy);
+            break;
+
+        case COMPLEX:
+            if (!ao) a.z=1.0; 
+            if (!bo) b.z=0.0;
+            if (trans == 'N' && n == 0)
+                zscal_(&m, &b.z, MAT_BUFZ(y)+oy, &iy);
+            else if ((trans == 'T' || trans == 'C') && m == 0)
+                zscal_(&n, &b.z, MAT_BUFZ(y)+oy, &iy);
+            else 
+                zgemv_(&trans, &m, &n, &a.z, MAT_BUFZ(A)+oA, &ldA, 
+                    MAT_BUFZ(x)+ox, &ix, &b.z, MAT_BUFZ(y)+oy, &iy);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_gbmv[] =
+    "Matrix-vector product with a general banded matrix.\n\n"
+    "gbmv(A, m, kl, x, y, trans='N', alpha=1.0, beta=0.0, n=A.size[1],\n"
+    "     ku=A.size[0]-kl-1, ldA=max(1,A.size[0]), incx=1, incy=1, \n"
+    "     offsetA=0, offsetx=0, offsety=0)\n\n"
+    "PURPOSE\n"
+    "If trans is 'N', computes y := alpha*A*x + beta*y.\n"
+    "If trans is 'T', computes y := alpha*A^T*x + beta*y.\n"
+    "If trans is 'C', computes y := alpha*A^H*x + beta*y.\n"
+    "The matrix A is m by n with upper bandwidth ku and lower\n"
+    "bandwidth kl.\n"
+    "Returns immediately if n=0 and trans is 'T' or 'C', or if m=0 \n"
+    "and trans is 'N'.\n"
+    "Computes y := beta*y if n=0, m>0, and trans is 'N', or if m=0, n>0,\n"
+    "and trans is 'T' or 'C'.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "m         nonnegative integer\n\n"
+    "kl        nonnegative integer\n\n"  
+    "x         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "y         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "trans     'N', 'T' or 'C'\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "beta      number (int, float or complex).  Complex beta is only\n"
+    "          allowed if A is complex.\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ku        nonnegative integer.  If negative, the default value is\n"
+    "          used.\n"
+    "ldA       positive integer.  ldA >= kl+ku+1. If zero, the default\n"
+    "          value is used.\n\n"
+    "incx      nonzero integer\n\n"
+    "incy      nonzero integer\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetx   nonnegative integer\n\n"
+    "offsety   nonnegative integer";
+
+static PyObject* gbmv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *x, *y;
+    PyObject *ao=NULL, *bo=NULL;
+    number a, b;
+    int m, kl, ku=-1, n=-1, ldA=0, ix=1, iy=1, oA=0, ox=0, oy=0;
+    char trans='N'; 
+    char *kwlist[] = {"A", "m", "kl", "x", "y", "trans", "alpha", "beta",
+        "n", "ku", "ldA", "incx", "incy", "offsetA", "offsetx", "offsety", 
+        NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OiiOO|cOOiiiiiiii", 
+        kwlist, &A, &m, &kl, &x, &y, &trans, &ao, &bo, &n, &ku, &ldA, &ix,
+        &iy, &oA, &ox, &oy))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (!Matrix_Check(y)) err_mtrx("y");
+    if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) ||
+        MAT_ID(x) != MAT_ID(y)) err_conflicting_ids;
+
+    if (trans != 'N' && trans != 'T' && trans != 'C') 
+        err_char("trans", "'N', 'T', 'C'");
+
+    if (ix == 0) err_nz_int("incx");
+    if (iy == 0) err_nz_int("incy");
+    if (n < 0) n = A->ncols;
+    if ((!m && trans == 'N') || (!n && (trans == 'T' || trans == 'C'))) 
+       return Py_BuildValue("");
+
+    if (kl < 0) err_nn_int("kl"); 
+    if (ku < 0) ku = A->nrows - 1 - kl;
+    if (ku < 0) err_nn_int("ku"); 
+
+    if (ldA == 0) ldA = A->nrows; 
+    if (ldA < kl+ku+1) err_ld("ldA");
+
+    if (oA < 0) err_nn_int("offsetA");
+    if (m>0 && n>0 && oA + (n-1)*ldA + kl + ku + 1 > len(A)) 
+        err_buf_len("A");
+    if (ox < 0) err_nn_int("offsetx");
+    if ((trans == 'N' && n > 0 && ox + (n-1)*abs(ix) + 1 > len(x)) || 
+        ((trans == 'T' || trans == 'C') && m > 0 && 
+        ox + (m-1)*abs(ix) + 1 > len(x))) err_buf_len("x");
+    if (oy < 0) err_nn_int("offsety");
+    if ((trans == 'N' && oy + (m-1)*abs(iy) + 1 > len(y)) || 
+	((trans == 'T' || trans == 'C') && 
+        oy + (n-1)*abs(iy) + 1 > len(y))) err_buf_len("y");
+
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) 
+        err_type("alpha");
+    if (bo && number_from_pyobject(bo, &b, MAT_ID(x))) 
+        err_type("beta");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            if (!ao) a.d=1.0; 
+            if (!bo) b.d=0.0;
+            if (trans == 'N' && n == 0)
+                dscal_(&m, &b.d, MAT_BUFD(y)+oy, &iy);
+            else if ((trans == 'T' || trans == 'C') && m == 0)
+                dscal_(&n, &b.d, MAT_BUFD(y)+oy, &iy);
+            else 
+                dgbmv_(&trans, &m, &n, &kl, &ku, &a.d, MAT_BUFD(A)+oA, 
+                    &ldA, MAT_BUFD(x)+ox, &ix, &b.d, MAT_BUFD(y)+oy, 
+                    &iy);
+            break;
+
+        case COMPLEX:
+            if (!ao) a.z=1.0; 
+            if (!bo) b.z=0.0;
+            if (trans == 'N' && n == 0)
+                zscal_(&m, &b.z, MAT_BUFZ(y)+oy, &iy);
+            else if ((trans == 'T' || trans == 'C') && m == 0)
+                zscal_(&n, &b.z, MAT_BUFZ(y)+oy, &iy);
+            else 
+                zgbmv_(&trans, &m, &n, &kl, &ku, &a.z, MAT_BUFZ(A)+oA, 
+                    &ldA, MAT_BUFZ(x)+ox, &ix, &b.z, MAT_BUFZ(y)+oy, 
+                    &iy);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_symv[] =
+    "Matrix-vector product with a real symmetric matrix.\n\n"
+    "symv(A, x, y, uplo='L', alpha=1.0, beta=0.0, n=A.size[0], \n"
+    "     ldA=max(1,A.size[0]), incx=1, incy=1, offsetA=0, offsetx=0,\n"
+    "     offsety=0)\n\n"
+    "PURPOSE\n"
+    "Computes y := alpha*A*x + beta*y with A real symmetric of order n."
+    "n\n"
+    "ARGUMENTS\n"
+    "A         'd' matrix\n\n"
+    "x         'd' matrix\n\n"
+    "y         'd' matrix\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "alpha     real number (int or float)\n\n"
+    "beta      real number (int or float)\n\n"
+    "n         integer.  If negative, the default value is used.\n"
+    "          If the default value is used, we require that\n"
+    "          A.size[0]=A.size[1].\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).\n"
+    "          If zero, the default value is used.\n\n"
+    "incx      nonzero integer\n\n"
+    "incy      nonzero integer\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetx   nonnegative integer\n\n"
+    "offsety   nonnegative integer";
+
+static PyObject* symv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *x, *y;
+    PyObject *ao=NULL, *bo=NULL;
+    number a, b;
+    int n=-1, ldA=0, ix=1, iy=1, oA=0, ox=0, oy=0; 
+    char uplo='L'; 
+    char *kwlist[] = {"A", "x", "y", "uplo", "alpha", "beta", "n", 
+        "ldA", "incx", "incy", "offsetA", "offsetx", "offsety", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOOiiiiiii", 
+        kwlist, &A, &x, &y, &uplo, &ao, &bo, &n, &ldA, &ix, &iy, &oA, 
+        &ox, &oy))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (!Matrix_Check(y)) err_mtrx("y");
+    if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) ||
+        MAT_ID(x) != MAT_ID(y)) err_conflicting_ids;
+
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+
+    if (ix == 0) err_nz_int("incx");
+    if (iy == 0) err_nz_int("incy");
+
+    if (n < 0){ 
+        if (A->nrows != A->ncols){
+            PyErr_SetString(PyExc_ValueError, "A is not square");
+            return NULL;
+        }
+        n = A->nrows;
+    }
+    if (n == 0) return Py_BuildValue("");
+
+    if (ldA == 0) ldA = MAX(1,A->nrows); 
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (ox < 0) err_nn_int("offsetx");
+    if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x");
+    if (oy < 0) err_nn_int("offsety");
+    if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y");
+
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) 
+        err_type("alpha");
+    if (bo && number_from_pyobject(bo, &b, MAT_ID(x))) 
+        err_type("beta");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            if (!ao) a.d=1.0; 
+            if (!bo) b.d=0.0;
+            dsymv_(&uplo, &n, &a.d, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(x)+ox, &ix, &b.d, MAT_BUFD(y)+oy, &iy);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+
+static char doc_hemv[] =
+    "Matrix-vector product with a real symmetric or complex Hermitian\n"
+    "matrix.\n\n"
+    "hemv(A, x, y, uplo='L', alpha=1.0, beta=0.0, n=A.size[0],\n"
+    "     ldA=max(1,A.size[0]), incx=1, incy=1, offsetA=0, offsetx=0,\n"
+    "     offsety=0)\n\n"
+    "PURPOSE\n"
+    "Computes y := alpha*A*x + beta*y, with A real symmetric or\n"
+    "complex Hermitian of order n.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "x         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "y         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         integer.  If negative, the default value is used.\n"
+    "          If the default value is used, we require that\n"
+    "          A.size[0]=A.size[1].\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).\n"
+    "          If zero, the default value is used.\n\n"
+    "incx      nonzero integer\n\n"
+    "beta      number (int, float or complex).  Complex beta is only\n"
+    "          allowed if A is complex.\n\n"
+    "incy      nonzero integer\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetx   nonnegative integer\n\n"
+    "offsety   nonnegative integer";
+
+
+static PyObject* hemv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *x, *y;
+    PyObject *ao=NULL, *bo=NULL;
+    number a, b;
+    int n=-1, ldA=0, ix=1, iy=1, oA=0, ox=0, oy=0; 
+    char uplo='L'; 
+    char *kwlist[] = {"A", "x", "y", "uplo", "alpha", "beta", "n", 
+        "ldA", "incx", "incy", "offsetA", "offsetx", "offsety", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOOiiiiiii", 
+        kwlist, &A, &x, &y, &uplo, &ao, &bo, &n, &ldA, &ix, &iy, &oA, 
+        &ox, &oy))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (!Matrix_Check(y)) err_mtrx("y");
+    if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) ||
+        MAT_ID(x) != MAT_ID(y)) err_conflicting_ids;
+
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+
+    if (ix == 0) err_nz_int("incx");
+    if (iy == 0) err_nz_int("incy");
+
+    if (n < 0){ 
+        if (A->nrows != A->ncols){
+            PyErr_SetString(PyExc_ValueError, "A is not square");
+            return NULL;
+        }
+        n = A->nrows;
+    }
+    if (n == 0) return Py_BuildValue(""); 
+
+    if (ldA == 0) ldA = MAX(1,A->nrows); 
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (ox < 0) err_nn_int("offsetx");
+    if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x");
+    if (oy < 0) err_nn_int("offsety");
+    if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y");
+
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) 
+        err_type("alpha");
+    if (bo && number_from_pyobject(bo, &b, MAT_ID(x))) 
+        err_type("beta");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            if (!ao) a.d=1.0; 
+            if (!bo) b.d=0.0;
+            dsymv_(&uplo, &n, &a.d, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(x)+ox, &ix, &b.d, MAT_BUFD(y)+oy, &iy);
+            break;
+
+        case COMPLEX:
+            if (!ao) a.z=1.0; 
+            if (!bo) b.z=0.0;
+            zhemv_(&uplo, &n, &a.z, MAT_BUFZ(A)+oA, &ldA, 
+                MAT_BUFZ(x)+ox, &ix, &b.z, MAT_BUFZ(y)+oy, &iy);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_sbmv[] =
+    "Matrix-vector product with a real symmetric band matrix.\n\n"
+    "sbmv(A, x, y, uplo='L', alpha=1.0, beta=0.0, n=A.size[1], \n"
+    "     k=None, ldA=A.size[0], incx=1, incy=1, offsetA=0,\n"
+    "     offsetx=0, offsety=0)\n\n"
+    "PURPOSE\n"
+    "Computes y := alpha*A*x + beta*y with A real symmetric and \n"
+    "banded of order n and with bandwidth k.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' matrix\n\n"
+    "x         'd' matrix\n\n"
+    "y         'd' matrix\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "alpha     real number (int or float)\n\n"
+    "beta      real number (int or float)\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "k         integer.  If negative, the default value is used.\n"
+    "          The default value is k = max(0,A.size[0]-1).\n\n"
+    "ldA       nonnegative integer.  ldA >= k+1.\n"
+    "          If zero, the default vaule is used.\n\n"
+    "incx      nonzero integer\n\n"
+    "incy      nonzero integer\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetx   nonnegative integer\n\n"
+    "offsety   nonnegative integer\n\n";
+
+static PyObject* sbmv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *x, *y;
+    PyObject *ao=NULL, *bo=NULL;
+    number a, b;
+    int n=-1, k=-1, ldA=0, ix=1, iy=1, oA=0, ox=0, oy=0; 
+    char uplo='L'; 
+    char *kwlist[] = {"A", "x", "y", "uplo", "alpha", "beta", "n", "k",
+        "ldA", "incx", "incy", "offsetA", "offsetx", "offsety", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOOiiiiiiii", 
+        kwlist, &A, &x, &y, &uplo, &ao, &bo, &n, &k, &ldA, &ix, &iy, 
+        &oA, &ox, &oy))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (!Matrix_Check(y)) err_mtrx("y");
+    if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) ||
+        MAT_ID(x) != MAT_ID(y)) err_conflicting_ids;
+
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+
+    if (ix == 0) err_nz_int("incx");
+    if (iy == 0) err_nz_int("incy");
+
+    if (n < 0) n = A->ncols; 
+    if (n == 0) return Py_BuildValue("");
+
+    if (k < 0) k = MAX(0, A->nrows-1);
+    if (ldA == 0) ldA = A->nrows;
+    if (ldA < 1+k) err_ld("ldA");
+
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + k+1 > len(A)) err_buf_len("A");
+    if (ox < 0) err_nn_int("offsetx");
+    if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x");
+    if (oy < 0) err_nn_int("offsety");
+    if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y");
+  
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) 
+        err_type("alpha");
+    if (bo && number_from_pyobject(bo, &b, MAT_ID(x))) 
+        err_type("beta");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            if (!ao) a.d=1.0; 
+            if (!bo) b.d=0.0;
+            dsbmv_(&uplo, &n, &k, &a.d, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(x)+ox, &ix, &b.d, MAT_BUFD(y)+oy, &iy);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_hbmv[] =
+    "Matrix-vector product with a real symmetric or complex Hermitian\n"
+    "band matrix.\n\n"
+    "hbmv(A, x, y, uplo='L', alpha=1.0, beta=0.0, n=A.size[1], \n"
+    "     k=None, ldA=A.size[0], incx=1, incy=1, offsetA=0, \n"
+    "     offsetx=0, offsety=0)\n\n"
+    "PURPOSE\n"
+    "Computes y := alpha*A*x + beta*y with A real symmetric or \n"
+    "complex Hermitian and banded of order n and with bandwidth k.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "x         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "y         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "beta      number (int, float or complex).  Complex beta is only\n"
+    "          allowed if A is complex.\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "k         integer.  If negative, the default value is used.\n"
+    "          The default value is k = max(0,A.size[0]-1).\n\n"
+    "ldA       nonnegative integer.  ldA >= k+1.\n"
+    "          If zero, the default vaule is used.\n\n"
+    "incx      nonzero integer\n\n"
+    "incy      nonzero integer\n\n"
+    "offsetA   nonnegative integer.\n\n"
+    "offsetx   nonnegative integer.\n\n"
+    "offsety   nonnegative integer.\n\n";
+
+static PyObject* hbmv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *x, *y;
+    PyObject *ao=NULL, *bo=NULL;
+    number a, b;
+    int n=-1, k=-1, ldA=0, ix=1, iy=1, oA=0, ox=0, oy=0; 
+    char uplo='L'; 
+    char *kwlist[] = {"A", "x", "y", "uplo", "alpha", "beta", "n", "k",
+        "ldA", "incx", "incy", "offsetA", "offsetx", "offsety", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOOiiiiiiii", 
+        kwlist, &A, &x, &y, &uplo, &ao, &bo, &n, &k, &ldA, &ix, &iy, 
+        &oA, &ox, &oy))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (!Matrix_Check(y)) err_mtrx("y");
+    if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) ||
+        MAT_ID(x) != MAT_ID(y)) err_conflicting_ids;
+
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+
+    if (ix == 0) err_nz_int("incx");
+    if (iy == 0) err_nz_int("incy");
+
+    if (n < 0) n = A->ncols; 
+    if (n == 0) return Py_BuildValue("");
+
+    if (k < 0) k = MAX(0, A->nrows-1);
+    if (ldA == 0) ldA = A->nrows;
+    if (ldA < 1+k) err_ld("ldA");
+
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + k+1 > len(A)) err_buf_len("A");
+    if (ox < 0) err_nn_int("offsetx");
+    if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x");
+    if (oy < 0) err_nn_int("offsety");
+    if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y");
+  
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) 
+        err_type("alpha");
+    if (bo && number_from_pyobject(bo, &b, MAT_ID(x))) 
+        err_type("beta");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            if (!ao) a.d=1.0; 
+            if (!bo) b.d=0.0;
+            dsbmv_(&uplo, &n, &k, &a.d, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(x)+ox, &ix, &b.d, MAT_BUFD(y)+oy, &iy);
+            break;
+
+        case COMPLEX:
+            if (!ao) a.z=1.0; 
+            if (!bo) b.z=0.0;
+            zhbmv_(&uplo, &n, &k, &a.z, MAT_BUFZ(A)+oA, &ldA, 
+                MAT_BUFZ(x)+ox, &ix, &b.z, MAT_BUFZ(y)+oy, &iy);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_trmv[] =
+    "Matrix-vector product with a triangular matrix.\n\n"
+    "trmv(A, x, uplo='L', trans='N', diag='N', n=A.size[0],\n"
+    "     ldA=max(1,A.size[0]), incx=1, offsetA=0, offsetx=0)\n\n"
+    "PURPOSE\n"
+    "If trans is 'N', computes x := A*x.\n"
+    "If trans is 'T', computes x := A^T*x.\n" 
+    "If trans is 'C', computes x := A^H*x.\n" 
+    "A is triangular of order n.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "x         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "trans     'N' or 'T'\n\n"
+    "diag      'N' or 'U'\n\n"
+    "n         integer.  If negative, the default value is used.\n"
+    "          If the default value is used, we require that\n"
+    "          A.size[0] = A.size[1].\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).\n"
+    "          If zero the default value is used.\n\n"
+    "incx      nonzero integer\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetx   nonnegative integer";
+
+static PyObject* trmv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *x; 
+    int n=-1, ldA=0, ix=1, oA=0, ox=0;
+    char uplo='L', trans='N', diag='N'; 
+    char *kwlist[] = {"A", "x", "uplo", "trans", "diag", "n", "ldA", 
+        "incx", "offsetA", "offsetx", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccciiiii", 
+        kwlist, &A, &x, &uplo, &trans, &diag, &n, &ldA, &ix, &oA, &ox))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (MAT_ID(A) != MAT_ID(x)) err_conflicting_ids;
+
+    if (trans != 'N' && trans != 'T' && trans != 'C') 
+        err_char("trans", "'N', 'T', 'C'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (diag != 'N' && diag != 'U') err_char("diag", "'U', 'N'");
+
+    if (ix == 0) err_nz_int("incx");
+
+    if (n < 0){ 
+        if (A->nrows != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A is not square");
+            return NULL;
+        }
+        n = A->nrows;
+    }
+    if (n == 0) return Py_BuildValue("");
+
+    if (ldA == 0) ldA = MAX(1,A->nrows); 
+    if (ldA < MAX(1,n)) err_ld("ldA"); 
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (ox < 0) err_nn_int("offsetx");
+    if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("offsetx");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            dtrmv_(&uplo, &trans, &diag, &n, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(x)+ox, &ix);
+            break;
+
+        case COMPLEX:
+            ztrmv_(&uplo, &trans, &diag, &n, MAT_BUFZ(A)+oA, &ldA, 
+                MAT_BUFZ(x)+ox, &ix);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_tbmv[] =
+    "Matrix-vector product with a triangular band matrix.\n\n"
+    "tbmv(A, x, uplo='L', trans='N', diag='N', n=A.size[1],\n"
+    "     k=max(0,A.size[0]-1), ldA=A.size[0], incx=1, offsetA=0,\n"
+    "     offsetx=0)\n\n"
+    "PURPOSE\n"
+    "If trans is 'N', computes x := A*x.\n"
+    "If trans is 'T', computes x := A^T*x.\n"
+    "If trans is 'C', computes x := A^H*x.\n"
+    "A is banded triangular of order n and with bandwith k.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "x         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "trans     'N', 'T' or 'C'\n\n"
+    "diag      'N' or 'U'\n\n"
+    "n         nonnegative integer.  If negative, the default value\n"
+    "          is used.\n\n"
+    "k         nonnegative integer.  If negative, the default value\n"
+    "          is used.\n\n"
+    "ldA       nonnegative integer.  lda >= 1+k.\n"
+    "          If zero the default value is used.\n\n"
+    "incx      nonzero integer\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetx   nonnegative integer";
+
+static PyObject* tbmv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *x; 
+    int n=-1, k=-1, ldA=0, ix=1, oA=0, ox=0; 
+    char uplo='L', trans='N', diag='N'; 
+    char *kwlist[] = {"A", "x", "uplo", "trans", "diag", "n", "k", 
+        "ldA", "incx", "offsetA", "offsetx", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccciiiiii", 
+        kwlist, &A, &x, &uplo, &trans, &diag, &n, &k, &ldA, &ix, &oA, 
+        &ox))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (MAT_ID(A) != MAT_ID(x)) err_conflicting_ids;
+
+    if (trans != 'N' && trans != 'T' && trans != 'C') 
+        err_char("trans", "'N', 'T', 'C'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (diag != 'N' && diag != 'U') err_char("diag", "'U', 'N'");
+
+    if (ix == 0) err_nz_int("incx");
+
+    if (n < 0) n = A->ncols;
+    if (n == 0) return Py_BuildValue("");
+    if (k < 0) k = MAX(0,A->nrows-1);
+
+    if (ldA == 0) ldA = A->nrows; 
+    if (ldA < k+1)  err_ld("ldA");
+
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + k + 1 > len(A)) err_buf_len("A");
+    if (ox < 0) err_nn_int("offsetx");
+    if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            dtbmv_(&uplo, &trans, &diag, &n, &k, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(x)+ox, &ix);
+            break;
+
+        case COMPLEX:
+            ztbmv_(&uplo, &trans, &diag, &n, &k, MAT_BUFZ(A)+oA, &ldA, 
+                MAT_BUFZ(x)+ox, &ix);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_trsv[] =
+    "Solution of a triangular set of equations with one righthand side."
+    "\n\n"
+    "trsv(A, x, uplo='L', trans='N', diag='N', n=A.size[0],\n"
+    "     ldA=max(1,A.size[0]), incx=1, offsetA=0, offsetx=0)\n\n"
+    "PURPOSE\n"
+    "If trans is 'N', computes x := A^{-1}*x.\n"
+    "If trans is 'T', computes x := A^{-T}*x.\n"
+    "If trans is 'C', computes x := A^{-H}*x.\n"
+    "A is triangular of order n.  The code does not verify whether A\n"
+    "is nonsingular.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "x         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "trans     'N', 'T' or 'C'\n\n"
+    "diag      'N' or 'U'\n\n"
+    "n         integer.  If negative, the default value is used.\n"
+    "          If the default value is used, we require that\n"
+    "          A.size[0] = A.size[1].\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).\n"
+    "          If zero, the default value is used.\n\n"
+    "incx      nonzero integer\n\n"
+    "offsetA   nonnegative integer\n\n"  
+    "offsetx   nonnegative integer";
+
+static PyObject* trsv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *x; 
+    int n=-1, ldA=0, ix=1, oA=0, ox=0;
+    char uplo='L', trans='N', diag='N'; 
+    char *kwlist[] = {"A", "x", "uplo", "trans", "diag", "n", "ldA", 
+        "incx", "offsetA", "offsetx", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccciiiii", 
+        kwlist, &A, &x, &uplo, &trans, &diag, &n, &ldA, &ix, &oA, &ox))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (MAT_ID(A) != MAT_ID(x)) err_conflicting_ids;
+
+    if (trans != 'N' && trans != 'T' && trans != 'C') 
+        err_char("trans", "'N', 'T', 'C'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (diag != 'N' && diag != 'U') err_char("diag", "'N', 'U'");
+
+    if (ix == 0) err_nz_int("incx");
+
+    if (n < 0){ 
+        if (A->nrows != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A is not square");
+            return NULL;
+        }
+        n = A->nrows;
+    }
+    if (n == 0) return Py_BuildValue("");
+
+    if (ldA == 0) ldA = MAX(1,A->nrows); 
+    if (ldA < MAX(1,n)) err_ld("ldA");
+
+    if (oA < 0) err_nn_int("offsetA"); 
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (ox < 0) err_nn_int("offsetx");
+    if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            dtrsv_(&uplo, &trans, &diag, &n, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(x)+ox, &ix);
+            break;
+
+        case COMPLEX:
+            ztrsv_(&uplo, &trans, &diag, &n, MAT_BUFZ(A)+oA, &ldA, 
+                MAT_BUFZ(x)+ox, &ix);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_tbsv[] =
+    "Solution of a triangular and banded set of equations.\n\n"
+    "tbsv(A, x, uplo='L', trans='N', diag='N', n=A.size[1],\n"
+    "     k=max(0,A.size[0]-1), ldA=A.size[0], incx=1, offsetA=0,\n"
+    "     offsetx=0)\n\n"
+    "PURPOSE\n"
+    "If trans is 'N', computes x := A^{-1}*x.\n"
+    "If trans is 'T', computes x := A^{-T}*x.\n"
+    "If trans is 'C', computes x := A^{-H}*x.\n"
+    "A is banded triangular of order n and with bandwidth k.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "x         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "trans     'N', 'T' or 'C'\n\n"
+    "diag      'N' or 'U'\n\n"
+    "n         nonnegative integer.  If negative, the default value\n"
+    "          is used.\n\n"
+    "k         nonnegative integer.  If negative, the default value\n"
+    "          is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= 1+k.\n"
+    "          If zero the default value is used.\n\n"
+    "incx      nonzero integer\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetx   nonnegative integer";
+
+static PyObject* tbsv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *x; 
+    int n=-1, k=-1, ldA=0, ix=1, oA=0, ox=0; 
+    char uplo='L', trans='N', diag='N'; 
+    char *kwlist[] = {"A", "x", "uplo", "trans", "diag", "n", "k", 
+        "ldA", "incx", "offsetA", "offsetx", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccciiiiii", 
+        kwlist, &A, &x, &uplo, &trans, &diag, &n, &k, &ldA, &ix, &oA, 
+        &ox))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (MAT_ID(A) != MAT_ID(x)) err_conflicting_ids;
+
+    if (trans != 'N' && trans != 'T' && trans != 'C') 
+        err_char("trans", "'N', 'T', 'C'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (diag != 'N' && diag != 'U') err_char("diag", "'N', 'U'");
+
+    if (ix == 0) err_nz_int("incx");
+
+    if (n < 0) n = A->ncols;
+    if (n == 0) return Py_BuildValue("");
+    if (k < 0) k = MAX(0, A->nrows-1);
+
+    if (ldA == 0) ldA = A->nrows; 
+    if (ldA < k+1) err_ld("ldA");
+
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + k + 1 > len(A)) err_buf_len("A");
+    if (ox < 0) err_nn_int("offsetx"); 
+    if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            dtbsv_(&uplo, &trans, &diag, &n, &k, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(x)+ox, &ix);
+            break;
+
+        case COMPLEX:
+            ztbsv_(&uplo, &trans, &diag, &n, &k, MAT_BUFZ(A)+oA, &ldA, 
+                MAT_BUFZ(x)+ox, &ix);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_ger[] =
+    "General rank-1 update.\n\n"
+    "ger(x, y, A, alpha=1.0, m=A.size[0], n=A.size[1], incx=1,\n"
+    "    incy=1, ldA=max(1,A.size[0]), offsetx=0, offsety=0,\n"
+    "    offsetA=0)\n\n"
+    "PURPOSE\n"
+    "Computes A := A + alpha*x*y^H with A m by n, real or complex.\n\n"
+    "ARGUMENTS\n"
+    "x         'd' or 'z' matrix\n\n"
+    "y         'd' or 'z' matrix.  Must have the same type as x.\n\n"
+    "A         'd' or 'z' matrix.  Must have the same type as x.\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "m         integer.  If negative, the default value is used.\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "incx      nonzero integer\n\n"
+    "incy      nonzero integer\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,m).\n"
+    "          If zero, the default value is used.\n\n"
+    "offsetx   nonnegative integer\n\n"
+    "offsety   nonnegative integer\n\n"
+    "offsetA   nonnegative integer";
+
+static PyObject* ger(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *x, *y; 
+    PyObject *ao=NULL;
+    number a;
+    int m=-1, n=-1, ldA=0, ix=1, iy=1, oA=0, ox=0, oy=0; 
+    char *kwlist[] = {"x", "y", "A", "alpha", "m", "n", "incx", "incy",
+        "ldA", "offsetx", "offsety", "offsetZ", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|Oiiiiiiii", 
+        kwlist, &x, &y, &A, &ao, &m, &n, &ix, &iy, &ldA, &ox, &oy, &oA))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (!Matrix_Check(y)) err_mtrx("y");
+    if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) ||
+        MAT_ID(x) != MAT_ID(y)) err_conflicting_ids;
+
+    if (ix == 0) err_nz_int("incx");
+    if (iy == 0) err_nz_int("incy");
+
+    if (m < 0) m = A->nrows;
+    if (n < 0) n = A->ncols;
+    if (m == 0 || n == 0) return Py_BuildValue("");
+
+    if (ldA == 0) ldA = MAX(1,A->nrows); 
+    if (ldA < MAX(1,m)) err_ld("ldA");
+
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + m > len(A)) err_buf_len("A");
+    if (ox < 0) err_nn_int("offsetx");
+    if (ox + (m-1)*abs(ix) + 1 > len(x)) err_buf_len("x");
+    if (oy < 0) err_nn_int("offsety");
+    if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y");
+
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) 
+        err_type("alpha");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            if (!ao) a.d = 1.0; 
+            dger_(&m, &n, &a.d, MAT_BUFD(x)+ox, &ix, MAT_BUFD(y)+oy, 
+                &iy, MAT_BUFD(A)+oA, &ldA);
+            break;
+
+        case COMPLEX:
+            if (!ao) a.z = 1.0; 
+            zgerc_(&m, &n, &a.z, MAT_BUFZ(x)+ox, &ix, MAT_BUFZ(y)+oy, 
+                &iy, MAT_BUFZ(A)+oA, &ldA);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_geru[] =
+    "General rank-1 update.\n\n"
+    "geru(x, y, A, m=A.size[0], n=A.size[1], alpha=1.0, incx=1,\n"
+    "     incy=1, ldA=max(1,A.size[0]), offsetx=0, offsety=0,\n"
+    "     offsetA=0)\n\n"
+    "PURPOSE\n"
+    "Computes A := A + alpha*x*y^T with A m by n, real or complex.\n\n"
+    "ARGUMENTS\n"
+    "x         'd' or 'z' matrix\n\n"
+    "y         'd' or 'z' matrix.  Must have the same type as x.\n\n"
+    "A         'd' or 'z' matrix.  Must have the same type as x.\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "m         integer.  If negative, the default value is used.\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "incx      nonzero integer\n\n"
+    "incy      nonzero integer\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,m).\n"
+    "          If zero, the default value is used.\n\n"
+    "offsetx   nonnegative integer\n\n"
+    "offsety   nonnegative integer\n\n"
+    "offsetA   nonnegative integer";
+
+static PyObject* geru(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *x, *y; 
+    PyObject *ao=NULL;
+    number a;
+    int m=-1, n=-1, ldA=0, ix=1, iy=1, oA=0, ox=0, oy=0; 
+    char *kwlist[] = {"x", "y", "A", "alpha", "m", "n", "incx", "incy",
+        "ldA", "offsetx", "offsety", "offsetZ", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|Oiiiiiiii", 
+        kwlist, &x, &y, &A, &ao, &m, &n, &ix, &iy, &ldA, &ox, &oy, &oA))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (!Matrix_Check(y)) err_mtrx("y");
+    if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) ||
+        MAT_ID(x) != MAT_ID(y)) err_conflicting_ids;
+
+    if (ix == 0) err_nz_int("incx");
+    if (iy == 0) err_nz_int("incy");
+
+    if (m < 0) m = A->nrows;
+    if (n < 0) n = A->ncols;
+    if (m == 0 || n == 0) return Py_BuildValue("");
+
+    if (ldA == 0) ldA = MAX(1,A->nrows); 
+    if (ldA < MAX(1,m)) err_ld("ldA");
+
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + m > len(A)) err_buf_len("A");
+    if (ox < 0) err_nn_int("offsetx");
+    if (ox + (m-1)*abs(ix) + 1 > len(x)) err_buf_len("x");
+    if (oy < 0) err_nn_int("offsety");
+    if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y");
+
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) 
+        err_type("alpha");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            if (!ao) a.d = 1.0; 
+            dger_(&m, &n, &a.d, MAT_BUFD(x)+ox, &ix, MAT_BUFD(y)+oy, 
+                &iy, MAT_BUFD(A)+oA, &ldA);
+            break;
+
+        case COMPLEX:
+            if (!ao) a.z = 1.0; 
+            zgeru_(&m, &n, &a.z, MAT_BUFZ(x)+ox, &ix, MAT_BUFZ(y)+oy, 
+                &iy, MAT_BUFZ(A)+oA, &ldA);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_syr[] =
+    "Symmetric rank-1 update.\n\n"
+    "syr(x, A, uplo='L', alpha=1.0, n=A.size[0], incx=1,\n"
+    "    ldA=max(1,A.size[0]), offsetx=0, offsetA=0)\n\n"
+    "PURPOSE\n"
+    "Computes A := A + alpha*x*x^T with A real symmetric of order n."
+    "\n\n"
+    "ARGUMENTS\n"
+    "x         'd' matrix\n\n"
+    "A         'd' matrix\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "alpha     real number (int or float)\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "incx      nonzero integer\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).\n"
+    "          If zero, the default value is used.\n\n"
+    "offsetx   nonnegative integer\n\n"
+    "offsetA   nonnegative integer";
+
+
+static PyObject* syr(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *x; 
+    PyObject *ao=NULL;
+    number a; 
+    int n=-1, ldA=0, ix=1, oA=0, ox=0; 
+    char uplo='L'; 
+    char *kwlist[] = {"x", "A", "uplo", "alpha", "n", "incx", "ldA", 
+        "offsetx", "offsetA", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cOiiiii", kwlist,
+        &x, &A, &uplo, &ao, &n, &ix, &ldA, &ox, &oA))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (MAT_ID(A) != MAT_ID(x)) err_conflicting_ids;
+
+    if (ix == 0)  err_nz_int("incx");
+
+    if (n < 0){ 
+        if (A->nrows != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A is not square");
+            return NULL;
+        }
+        n = A->nrows;
+    }
+    if (n == 0) return Py_BuildValue("");
+
+    if (ldA == 0) ldA = MAX(1,A->nrows); 
+    if (ldA < MAX(1,n)) err_ld("ldA"); 
+
+    if (oA < 0) err_nn_int("offsetA"); 
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (ox < 0) err_nn_int("offsetx");
+    if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x");
+
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+
+    if (ao && number_from_pyobject(ao, &a, DOUBLE)) err_type("alpha");
+    if (!ao) a.d = 1.0; 
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            dsyr_(&uplo, &n, &a.d, MAT_BUFD(x)+ox, &ix, MAT_BUFD(A)+oA,
+                &ldA);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_her[] =
+    "Hermitian rank-1 update.\n\n"
+    "her(x, A, uplo='L', alpha=1.0, n=A.size[0], incx=1,\n"
+    "    ldA=max(1,A.size[0]), offsetx=0, offsetA=0)\n\n"
+    "PURPOSE\n"
+    "Computes A := A + alpha*x*x^H with A real symmetric or complex\n"
+    "Hermitian of order n.\n\n"
+    "ARGUMENTS\n"
+    "x         'd' or 'z' matrix\n\n"
+    "A         'd' or 'z' matrix.  Must have the same type as x.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "alpha     real number (int or float)\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "incx      nonzero integer\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).\n"
+    "          If zero, the default value is used.\n\n"
+    "offsetx   nonnegative integer\n\n"
+    "offsetA   nonnegative integer";
+
+
+static PyObject* her(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *x; 
+    PyObject *ao=NULL;
+    number a; 
+    int n=-1, ldA=0, ix=1, oA=0, ox=0; 
+    char uplo='L'; 
+    char *kwlist[] = {"x", "A", "uplo", "alpha", "n", "incx", "ldA", 
+        "offsetx", "offsetA", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cOiiiii", 
+        kwlist, &x, &A, &uplo, &ao, &n, &ix, &ldA, &ox, &oA))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (MAT_ID(A) != MAT_ID(x)) err_conflicting_ids;
+
+    if (ix == 0)  err_nz_int("incx");
+
+    if (n < 0){ 
+        if (A->nrows != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A is not square");
+            return NULL;
+        }
+        n = A->nrows;
+    }
+    if (n == 0) return Py_BuildValue("");
+
+    if (ldA == 0) ldA = MAX(1,A->nrows); 
+    if (ldA < MAX(1,n)) err_ld("ldA"); 
+
+    if (oA < 0) err_nn_int("offsetA"); 
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (ox < 0) err_nn_int("offsetx");
+    if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x");
+
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+
+    if (ao && number_from_pyobject(ao, &a, DOUBLE)) err_type("alpha");
+    if (!ao) a.d = 1.0; 
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            dsyr_(&uplo, &n, &a.d, MAT_BUFD(x)+ox, &ix, MAT_BUFD(A)+oA,
+                &ldA);
+            break;
+
+        case COMPLEX:
+            zher_(&uplo, &n, &a.d, MAT_BUFZ(x)+ox, &ix, MAT_BUFZ(A)+oA,
+                &ldA);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+
+static char doc_syr2[] =
+    "Symmetric rank-2 update.\n\n"
+    "syr2(x, y, A, uplo='L', alpha=1.0, n=A.size[0], incx=1, incy=1,\n"
+    "    ldA=max(1,A.size[0]), offsetx=0, offsety=0, offsetA=0)\n\n"
+    "PURPOSE\n"
+    "Computes A := A + alpha*(x*y^T + y*x^T) with A real symmetric.\n\n"
+    "ARGUMENTS\n"
+    "x         'd' matrix\n\n" 
+    "y         'd' matrix\n\n"
+    "A         'd' matrix\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "alpha     real number (int or float)\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "incx      nonzero integer\n\n"
+    "incy      nonzero integer\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).\n"
+    "          If zero the default value is used.\n\n"
+    "offsetx   nonnegative integer\n\n"
+    "offsety   nonnegative integer\n\n"
+    "offsetA   nonnegative integer";
+
+static PyObject* syr2(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *x, *y; 
+    PyObject *ao=NULL;
+    number a;
+    int n=-1, ldA=0, ix=1, iy=1, ox=0, oy=0, oA=0; 
+    char uplo='L'; 
+    char *kwlist[] = {"x", "y", "A", "uplo", "alpha", "n", "incx", 
+        "incy", "ldA", "offsetx", "offsety", "offsetA", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOiiiiiii", 
+        kwlist, &x, &y, &A, &uplo, &ao, &n, &ix, &iy, &ldA, &ox, &oy, 
+        &oA))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (!Matrix_Check(y)) err_mtrx("y");
+    if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) ||
+        MAT_ID(x) != MAT_ID(y)) err_conflicting_ids;
+
+    if (ix == 0) err_nz_int("incx");
+    if (iy == 0) err_nz_int("incy");
+
+    if (n < 0){ 
+        if (A->nrows != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A is not square");
+            return NULL;
+        }
+        n = A->nrows;
+    }
+    if (n == 0) return Py_BuildValue("");
+
+    if (ldA == 0) ldA = MAX(1,A->nrows); 
+    if (ldA < MAX(1,n)) err_ld("ldA"); 
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (ox < 0) err_nn_int("offsetx");
+    if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x");
+    if (oy < 0) err_nn_int("offsety");
+    if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y");
+
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L','U'");
+
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) 
+        err_type("alpha");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            if (!ao) a.d = 1.0; 
+            dsyr2_(&uplo, &n, &a.d, MAT_BUFD(x)+ox, &ix, MAT_BUFD(y)+oy,
+                &iy, MAT_BUFD(A)+oA, &ldA);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_her2[] =
+    "Hermitian rank-2 update.\n\n"
+    "her2(x, y, A, uplo='L', alpha=1.0, n=A.size[0], incx=1, incy=1,\n"
+    "     ldA=max(1,A.size[0]), offsetx=0, offsety=0, offsetA=0)\n\n"
+    "PURPOSE\n"
+    "Computes A := A + alpha*x*y^H + conj(alpha)*y*x^H with A \n"
+    "real symmetric or complex Hermitian of order n.\n\n"
+    "ARGUMENTS\n"
+    "x         'd' or 'z' matrix\n\n" 
+    "y         'd' or 'z' matrix.  Must have the same type as x.\n\n" 
+    "A         'd' or 'z' matrix.  Must have the same type as x.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "incx      nonzero integer\n\n"
+    "incy      nonzero integer\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).\n"
+    "          If zero the default value is used.\n\n"
+    "offsetx   nonnegative integer\n\n"
+    "offsety   nonnegative integer\n\n"
+    "offsetA   nonnegative integer";
+
+static PyObject* her2(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *x, *y; 
+    PyObject *ao=NULL;
+    number a;
+    int n=-1, ldA=0, ix=1, iy=1, ox=0, oy=0, oA=0; 
+    char uplo='L'; 
+    char *kwlist[] = {"x", "y", "A", "uplo", "alpha", "n", "incx", 
+        "incy", "ldA", "offsetx", "offsety", "offsetA", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOiiiiiii", 
+        kwlist, &x, &y, &A, &uplo, &ao, &n, &ix, &iy, &ldA, &ox, &oy, 
+        &oA))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(x)) err_mtrx("x");
+    if (!Matrix_Check(y)) err_mtrx("y");
+    if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) ||
+        MAT_ID(x) != MAT_ID(y)) err_conflicting_ids;
+
+    if (ix == 0) err_nz_int("incx");
+    if (iy == 0) err_nz_int("incy");
+
+    if (n < 0){ 
+        if (A->nrows != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A is not square");
+            return NULL;
+        }
+        n = A->nrows;
+    }
+    if (n == 0) return Py_BuildValue("");
+
+    if (ldA == 0) ldA = MAX(1,A->nrows); 
+    if (ldA < MAX(1,n)) err_ld("ldA"); 
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (ox < 0) err_nn_int("offsetx");
+    if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x");
+    if (oy < 0) err_nn_int("offsety");
+    if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y");
+
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L','U'");
+
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) 
+        err_type("alpha");
+
+    switch (MAT_ID(x)){
+        case DOUBLE:
+            if (!ao) a.d = 1.0; 
+            dsyr2_(&uplo, &n, &a.d, MAT_BUFD(x)+ox, &ix, MAT_BUFD(y)+oy,
+                &iy, MAT_BUFD(A)+oA, &ldA);
+            break;
+
+        case COMPLEX:
+            if (!ao) a.z = 1.0; 
+            zher2_(&uplo, &n, &a.z, MAT_BUFZ(x)+ox, &ix, MAT_BUFZ(y)+oy,
+                &iy, MAT_BUFZ(A)+oA, &ldA);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_gemm[] =
+    "General matrix-matrix product.\n\n"
+    "gemm(A, B, C, transA='N', transB='N', alpha=1.0, beta=0.0, \n"
+    "     m=None, n=None, k=None, ldA=max(1,A.size[0]), \n"
+    "     ldB=max(1,B.size[0]), ldC=max(1,C.size[0]), offsetA=0, \n"
+    "     offsetB=0, offsetC=0) \n\n"
+    "PURPOSE\n"   
+    "Computes \n"
+    "C := alpha*A*B + beta*C     if transA = 'N' and transB = 'N'.\n"
+    "C := alpha*A^T*B + beta*C   if transA = 'T' and transB = 'N'.\n"
+    "C := alpha*A^H*B + beta*C   if transA = 'C' and transB = 'N'.\n"
+    "C := alpha*A*B^T + beta*C   if transA = 'N' and transB = 'T'.\n"
+    "C := alpha*A^T*B^T + beta*C if transA = 'T' and transB = 'T'.\n"
+    "C := alpha*A^H*B^T + beta*C if transA = 'C' and transB = 'T'.\n"
+    "C := alpha*A*B^H + beta*C   if transA = 'N' and transB = 'C'.\n"
+    "C := alpha*A^T*B^H + beta*C if transA = 'T' and transB = 'C'.\n"
+    "C := alpha*A^H*B^H + beta*C if transA = 'C' and transB = 'C'.\n"
+    "If k=0, this reduces to C := beta*C.\n\n"
+    "ARGUMENTS\n\n" 
+    "A         'd' or 'z' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "C         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "transA    'N', 'T' or 'C'\n\n"
+    "transB    'N', 'T' or 'C'\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "beta      number (int, float or complex).  Complex beta is only\n"
+    "          allowed if A is complex.\n\n"
+    "m         integer.  If negative, the default value is used.\n"
+    "          The default value is\n"
+    "          m = (transA == 'N') ? A.size[0] : A.size[1].\n\n"
+    "n         integer.  If negative, the default value is used.\n"
+    "          The default value is\n"
+    "          n = (transB == 'N') ? B.size[1] : B.size[0].\n\n"
+    "k         integer.  If negative, the default value is used.\n"
+    "          The default value is\n"
+    "          (transA == 'N') ? A.size[1] : A.size[0], transA='N'.\n"
+    "          If the default value is used it should also be equal to\n"
+    "          (transB == 'N') ? B.size[0] : B.size[1].\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,(transA == 'N') ? m : k).\n"
+    "          If zero, the default value is used.\n\n"
+    "ldB       nonnegative integer.  ldB >= max(1,(transB == 'N') ? k : n).\n"
+    "          If zero, the default value is used.\n\n"
+    "ldC       nonnegative integer.  ldC >= max(1,m).\n"
+    "          If zero, the default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer\n\n"
+    "offsetC   nonnegative integer";
+
+static PyObject* gemm(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B, *C;
+    PyObject *ao=NULL, *bo=NULL;
+    number a, b;
+    int m=-1, n=-1, k=-1, ldA=0, ldB=0, ldC=0, oA=0, oB=0, oC=0;
+    char transA='N', transB='N';
+    char *kwlist[] = {"A", "B", "C", "transA", "transB", "alpha", 
+        "beta", "m", "n", "k", "ldA", "ldB", "ldC", "offsetA", 
+        "offsetB", "offsetC", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ccOOiiiiiiiii", 
+        kwlist, &A, &B, &C, &transA, &transB, &ao, &bo, &m, &n, &k, 
+        &ldA, &ldB, &ldC, &oA, &oB, &oC))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (!Matrix_Check(C)) err_mtrx("C");
+    if (MAT_ID(A) != MAT_ID(B) || MAT_ID(A) != MAT_ID(C) ||
+        MAT_ID(B) != MAT_ID(C)) err_conflicting_ids;
+
+    if (transA != 'N' && transA != 'T' && transA != 'C') 
+        err_char("transA", "'N', 'T', 'C'");
+    if (transB != 'N' && transB != 'T' && transB != 'C')
+        err_char("transB", "'N', 'T', 'C'");
+
+    if (m < 0) m = (transA == 'N') ? A->nrows : A->ncols;
+    if (n < 0) n = (transB == 'N') ? B->ncols : B->nrows;
+    if (k < 0){ 
+        k = (transA == 'N') ? A->ncols : A->nrows;
+        if (k != ((transB == 'N') ? B->nrows : B->ncols)){
+             PyErr_SetString(PyExc_TypeError, "dimensions of A and B "
+                  "do not match");
+             return NULL;
+        }
+    }
+    if (m == 0 || n == 0) return Py_BuildValue("");
+
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (k > 0 && ldA < MAX(1, (transA == 'N') ? m : k)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (k > 0 && ldB < MAX(1, (transB == 'N') ? k : n)) err_ld("ldB");
+    if (ldC == 0) ldC = MAX(1,C->nrows);
+    if (ldC < MAX(1,m)) err_ld("ldB");
+
+    if (oA < 0) err_nn_int("offsetA");
+    if (k > 0 && ((transA == 'N' && oA + (k-1)*ldA + m > len(A)) ||
+        ((transA == 'T' || transA == 'C') && 
+        oA + (m-1)*ldA + k > len(A)))) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (k > 0 && ((transB == 'N' && oB + (n-1)*ldB + k > len(B)) ||
+        ((transB == 'T' || transB == 'C') && 
+        oB + (k-1)*ldB + n > len(B)))) err_buf_len("B");
+    if (oC < 0) err_nn_int("offsetC");
+    if (oC + (n-1)*ldC + m > len(C)) err_buf_len("C");
+
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(A))) 
+        err_type("alpha");
+    if (bo && number_from_pyobject(bo, &b, MAT_ID(A))) 
+        err_type("beta");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            if (!ao) a.d = 1.0; 
+            if (!bo) b.d = 0.0; 
+            dgemm_(&transA, &transB, &m, &n, &k, &a.d, 
+                MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB, &b.d, 
+                MAT_BUFD(C)+oC, &ldC);
+            break;
+
+        case COMPLEX:
+            if (!ao) a.z = 1.0; 
+            if (!bo) b.z = 0.0; 
+            zgemm_(&transA, &transB, &m, &n, &k, &a.z, 
+                MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB, &b.z, 
+                MAT_BUFZ(C)+oC, &ldC);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_symm[] =
+    "Matrix-matrix product where one matrix is symmetric."
+    "\n\n"
+    "symm(A, B, C, side='L', uplo='L', alpha=1.0, beta=0.0, \n"
+    "     m=B.size[0], n=B.size[1], ldA=max(1,A.size[0]), \n"
+    "     ldB=max(1,B.size[0]), ldC=max(1,C.size[0]), offsetA=0, \n"
+    "     offsetB=0, offsetC=0)\n\n"
+    "PURPOSE\n"
+    "If side is 'L', computes C := alpha*A*B + beta*C.\n"
+    "If side is 'R', computes C := alpha*B*A + beta*C.\n"
+    "C is m by n and A is real or complex symmetric.  (Use hemm for\n"
+    "Hermitian A).\n\n" 
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "C         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "side      'L' or 'R'\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "beta      number (int, float or complex).  Complex beta is only\n"
+    "          allowed if A is complex.\n\n"
+    "m         integer.  If negative, the default value is used.\n"
+    "          If the default value is used and side = 'L', then m\n"
+    "          must be equal to A.size[0] and A.size[1].\n\n"
+    "n         integer.  If negative, the default value is used.\n"
+    "          If the default value is used and side = 'R', then \n\n"
+    "          must be equal to A.size[0] and A.size[1].\n\n"
+    "ldA       nonnegative integer.\n"
+    "          ldA >= max(1, (side == 'L') ? m : n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "ldB       nonnegative integer.\n"
+    "          ldB >= max(1, (side == 'L') ? n : m).  If zero, the\n"
+    "          default value is used.\n\n"
+    "ldC       nonnegative integer.  ldC >= max(1,m).\n"
+    "          If zero, the default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer\n\n"
+    "offsetC   nonnegative integer";
+
+static PyObject* symm(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B, *C;
+    PyObject *ao=NULL, *bo=NULL;
+    number a, b; 
+    int m=-1, n=-1, ldA=0, ldB=0, ldC=0, oA=0, oB=0, oC = 0; 
+    char side='L', uplo='L';
+    char *kwlist[] = {"A", "B", "C", "side", "uplo", "alpha", "beta",
+        "m", "n", "ldA", "ldB", "ldC", "offsetA", "offsetB", "offsetC", 
+        NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ccOOiiiiiiii", 
+        kwlist, &A, &B, &C, &side, &uplo, &ao, &bo, &m, &n, &ldA, &ldB, 
+        &ldC, &oA, &oB, &oC))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (!Matrix_Check(C)) err_mtrx("C");
+    if (MAT_ID(A) != MAT_ID(B) || MAT_ID(A) != MAT_ID(C) ||
+        MAT_ID(B) != MAT_ID(C)) err_conflicting_ids;
+
+    if (side != 'L' && side != 'R') err_char("side", "'L', 'R'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+
+    if (m < 0){
+        m = B->nrows;
+        if (side == 'L' && (m != A->nrows || m != A->ncols)){
+            PyErr_SetString(PyExc_TypeError, "dimensions of A and B "
+                "do not match");
+            return NULL;
+        }
+    }
+    if (n < 0){ 
+        n = B->ncols;
+        if (side == 'R' && (n != A->nrows || n != A->ncols)){
+            PyErr_SetString(PyExc_TypeError, "dimensions of A and B "
+                "do not match");
+            return NULL;
+        }
+    }
+    if (m == 0 || n == 0) return Py_BuildValue("");
+
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1, (side == 'L') ? m : n)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1,m)) err_ld("ldB"); 
+    if (ldC == 0) ldC = MAX(1,C->nrows);
+    if (ldC < MAX(1,m)) err_ld("ldC");
+
+    if (oA < 0) err_nn_int("offsetA"); 
+    if ((side == 'L' && oA + (m-1)*ldA + m > len(A)) ||
+        (side == 'R' && oA + (n-1)*ldA + n > len(A))) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (n-1)*ldB + m > len(B)) err_buf_len("B");
+    if (oC < 0) err_nn_int("offsetC");
+    if (oC + (n-1)*ldC + m > len(C)) err_buf_len("C");
+
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(A))) 
+        err_type("alpha");
+    if (bo && number_from_pyobject(bo, &b, MAT_ID(A))) 
+        err_type("beta");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            if (!ao) a.d = 1.0; 
+            if (!bo) b.d = 0.0; 
+            dsymm_(&side, &uplo, &m, &n, &a.d, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(B)+oB, &ldB, &b.d, MAT_BUFD(C)+oC, &ldC);
+            break;
+
+        case COMPLEX:
+            if (!ao) a.z = 1.0; 
+            if (!bo) b.z = 0.0; 
+            zsymm_(&side, &uplo, &m, &n, &a.z, MAT_BUFZ(A)+oA, &ldA, 
+                MAT_BUFZ(B)+oB, &ldB, &b.z, MAT_BUFZ(C)+oC, &ldC);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_hemm[] =
+    "Matrix-matrix product where one matrix is real symmetric or\n"
+    "complex Hermitian."
+    "\n\n"
+    "hemm(A, B, C, side='L', uplo='L', alpha=1.0, beta=0.0, \n"
+    "     m=B.size[0], n=B.size[1], ldA=max(1,A.size[0]), \n"
+    "     ldB=max(1,B.size[0]), ldC=max(1,C.size[0]), offsetA=0, \n"
+    "     offsetB=0, offsetC=0)\n\n"
+    "PURPOSE\n"
+    "If side is 'L', computes C := alpha*A*B + beta*C.\n"
+    "If side is 'R', computes C := alpha*B*A + beta*C.\n"
+    "C is m by n and A is real symmetric or complex Hermitian.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "C         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "side      'L' or 'R'\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "beta      number (int, float or complex).  Complex beta is only\n"
+    "          allowed if A is complex.\n\n"
+    "m         integer.  If negative, the default value is used.\n"
+    "          If the default value is used and side = 'L', then m\n"
+    "          must be equal to A.size[0] and A.size[1].\n\n"
+    "n         integer.  If negative, the default value is used.\n"
+    "          If the default value is used and side = 'R', then \n\n"
+    "          must be equal to A.size[0] and A.size[1].\n\n"
+    "ldA       nonnegative integer.\n"
+    "          ldA >= max(1, (side == 'L') ? m : n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "ldB       nonnegative integer.\n"
+    "          ldB >= max(1, (side == 'L') ? n : m).  If zero, the\n"
+    "          default value is used.\n\n"
+    "ldC       nonnegative integer.  ldC >= max(1,m).\n"
+    "          If zero, the default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer\n\n"
+    "offsetC   nonnegative integer";
+
+static PyObject* hemm(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B, *C;
+    PyObject *ao=NULL, *bo=NULL;
+    number a, b; 
+    int m=-1, n=-1, ldA=0, ldB=0, ldC=0, oA=0, oB=0, oC = 0; 
+    char side='L', uplo='L';
+    char *kwlist[] = {"A", "B", "C", "side", "uplo", "alpha", "beta",
+        "m", "n", "ldA", "ldB", "ldC", "offsetA", "offsetB", "offsetC", 
+        NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ccOOiiiiiiii", 
+        kwlist, &A, &B, &C, &side, &uplo, &ao, &bo, &m, &n, &ldA, &ldB, 
+        &ldC, &oA, &oB, &oC))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (!Matrix_Check(C)) err_mtrx("C");
+    if (MAT_ID(A) != MAT_ID(B) || MAT_ID(A) != MAT_ID(C) ||
+        MAT_ID(B) != MAT_ID(C)) err_conflicting_ids;
+
+    if (side != 'L' && side != 'R') err_char("side", "'L', 'R'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+
+    if (m < 0){
+        m = B->nrows;
+        if (side == 'L' && (m != A->nrows || m != A->ncols)){
+            PyErr_SetString(PyExc_TypeError, "dimensions of A and B "
+                "do not match");
+            return NULL;
+        }
+    }
+    if (n < 0){ 
+        n = B->ncols;
+        if (side == 'R' && (n != A->nrows || n != A->ncols)){
+            PyErr_SetString(PyExc_TypeError, "dimensions of A and B "
+                "do not match");
+            return NULL;
+        }
+    }
+    if (m == 0 || n == 0) return Py_BuildValue("");
+
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1, (side == 'L') ? m : n)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1,m)) err_ld("ldB"); 
+    if (ldC == 0) ldC = MAX(1,C->nrows);
+    if (ldC < MAX(1,m)) err_ld("ldC");
+
+    if (oA < 0) err_nn_int("offsetA"); 
+    if ((side == 'L' && oA + (m-1)*ldA + m > len(A)) ||
+        (side == 'R' && oA + (n-1)*ldA + n > len(A))) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (n-1)*ldB + m > len(B)) err_buf_len("B");
+    if (oC < 0) err_nn_int("offsetC");
+    if (oC + (n-1)*ldC + m > len(C)) err_buf_len("C");
+
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(A))) 
+        err_type("alpha");
+    if (bo && number_from_pyobject(bo, &b, MAT_ID(A))) 
+        err_type("beta");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            if (!ao) a.d = 1.0; 
+            if (!bo) b.d = 0.0; 
+            dsymm_(&side, &uplo, &m, &n, &a.d, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(B)+oB, &ldB, &b.d, MAT_BUFD(C)+oC, &ldC);
+            break;
+
+        case COMPLEX:
+            if (!ao) a.z = 1.0; 
+            if (!bo) b.z = 0.0; 
+            zhemm_(&side, &uplo, &m, &n, &a.z, MAT_BUFZ(A)+oA, &ldA, 
+                MAT_BUFZ(B)+oB, &ldB, &b.z, MAT_BUFZ(C)+oC, &ldC);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+
+static char doc_syrk[] =
+    "Rank-k update of symmetric matrix.\n\n"
+    "syrk(A, C, uplo='L', trans='N', alpha=1.0, beta=0.0, n=None, \n"
+    "     k=None, ldA=max(1,A.size[0]), ldC=max(1,C.size[0]),\n"
+    "     offsetA=0, offsetB=0)\n\n"
+    "PURPOSE   \n"
+    "If trans is 'N', computes C := alpha*A*A^T + beta*C.\n"
+    "If trans is 'T', computes C := alpha*A^T*A + beta*C.\n"
+    "C is symmetric (real or complex) of order n. \n"
+    "The inner dimension of the matrix product is k.  If k=0 this is\n"
+    "interpreted as C := beta*C.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "C         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "trans     'N' or 'T'\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "beta      number (int, float or complex).  Complex beta is only\n"
+    "          allowed if A is complex.\n\n"
+    "n         integer.  If negative, the default value is used.\n"
+    "          The default value is\n"
+    "          n = (trans == N) ? A.size[0] : A.size[1].\n\n"
+    "k         integer.  If negative, the default value is used.\n"
+    "          The default value is\n"
+    "          k = (trans == 'N') ? A.size[1] : A.size[0].\n\n"
+    "ldA       nonnegative integer.\n"  
+    "          ldA >= max(1, (trans == 'N') ? n : k).  If zero,\n"
+    "          the default value is used.\n\n"
+    "ldC       nonnegative integer.  ldC >= max(1,n).\n"
+    "          If zero, the default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetC   nonnegative integer";
+
+static PyObject* syrk(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *C;
+    PyObject *ao=NULL, *bo=NULL;
+    number a, b; 
+    int n=-1, k=-1, ldA=0, ldC=0, oA = 0, oC = 0;
+    char trans='N', uplo='L';
+    char *kwlist[] = {"A", "C", "uplo", "trans", "alpha", "beta", "n", 
+        "k", "ldA", "ldC", "offsetA", "offsetC", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccOOiiiiii", 
+        kwlist, &A, &C, &uplo, &trans, &ao, &bo, &n, &k, &ldA, &ldC, 
+	&oA, &oC))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(C)) err_mtrx("C");
+    if (MAT_ID(A) != MAT_ID(C)) err_conflicting_ids;
+
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (MAT_ID(A) == DOUBLE && trans != 'N' && trans != 'T' &&
+        trans != 'C') err_char("trans", "'N', 'T', 'C'");
+    if (MAT_ID(A) == COMPLEX && trans != 'N' && trans != 'T') 
+	err_char("trans", "'N', 'T'");
+
+    if (n < 0) n = (trans == 'N') ? A->nrows : A->ncols;
+    if (k < 0) k = (trans == 'N') ? A->ncols : A->nrows;
+    if (n == 0) return Py_BuildValue("");
+
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (k > 0 && ldA < MAX(1, (trans == 'N') ? n : k)) err_ld("ldA");
+    if (ldC == 0) ldC = MAX(1,C->nrows);
+    if (ldC < MAX(1,n)) err_ld("ldC");
+    if (oA < 0) err_nn_int("offsetA");
+    if (k > 0 && ((trans == 'N' && oA + (k-1)*ldA + n > len(A)) ||
+        ((trans == 'T' || trans == 'C') && 
+	oA + (n-1)*ldA + k > len(A))))
+        err_buf_len("A");
+    if (oC < 0) err_nn_int("offsetC"); 
+    if (oC + (n-1)*ldC + n > len(C)) err_buf_len("C");
+    
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(A))) 
+        err_type("alpha");
+    if (bo && number_from_pyobject(bo, &b, MAT_ID(A))) 
+        err_type("beta");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            if (!ao) a.d = 1.0; 
+            if (!bo) b.d = 0.0; 
+            dsyrk_(&uplo, &trans, &n, &k, &a.d, MAT_BUFD(A)+oA, &ldA, 
+                &b.d, MAT_BUFD(C)+oC, &ldC);
+            break;
+
+        case COMPLEX:
+            if (!ao) a.z = 1.0; 
+            if (!bo) b.z = 0.0; 
+            zsyrk_(&uplo, &trans, &n, &k, &a.z, MAT_BUFZ(A)+oA, &ldA, 
+                &b.z, MAT_BUFZ(C)+oC, &ldC);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_herk[] =
+    "Rank-k update of Hermitian matrix.\n\n"
+    "herk(A, C, uplo='L', trans='N', alpha=1.0, beta=0.0, n=None, \n"
+    "     k=None, ldA=max(1,A.size[0]), ldC=max(1,C.size[0]),\n"
+    "     offsetA=0, offsetB=0)\n\n"
+    "PURPOSE   \n"
+    "If trans is 'N', computes C := alpha*A*A^H + beta*C.\n"
+    "If trans is 'C', computes C := alpha*A^H*A + beta*C.\n"
+    "C is real symmetric or Hermitian of order n.  The inner \n"
+    "dimension of the matrix product is k.\n"
+    "If k=0 this is interpreted as C := beta*C.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "C         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "trans     'N' or 'C'\n\n" 
+    "alpha     real number (int or float)\n\n"
+    "beta      number (int, float or complex)\n\n"
+    "n         integer.  If negative, the default value is used.\n"
+    "          The default value is\n"
+    "          n = (trans == N) ? A.size[0] : A.size[1].\n\n"
+    "k         integer.  If negative, the default value is used.\n"
+    "          The default value is\n"
+    "          k = (trans == 'N') ? A.size[1] : A.size[0].\n\n"
+    "ldA       nonnegative integer.\n"  
+    "          ldA >= max(1, (trans == 'N') ? n : k).  If zero,\n"
+    "          the default value is used.\n\n"
+    "ldC       nonnegative integer.  ldC >= max(1,n).\n"
+    "          If zero, the default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetC   nonnegative integer";
+
+static PyObject* herk(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *C;
+    PyObject *ao=NULL, *bo=NULL;
+    number a, b; 
+    int n=-1, k=-1, ldA=0, ldC=0, oA = 0, oC = 0;
+    char trans='N', uplo='L';
+    char *kwlist[] = {"A", "C", "uplo", "trans", "alpha", "beta", "n", 
+        "k", "ldA", "ldC", "offsetA", "offsetC", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccOOiiiiii", 
+        kwlist, &A, &C, &uplo, &trans, &ao, &bo, &n, &k, &ldA, &ldC, 
+	&oA, &oC))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(C)) err_mtrx("C");
+    if (MAT_ID(A) != MAT_ID(C)) err_conflicting_ids;
+
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (MAT_ID(A) == DOUBLE && trans != 'N' && trans != 'T' &&
+        trans != 'C') err_char("trans", "'N', 'T', 'C'");
+    if (MAT_ID(A) == COMPLEX && trans != 'N' && trans != 'C') 
+	err_char("trans", "'N', 'C'");
+
+    if (n < 0) n = (trans == 'N') ? A->nrows : A->ncols;
+    if (k < 0) k = (trans == 'N') ? A->ncols : A->nrows;
+    if (n == 0) return Py_BuildValue("");
+
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (k > 0 && ldA < MAX(1, (trans == 'N') ? n : k)) err_ld("ldA");
+    if (ldC == 0) ldC = MAX(1,C->nrows);
+    if (ldC < MAX(1,n)) err_ld("ldC");
+    if (oA < 0) err_nn_int("offsetA");
+    if (k > 0 && ((trans == 'N' && oA + (k-1)*ldA + n > len(A)) ||
+        ((trans == 'T' || trans == 'C') && 
+	oA + (n-1)*ldA + k > len(A))))
+        err_buf_len("A");
+    if (oC < 0) err_nn_int("offsetC"); 
+    if (oC + (n-1)*ldC + n > len(C)) err_buf_len("C");
+    
+    if (ao && number_from_pyobject(ao, &a, DOUBLE)) err_type("alpha");
+    if (bo && number_from_pyobject(bo, &b, DOUBLE)) err_type("beta");
+    if (!ao) a.d = 1.0; 
+    if (!bo) b.d = 0.0; 
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            dsyrk_(&uplo, &trans, &n, &k, &a.d, MAT_BUFD(A)+oA, &ldA, 
+                &b.d, MAT_BUFD(C)+oC, &ldC);
+            break;
+
+        case COMPLEX:
+            zherk_(&uplo, &trans, &n, &k, &a.d, MAT_BUFZ(A)+oA, &ldA, 
+                &b.d, MAT_BUFZ(C)+oC, &ldC);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_syr2k[] =
+    "Rank-2k update of symmetric matrix.\n\n"
+    "syr2k(A, B, C, uplo='L', trans='N', alpha=1.0, beta=0.0, n=None,\n"
+    "      k=None, ldA=max(1,A.size[0]), ldB=max(1,B.size[0]), \n"
+    "      ldC=max(1,C.size[0])), offsetA=0, offsetB=0, offsetC=0)\n\n"
+    "PURPOSE\n"
+    "If trans is 'N', computes C := alpha*(A*B^T + B*A^T) + beta*C.\n"
+    "If trans is 'T', computes C := alpha*(A^T*B + B^T*A) + beta*C.\n"
+    "C is symmetric (real or complex) of order n.\n"
+    "The inner dimension of the matrix product is k.  If k=0 this is\n"
+    "interpreted as C := beta*C.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "C         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "trans     'N', 'T' or 'C' ('C' is only allowed when in the real\n"
+    "          case and means the same as 'T')\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "beta      number (int, float or complex).  Complex beta is only\n"
+    "          allowed if A is complex.\n\n"
+    "n         integer.  If negative, the default value is used.\n"
+    "          The default value is\n"
+    "          n = (trans == 'N') ? A.size[0] : A.size[1].\n" 
+    "          If the default value is used, it should be equal to\n"
+    "          (trans == 'N') ? B.size[0] : B.size[1].\n\n" 
+    "k         integer.  If negative, the default value is used.\n"
+    "          The default value is\n"
+    "          k = (trans == 'N') ? A.size[1] : A.size[0].\n"
+    "          If the default value is used, it should be equal to\n"
+    "          (trans == 'N') ? B.size[1] : B.size[0].\n\n"
+    "ldA       nonnegative integer.\n"
+    "          ldA >= max(1, (trans=='N') ? n : k).\n"
+    "          If zero, the default value is used.\n\n"
+    "ldB       nonnegative integer.\n"
+    "          ldB >= max(1, (trans=='N') ? n : k).\n"
+    "          If zero, the default value is used.\n\n"
+    "ldC       nonnegative integer.  ldC >= max(1,n).\n"
+    "          If zero, the default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer\n\n"
+    "offsetC   nonnegative integer";
+
+static PyObject* syr2k(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B, *C;
+    PyObject *ao=NULL, *bo=NULL;
+    number a, b;
+    int n=-1, k=-1, ldA=0, ldB=0, ldC=0, oA = 0, oB = 0, oC = 0; 
+    char trans='N', uplo='L';
+    char *kwlist[] = {"A", "B", "C", "uplo", "trans", "alpha", "beta",
+        "n", "k", "ldA", "ldB", "ldC", "offsetA", "offsetB", "offsetC",
+        NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ccOOiiiiiiii", 
+        kwlist, &A, &B, &C, &uplo, &trans, &ao, &bo, &n, &k, &ldA, &ldB,
+	&ldC, &oA, &oB, &oC))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (!Matrix_Check(C)) err_mtrx("C");
+    if (MAT_ID(A) != MAT_ID(B) || MAT_ID(A) != MAT_ID(C) ||
+        MAT_ID(B) != MAT_ID(C)) err_conflicting_ids;
+
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (MAT_ID(A) == DOUBLE && trans != 'N' && trans != 'T' &&
+        trans != 'C') err_char("trans", "'N', 'T', 'C'");
+    if (MAT_ID(A) == COMPLEX && trans != 'N' && trans != 'T') 
+	err_char("trans", "'N', 'T'");
+  
+    if (n < 0){ 
+        n = (trans == 'N') ? A->nrows : A->ncols;
+        if (n != ((trans == 'N') ? B->nrows : B->ncols)){
+            PyErr_SetString(PyExc_TypeError, "dimensions of A and B "
+                "do not match");
+            return NULL;
+        }
+    }
+    if (n == 0) return Py_BuildValue("");
+    if (k < 0){
+        k = (trans == 'N') ? A->ncols : A->nrows;
+        if (k != ((trans == 'N') ? B->ncols : B->nrows)){
+            PyErr_SetString(PyExc_TypeError, "dimensions of A and B "
+                "do not match");
+            return NULL;
+        }
+    }
+
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (k > 0 && ldA < MAX(1, (trans == 'N') ? n : k)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (k > 0 && ldB < MAX(1, (trans == 'N') ? n : k)) err_ld("ldB");
+    if (ldC == 0) ldC = MAX(1,C->nrows);
+    if (ldC < MAX(1,n)) err_ld("ldC");
+
+    if (oA < 0) err_nn_int("offsetA");
+    if (k > 0 && ((trans == 'N' && oA + (k-1)*ldA + n > len(A)) ||
+        ((trans == 'T' || trans == 'C') && 
+	oA + (n-1)*ldA + k > len(A))))
+        err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (k > 0 && ((trans == 'N' && oB + (k-1)*ldB + n > len(B)) ||
+        ((trans == 'T' || trans == 'C') && 
+	oB + (n-1)*ldB + k > len(B))))
+        err_buf_len("B");
+    if (oC < 0) err_nn_int("offsetC");
+    if (oC + (n-1)*ldC + n > len(C))  err_buf_len("C");
+
+    
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(A))) 
+        err_type("alpha");
+    if (bo && number_from_pyobject(bo, &b, MAT_ID(A))) 
+        err_type("beta");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            if (!ao) a.d = 1.0; 
+            if (!bo) b.d = 0.0; 
+            dsyr2k_(&uplo, &trans, &n, &k, &a.d, MAT_BUFD(A)+oA, &ldA,
+                MAT_BUFD(B)+oB, &ldB, &b.d, MAT_BUFD(C)+oC, &ldC);
+            break;
+
+        case COMPLEX:
+            if (!ao) a.z = 1.0; 
+            if (!bo) b.z = 0.0; 
+            zsyr2k_(&uplo, &trans, &n, &k, &a.z, MAT_BUFZ(A)+oA, &ldA,
+                MAT_BUFZ(B)+oB, &ldB, &b.z, MAT_BUFZ(C)+oC, &ldC);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+
+static char doc_her2k[] =
+    "Rank-2k update of Hermitian matrix.\n\n"
+    "her2k(A, B, C, alpha=1.0, beta=0.0, uplo='L', trans='N', n=None,\n"
+    "      k=None, ldA=max(1,A.size[0]), ldB=max(1,B.size[0]),\n"
+    "      ldC=max(1,C.size[0])), offsetA=0, offsetB=0, offsetC=0)\n\n"
+    "PURPOSE\n"
+    "Computes\n"
+    "C := alpha*A*B^H + conj(alpha)*B*A^H + beta*C  (trans=='N')\n"
+    "C := alpha*A^H*B + conj(alpha)*B^H*A + beta*C  (trans=='C')\n"
+    "C is real symmetric or complex Hermitian of order n.  The inner\n"
+    "dimension of the matrix product is k.  If k=0 this is interpreted\n"
+    "as C := beta*C.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "C         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "trans     'N' or 'C'\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "beta      real number (int or float)\n\n"
+    "n         integer.  If negative, the default value is used.\n"
+    "          The default value is\n"
+    "          n = (trans == 'N') ? A.size[0] : A.size[1].\n" 
+    "          If the default value is used, it should be equal to\n"
+    "          (trans == 'N') ? B.size[0] : B.size[1].\n\n" 
+    "k         integer.  If negative, the default value is used.\n"
+    "          The default value is\n"
+    "          k = (trans == 'N') ? A.size[1] : A.size[0].\n"
+    "          If the default value is used, it should be equal to\n"
+    "          (trans == 'N') ? B.size[1] : B.size[0].\n\n"
+    "ldA       nonnegative integer.\n"
+    "          ldA >= max(1, (trans=='N') ? n : k).\n"
+    "          If zero, the default value is used.\n\n"
+    "ldB       nonnegative integer.\n"
+    "          ldB >= max(1, (trans=='N') ? n : k).\n"
+    "          If zero, the default value is used.\n\n"
+    "ldC       nonnegative integer.  ldC >= max(1,n).\n"
+    "          If zero, the default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer\n\n"
+    "offsetC   nonnegative integer";
+
+static PyObject* her2k(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B, *C;
+    PyObject *ao=NULL, *bo=NULL;
+    number a, b;
+    int n=-1, k=-1, ldA=0, ldB=0, ldC=0, oA = 0, oB = 0, oC = 0; 
+    char trans='N', uplo='L';
+    char *kwlist[] = {"A", "B", "C", "uplo", "trans", "alpha", "beta",
+        "n", "k", "ldA", "ldB", "ldC", "offsetA", "offsetB", "offsetC",
+        NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ccOOiiiiiiii", 
+        kwlist, &A, &B, &C, &uplo, &trans, &ao, &bo, &n, &k, &ldA, &ldB,
+	&ldC, &oA, &oB, &oC))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (!Matrix_Check(C)) err_mtrx("C");
+    if (MAT_ID(A) != MAT_ID(B) || MAT_ID(A) != MAT_ID(C) ||
+        MAT_ID(B) != MAT_ID(C)) err_conflicting_ids;
+
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (MAT_ID(A) == DOUBLE && trans != 'N' && trans != 'T' &&
+        trans != 'C') err_char("trans", "'N', 'T', 'C'");
+    if (MAT_ID(A) == COMPLEX && trans != 'N' && trans != 'C') 
+	err_char("trans", "'N', 'C'");
+  
+    if (n < 0){ 
+        n = (trans == 'N') ? A->nrows : A->ncols;
+        if (n != ((trans == 'N') ? B->nrows : B->ncols)){
+            PyErr_SetString(PyExc_TypeError, "dimensions of A and B "
+                "do not match");
+            return NULL;
+        }
+    }
+    if (n == 0) return Py_BuildValue("");
+    if (k < 0){
+        k = (trans == 'N') ? A->ncols : A->nrows;
+        if (k != ((trans == 'N') ? B->ncols : B->nrows)){
+            PyErr_SetString(PyExc_TypeError, "dimensions of A and B "
+                "do not match");
+            return NULL;
+        }
+    }
+
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (k > 0 && ldA < MAX(1, (trans == 'N') ? n : k)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (k > 0 && ldB < MAX(1, (trans == 'N') ? n : k)) err_ld("ldB");
+    if (ldC == 0) ldC = MAX(1,C->nrows);
+    if (ldC < MAX(1,n)) err_ld("ldC");
+
+    if (oA < 0) err_nn_int("offsetA");
+    if (k > 0 && ((trans == 'N' && oA + (k-1)*ldA + n > len(A)) ||
+        ((trans == 'T' || trans == 'C') && 
+	oA + (n-1)*ldA + k > len(A))))
+        err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (k > 0 && ((trans == 'N' && oB + (k-1)*ldB + n > len(B)) ||
+        ((trans == 'T' || trans == 'C') && 
+	oB + (n-1)*ldB + k > len(B))))
+        err_buf_len("B");
+    if (oC < 0) err_nn_int("offsetC");
+    if (oC + (n-1)*ldC + n > len(C))  err_buf_len("C");
+
+
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(A))) 
+        err_type("alpha");
+    if (bo && number_from_pyobject(bo, &b, MAT_ID(A))) 
+        err_type("beta");
+    if (!bo) b.d = 0.0; 
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            if (!ao) a.d = 1.0; 
+            dsyr2k_(&uplo, &trans, &n, &k, &a.d, MAT_BUFD(A)+oA, &ldA,
+                MAT_BUFD(B)+oB, &ldB, &b.d, MAT_BUFD(C)+oC, &ldC);
+            break;
+
+        case COMPLEX:
+	    if (!ao) a.z = 1.0; 
+            zher2k_(&uplo, &trans, &n, &k, &a.z, MAT_BUFZ(A)+oA, &ldA,
+                MAT_BUFZ(B)+oB, &ldB, &b.d, MAT_BUFZ(C)+oC, &ldC);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_trmm[] =
+    "Matrix-matrix product where one matrix is triangular.\n\n"
+    "trmm(A, B, side='L', uplo='L', transA='N', diag='N', alpha=1.0,\n"
+    "     m=None, n=None, ldA=max(1,A.size[0]), ldB=max(1,B.size[0]),\n"
+    "     offsetA=0, offsetB=0)\n\n"
+    "PURPOSE\n"
+    "Computes\n"
+    "B := alpha*A*B   if transA is 'N' and side = 'L'.\n"
+    "B := alpha*B*A   if transA is 'N' and side = 'R'.\n"
+    "B := alpha*A^T*B if transA is 'T' and side = 'L'.\n"
+    "B := alpha*B*A^T if transA is 'T' and side = 'R'.\n"
+    "B := alpha*A^H*B if transA is 'C' and side = 'L'.\n"
+    "B := alpha*B*A^H if transA is 'C' and side = 'R'.\n"
+    "B is m by n and A is triangular.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "side      'L' or 'R'\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "transA    'N' or 'T'\n\n"
+    "diag      'N' or 'U'\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "m         integer.  If negative, the default value is used.\n"
+    "          The default value is\n"
+    "          m = (side == 'L') ? A.size[0] : B.size[0].\n"
+    "          If the default value is used and side is 'L', m must\n" 
+    "          be equal to A.size[1].\n\n"
+    "n         integer.  If negative, the default value is used.\n"
+    "          The default value is\n"
+    "          n = (side == 'L') ? B.size[1] : A.size[0].\n" 
+    "          If the default value is used and side is 'R', n must\n" 
+    "          be equal to A.size[1].\n\n"
+    "ldA       nonnegative integer.\n"
+    "          ldA >= max(1, (side == 'L') ? m : n).\n"
+    "          If zero, the default value is used. \n\n"
+    "ldB       nonnegative integer.  ldB >= max(1,m).\n"
+    "          If zero, the default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* trmm(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B;
+    PyObject *ao=NULL;
+    number a;
+    int m=-1, n=-1, ldA=0, ldB=0, oA=0, oB=0;
+    char side='L', uplo='L', transA='N', diag='N';
+    char *kwlist[] = {"A", "B", "side", "uplo", "transA", "diag", 
+        "alpha", "m", "n", "ldA", "ldB", "offsetA", "offsetB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccccOiiiiii", 
+        kwlist, &A, &B, &side, &uplo, &transA, &diag, &ao, &m, &n, &ldA,
+        &ldB, &oA, &oB))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids;
+
+    if (side != 'L' && side != 'R') err_char("side", "'L', 'R'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (diag != 'N' && diag != 'U') err_char("diag", "'N', 'U'");
+    if (transA != 'N' && transA != 'T' && transA != 'C') 
+        err_char("transA", "'N', 'T', 'C'");
+
+    if (n < 0){ 
+        n = (side == 'L') ? B->ncols : A->nrows;
+        if (side != 'L' && n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (m < 0){
+        m = (side == 'L') ? A->nrows: B->nrows;
+        if (side == 'L' && m != A->ncols){ 
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (m == 0 || n == 0) return Py_BuildValue("");
+
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1, (side == 'L') ? m : n)) err_ld("ldA"); 
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1, m)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA"); 
+    if ((side == 'L' && oA + (m-1)*ldA + m > len(A)) ||
+        (side == 'R' && oA + (n-1)*ldA + n > len(A))) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB"); 
+    if (oB + (n-1)*ldB + m > len(B)) err_buf_len("B");
+
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(A))) 
+        err_type("alpha");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            if (!ao) a.d = 1.0; 
+            dtrmm_(&side, &uplo, &transA, &diag, &m, &n, &a.d, 
+                MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB);
+            break;
+
+        case COMPLEX:
+   	    if (!ao) a.z = 1.0;
+            ztrmm_(&side, &uplo, &transA, &diag, &m, &n, &a.z, 
+                MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+
+static char doc_trsm[] =
+    "Solution of a triangular system of equations with multiple \n"
+    "righthand sides.\n\n"
+    "trsm(A, B, side='L', uplo='L', transA='N', diag='N', alpha=1.0,\n"
+    "     m=None, n=None, ldA=max(1,A.size[0]), ldB=max(1,B.size[0]),\n"
+    "     offsetA=0, offsetB=0)\n\n"
+    "PURPOSE\n"   
+    "Computes\n"
+    "B := alpha*A^{-1}*B if transA is 'N' and side = 'L'.\n"
+    "B := alpha*B*A^{-1} if transA is 'N' and side = 'R'.\n"
+    "B := alpha*A^{-T}*B if transA is 'T' and side = 'L'.\n"
+    "B := alpha*B*A^{-T} if transA is 'T' and side = 'R'.\n"
+    "B := alpha*A^{-H}*B if transA is 'C' and side = 'L'.\n"
+    "B := alpha*B*A^{-H} if transA is 'C' and side = 'R'.\n"
+    "B is m by n and A is triangular.  The code does not verify \n"
+    "whether A is nonsingular.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "side      'L' or 'R'\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "transA    'N' or 'T'\n\n"
+    "diag      'N' or 'U'\n\n"
+    "alpha     number (int, float or complex).  Complex alpha is only\n"
+    "          allowed if A is complex.\n\n"
+    "m         integer.  If negative, the default value is used.\n"
+    "          The default value is\n"
+    "          m = (side == 'L') ? A.size[0] : B.size[0].\n"
+    "          If the default value is used and side is 'L', m must\n"
+    "          be equal to A.size[1].\n\n"
+    "n         integer.  If negative, the default value is used.\n"
+    "          The default value is\n"
+    "          n = (side == 'L') ? B.size[1] : A.size[0].\n"
+    "          If the default value is used and side is 'R', n must\n"
+    "          be equal to A.size[1].\n\n"
+    "ldA       nonnegative integer.\n"
+    "          ldA >= max(1, (side == 'L') ? m : n).\n"
+    "          If zero, the default value is used.\n\n" 
+    "ldB       nonnegative integer.  ldB >= max(1,m).\n"
+    "          If zero, the default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* trsm(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B;
+    PyObject *ao=NULL;
+    number a;
+    int m=-1, n=-1, ldA=0, ldB=0, oA=0, oB=0;
+    char side='L', uplo='L', transA='N', diag='N';
+    char *kwlist[] = {"A", "B", "side", "uplo", "transA", "diag", 
+        "alpha", "m", "n", "ldA", "ldB", "offsetA", "offsetB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccccOiiiiii", 
+        kwlist, &A, &B, &side, &uplo, &transA, &ao, &diag, &m, &n, &ldA,
+        &ldB, &oA, &oB))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids;
+
+    if (side != 'L' && side != 'R') err_char("side", "'L', 'R'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (diag != 'N' && diag != 'U') err_char("diag", "'N', 'U'");
+    if (transA != 'N' && transA != 'T' && transA != 'C') 
+        err_char("transA", "'N', 'T', 'C'");
+
+    if (n < 0){ 
+        n = (side == 'L') ? B->ncols : A->nrows;
+        if (side != 'L' && n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (m < 0){
+        m = (side == 'L') ? A->nrows: B->nrows;
+        if (side == 'L' && m != A->ncols){ 
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (n == 0 || m == 0) return Py_BuildValue("");
+
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1, (side == 'L') ? m : n)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1,m)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA");
+    if ((side == 'L' && oA + (m-1)*ldA + m > len(A)) ||
+        (side == 'R' && oA + (n-1)*ldA + n > len(A))) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB"); 
+    if (oB < 0 || oB + (n-1)*ldB + m > len(B)) err_buf_len("B");
+
+    if (ao && number_from_pyobject(ao, &a, MAT_ID(A))) 
+        err_type("alpha");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            if (!ao) a.d = 1.0; 
+            dtrsm_(&side, &uplo, &transA, &diag, &m, &n, &a.d, 
+                MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB);
+            break;
+
+        case COMPLEX:
+  	    if (!ao) a.z = 1.0;
+            ztrsm_(&side, &uplo, &transA, &diag, &m, &n, &a.z, 
+                MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static PyMethodDef blas_functions[] = {
+  {"swap", (PyCFunction) swap,  METH_VARARGS|METH_KEYWORDS, doc_swap},
+  {"scal", (PyCFunction) scal,  METH_VARARGS|METH_KEYWORDS, doc_scal},
+  {"copy", (PyCFunction) copy,  METH_VARARGS|METH_KEYWORDS, doc_copy},
+  {"axpy", (PyCFunction) axpy,  METH_VARARGS|METH_KEYWORDS, doc_axpy},
+  {"dot",  (PyCFunction) dot,   METH_VARARGS|METH_KEYWORDS, doc_dot},
+  {"dotu", (PyCFunction) dotu,  METH_VARARGS|METH_KEYWORDS, doc_dotu},
+  {"nrm2", (PyCFunction) nrm2,  METH_VARARGS|METH_KEYWORDS, doc_nrm2},
+  {"asum", (PyCFunction) asum,  METH_VARARGS|METH_KEYWORDS, doc_asum},
+  {"iamax",(PyCFunction) iamax, METH_VARARGS|METH_KEYWORDS, doc_iamax},
+  {"gemv", (PyCFunction) gemv,  METH_VARARGS|METH_KEYWORDS, doc_gemv},
+  {"gbmv", (PyCFunction) gbmv,  METH_VARARGS|METH_KEYWORDS, doc_gbmv},
+  {"symv", (PyCFunction) symv,  METH_VARARGS|METH_KEYWORDS, doc_symv},
+  {"hemv", (PyCFunction) hemv,  METH_VARARGS|METH_KEYWORDS, doc_hemv},
+  {"sbmv", (PyCFunction) sbmv,  METH_VARARGS|METH_KEYWORDS, doc_sbmv},
+  {"hbmv", (PyCFunction) hbmv,  METH_VARARGS|METH_KEYWORDS, doc_hbmv},
+  {"trmv", (PyCFunction) trmv,  METH_VARARGS|METH_KEYWORDS, doc_trmv},
+  {"tbmv", (PyCFunction) tbmv,  METH_VARARGS|METH_KEYWORDS, doc_tbmv},
+  {"trsv", (PyCFunction) trsv,  METH_VARARGS|METH_KEYWORDS, doc_trsv},
+  {"tbsv", (PyCFunction) tbsv,  METH_VARARGS|METH_KEYWORDS, doc_tbsv},
+  {"ger",  (PyCFunction) ger,   METH_VARARGS|METH_KEYWORDS, doc_ger},
+  {"geru", (PyCFunction) geru,  METH_VARARGS|METH_KEYWORDS, doc_geru},
+  {"syr",  (PyCFunction) syr,   METH_VARARGS|METH_KEYWORDS, doc_syr},
+  {"her",  (PyCFunction) her,   METH_VARARGS|METH_KEYWORDS, doc_her},
+  {"syr2", (PyCFunction) syr2,  METH_VARARGS|METH_KEYWORDS, doc_syr2},
+  {"her2", (PyCFunction) her2,  METH_VARARGS|METH_KEYWORDS, doc_her2},
+  {"gemm", (PyCFunction) gemm,  METH_VARARGS|METH_KEYWORDS, doc_gemm},
+  {"symm", (PyCFunction) symm,  METH_VARARGS|METH_KEYWORDS, doc_symm},
+  {"hemm", (PyCFunction) hemm,  METH_VARARGS|METH_KEYWORDS, doc_hemm},
+  {"syrk", (PyCFunction) syrk,  METH_VARARGS|METH_KEYWORDS, doc_syrk},
+  {"herk", (PyCFunction) herk,  METH_VARARGS|METH_KEYWORDS, doc_herk},
+  {"syr2k",(PyCFunction) syr2k, METH_VARARGS|METH_KEYWORDS, doc_syr2k},
+  {"her2k",(PyCFunction) her2k, METH_VARARGS|METH_KEYWORDS, doc_her2k},
+  {"trmm", (PyCFunction) trmm,  METH_VARARGS|METH_KEYWORDS, doc_trmm},
+  {"trsm", (PyCFunction) trsm,  METH_VARARGS|METH_KEYWORDS, doc_trsm},
+  {NULL}  /* Sentinel */
+};
+
+
+PyMODINIT_FUNC initblas(void)
+{
+  PyObject *m;
+  m = Py_InitModule3("cvxopt.blas", blas_functions, blas__doc__);
+  if (import_cvxopt() < 0) return;
+}
diff --git a/src/C/blas_redefines.h b/src/C/blas_redefines.h
new file mode 100644
index 0000000..7b60c44
--- /dev/null
+++ b/src/C/blas_redefines.h
@@ -0,0 +1,140 @@
+#ifdef BLAS_NO_UNDERSCORE
+
+#define dswap_ dswap
+#define zswap_ zswap
+#define dscal_ dscal
+#define zscal_ zscal
+#define zdscal_ zdscal
+#define dcopy_ dcopy
+#define zcopy_ zcopy
+#define daxpy_ daxpy
+#define zaxpy_ zaxpy
+#define ddot_ ddot
+#define dnrm2_ dnrm2
+#define dznrm2_ dznrm2
+#define dasum_ dasum
+#define dzasum_ dzasum
+#define idamax_ idamax
+#define izamax_ izamax
+#define dgemv_ dgemv
+#define zgemv_ zgemv
+#define dgbmv_ dgbmv
+#define zgbmv_ zgbmv
+#define dsymv_ dsymv
+#define zsymv_ zsymv
+#define zhemv_ zhemv
+#define dsbmv_ dsbmv
+#define zhbmv_ zhbmv
+#define dtrmv_ dtrmv
+#define ztrmv_ ztrmv
+#define dtbmv_ dtbmv
+#define ztbmv_ ztbmv
+#define dtrsv_ dtrsv
+#define ztrsv_ ztrsv
+#define dtbsv_ dtbsv
+#define ztbsv_ ztbsv
+#define dger_ dger
+#define zgerc_ zgerc
+#define zgeru_ zgeru
+#define dsyr_ dsyr
+#define zher_ zher
+#define dsyr2_ dsyr2
+#define zher2_ zher2
+#define dgemm_ dgemm
+#define zgemm_ zgemm
+#define dsymm_ dsymm
+#define zsymm_ zsymm
+#define zhemm_ zhemm
+#define dsyrk_ dsyrk
+#define zsyrk_ zsyrk
+#define zherk_ zherk
+#define dsyr2k_ dsyr2k
+#define zsyr2k_ zsyr2k
+#define zher2k_ zher2k
+#define dtrmm_ dtrmm
+#define ztrmm_ ztrmm
+#define dtrsm_ dtrsm
+#define ztrsm_ ztrsm
+#define dgetrf_ dgetrf
+#define zgetrf_ zgetrf
+#define dgetrs_ dgetrs
+#define zgetrs_ zgetrs
+#define dgetri_ dgetri
+#define zgetri_ zgetri
+#define dgesv_ dgesv
+#define zgesv_ zgesv
+#define dpotrf_ dpotrf
+#define dpotri_ dpotri
+#define zpotri_ zpotri
+#define zpotrf_ zpotrf
+#define dpotrs_ dpotrs
+#define zpotrs_ zpotrs
+#define dposv_ dposv
+#define zposv_ zposv
+#define dsytrf_ dsytrf
+#define zsytrf_ zsytrf
+#define zhetrf_ zhetrf
+#define dsytri_ dsytri
+#define zsytri_ zsytri
+#define dsytrs_ dsytrs
+#define zsytrs_ zsytrs
+#define zhetrs_ zhetrs
+#define zhetri_ zhetri
+#define dsysv_ dsysv
+#define zsysv_ zsysv
+#define dsygv_ dsygv
+#define zhesv_ zhesv
+#define dgels_ dgels
+#define zgels_ zgels
+#define dsyev_ dsyev
+#define zheev_ zheev
+#define dsyevx_ dsyevx
+#define zheevx_ zheevx
+#define dsyevd_ dsyevd
+#define zheevd_ zheevd
+#define dsyevr_ dsyevr
+#define zheevr_ zheevr
+#define ilaenv_ ilaenv
+#define zhegv_ zhegv
+#define dgesvd_ dgesvd
+#define zgesvd_ zgesvd
+#define dgesdd_ dgesdd
+#define zgesdd_ zgesdd
+#define dgeqrf_ dgeqrf
+#define zgeqrf_ zgeqrf
+#define dormqr_ dormqr
+#define zunmqr_ zunmqr
+#define dtrtrs_ dtrtrs
+#define ztrtrs_ ztrtrs
+#define dgbtrf_ dgbtrf
+#define zgbtrf_ zgbtrf
+#define dgbtrs_ dgbtrs
+#define zgbtrs_ zgbtrs
+#define dgbsv_  dgbsv
+#define zgbsv_  zgbsv
+#define dgtsv_  dgtsv
+#define zgtsv_  zgtsv
+#define dpbsv_  dpbsv
+#define zpbsv_  zpbsv
+#define dptsv_  dptsv
+#define zptsv_  zptsv
+#define dgttrf_ dgttrf
+#define zgttrf_ zgttrf
+#define dgttrs_ dgttrs
+#define zgttrs_ zgttrs
+#define dtrtri_ dtrtri
+#define ztrtri_ ztrtri
+#define dpbtrf_ dpbtrf
+#define zpbtrf_ zpbtrf
+#define dtbtrs_ dtbtrs
+#define ztbtrs_ ztbtrs
+#define dtbtrf_ dtbtrf
+#define ztbtrf_ ztbtrf
+#define dpttrf_ dpttrf
+#define zpttrf_ zpttrf
+#define dpbtrs_ dpbtrs
+#define zpbtrs_ zpbtrs
+#define dpttrs_ dpttrs
+#define zpttrs_ zpttrs
+
+#endif
diff --git a/src/C/cholmod.c b/src/C/cholmod.c
new file mode 100644
index 0000000..5a2c8a1
--- /dev/null
+++ b/src/C/cholmod.c
@@ -0,0 +1,947 @@
+/*
+ * This file is part of CVXOPT version 0.8.2.
+ * Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+ */
+
+#define NO_ANSI99_COMPLEX
+
+#include "cvxopt.h"
+#include "misc.h"
+#include "cholmod.h"
+#include "complex.h"
+
+const int E_SIZE[] = { sizeof(int_t), sizeof(double), sizeof(complex) };
+
+/* defined in pyconfig.h */
+#if (SIZEOF_INT < SIZEOF_LONG)
+#define CHOL(name) cholmod_l_ ## name
+#else
+#define CHOL(name) cholmod_ ## name
+#endif
+
+PyDoc_STRVAR(cholmod__doc__, "Interface to the CHOLMOD library.\n\n"
+"Routines for sparse Cholesky factorization.\n\n"
+"The default values of the control parameters in the CHOLMOD 'Common'\n"
+"object are used, except Common->print, which is set to 0, and \n"
+"Common->supernodal, which is set to 2.\n"
+"The parameters Common->supernodal, Common->print, Common->nmethods, \n"
+"Common->postorder and Common->dbound can be modified by making an\n"
+"entry in the dictionary cholmod.options, with key value 'supernodal', "
+"\n'print', 'nmethods', 'postorder', or 'dbound', respectively.\n \n"
+"These parameters have the following meaning.\n\n"
+"options['supernodal']: If equal to 0, an LDL^T or LDL^H factorization"
+"\n    is computed using a simplicial algorithm.  If equal to 2, an\n"
+"    LL^T or LL^H factorization is computed using a supernodal\n"
+"    algorithm.  If equal to 1, the most efficient of the two\n"
+"    factorizations is selected, based on the sparsity pattern.\n\n"
+"options['print']:  A nonnegative integer that controls the amount of\n"
+"    output printed to the screen.\n\n"  
+"options['nmethods']: A nonnegative integer that specifies how many\n"
+"    orderings are attempted prior to factorization.  If equal to 0,\n"
+"    the AMD ordering and the user-provided permutation (if any) are\n"
+"    compared, and the best one is used.  If equal to 1, the AMD\n"
+"    ordering is used when no permutation is provided by the user,\n"
+"    and the user-provided permutation is used otherwise.  Default: 0."
+"\n\noptions['postorder']: True or False.  If True the symbolic\n"
+"    analysis is followed by a postordering.  Default: True.\n\n"
+"options['dbound']: Smallest absolute value for the diagonal\n"
+"    elements of D in an LDL^T factorization, or the diagonal\n"
+"    elements of L in a Cholesky factorization.  Default: 0.0.\n\n"
+"CHOLMOD is available from http://www.cise.ufl.edu/research/sparse.");
+
+
+static PyObject *cholmod_module;
+static cholmod_common Common;   
+
+static int set_options(void)
+{
+    int_compat pos=0;
+    PyObject *param, *key, *value;
+    char *keystr, err_str[100];
+
+    CHOL(defaults)(&Common); 
+    Common.print = 0;         
+    Common.supernodal = 2;         
+    
+    if (!(param = PyObject_GetAttrString(cholmod_module, "options")) ||
+        ! PyDict_Check(param)) {
+        PyErr_SetString(PyExc_AttributeError, "missing cholmod.options"
+            "dictionary");
+        return 0;
+    }
+    while (PyDict_Next(param, &pos, &key, &value)) 
+        if ((keystr = PyString_AsString(key))) {
+
+            if (!strcmp("supernodal", keystr) && PyInt_Check(value))
+                Common.supernodal = (int) PyInt_AsLong(value);
+            else if (!strcmp("print", keystr) && PyInt_Check(value)){
+                Common.print = (int) PyInt_AsLong(value);
+            }
+            else if (!strcmp("nmethods", keystr) && PyInt_Check(value))
+                Common.nmethods = (int) PyInt_AsLong(value);
+            else if (!strcmp("postorder", keystr) && 
+                PyBool_Check(value))
+                Common.postorder = (int) PyInt_AsLong(value);
+            else if (!strcmp("dbound", keystr) && PyFloat_Check(value))
+                Common.dbound = (double) PyFloat_AsDouble(value);
+            else {
+                sprintf(err_str, "invalid value for CHOLMOD parameter: "
+                    "%-.20s", keystr);
+                PyErr_SetString(PyExc_ValueError, err_str); 
+                Py_DECREF(param);
+                return 0;
+            }
+    }
+    Py_DECREF(param);
+    return 1;
+}
+
+
+static cholmod_sparse *pack(spmatrix *A, char uplo)
+{
+    int j, k, n = SP_NROWS(A), nnz = 0, cnt = 0;
+    cholmod_sparse *B;
+
+    if (uplo == 'L'){
+        for (j=0; j<n; j++){ 
+            for (k=SP_COL(A)[j]; k<SP_COL(A)[j+1] && SP_ROW(A)[k] < j; 
+                k++);
+            nnz += SP_COL(A)[j+1] - k;
+        }
+        if (!(B = CHOL(allocate_sparse)(n, n, nnz, 1, 1, -1, 
+            (SP_ID(A) == DOUBLE ? CHOLMOD_REAL : CHOLMOD_COMPLEX), 
+            &Common))) return 0;
+        for (j=0; j<n; j++){
+            for (k=SP_COL(A)[j]; k<SP_COL(A)[j+1] && SP_ROW(A)[k] < j; 
+                k++);
+       	    for (; k<SP_COL(A)[j+1]; k++) {
+                if (SP_ID(A) == DOUBLE)
+                    ((double *)B->x)[cnt] = SP_VALD(A)[k]; 
+                else 
+                    ((complex *)B->x)[cnt] = SP_VALZ(A)[k]; 
+                ((int_t *)B->p)[j+1]++;
+                ((int_t *)B->i)[cnt++] = SP_ROW(A)[k];
+	    }
+        }
+    }
+    else {
+        for (j=0; j<n; j++) 
+            for (k=SP_COL(A)[j]; k<SP_COL(A)[j+1] && SP_ROW(A)[k] <= j;
+                k++)
+                nnz++;
+        if (!(B = CHOL(allocate_sparse)(n, n, nnz, 1, 1, 1, 
+            (SP_ID(A) == DOUBLE ? CHOLMOD_REAL : CHOLMOD_COMPLEX), 
+            &Common))) return 0;
+
+        for (j=0; j<n; j++) 
+            for (k=SP_COL(A)[j]; k<SP_COL(A)[j+1] && SP_ROW(A)[k] <= j; 
+                k++) {
+                if (SP_ID(A) == DOUBLE)
+                    ((double *)B->x)[cnt] = SP_VALD(A)[k]; 
+                else 
+                    ((complex *)B->x)[cnt] = SP_VALZ(A)[k]; 
+            ((int_t *)B->p)[j+1]++;
+            ((int_t *)B->i)[cnt++] = SP_ROW(A)[k];
+        }
+    }
+    for (j=0; j<n; j++) ((int_t *)B->p)[j+1] += ((int_t *)B->p)[j];
+    return B;
+}
+
+
+static cholmod_sparse * create_matrix(spmatrix *A)
+{
+    cholmod_sparse *B;
+  
+    if (!(B = CHOL(allocate_sparse)(SP_NROWS(A), SP_NCOLS(A), 0, 
+        1, 0, 0, (SP_ID(A) == DOUBLE ? CHOLMOD_REAL : CHOLMOD_COMPLEX),
+        &Common))) return NULL;
+
+    int i;
+    for (i=0; i<SP_NCOLS(A); i++)
+        ((int_t *)B->nz)[i] = SP_COL(A)[i+1] - SP_COL(A)[i];
+    B->x = SP_VAL(A);
+    B->i = SP_ROW(A);
+    B->nzmax = SP_NNZ(A);
+    memcpy(B->p, SP_COL(A), (SP_NCOLS(A)+1)*sizeof(int_t));
+    return B;
+}
+
+
+static void free_matrix(cholmod_sparse *A)
+{
+    A->x = NULL;
+    A->i = NULL;  
+    CHOL(free_sparse)(&A, &Common);
+}
+
+static void cvxopt_free_cholmod_factor(void *L, void *descr)
+{
+    CHOL(free_factor) ((cholmod_factor **) &L, &Common) ;
+}
+
+
+static char doc_symbolic[] = 
+    "Symbolic Cholesky factorization of a real symmetric or Hermitian\n"
+    "sparse matrix.\n\n"
+    "F = symbolic(A, p=None, uplo='L')\n\n" 
+    "PURPOSE\n"
+    "If cholmod.options['supernodal'] = 2, factors A as\n"
+    "P*A*P^T = L*L^T or P*A*P^T = L*L^H.  This is the default value.\n"
+    "If cholmod.options['supernodal'] = 0, factors A as\n"
+    "P*A*P^T = L*D*L^T or P*A*P^T = L*D*L^H with D diagonal and \n"
+    "possibly nonpositive.\n"
+    "If cholmod.options['supernodal'] = 1, the most efficient of the\n"
+    "two factorizations is used.\n\n"
+    "ARGUMENTS\n"
+    "A         square sparse matrix of order n.\n\n"
+    "p         None, or an 'i' matrix of length n that contains a \n"
+    "          permutation vector.  If p is not provided, CHOLMOD\n"
+    "          uses a permutation from the AMD library.\n\n"
+    "uplo      'L' or 'U'.  If uplo is 'L', only the lower triangular\n"
+    "          part of A is used and the upper triangular part is\n"
+    "          ignored.  If uplo is 'U', only the upper triangular\n"
+    "          part of A is used and the lower triangular part is\n" 
+    "          ignored.\n\n"
+    "F         the symbolic factorization, including the permutation,\n"
+    "          as an opaque C object that can be passed to\n"
+    "          cholmod.numeric\n\n";
+
+static PyObject* symbolic(PyObject *self, PyObject *args, 
+    PyObject *kwrds)
+{
+    spmatrix *A;
+    cholmod_sparse *Ac = NULL;
+    cholmod_factor *L;  
+    matrix *P=NULL; 
+    char uplo='L';
+    int n;
+    char *kwlist[] = {"A", "p", "uplo", NULL};
+
+    if (!set_options()) return NULL;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|Oc", kwlist, &A, 
+        &P, &uplo)) return NULL;
+    if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A)) 
+        PY_ERR_TYPE("A is not a square sparse matrix");
+    n = SP_NROWS(A);
+
+    if (P) {
+        if (!Matrix_Check(P) || MAT_ID(P) != INT) err_int_mtrx("p");
+        if (MAT_LGT(P) != n) err_buf_len("p");
+        if (!CHOL(check_perm)(P->buffer, n, n, &Common)) 
+            PY_ERR(PyExc_ValueError, "p is not a valid permutation");
+    }
+    if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'");
+    if (!(Ac = pack(A, uplo))) return PyErr_NoMemory();
+    L = CHOL(analyze_p)(Ac, P ? MAT_BUFI(P): NULL, NULL, 0, &Common);
+    CHOL(free_sparse)(&Ac, &Common);
+
+    if (Common.status != CHOLMOD_OK){
+        if (Common.status == CHOLMOD_OUT_OF_MEMORY)
+            return PyErr_NoMemory();
+        else
+            PyErr_SetString(PyExc_ValueError, "symbolic factorization "
+                "failed");
+            return NULL; 	    
+    }
+    return (PyObject *) PyCObject_FromVoidPtrAndDesc((void *) L, 
+        SP_ID(A)==DOUBLE ?  (uplo == 'L' ?  
+            "CHOLMOD FACTOR D L" : "CHOLMOD FACTOR D U") :
+            (uplo == 'L' ?  
+            "CHOLMOD FACTOR Z L" : "CHOLMOD FACTOR Z U"), 
+	    cvxopt_free_cholmod_factor);  
+}
+
+
+static char doc_numeric[] = 
+    "Numeric Cholesky factorization of a real symmetric or Hermitian\n"
+    "sparse matrix.\n\n"
+    "numeric(A, F)\n\n" 
+    "PURPOSE\n"
+    "If cholmod.options['supernodal'] = 2, factors A as\n"
+    "P*A*P^T = L*L^T or P*A*P^T = L*L^H.  This is the default value.\n"
+    "If cholmod.options['supernodal'] = 0, factors A as\n"
+    "P*A*P^T = L*D*L^T or P*A*P^T = L*D*L^H with D diagonal and \n"
+    "possibly nonpositive.\n"
+    "If cholmod.options['supernodal'] = 1, the most efficient of the\n"
+    "two factorizations is used. \n"
+    "On entry, F is the symbolic factorization computed by \n"
+    "cholmod.symbolic.  On exit, F contains the numeric\n"
+    "factorization.  If the matrix is singular, an ArithmeticError\n"
+    "exception is raised, with as its first argument the index of the\n"
+    "column at which the factorization failed.\n\n"
+    "ARGUMENTS\n"
+    "A         square sparse matrix.  If F was created by calling\n"
+    "          cholmod.symbolic with uplo='L', then only the lower\n"
+    "          triangular part of A is used.  If F was created with\n"
+    "          uplo='U', then only the upper triangular part is used.\n"
+    "\n"
+    "F         symbolic factorization computed by cholmod.symbolic\n"
+    "          applied to a matrix with the same sparsity patter and\n"
+    "          type as A.  After a successful call, F contains the\n"
+    "          numeric factorization.";
+
+static PyObject* numeric(PyObject *self, PyObject *args)
+{
+    spmatrix *A;
+    PyObject *F;
+    cholmod_factor *Lc;
+    cholmod_sparse *Ac = NULL;
+    char *descr, uplo;
+
+    if (!set_options()) return NULL;
+
+    if (!PyArg_ParseTuple(args, "OO", &A, &F)) return NULL;
+
+    if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A)) 
+        PY_ERR_TYPE("A is not a sparse matrix");
+
+    if (!PyCObject_Check(F)) err_CO("F");  
+    descr = PyCObject_GetDesc(F);
+    if (!descr) PY_ERR_TYPE("F is not a CHOLMOD factor");
+    if (SP_ID(A) == DOUBLE){
+        if (!strcmp(descr, "CHOLMOD FACTOR D L")) 
+	    uplo = 'L';
+	else if (!strcmp(descr, "CHOLMOD FACTOR D U")) 
+	    uplo = 'U';
+        else 
+	    PY_ERR_TYPE("F is not the CHOLMOD factor of a 'd' matrix");
+    } else {
+        if (!strcmp(descr, "CHOLMOD FACTOR Z L")) 
+	    uplo = 'L';
+	else if (!strcmp(descr, "CHOLMOD FACTOR Z U")) 
+	    uplo = 'U';
+        else 
+	    PY_ERR_TYPE("F is not the CHOLMOD factor of a 'z' matrix");
+    }
+    Lc = (cholmod_factor *) PyCObject_AsVoidPtr(F);
+    if (!(Ac = pack(A, uplo))) return PyErr_NoMemory();
+    CHOL(factorize) (Ac, Lc, &Common);
+    CHOL(free_sparse)(&Ac, &Common);    
+
+    if (Common.status < 0) switch (Common.status) {
+        case CHOLMOD_OUT_OF_MEMORY: 
+            return PyErr_NoMemory();
+
+        default:
+            PyErr_SetString(PyExc_ValueError, "factorization failed");
+            return NULL;
+    }
+
+    if (Common.status > 0) switch (Common.status) {   
+        case CHOLMOD_NOT_POSDEF:
+            PyErr_SetObject(PyExc_ArithmeticError, Py_BuildValue("i", 
+                Lc->minor));
+            return NULL;
+            break;
+
+        case CHOLMOD_DSMALL:  
+            /* This never happens unless we change the default value 
+             * of Common.dbound (0.0).  */
+            if (Lc->is_ll)
+                PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal "\
+                    "elements in L");
+            else
+                PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal "\
+                    "elements in D");
+            break;
+
+        default:
+            PyErr_Warn(PyExc_UserWarning, "");
+    }
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_solve[] = 
+    "Solves a sparse set of linear equations with a factored\n"
+    "coefficient matrix and an dense matrix as right-hand side.\n\n"
+    "solve(F, B, sys=0, nrhs=B.size[1], ldB=max(1,B.size[0], "
+    "offsetB=0)\n\n"
+    "PURPOSE\n"
+    "Solves one of the following systems using the factorization\n"
+    "computed by cholmod.numeric:\n\n"
+    "   sys   System              sys   System\n"
+    "   0     A*X = B             5     L'*X = B\n" 
+    "   1     L*D*L'*X = B        6     D*X = B\n"       
+    "   2     L*D*X = B           7     P'*X = B\n"
+    "   3     D*L'*X = B          8     P*X = B\n"
+    "   4     L*X = B\n\n"       
+    "If A was factored as P*A*P' = L*L', then D = I in this table.\n"
+    "B is stored using the LAPACK and BLAS conventions.  On exit it\n"
+    "is overwritten with the solution.\n\n"
+    "ARGUMENTS\n"
+    "F         the factorization object of A computed by\n"
+    "          cholmod.numeric\n\n"
+    "B         dense 'd' or 'z' matrix.  Must have the same type\n"
+    "          as A.\n\n"
+    "sys       integer (0 <= sys <= 8)\n\n"  
+    "nrhs      integer.  If negative, the default value is used.\n\n"
+    "ldB       nonnegative integer.  ldB >= max(1,n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* solve(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *B;
+    PyObject *F;
+    int i, n, oB=0, ldB=0, nrhs=-1, sys=0; 
+    char *descr;
+    char *kwlist[] = {"F", "B", "sys", "nrhs", "ldB", "offsetB", NULL};
+    int sysvalues[] = { CHOLMOD_A, CHOLMOD_LDLt, CHOLMOD_LD, 
+        CHOLMOD_DLt, CHOLMOD_L, CHOLMOD_Lt, CHOLMOD_D, CHOLMOD_P,
+        CHOLMOD_Pt };
+
+    if (!set_options()) return NULL;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiii", kwlist, 
+        &F, &B, &sys, &nrhs, &ldB, &oB)) return NULL;
+
+    if (!PyCObject_Check(F)) err_CO("F");
+    descr = PyCObject_GetDesc(F);
+    if (!descr || strncmp(descr, "CHOLMOD FACTOR", 14))
+        PY_ERR_TYPE("F is not a CHOLMOD factor");
+    cholmod_factor *L = (cholmod_factor *) PyCObject_AsVoidPtr(F);
+    if (L->xtype == CHOLMOD_PATTERN) 
+        PY_ERR(PyExc_ValueError, "called with symbolic factor");
+
+    n = L->n;
+    if (L->minor<n) PY_ERR(PyExc_ArithmeticError, "singular matrix");
+
+    if (sys < 0 || sys > 8) 
+         PY_ERR(PyExc_ValueError, "invalid value for sys");
+
+    if (!Matrix_Check(B) || MAT_ID(B) == INT ||
+        (MAT_ID(B) == DOUBLE && L->xtype == CHOLMOD_COMPLEX) ||
+        (MAT_ID(B) == COMPLEX && L->xtype == CHOLMOD_REAL))		
+            PY_ERR_TYPE("B must a dense matrix of the same numerical "
+                "type as F");
+
+    if (nrhs < 0) nrhs = MAT_NCOLS(B);  
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldB == 0) ldB = MAX(1,MAT_NROWS(B));
+    if (ldB < MAX(1,n)) err_ld("ldB");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (nrhs-1)*ldB + n > MAT_LGT(B)) err_buf_len("B");
+  
+    cholmod_dense *x;
+    cholmod_dense *b = CHOL(allocate_dense)(n, 1, n, 
+        (MAT_ID(B) == DOUBLE ? CHOLMOD_REAL : CHOLMOD_COMPLEX), 
+        &Common);
+    if (Common.status == CHOLMOD_OUT_OF_MEMORY) return PyErr_NoMemory();
+
+    void *b_old = b->x;    
+    for (i=0; i<nrhs; i++){
+        b->x = MAT_BUF(B) + (i*ldB + oB)*E_SIZE[MAT_ID(B)];
+        x = CHOL(solve) (sysvalues[sys], L, b, &Common);  
+        if (Common.status != CHOLMOD_OK){
+            PyErr_SetString(PyExc_ValueError, "solve step failed");
+            CHOL(free_dense)(&x, &Common);
+            CHOL(free_dense)(&b, &Common);
+	    return NULL;
+	}
+	memcpy(b->x, x->x, n*E_SIZE[MAT_ID(B)]);
+        CHOL(free_dense)(&x, &Common);
+    }
+    b->x = b_old;
+    CHOL(free_dense)(&b, &Common);  
+
+    return Py_BuildValue("");
+}
+
+
+static char doc_spsolve[] = 
+    "Solves a sparse set of linear equations with a factored\n"
+    "coefficient matrix and sparse righthand side.\n\n"
+    "X = spsolve(F, B, sys=0)\n\n"
+    "PURPOSE\n"
+    "Solves one of the following systems using the factorization F\n"
+    "computed by cholmod.numeric:\n\n"
+    "   sys   System              sys   System\n"
+    "   0     A*X = B             5     L'*X = B\n" 
+    "   1     L*D*L'*X = B        6     D*X = B\n"       
+    "   2     L*D*X = B           7     P'*X = B\n"
+    "   3     D*L'*X = B          8     P*X = B\n"
+    "   4     L*X = B\n\n"       
+    "If A was factored as P*A*P^T = L*L^T, then D = I in this table.\n"
+    "On exit B is overwritten with the solution.\n\n"
+    "ARGUMENTS\n"
+    "F         the factorization object of A computed by\n"
+    "          cholmod.numeric\n\n"
+    "B         sparse unsymmetric matrix\n\n"
+    "sys       integer (0 <= sys <= 8)\n\n"  
+    "X         sparse unsymmetric matrix";
+
+static PyObject* spsolve(PyObject *self, PyObject *args, 
+    PyObject *kwrds)
+{
+    spmatrix *B, *X=NULL;
+    cholmod_sparse *Bc=NULL, *Xc=NULL;
+    PyObject *F;
+    cholmod_factor *L;
+    int n, sys=0; 
+    char *descr;
+    char *kwlist[] = {"F", "B", "sys", NULL};
+    int sysvalues[] = {CHOLMOD_A, CHOLMOD_LDLt, CHOLMOD_LD, 
+        CHOLMOD_DLt, CHOLMOD_L, CHOLMOD_Lt, CHOLMOD_D, CHOLMOD_P,
+        CHOLMOD_Pt };
+
+    if (!set_options()) return NULL;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|i", kwlist, &F, 
+        &B, &sys)) return NULL;
+
+    if (!PyCObject_Check(F)) err_CO("F");
+    descr = PyCObject_GetDesc(F);
+    if (!descr || strncmp(descr, "CHOLMOD FACTOR", 14))
+        PY_ERR_TYPE("F is not a CHOLMOD factor");
+    L = (cholmod_factor *) PyCObject_AsVoidPtr(F);
+    if (L->xtype == CHOLMOD_PATTERN) 
+        PY_ERR(PyExc_ValueError, "called with symbolic factor");
+    n = L->n;
+    if (L->minor<n) PY_ERR(PyExc_ArithmeticError, "singular matrix");
+
+    if (sys < 0 || sys > 8) 
+         PY_ERR(PyExc_ValueError, "invalid value for sys");
+    
+    if (!SpMatrix_Check(B) || 
+        (SP_ID(B) == DOUBLE  && L->xtype == CHOLMOD_COMPLEX) ||
+        (SP_ID(B) == COMPLEX && L->xtype == CHOLMOD_REAL))		
+            PY_ERR_TYPE("B must a sparse matrix of the same "
+                "numerical type as F");
+    if (SP_NROWS(B) != n) 
+        PY_ERR(PyExc_ValueError, "incompatible dimensions for B");
+
+    if (!(Bc = create_matrix(B))) return PyErr_NoMemory();
+    Xc = CHOL(spsolve)(sysvalues[sys], L, Bc, &Common);
+    free_matrix(Bc);    
+    if (Common.status == CHOLMOD_OUT_OF_MEMORY) return PyErr_NoMemory();
+    if (Common.status != CHOLMOD_OK)
+        PY_ERR(PyExc_ValueError, "solve step failed");
+    
+    if (!(X = SpMatrix_New(Xc->nrow, Xc->ncol, 
+        ((int_t*)Xc->p)[Xc->ncol], (L->xtype == CHOLMOD_REAL ? DOUBLE : 
+        COMPLEX)))) {
+        CHOL(free_sparse)(&Xc, &Common);    
+        return PyErr_NoMemory();
+    }
+    memcpy(SP_COL(X), Xc->p, (Xc->ncol+1)*sizeof(int_t));
+    memcpy(SP_ROW(X), Xc->i, ((int_t *)Xc->p)[Xc->ncol]*sizeof(int_t));
+    memcpy(SP_VAL(X), Xc->x, 
+        ((int_t *) Xc->p)[Xc->ncol]*E_SIZE[SP_ID(X)]);
+    CHOL(free_sparse)(&Xc, &Common);    
+    return (PyObject *) X;
+}
+
+
+static char doc_linsolve[] = 
+    "Solves a sparse positive definite set of linear equations.\n\n"
+    "linsolve(A, B, p=None, uplo='L', nrhs=B.size[1], \n"
+    "         ldB=max(1,B.size[0]), offsetB=0)\n\n"
+    "PURPOSE\n"
+    "Solves A*X = B using a sparse Cholesky factorization.  On exit\n"
+    "B is overwritten with the solution.  The argument p specifies\n"
+    "an optional permutation matrix.  If it is not provided, CHOLMOD\n"
+    "uses a permutation from the AMD library.  An ArithmeticError\n"
+    "exception is raised if the matrix is singular, with as its first\n"
+    "argument the index of the column at which the factorization\n"
+    "failed.\n\n"
+    "ARGUMENTS\n"
+    "A         square sparse matrix\n\n"  
+    "B         dense 'd' or 'z' matrix.  Must have the same type\n"
+    "          as A.\n\n" 
+    "p         None, or an 'i' matrix of length n that contains\n"
+    "          a permutation vector\n\n"
+    "uplo      'L' or 'U'.  If uplo is 'L', only the lower triangular\n"
+    "          part of A is used and the upper triangular part is\n"
+    "          ignored.  If uplo is 'U', only the upper triangular\n"
+    "          part is used, and the lower triangular part is ignored."
+    "\n\n"
+    "nrhs      integer.  If negative, the default value is used.\n\n"
+    "ldB       nonnegative integer.  ldB >= max(1,n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* linsolve(PyObject *self, PyObject *args, 
+    PyObject *kwrds)
+{
+    spmatrix *A;
+    matrix *B, *P=NULL; 
+    int i, n, nnz, oB=0, ldB=0, nrhs=-1; 
+    cholmod_sparse *Ac=NULL;
+    cholmod_factor *L=NULL;
+    cholmod_dense *x=NULL, *b=NULL;
+    void *b_old;
+    char uplo='L';
+    char *kwlist[] = {"A", "B", "p", "uplo", "nrhs", "ldB", "offsetB", 
+        NULL};
+  
+    if (!set_options()) return NULL;
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ociii", kwlist, 
+        &A,  &B, &P, &uplo, &nrhs, &ldB, &oB)) return NULL;
+
+    if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A)) 
+        PY_ERR_TYPE("A is not a sparse matrix");
+    n = SP_NROWS(A);
+    nnz = SP_NNZ(A);
+  
+    if (!Matrix_Check(B) || MAT_ID(B) != SP_ID(A))
+        PY_ERR_TYPE("B must be a dense matrix of the same numerical "
+            "type as A");
+    if (nrhs < 0) nrhs = MAT_NCOLS(B);  
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldB == 0) ldB = MAX(1,MAT_NROWS(B));
+    if (ldB < MAX(1,n)) err_ld("ldB");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (nrhs-1)*ldB + n > MAT_LGT(B)) err_buf_len("B");
+  
+    if (P) {
+        if (!Matrix_Check(P) || MAT_ID(P) != INT) err_int_mtrx("p");
+        if (MAT_LGT(P) != n) err_buf_len("p");
+        if (!CHOL(check_perm)(P->buffer, n, n, &Common)) 
+            PY_ERR(PyExc_ValueError, "not a valid permutation");
+    }
+    if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'");
+  
+    if (!(Ac = pack(A, uplo))) return PyErr_NoMemory();
+    L = CHOL(analyze_p)(Ac, P ? MAT_BUFI(P): NULL, NULL, 0, &Common);
+    if (Common.status != CHOLMOD_OK){
+        free_matrix(Ac);
+        CHOL(free_sparse)(&Ac, &Common);    
+        CHOL(free_factor)(&L, &Common);    
+        if (Common.status == CHOLMOD_OUT_OF_MEMORY) 
+            return PyErr_NoMemory();
+        else {
+            PyErr_SetString(PyExc_ValueError, "symbolic factorization "
+                "failed");
+            return NULL; 	    
+        }
+    }
+  
+    CHOL(factorize) (Ac, L, &Common);
+    CHOL(free_sparse)(&Ac, &Common);    
+    if (Common.status < 0) {
+        CHOL(free_factor)(&L, &Common);    
+        switch (Common.status) {
+            case CHOLMOD_OUT_OF_MEMORY: 
+                return PyErr_NoMemory();
+
+            default:
+                PyErr_SetString(PyExc_ValueError, "factorization "
+                    "failed");
+                return NULL;
+        }
+    }
+    if (Common.status > 0) switch (Common.status) {   
+        case CHOLMOD_NOT_POSDEF:
+            PyErr_SetObject(PyExc_ArithmeticError, 
+                Py_BuildValue("i", L->minor));
+            CHOL(free_factor)(&L, &Common);    
+            return NULL;
+            break;
+
+        case CHOLMOD_DSMALL:  
+            /* This never happens unless we change the default value 
+             * of Common.dbound (0.0).  */
+            if (L->is_ll)
+                PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal "
+                    "elements in L");
+            else
+                PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal "
+                    "elements in D");
+            break;
+    
+        default:
+            PyErr_Warn(PyExc_UserWarning, "");
+    }
+
+    if (L->minor<n) {
+        CHOL(free_factor)(&L, &Common);    
+        PY_ERR(PyExc_ArithmeticError, "singular matrix");
+    }
+    b = CHOL(allocate_dense)(n, 1, n, (MAT_ID(B) == DOUBLE ? 
+        CHOLMOD_REAL : CHOLMOD_COMPLEX) , &Common);
+    if (Common.status == CHOLMOD_OUT_OF_MEMORY) { 
+        CHOL(free_factor)(&L, &Common);    
+        CHOL(free_dense)(&b, &Common);    
+        return PyErr_NoMemory();
+    }
+    b_old = b->x;    
+    for (i=0; i<nrhs; i++) {
+        b->x = MAT_BUF(B) + (i*ldB + oB)*E_SIZE[MAT_ID(B)];
+        x = CHOL(solve) (CHOLMOD_A, L, b, &Common);
+        if (Common.status != CHOLMOD_OK){
+            PyErr_SetString(PyExc_ValueError, "solve step failed");
+            CHOL(free_factor)(&L, &Common);    
+            b->x = b_old;
+            CHOL(free_dense)(&b, &Common);
+            CHOL(free_dense)(&x, &Common);
+            return NULL;
+        }
+        memcpy(b->x, x->x, SP_NROWS(A)*E_SIZE[MAT_ID(B)]);
+        CHOL(free_dense)(&x, &Common);
+    }
+    b->x = b_old;
+    CHOL(free_dense)(&b, &Common);
+    CHOL(free_factor)(&L, &Common);    
+    return Py_BuildValue("");      
+}
+
+
+
+static char doc_splinsolve[] = 
+    "Solves a sparse positive definite set of linear equations with\n"
+    "sparse righthand side.\n\n"
+    "X = splinsolve(A, B, p=None, uplo='L')\n\n"
+    "PURPOSE\n"
+    "Solves A*X = B using a sparse Cholesky factorization.\n"
+    "The argument p specifies an optional permutation matrix.  If it\n"
+    "is not provided, CHOLMOD uses a permutation from the AMD\n"
+    "library.  An ArithmeticError exception is raised if the\n"
+    "factorization does not exist.\n\n"
+    "ARGUMENTS\n"
+    "A         square sparse matrix.  Only the lower triangular part\n"
+    "          of A is used; the upper triangular part is ignored.\n\n"
+    "B         sparse matrix of the same type as A\n\n" 
+    "p         None, or an 'i' matrix of length n that contains\n"
+    "          a permutation vector";
+
+static PyObject* splinsolve(PyObject *self, PyObject *args, 
+    PyObject *kwrds)
+{
+    spmatrix *A, *B, *X;
+    matrix *P=NULL; 
+    int n, nnz;
+    cholmod_sparse *Ac=NULL, *Bc=NULL, *Xc=NULL;
+    cholmod_factor *L=NULL;
+    char uplo='L';
+    char *kwlist[] = {"A", "B", "p", "uplo", NULL};
+
+    if (!set_options()) return NULL;
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Oc", kwlist, &A,
+        &B, &P, &uplo)) return NULL;
+
+    if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A)) 
+        PY_ERR_TYPE("A is not a square sparse matrix");
+    n = SP_NROWS(A);
+    nnz = SP_NNZ(A);
+
+    if (!SpMatrix_Check(B) || SP_ID(A) != SP_ID(B)) 
+        PY_ERR_TYPE("B must be a sparse matrix of the same type as A");
+    if (SP_NROWS(B) != n) 
+        PY_ERR(PyExc_ValueError, "incompatible dimensions for B");
+
+    if (P) {
+        if (!Matrix_Check(P) || MAT_ID(P) != INT) err_int_mtrx("p");
+        if (MAT_LGT(P) != n) err_buf_len("p");
+        if (!CHOL(check_perm)(P->buffer, n, n, &Common)) 
+            PY_ERR(PyExc_ValueError, "not a valid permutation");
+    }
+
+    if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'");
+    if (!(Ac = pack(A, uplo))) return PyErr_NoMemory();
+
+    L = CHOL(analyze_p) (Ac, P ? MAT_BUFI(P): NULL, NULL, 0, &Common);
+    if (Common.status != CHOLMOD_OK){
+        CHOL(free_factor)(&L, &Common);    
+        CHOL(free_sparse)(&Ac, &Common);    
+        if (Common.status == CHOLMOD_OUT_OF_MEMORY)
+            return PyErr_NoMemory();
+        else
+            PyErr_SetString(PyExc_ValueError, "symbolic factorization "
+                "failed");
+            return NULL; 	    
+    }
+
+    CHOL(factorize) (Ac, L, &Common);
+    CHOL(free_sparse)(&Ac, &Common);    
+    if (Common.status > 0) switch (Common.status) {   
+        case CHOLMOD_NOT_POSDEF:
+            PyErr_SetObject(PyExc_ArithmeticError, Py_BuildValue("i", 
+                L->minor));
+            CHOL(free_factor)(&L, &Common);    
+            return NULL;
+            break;
+
+        case CHOLMOD_DSMALL:  
+            /* This never happens unless we change the default value 
+             * of Common.dbound (0.0).  */
+            if (L->is_ll)
+                PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal "
+                    "elements in L");
+            else
+                PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal "
+                    "elements in D");
+            break;
+
+        default:
+            PyErr_Warn(PyExc_UserWarning, "");
+    }
+
+    if (L->minor<n) {
+        CHOL(free_factor)(&L, &Common);    
+        PY_ERR(PyExc_ArithmeticError, "singular matrix");
+    }
+    if (!(Bc = create_matrix(B))) {
+      CHOL(free_factor)(&L, &Common);    
+      return PyErr_NoMemory();
+    }
+
+    Xc = CHOL(spsolve)(0, L, Bc, &Common);
+    free_matrix(Bc);    
+    CHOL(free_factor)(&L, &Common);    
+    if (Common.status != CHOLMOD_OK){
+        CHOL(free_sparse)(&Xc, &Common);
+        if (Common.status == CHOLMOD_OUT_OF_MEMORY) 
+            return PyErr_NoMemory();
+        else
+            PY_ERR(PyExc_ValueError, "solve step failed");
+    }
+
+    if (!(X = SpMatrix_New(Xc->nrow, Xc->ncol, 
+        ((int_t*)Xc->p)[Xc->ncol], SP_ID(A)))) {
+        CHOL(free_sparse)(&Xc, &Common);    
+        return PyErr_NoMemory();
+    }
+    memcpy(SP_COL(X), (int_t *) Xc->p, (Xc->ncol+1)*sizeof(int_t));
+    memcpy(SP_ROW(X), (int_t *) Xc->i, 
+        ((int_t *) Xc->p)[Xc->ncol]*sizeof(int_t));
+    memcpy(SP_VAL(X), (double *) Xc->x, 
+        ((int_t *) Xc->p)[Xc->ncol]*E_SIZE[SP_ID(X)]);
+    CHOL(free_sparse)(&Xc, &Common);    
+    return (PyObject *) X;
+}
+
+
+static char doc_diag[] = 
+    "Returns the diagonal of a Cholesky factor.\n\n"
+    "D = diag(F)\n\n" 
+    "PURPOSE\n"
+    "Returns the diagonal of the Cholesky factor L in a \n"
+    "factorization P*A*P^T = L*L^T or P*A*P^T = L*L^H.\n\n"
+    "ARGUMENTS\n"
+    "D         an nx1 'd' matrix with the diagonal elements of L.\n"
+    "          Note that the permutation P is not returned, so the\n"
+    "          order of the diagonal elements is unknown.\n\n"
+    "F         a numeric Cholesky factor obtained by a call to\n"
+    "          cholmod.numeric computed with options['supernodal'] = 2";
+
+extern void dcopy_(int *n, double *x, int *incx, double *y, int *incy);
+extern void zcopy_(int *n, complex *x, int *incx, complex *y, int *incy);
+
+static PyObject* diag(PyObject *self, PyObject *args)
+{
+    PyObject *F;
+    matrix *d=NULL;
+    cholmod_factor *L;
+    char *descr;
+    int k, strt, incx=1, incy, nrows, ncols;
+
+    if (!set_options()) return NULL;
+    if (!PyArg_ParseTuple(args, "O", &F)) return NULL;
+
+    if (!PyCObject_Check(F)) err_CO("F"); 
+    descr = PyCObject_GetDesc(F);
+    if (!descr || strncmp(descr, "CHOLMOD FACTOR", 14))
+        PY_ERR_TYPE("F is not a CHOLMOD factor");
+    L = (cholmod_factor *) PyCObject_AsVoidPtr(F);
+
+    /* Check factorization */
+    if (L->xtype == CHOLMOD_PATTERN  || L->minor<L->n || !L->is_ll 
+        || !L->is_super) 
+        PY_ERR(PyExc_ValueError, "F must be a nonsingular supernodal "
+            "Cholesky factor");
+    if (!(d = Matrix_New(L->n,1,L->xtype == CHOLMOD_REAL ? DOUBLE : 
+        COMPLEX))) return PyErr_NoMemory();
+
+    strt = 0;
+    for (k=0; k<L->nsuper; k++){
+	/* x[L->px[k], .... ,L->px[k+1]-1] is a dense lower-triangular 
+	 * nrowx times ncols matrix.  We copy its diagonal to 
+	 * d[strt, ..., strt+ncols-1] */
+
+        ncols = (int)((int_t *) L->super)[k+1] - 
+            ((int_t *) L->super)[k]; 
+        nrows = (int)((int_t *) L->pi)[k+1] - ((int_t *) L->pi)[k]; 
+        incy = nrows+1;
+        if (MAT_ID(d) == DOUBLE)
+	    dcopy_(&ncols, ((double *) L->x) + ((int_t *) L->px)[k], 
+                &incy, MAT_BUFD(d)+strt, &incx);
+        else
+	    zcopy_(&ncols, ((complex *) L->x) + ((int_t *) L->px)[k], 
+                &incy, MAT_BUFZ(d)+strt, &incx);
+        strt += ncols;
+    }
+    return (PyObject *)d;
+}
+
+
+static PyObject* getfactor(PyObject *self, PyObject *args)
+{
+    PyObject *F;
+    cholmod_factor *Lf;
+    cholmod_sparse *Ls;
+    char *descr;
+
+    if (!set_options()) return NULL;
+    if (!PyArg_ParseTuple(args, "O", &F)) return NULL;
+  
+    if (!PyCObject_Check(F)) err_CO("F"); 
+    descr = PyCObject_GetDesc(F);
+    if (!descr || strncmp(descr, "CHOLMOD FACTOR", 14))
+        PY_ERR_TYPE("F is not a CHOLMOD factor");
+    Lf = (cholmod_factor *) PyCObject_AsVoidPtr(F);
+  
+    /* Check factorization */
+    if (Lf->xtype == CHOLMOD_PATTERN) 
+        PY_ERR(PyExc_ValueError, "F must be a numeric Cholesky factor");
+
+    if (!(Ls = CHOL(factor_to_sparse)(Lf, &Common)))
+        return PyErr_NoMemory();
+
+    spmatrix *ret = SpMatrix_New(Ls->nrow, Ls->ncol, Ls->nzmax, 
+       (Ls->xtype == CHOLMOD_REAL ? DOUBLE : COMPLEX)); 
+    if (!ret) {
+        CHOL(free_sparse)(&Ls, &Common);
+        return PyErr_NoMemory();
+    }
+
+    memcpy(SP_COL(ret), Ls->p, (Ls->ncol+1)*sizeof(int_t));
+    memcpy(SP_ROW(ret), Ls->i, (Ls->nzmax)*sizeof(int_t));
+    memcpy(SP_VAL(ret), Ls->x, (Ls->nzmax)*E_SIZE[SP_ID(ret)]);
+    CHOL(free_sparse)(&Ls, &Common);
+
+    return (PyObject *)ret;
+}
+
+
+static PyMethodDef cholmod_functions[] = {
+  {"symbolic", (PyCFunction) symbolic, METH_VARARGS|METH_KEYWORDS, 
+   doc_symbolic},
+  {"numeric", (PyCFunction) numeric, METH_VARARGS|METH_KEYWORDS, 
+   doc_numeric},
+  {"solve", (PyCFunction) solve, METH_VARARGS|METH_KEYWORDS, 
+   doc_solve},
+  {"spsolve", (PyCFunction) spsolve, METH_VARARGS|METH_KEYWORDS, 
+   doc_spsolve},
+  {"linsolve", (PyCFunction) linsolve, METH_VARARGS|METH_KEYWORDS, 
+   doc_linsolve},
+  {"splinsolve", (PyCFunction) splinsolve, METH_VARARGS|METH_KEYWORDS, 
+   doc_splinsolve},
+  {"diag", (PyCFunction) diag, METH_VARARGS|METH_KEYWORDS, doc_diag},
+  {"getfactor", (PyCFunction) getfactor, METH_VARARGS|METH_KEYWORDS, 
+   ""},
+  {NULL}  /* Sentinel */
+};
+
+PyMODINIT_FUNC initcholmod(void)
+{
+    CHOL(start) (&Common);   
+
+    cholmod_module = Py_InitModule3("cvxopt.cholmod", cholmod_functions,
+        cholmod__doc__);
+    PyModule_AddObject(cholmod_module, "options", PyDict_New());
+    if (import_cvxopt() < 0) return;
+}
diff --git a/src/C/cvxopt.h b/src/C/cvxopt.h
new file mode 100644
index 0000000..f37f7a8
--- /dev/null
+++ b/src/C/cvxopt.h
@@ -0,0 +1,127 @@
+/*
+ * This file is part of CVXOPT version 0.8.2.
+ * Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+ */
+
+#include "Python.h"
+#include "structmember.h"
+#include "blas_redefines.h"
+
+/* ANSI99 complex is disabled during build of CHOLMOD */
+
+#ifndef NO_ANSI99_COMPLEX 
+#include "complex.h"
+#define MAT_BUFZ(O)  ((complex *)((matrix *)O)->buffer)
+#endif
+
+
+#ifndef __CVXOPT__
+#define __CVXOPT__
+
+#define INT       0
+#define DOUBLE    1
+#define COMPLEX   2
+
+/* compatibility between Python2.5 and lower versions */
+#if PY_VERSION_HEX < 0x02050000 
+#define int_t      Py_intptr_t
+#define lenfunc    inquiry
+#define int_compat int
+#else
+#define int_t      Py_ssize_t
+#define int_compat Py_ssize_t
+#endif
+
+typedef struct {
+  PyObject_HEAD
+  void *buffer;          /* in column-major-mode array of type 'id' */
+  int   nrows, ncols;    /* number of rows and columns */
+  int   id;              /* DOUBLE, INT, COMPLEX */
+} matrix;
+
+typedef struct {
+  void  *values;      /* value list */
+  int_t *colptr;      /* column pointer list */
+  int_t *rowind;      /* row index list */
+  int_t nrows, ncols; /* number of rows and columns */
+  int   nzmax;        /* number of allocated elements */
+  int   id;           /* DOUBLE, COMPLEX */
+} ccs;
+
+typedef struct {
+  PyObject_HEAD
+  ccs *obj;
+} spmatrix;
+
+#ifdef BASE_MODULE
+
+#define Matrix_Check(v) ((v)->ob_type == &matrix_tp) 
+#define SpMatrix_Check(v) ((v)->ob_type == &spmatrix_tp) 
+
+#else
+
+static void **cvxopt_API;
+
+#define Matrix_New (*(matrix * (*)(int, int, int)) cvxopt_API[0])
+#define Matrix_NewFromMatrix (*(matrix * (*)(matrix *, int)) cvxopt_API[1])
+#define Matrix_NewFromList (*(matrix * (*)(PyObject *, int)) cvxopt_API[2])
+#define Matrix_Check (*(int * (*)(void *)) cvxopt_API[3])
+
+#define SpMatrix_New (*(spmatrix * (*)(int, int, int, int)) cvxopt_API[4])
+#define SpMatrix_NewFromSpMatrix \
+  (*(spmatrix * (*)(spmatrix *, int)) cvxopt_API[5])
+#define SpMatrix_NewFromIJV \
+  (*(spmatrix * (*)(matrix *, matrix *, matrix *, int, int, int, int)) \
+      cvxopt_API[6])
+#define SpMatrix_Check (*(int * (*)(void *)) cvxopt_API[7])
+
+/* Return -1 and set exception on error, 0 on success. */
+static int
+import_cvxopt(void)
+{
+  PyObject *module = PyImport_ImportModule("cvxopt.base");
+    
+  if (module != NULL) {
+    PyObject *c_api_object = PyObject_GetAttrString(module, "_C_API");
+    if (c_api_object == NULL)
+      return -1;
+    if (PyCObject_Check(c_api_object))
+      cvxopt_API = (void **)PyCObject_AsVoidPtr(c_api_object);
+    Py_DECREF(c_api_object);
+  }
+  return 0;
+}
+
+#endif
+
+/*
+ * Below this line are non-essential convenience macros 
+ */
+
+#define MAT_BUF(O)   ((matrix *)O)->buffer
+#define MAT_BUFI(O)  ((int_t *)((matrix *)O)->buffer) 
+#define MAT_BUFD(O)  ((double *)((matrix *)O)->buffer)
+#define MAT_BUFZ(O)  ((complex *)((matrix *)O)->buffer)
+
+#define MAT_NROWS(O) ((matrix *)O)->nrows 
+#define MAT_NCOLS(O) ((matrix *)O)->ncols 
+#define MAT_LGT(O)   (MAT_NROWS(O)*MAT_NCOLS(O))
+#define MAT_ID(O)    ((matrix *)O)->id
+
+#define SP_NCOLS(O)  ((spmatrix *)O)->obj->ncols
+#define SP_NROWS(O)  ((spmatrix *)O)->obj->nrows
+#define SP_LGT(O)    (SP_NROWS(O)*SP_NCOLS(O))
+#define SP_NNZ(O)    ((spmatrix *)O)->obj->colptr[SP_NCOLS(O)]
+#define SP_NZMAX(O)  ((spmatrix *)O)->obj->nzmax
+#define SP_ID(O)     ((spmatrix *)O)->obj->id    
+#define SP_COL(O)    ((spmatrix *)O)->obj->colptr
+#define SP_ROW(O)    ((spmatrix *)O)->obj->rowind
+#define SP_VAL(O)    ((spmatrix *)O)->obj->values
+#define SP_VALD(O)   ((double *)((spmatrix *)O)->obj->values)
+#define SP_VALZ(O)   ((complex *)((spmatrix *)O)->obj->values)
+
+#define CCS_NROWS(O) ((ccs *)O)->nrows
+#define CCS_NCOLS(O) ((ccs *)O)->ncols
+#define CCS_NNZ(O)   ((ccs *)O)->colptr[CCS_NCOLS(O)]
+
+#endif 
diff --git a/src/C/dense.c b/src/C/dense.c
new file mode 100644
index 0000000..882cbc4
--- /dev/null
+++ b/src/C/dense.c
@@ -0,0 +1,2129 @@
+/*
+ * This file is part of CVXOPT version 0.8.2.
+ * Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+ */
+
+#define BASE_MODULE
+
+#include "Python.h"
+#include "cvxopt.h"
+#include "misc.h" 
+
+#include <complexobject.h>
+
+
+/* NumPy array protocol */
+typedef struct {
+     int version;       
+     int nd;            
+     char typekind;     
+     int itemsize;      
+     int flags;         
+     int_t *shape; 
+     int_t *strides;
+     void *data;           
+ } PyArrayInterface;
+
+static const char PY_ARRAY_TC[3] = { 'i', 'f', 'c' }; 
+
+/* prototyping and forward declarations */
+PyObject *base_mod;
+extern void (*axpy[])(int *, number *, void *, int *, void *, int *) ;
+extern void (*scal[])(int *, number *, void *, int *) ;
+extern void (*gemm[])(char *, char *, int *, int *, int *, void *, void *, 
+    int *, void *, int *, void *, void *, int *) ;
+extern void (*mtx_abs[])(void *, void *, int) ;
+extern int (*div_array[])(void *, number, int) ;
+extern int (*mtx_rem[])(void *, number, int) ;
+
+extern void (*write_num[])(void *, int, void *, int) ;
+extern int (*convert_num[])(void *, void *, int, int_t) ;
+extern PyObject * (*num2PyObject[])(void *, int) ;
+int get_id(void *, int ) ;
+
+extern const int  E_SIZE[];
+extern const char TC_CHAR[][2];
+extern const char PRINTOPT[][15];
+extern number One[3], MinusOne[3], Zero[3];
+
+
+PyTypeObject spmatrix_tp ;
+/*
+spmatrix * SpMatrix_New(int_t, int_t, int, int ) ;
+spmatrix * SpMatrix_NewFromSpMatrix(spmatrix *, int, int) ; 
+spmatrix * SpMatrix_NewFromIJV(matrix *, matrix *, matrix *, 
+    int_t, int_t, int, int) ;
+*/
+
+PyTypeObject matrix_tp ;
+matrix * Matrix_NewFromNumber(int , int , int , void *, int ) ;
+static PyNumberMethods matrix_as_number ;
+static PyObject * matrix_iter(matrix *) ;
+
+
+void dscal_(int *, double *, double *, int *) ;
+void zscal_(int *, complex *, complex *, int *) ;
+void daxpy_(int *, double *, double *, int *, double *, int *) ;
+void zaxpy_(int *, complex *, complex *, int *, complex *, int *) ;
+void dgemm_(char *, char *, int *, int *, int *, double *, double *,
+    int *, double *, int *, double *, double *, int *) ;
+void zgemm_(char *, char *, int *, int *, int *, complex *, complex *,
+    int *, complex *, int *, complex *, complex *, int *) ;
+
+
+
+static const char err_mtx_list2matrix[][35] = 
+  {"not an integer list", 
+   "not a floating point list",
+   "not a complex floating point list" };
+
+#define free_convert_mtx_alloc(O1, O2, id) { \
+if (MAT_BUF(O1) != O2) { \
+  free(MAT_BUF(O1)); MAT_BUF(O1) = O2; MAT_ID(O1) = id; \
+  } \
+}
+
+#define free_lists_exit(argI,argJ,I,J,ret) { \
+   if (argI && !Matrix_Check(argI)) { Py_XDECREF(I); } \
+    if (argJ && !Matrix_Check(argJ)) { Py_XDECREF(J); } \
+    return ret; }
+
+
+static int convert_mtx(matrix *src, void *dest, int id) 
+{
+  if (PY_NUMBER((PyObject *)src))
+    return convert_num[id](dest, src, 1, 0);
+
+  if (MAT_ID(src) == id) {
+    memcpy(dest, src->buffer, E_SIZE[src->id]*MAT_LGT(src) );
+    return 0;
+  }
+
+  int_t i;
+  for (i=0; i<MAT_LGT(src); i++) 
+    if (convert_num[id](dest + i*E_SIZE[id], src, 0,i)) return -1;    
+  
+  return 0;
+}
+
+void * convert_mtx_alloc(matrix *src, int id) 
+{
+  void *ptr;  
+  if (MAT_ID(src) == id) return MAT_BUF(src);
+  
+  if (!(ptr = malloc(E_SIZE[id]*MAT_LGT(src)))) return NULL;
+
+  int_t i;
+  for (i=0; i<MAT_LGT(src); i++) 
+    if (convert_num[id](ptr + i*E_SIZE[id], src, 0,i)) 
+    { free(ptr); return NULL; }
+  
+  return ptr;
+}
+
+
+/*
+  Creates an unpopulated "empty" matrix. In API
+*/
+matrix * Matrix_New(int nrows, int ncols, int id)
+{
+  matrix *a;
+  if ((nrows < 0) || (ncols < 0) || (id < INT) || (id > COMPLEX)) {
+    PyErr_BadInternalCall();
+    return NULL;
+  }
+  
+  if (!(a = (matrix *)matrix_tp.tp_alloc(&matrix_tp, 0)))
+    return NULL;
+  
+  a->id = id; a->nrows = nrows; a->ncols = ncols;  
+  if (!(a->buffer =  malloc(E_SIZE[id]*nrows*ncols))) {
+    a->ob_type->tp_free((PyObject*)a);
+    return (matrix *)PyErr_NoMemory();
+  }
+
+  int i;
+  for (i=0; i<MAT_LGT(a); i++)
+    write_num[MAT_ID(a)](MAT_BUF(a), i, &Zero[MAT_ID(a)], 0);
+
+  return a;
+}
+
+/*
+  Creates a copy of matrix as a new object. In API.
+*/
+matrix *Matrix_NewFromMatrix(matrix *src, int id)
+{
+  matrix *a;
+  
+  if (PY_NUMBER((PyObject *)src))
+    return Matrix_NewFromNumber(1, 1, id, src, 1);
+
+  if (!(a = Matrix_New(src->nrows, src->ncols, id)))
+    return (matrix *)PyErr_NoMemory();
+
+  if (convert_mtx(src, a->buffer, id)) {
+    Py_DECREF(a); PY_ERR_TYPE("illegal type conversion");
+  }
+
+  return a;
+}
+
+/*
+  Creates a matrix from a PyArrayInterface.
+*/
+matrix *Matrix_NewFromArrayStruct(PyObject *obj, int id, int_t *ndim)
+{
+  PyObject *cobj = PyObject_GetAttrString(obj, "__array_struct__");
+  PyArrayInterface *src =  (PyArrayInterface *)PyCObject_AsVoidPtr(cobj);
+
+  if (src->version != 2) 
+    PY_ERR(PyExc_AssertionError, "unexpected format in array structure");
+  
+  if (src->nd != 1 && src->nd != 2)
+    PY_ERR(PyExc_TypeError, "imported array must have 1 or 2 dimensions");
+  
+  int src_id;
+  switch (src->typekind) {
+  case 'i' : src_id = INT; break;
+  case 'f' : src_id = DOUBLE; break;
+  case 'c' : src_id = COMPLEX; break;
+  default: 
+    Py_DECREF(cobj); PY_ERR_TYPE("invalid array type");
+  }
+
+  if (id == -1) id = src_id;
+  if ((src_id > id) || (src->itemsize != E_SIZE[src_id])) {
+    Py_DECREF(cobj);
+    PY_ERR_TYPE("invalid array type");
+  }
+
+  /* XXX: revise flags check */
+  //if (src->flags != 0x701) {
+  if (!(src->flags & 0x001)) {
+    Py_DECREF(cobj);
+    PY_ERR_TYPE("array not contiguous)");    
+  }
+
+  *ndim = src->nd;
+  matrix *a = Matrix_New(src->shape[0], src->nd == 2 ? src->shape[1] : 1, id);
+  if (!a) {
+    Py_DECREF(cobj); return (matrix *)PyErr_NoMemory();
+  }
+
+  int i, j, cnt;
+  
+  for (j=0, cnt=0; j<MAT_NCOLS(a); j++) {
+    for (i=0; i<src->shape[0]; i++, cnt++) {
+
+      number n;
+      switch (id) {
+      case INT : 
+	MAT_BUFI(a)[cnt] = 
+	  *(int_t *)(src->data+i*src->strides[0]+j*src->strides[1]); 
+	break;
+      case DOUBLE:
+	switch (src_id) {
+	case INT: 
+	  n.d = *(int_t *)(src->data + i*src->strides[0]+j*src->strides[1]);
+	  break;
+	case DOUBLE:
+	  n.d = *(double *)(src->data + i*src->strides[0]+j*src->strides[1]);
+	  break;
+	}
+	MAT_BUFD(a)[cnt] = n.d;
+	break;
+      case COMPLEX:
+	switch (src_id) {
+	case INT: 
+	  n.z = *(int_t *)(src->data+i*src->strides[0]+j*src->strides[1]);
+	  break;
+	case DOUBLE:
+	  n.z = *(double *)(src->data+i*src->strides[0]+j*src->strides[1]);
+	  break;
+	case COMPLEX:
+	  n.z = *(complex *)(src->data+i*src->strides[0]+j*src->strides[1]);
+	  break;
+	}
+	MAT_BUFZ(a)[cnt] = n.z;
+	break;
+      }
+    }
+  }
+
+  Py_DECREF(cobj);
+  return a;
+}
+
+/*
+  Generates a matrix with all entries equal.
+*/
+matrix *
+Matrix_NewFromNumber(int nrows, int ncols, int id, void *val, int val_id)
+{
+
+  int i;
+  matrix *a = Matrix_New(nrows, ncols, id);
+  if (!a) return (matrix *)PyErr_NoMemory();
+
+  number n; 
+  if (convert_num[id](&n, val, val_id, 0)) { Py_DECREF(a); return NULL; }
+  for (i=0; i<MAT_LGT(a); i++) write_num[id](MAT_BUF(a), i, &n, 0);
+  
+  return a;
+}
+
+/*
+  Converts a Python list to a matrix. Part of API
+*/
+matrix * Matrix_NewFromSequence(PyObject *x, int id) 
+{
+  int i, len = PySequence_Size(x);
+  PyObject *seq = PySequence_Fast(x, "list is not iterable");
+  if (!seq) return NULL;
+  
+  if (id == -1) {
+    for (i=0; i<len; i++) {
+      PyObject *item = PySequence_Fast_GET_ITEM(seq, i);
+	
+      if (!PY_NUMBER(item)) {
+	Py_DECREF(seq); PY_ERR_TYPE("non-numeric element in list");
+      }
+      
+      id = MAX(id, get_id(item, 1));
+    }    
+  }
+
+  if (!len) return Matrix_New(0, 0, (id < 0 ? INT : id));
+
+  matrix *L = Matrix_New(len,1,id);
+  if (!L) { Py_DECREF(seq); return (matrix *)PyErr_NoMemory(); }
+
+  for (i=0; i<len; i++) {
+    PyObject *item = PySequence_Fast_GET_ITEM(seq, i);
+	
+    if (!PY_NUMBER(item)) {
+      Py_DECREF(seq); Py_DECREF(L); 
+      PY_ERR_TYPE("non-numeric type in list");
+    }
+
+    number n;
+    if (convert_num[id](&n, item, 1, 0)) {
+      Py_DECREF(L); Py_DECREF(seq);
+      PY_ERR(PyExc_TypeError, err_mtx_list2matrix[id]);
+    }
+    write_num[id](L->buffer, i, &n, 0);
+  }
+  Py_DECREF(seq);
+  return L;
+}
+
+matrix * dense(spmatrix *self) 
+{
+  matrix *A; 
+  int_t i, j, k; 
+  
+  if (!(A = Matrix_New(SP_NROWS(self),SP_NCOLS(self),SP_ID(self))))
+    return (matrix *)PyErr_NoMemory();
+
+  for (i=0; i<SP_LGT(self); i++)
+    write_num[SP_ID(self)](MAT_BUF(A),i,&Zero,0);
+
+  for (k=0; k<SP_NCOLS(self); k++)
+    for (j=SP_COL(self)[k]; j<SP_COL(self)[k+1]; j++) {
+      write_num[SP_ID(self)](MAT_BUF(A),k*SP_NROWS(self)+SP_ROW(self)[j],
+	  SP_VAL(self), j);
+    }
+  return A;
+}
+
+int convert_array(void *dest, void *src, int dest_id, int src_id, int n);
+
+matrix * dense_concat(PyObject *L, int id_arg)
+{ 
+  int m=0, n=0, mk=0, nk=0, i=0, j, id = 0;
+  PyObject *col;
+  
+  int single_col = (PyList_GET_SIZE(L) > 0 && 
+      !PyList_Check(PyList_GET_ITEM(L, 0)));
+
+  for (j=0; j<(single_col ? 1 : PyList_GET_SIZE(L)); j++) {
+
+    col = (single_col ? L : PyList_GET_ITEM(L, j));
+    if (!PyList_Check(col))  
+      PY_ERR_TYPE("invalid type in list");
+    
+    mk = 0;
+    for (i=0; i<PyList_GET_SIZE(col); i++) {
+      PyObject *Lij = PyList_GET_ITEM(col, i);
+      if (!Matrix_Check(Lij) && !SpMatrix_Check(Lij) && !PY_NUMBER(Lij)) 
+	PY_ERR_TYPE("invalid type in list");
+
+      int blk_nrows, blk_ncols;
+      if (Matrix_Check(Lij) || SpMatrix_Check(Lij)) {
+	blk_nrows = X_NROWS(Lij); blk_ncols = X_NCOLS(Lij);
+	id = MAX(id, X_ID(Lij));
+      } else {
+	blk_nrows = 1; blk_ncols = 1;
+	id = MAX(id, get_id(Lij,1));
+      }
+	
+      if (i==0) {
+	nk = blk_ncols; n += nk;
+	mk = blk_nrows; 
+      } else {
+	if (blk_ncols != nk) 
+	  PY_ERR_TYPE("incompatible dimensions of subblocks");
+	mk += blk_nrows;
+      }
+    }
+    if (j==0) 
+      m = mk;
+    else if (m != mk) PY_ERR_TYPE("incompatible dimensions of subblocks");   
+  }
+
+  if ((id_arg >= 0) && (id_arg < id))
+    PY_ERR_TYPE("illegal type conversion");
+
+  id = MAX(id, id_arg);
+
+  matrix *A = Matrix_New(m, n, id);
+  if (!A) return (matrix *)PyErr_NoMemory();
+
+  nk = 0;
+  for (j=0; j<(single_col ? 1 : PyList_GET_SIZE(L)); j++) {
+    col = (single_col ? L : PyList_GET_ITEM(L, j));
+
+    mk = 0;  
+    int blk_nrows = 0, blk_ncols = 0;
+    for (i=0; i<PyList_GET_SIZE(col); i++) {
+      PyObject *Lij = PyList_GET_ITEM(col, i);
+
+      if (Matrix_Check(Lij) || SpMatrix_Check(Lij)) {
+	blk_nrows = X_NROWS(Lij); blk_ncols = X_NCOLS(Lij);
+      } else {
+	blk_nrows = 1; blk_ncols = 1;
+      }
+
+      int ik, jk;
+      for (jk=0; jk<blk_ncols; jk++) {
+	
+	if (Matrix_Check(Lij)) {
+	  for (ik=0; ik<blk_nrows; ik++) 
+	    convert_num[id](MAT_BUF(A) + (mk+ik+(nk+jk)*m)*E_SIZE[id],
+		Lij, 0, ik + jk*blk_nrows);
+
+	} else if (SpMatrix_Check(Lij)) {
+	  for (ik=SP_COL(Lij)[jk]; ik<SP_COL(Lij)[jk+1]; ik++) 
+	    convert_array(MAT_BUF(A) + ((nk+jk)*m+mk+SP_ROW(Lij)[ik])*
+		E_SIZE[id], SP_VAL(Lij) + ik*E_SIZE[SP_ID(Lij)], 
+		id, SP_ID(Lij), 1);	      
+
+	} else {
+	  
+	  convert_num[id](MAT_BUF(A) + (mk+(nk+jk)*m)*E_SIZE[id], 
+	      Lij, 1, 0);
+	}
+      }
+      mk += blk_nrows;
+    }
+    nk += blk_ncols;
+  }
+  return A;
+}
+
+static void
+matrix_dealloc(matrix* self)
+{
+  free(self->buffer);
+  self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+  PyObject *Objx = NULL, *size = NULL;
+  static char *kwlist[] = { "x", "size", "tc", NULL};
+ 
+  int nrows=0, ncols=0;
+  char tc = 0;
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|Oc:matrix", kwlist, 
+	  &Objx, &size, &tc))
+    return NULL;
+
+  if (size && !PyArg_ParseTuple(size, "ii", &nrows, &ncols)) 
+    PY_ERR_TYPE("invalid dimension tuple") ;
+
+  if (nrows < 0 || ncols < 0) 
+    PY_ERR_TYPE("dimensions must be non-negative");
+
+  if (tc && !(VALID_TC_MAT(tc))) PY_ERR_TYPE("tc must be 'i', 'd' or 'z'");  
+  int id = (tc ? TC2ID(tc) : -1);
+
+  matrix *ret = NULL;
+  /* x is a number */
+  if (PY_NUMBER(Objx)) 
+    return (PyObject *)
+      Matrix_NewFromNumber(MAX(nrows, size ? 0 : 1),
+	  MAX(ncols, size ? 0 : 1), (id == -1 ? get_id(Objx,1):id),Objx,1);
+
+  /* a matrix */
+  else if (Matrix_Check(Objx)) 
+    ret = Matrix_NewFromMatrix((matrix *)Objx, (id == -1 ?MAT_ID(Objx):id));
+  
+  /* sparse matrix */
+  else if (SpMatrix_Check(Objx)) {
+    matrix *tmp = dense((spmatrix *)Objx);
+    if (!tmp) return PyErr_NoMemory();
+    ret = Matrix_NewFromMatrix(tmp, (id == -1 ? SP_ID(Objx) : id));
+    Py_DECREF(tmp);
+  }
+
+  /* PyArrayStructure */
+  else if (PyObject_HasAttrString(Objx,"__array_struct__")) {
+    int_t ndim = 0;
+    ret = Matrix_NewFromArrayStruct(Objx, id, &ndim);
+  }
+  
+  /* x is a list */
+  else if (PyList_Check(Objx)) {
+
+    /* first try a regular list */
+    if (!(ret = Matrix_NewFromSequence(Objx, id))) { 
+      PyErr_Clear();
+      /* try concatenation */
+      ret = dense_concat(Objx, id);
+    }
+  }
+
+  /* x is a sequence */
+  else if (PySequence_Check(Objx)) {
+    ret = Matrix_NewFromSequence(Objx, id);  
+  }
+  else PY_ERR_TYPE("invalid matrix initialization");
+
+  if (ret && size) {
+    if (nrows*ncols == MAT_LGT(ret)) { 
+      ret->nrows=nrows; ret->ncols=ncols; 
+    } else {
+      Py_DECREF(ret); PY_ERR_TYPE("wrong matrix dimensions");
+    }
+  }
+
+  return (PyObject *)ret;
+}
+
+static PyObject *
+matrix_str(matrix *self)
+{  
+  PyObject *printopt;
+
+  /* these PyObject variables will all be borrowed references */
+  PyObject *opt, *s, *stmp=NULL;
+
+  if (self->nrows == 0 || self->ncols == 0)
+    return Py_BuildValue("s","");
+  
+  if (!(printopt = PyObject_GetAttrString(base_mod, "print_options")) ||
+      !PyDict_Check(printopt)) {
+    PY_ERR(PyExc_AttributeError, "cannot access 'print_options' dictionary");
+  }
+ 
+  if (!(opt = PyDict_GetItemString(printopt, PRINTOPT[self->id]))) {
+    Py_DECREF(printopt);
+    PY_ERR(PyExc_KeyError, "missing print format key in 'base_options'");
+  }
+
+  char tmp[50], format[20] = "%- ", format_im[20] = "%";
+  strncat(format, PyString_AsString(opt), 18);
+  if (MAT_ID(self)==COMPLEX)
+    strncat(format_im, PyString_AsString(opt), 18);
+
+  if (!(s = PyString_FromString(""))) {
+    Py_DECREF(printopt);
+    return PyErr_NoMemory();
+  }
+
+  int i, j;
+  for (i=0; i<self->nrows; i++) {
+
+    for (j=0; j<self->ncols; j++) {
+      PyString_ConcatAndDel(&s, PyString_FromString("  "));
+      switch (MAT_ID(self)) {
+      case DOUBLE: 
+	if ((snprintf(tmp,50,format, MAT_BUFD(self)[j*self->nrows+i])<0) ||
+	    !(stmp = PyString_FromString(tmp)))
+	  goto fail;
+	break;
+      case INT: 
+	if ((snprintf(tmp,50,format,MAT_BUFI(self)[j*self->nrows+i])<0) ||
+	    !(stmp = PyString_FromString(tmp)))
+	  goto fail;
+	break;
+      case COMPLEX:
+	if ((snprintf(tmp,50,format,
+		    creal(MAT_BUFZ(self)[j*self->nrows+i]))<0) ||
+	    !(stmp = PyString_FromString(tmp)))
+	  goto fail;
+	
+	if (snprintf(tmp,50,format_im, 
+		fabs(cimag(MAT_BUFZ(self)[j*self->nrows+i])))<0)
+	  goto fail;
+	
+	PyString_ConcatAndDel(&stmp, cimag(MAT_BUFZ(self)[j*self->nrows+i])>0 ?
+	    PyString_FromString("+j") : PyString_FromString("-j"));
+	PyString_ConcatAndDel(&stmp, PyString_FromString(tmp));       
+	break;
+      }   
+      PyString_ConcatAndDel(&s, stmp);
+    }
+    PyString_ConcatAndDel(&s, PyString_FromString("\n"));
+  }
+  
+  Py_DECREF(printopt);
+  return s;
+   
+ fail:
+  Py_DECREF(printopt); 
+  Py_DECREF(s); return PyErr_NoMemory();
+}
+
+static PyObject *
+matrix_repr(matrix *self) {
+
+  PyObject *s = PyString_FromFormat("<%ldx%ld matrix, tc='%s'>",
+      (long)self->nrows,(long)self->ncols,TC_CHAR[self->id]);
+
+  return s;
+}
+
+/*
+ * This method converts different index sets into a matrix indexlist
+ */
+matrix * create_indexlist(int dim, PyObject *A) 
+{
+  matrix *x;
+  int_t i, j;
+
+  /* integer */
+  if (PyInt_Check(A)) {
+    i = PyInt_AS_LONG(A);    
+    if (OUT_RNG(i,dim)) PY_ERR(PyExc_IndexError, "index out of range");
+
+    if ((x = Matrix_New(1,1,INT))) MAT_BUFI(x)[0] = i;    
+    return x;
+  }
+  /* slice */
+  else if (PySlice_Check(A)) {
+    int_compat start, stop, step, lgt;
+
+    if (PySlice_GetIndicesEx((PySliceObject*)A, dim,
+	    &start, &stop, &step, &lgt) < 0) return NULL;
+
+    if ((x = Matrix_New(lgt, 1, INT)))
+      for (i=start, j=0; j<lgt; i += step, j++) MAT_BUFI(x)[j] = i;
+
+    return x;
+  }  
+  /* Matrix index list */
+  else if (Matrix_Check(A)) {
+    if (MAT_ID(A) != INT) PY_ERR_TYPE("not an integer index list");
+
+    for (i=0; i<MAT_LGT(A); i++) 
+      if ( OUT_RNG(MAT_BUFI(A)[i], dim) )
+	PY_ERR(PyExc_IndexError, "index out of range");
+    
+    return (matrix *)A;
+  }
+  /* List */
+  else if (PyList_Check(A)) {
+    if (!(x = (matrix *)Matrix_NewFromSequence(A, INT))) return NULL;
+    
+    return create_indexlist(dim, (PyObject *)x);
+  } 
+  else PY_ERR(PyExc_TypeError, "invalid index argument");
+}
+
+static int
+matrix_length(matrix *self)
+{
+  return MAT_LGT(self);
+}
+
+static PyObject *
+matrix_subscr(matrix* self, PyObject* args) 
+{
+  matrix *Il = NULL, *Jl = NULL, *ret;
+  if (PyInt_Check(args)) {
+    int_t i = PyInt_AS_LONG(args);
+    if (OUT_RNG(i,MAT_LGT(self))) 
+      PY_ERR(PyExc_IndexError, "index out of range");
+
+    return num2PyObject[self->id](self->buffer, CWRAP(i,MAT_LGT(self)));
+  }
+
+  else if (PyList_Check(args) || Matrix_Check(args) || PySlice_Check(args)) {  
+    
+    if (!(Il = create_indexlist(MAT_LGT(self), args))) return NULL;    
+    
+    int i;        
+    if (!(ret = Matrix_New(MAT_LGT(Il), 1, self->id) )) 
+      free_lists_exit(args,(PyObject *)NULL,Il,(PyObject *)NULL,
+	  PyErr_NoMemory());
+    
+    for (i=0; i<MAT_LGT(Il); i++) 
+      write_num[self->id](ret->buffer, i, self->buffer,
+	  CWRAP(MAT_BUFI(Il)[i],MAT_LGT(self)));
+
+    free_lists_exit(args,(PyObject *)NULL,Il,(PyObject *)NULL,(PyObject *)ret);
+  }
+  
+  /* remainding cases are different two argument indexing */  
+  PyObject *argI = NULL, *argJ = NULL;
+  if (!PyArg_ParseTuple(args, "OO", &argI,&argJ))
+    PY_ERR_TYPE("invalid index arguments");
+  
+  /* handle normal subscripts (two integers) separately */
+  if (PyInt_Check(argI) && PyInt_Check(argJ)) {
+    
+    int i = PyInt_AS_LONG(argI), j = PyInt_AS_LONG(argJ);
+    if ( OUT_RNG(i, self->nrows) || OUT_RNG(j, self->ncols))
+      PY_ERR(PyExc_IndexError, "index out of range");
+
+    return num2PyObject[self->id](self->buffer, 
+	CWRAP(i,self->nrows) + CWRAP(j,self->ncols)*self->nrows);
+  }
+
+  /* two slices, handled separately for speed */
+  if (PySlice_Check(argI) && PySlice_Check(argJ)) {
+    int_compat rowstart, rowstop, rowstep, rowlgt;
+    int_compat colstart, colstop, colstep, collgt;
+
+    if ( (PySlice_GetIndicesEx((PySliceObject*)argI, MAT_NROWS(self),
+		&rowstart, &rowstop, &rowstep, &rowlgt) < 0) ||	
+	(PySlice_GetIndicesEx((PySliceObject*)argJ, MAT_NCOLS(self),
+	    &colstart, &colstop, &colstep, &collgt) < 0)) return NULL;
+    
+    if (!(ret = Matrix_New(rowlgt, collgt, self->id))) 
+      return PyErr_NoMemory();
+
+    int i, j, icnt, jcnt, cnt=0;
+    for (j=colstart, jcnt=0; jcnt<collgt; jcnt++, j+=colstep) 
+      for (i=rowstart, icnt=0; icnt<rowlgt; icnt++, i+=rowstep) {
+	switch (self->id) {
+	case INT:
+	  MAT_BUFI(ret)[cnt++] = MAT_BUFI(self)[j*self->nrows+i];
+	  break;
+	case DOUBLE:
+	  MAT_BUFD(ret)[cnt++] = MAT_BUFD(self)[j*self->nrows+i];
+	  break;
+	case COMPLEX:
+	  MAT_BUFZ(ret)[cnt++] = MAT_BUFZ(self)[j*self->nrows+i];
+	  break;
+	}
+      }
+
+    return (PyObject *)ret;
+  }
+
+  /* remaining two indexing cases */
+  if (!(Il = create_indexlist(self->nrows, argI)) ||
+      !(Jl = create_indexlist(self->ncols, argJ))) 
+    free_lists_exit(argI, argJ, Il, Jl, (PyObject *)NULL);
+
+  int i, j, cnt;
+  if (!(ret = Matrix_New(MAT_LGT(Il), MAT_LGT(Jl), self->id))) 
+    free_lists_exit(argI, argJ, Il, Jl, PyErr_NoMemory());
+    
+  for (j=0, cnt=0; j < MAT_LGT(Jl); j++)
+    for (i=0; i < MAT_LGT(Il); i++) {
+      write_num[self->id](ret->buffer, cnt++, self->buffer, 
+	  CWRAP(MAT_BUFI(Il)[i],self->nrows) + 
+	  CWRAP(MAT_BUFI(Jl)[j],self->ncols)*self->nrows); 
+    }
+
+  free_lists_exit(argI, argJ, Il, Jl, (PyObject *)ret);
+}
+
+#define spmatrix_getitem_i(O,i,v) \
+  spmatrix_getitem_ij(O,i%SP_NROWS(O),i/SP_NROWS(O),v)
+
+int spmatrix_getitem_ij(spmatrix *, int_t, int_t, number *) ;
+
+static int
+matrix_ass_subscr(matrix* self, PyObject* args, PyObject* val)
+{
+  matrix *Il = NULL, *Jl = NULL;
+  int_t i, j, id = self->id, decref_val = 0, arraystruct_nd = 0;    
+
+  if (!val) PY_ERR_INT(PyExc_NotImplementedError, 
+      "cannot delete matrix entries");
+
+  if (!(PY_NUMBER(val) || Matrix_Check(val) || SpMatrix_Check(val))) {
+    
+    if (PyObject_HasAttrString(val,"__array_struct__")) 
+      val = (PyObject *)Matrix_NewFromArrayStruct(val, -1, &arraystruct_nd);
+    else 
+      val = (PyObject *)Matrix_NewFromSequence(val, MAT_ID(self));
+
+    if (!val)
+      PY_ERR_INT(PyExc_NotImplementedError, "invalid type in assignment");    
+
+    decref_val = 1;
+  }
+
+  if (get_id(val, (PY_NUMBER(val) ? 1 : 0)) > id) 
+    PY_ERR_INT(PyExc_TypeError, "invalid type in assignment");
+
+  if (PyInt_Check(args) || PyList_Check(args) || 
+      Matrix_Check(args) || PySlice_Check(args)) {    
+
+    if (!(Il = create_indexlist(MAT_LGT(self), args))) {
+      if (decref_val) { Py_DECREF(val); }
+      return -1;
+    }
+    number n;
+    if (PY_NUMBER(val) || (Matrix_Check(val) && MAT_LGT(val)==1)) {
+      convert_num[id](&n, val, (Matrix_Check(val) ? 0 : 1), 0);      
+
+      for (i=0; i<MAT_LGT(Il); i++) 
+	write_num[id](self->buffer,CWRAP(MAT_BUFI(Il)[i],MAT_LGT(self)),&n,0);
+    }
+    else {
+
+      if (Matrix_Check(val)) {
+	if (MAT_LGT(val) != MAT_LGT(Il) || MAT_NCOLS(val) > 1) {
+	  if (!Matrix_Check(args)) { Py_DECREF(Il); }
+	  if (decref_val) { Py_DECREF(val); }
+	  PY_ERR_INT(PyExc_TypeError, "argument has wrong size");
+	}
+     
+	for (i=0; i < MAT_LGT(Il); i++) {
+	  convert_num[id](&n, val, 0, i);
+	  write_num[id](self->buffer,
+	      CWRAP(MAT_BUFI(Il)[i], MAT_LGT(self)), &n, 0);
+	}
+      } 
+      else { /* spmatrix */
+
+	if (SP_NROWS(val) != MAT_LGT(Il) || SP_NCOLS(val) > 1) {
+	  if (!Matrix_Check(args)) { Py_DECREF(Il); }
+	  if (decref_val) { Py_DECREF(val); }
+	  PY_ERR_INT(PyExc_TypeError, "argument has wrong size");
+	}
+	
+	for (i=0; i < MAT_LGT(Il); i++) {
+	  spmatrix_getitem_i((spmatrix *)val, i, &n);
+	  write_num[id](self->buffer,
+	      CWRAP(MAT_BUFI(Il)[i], MAT_LGT(self)), &n, 0);
+	}
+      }
+    }
+
+    if (decref_val) { Py_DECREF(val); }
+    free_lists_exit(args,(PyObject *)NULL,Il,(PyObject *)NULL,0);
+  }
+
+  /* remainding cases are different two argument indexing */
+  PyObject *argI = NULL, *argJ = NULL;
+  if (!PyArg_ParseTuple(args, "OO", &argI,&argJ)) 
+    PY_ERR_INT(PyExc_TypeError, "invalid index arguments");
+
+  /* two slices, RHS of same type, handled separately for speed */
+  if (PySlice_Check(argI) && PySlice_Check(argJ) && 
+      Matrix_Check(val) && MAT_ID(val) == MAT_ID(self)) {
+
+    int_compat rowstart, rowstop, rowstep, rowlgt;
+    int_compat colstart, colstop, colstep, collgt;
+
+    if ( (PySlice_GetIndicesEx((PySliceObject*)argI, MAT_NROWS(self),
+		&rowstart, &rowstop, &rowstep, &rowlgt) < 0) ||	
+	(PySlice_GetIndicesEx((PySliceObject*)argJ, MAT_NCOLS(self),
+	    &colstart, &colstop, &colstep, &collgt) < 0)) return -1;
+
+    if (decref_val && MAT_LGT(val) == rowlgt*collgt) {
+      MAT_NROWS(val) = rowlgt; MAT_NCOLS(val) = collgt;
+    }
+
+    if (MAT_NROWS(val)!=rowlgt || MAT_NCOLS(val)!=collgt) 
+      PY_ERR_INT(PyExc_TypeError, "argument has wrong size");    
+
+    int i, j, icnt, jcnt, cnt=0;
+    for (j=colstart, jcnt=0; jcnt<collgt; jcnt++, j+=colstep) 
+      for (i=rowstart, icnt=0; icnt<rowlgt; icnt++, i+=rowstep) {
+	switch (self->id) {
+	case INT:
+	  MAT_BUFI(self)[j*self->nrows+i] = MAT_BUFI(val)[cnt++];
+	  break;
+	case DOUBLE:
+	  MAT_BUFD(self)[j*self->nrows+i] = MAT_BUFD(val)[cnt++]; 
+	  break;
+	case COMPLEX:
+	  MAT_BUFZ(self)[j*self->nrows+i] = MAT_BUFZ(val)[cnt++];
+	  break;
+	}
+      }
+
+    return 0;
+  }
+
+  if (!(Il = create_indexlist(self->nrows, argI)) ||
+      !(Jl = create_indexlist(self->ncols, argJ))) {
+    if (decref_val) { Py_DECREF(val); }
+    free_lists_exit(argI,argJ,Il,Jl,-1);
+  }
+
+  if (decref_val && arraystruct_nd < 2 && 
+      MAT_LGT(val) == MAT_LGT(Il)*MAT_LGT(Jl)) {
+    MAT_NROWS(val) = MAT_LGT(Il); MAT_NCOLS(val) = MAT_LGT(Jl);
+  }
+
+  number n;
+  if (PY_NUMBER(val) || (Matrix_Check(val) && MAT_LGT(val)==1)) {
+    if (convert_num[id](&n, val, (Matrix_Check(val) ? 0 : 1), 0)) {
+      if (decref_val) { Py_DECREF(val); }
+      free_lists_exit(Il,Jl,argI,argJ,-1);
+    }
+    
+    for (j=0; j < MAT_LGT(Jl); j++)
+      for (i=0; i < MAT_LGT(Il); i++) {
+	write_num[id](self->buffer,CWRAP(MAT_BUFI(Il)[i],self->nrows) + 
+	    CWRAP(MAT_BUFI(Jl)[j],self->ncols)*self->nrows, &n, 0); 
+      }    
+  }
+  else if (Matrix_Check(val)) {    
+    if (MAT_LGT(Il) != MAT_NROWS(val) || MAT_LGT(Jl) != MAT_NCOLS(val) ) {
+      if (!Matrix_Check(argI)) { Py_DECREF(Il); }
+      if (!Matrix_Check(argJ)) { Py_DECREF(Jl); }
+      if (decref_val) { Py_DECREF(val); }
+      PY_ERR_INT(PyExc_TypeError, "argument has wrong size");
+    }
+    
+    int cnt = 0;
+    for (j=0; j < MAT_LGT(Jl); j++)
+      for (i=0; i < MAT_LGT(Il); i++, cnt++) {
+	if (convert_num[id](&n, val, 0, cnt)) 
+	  free_lists_exit(argI,argJ,Il,Jl,-1);
+	
+	write_num[id](self->buffer,CWRAP(MAT_BUFI(Il)[i],self->nrows) + 
+	    CWRAP(MAT_BUFI(Jl)[j],self->ncols)*self->nrows, &n, 0);	
+      }
+  }
+  else { /* spmatrix */
+    if (MAT_LGT(Il) != SP_NROWS(val) || MAT_LGT(Jl) != SP_NCOLS(val) ) {
+      if (!Matrix_Check(argI)) { Py_DECREF(Il); }
+      if (!Matrix_Check(argJ)) { Py_DECREF(Jl); }
+      if (decref_val) { Py_DECREF(val); }
+      PY_ERR_INT(PyExc_TypeError, "argument has wrong size");
+    }
+
+    int cnt = 0;
+    for (j=0; j < MAT_LGT(Jl); j++)
+      for (i=0; i < MAT_LGT(Il); i++, cnt++) {
+
+	spmatrix_getitem_i((spmatrix *)val, cnt, &n);	
+	write_num[id](self->buffer,CWRAP(MAT_BUFI(Il)[i],self->nrows)  + 
+	    CWRAP(MAT_BUFI(Jl)[j],self->ncols)*self->nrows, &n, 0);	
+      }
+  }
+
+  if (decref_val) { Py_DECREF(val); }
+  free_lists_exit(argI,argJ,Il,Jl,0);
+}
+
+static PyMappingMethods matrix_as_mapping = {
+  (lenfunc)matrix_length,
+  (binaryfunc)matrix_subscr,
+  (objobjargproc)matrix_ass_subscr
+};
+
+static PyObject * matrix_transpose(matrix *self) {
+
+  matrix *ret = Matrix_New(self->ncols, self->nrows, self->id);
+  if (!ret) return PyErr_NoMemory();
+
+  int i, j, cnt = 0;
+  for (i=0; i < ret->nrows; i++)
+    for (j=0; j < ret->ncols; j++) 
+      write_num[self->id](ret->buffer, i + j*ret->nrows, self->buffer, cnt++);
+
+  return (PyObject *)ret;
+}
+
+static PyObject * matrix_ctranspose(matrix *self) {
+
+  if (self->id != COMPLEX) return matrix_transpose(self);
+  
+  matrix *ret = Matrix_New(self->ncols, self->nrows, self->id);
+  if (!ret) return PyErr_NoMemory();
+
+  int i, j, cnt = 0;
+  for (i=0; i < ret->nrows; i++)
+    for (j=0; j < ret->ncols; j++)       
+      MAT_BUFZ(ret)[i + j*ret->nrows] = conj(MAT_BUFZ(self)[cnt++]);
+    
+  return (PyObject *)ret;
+}
+
+static PyObject * matrix_real(matrix *self) {
+
+  if (self->id != COMPLEX) 
+    return (PyObject *)Matrix_NewFromMatrix(self,self->id);
+  
+  matrix *ret = Matrix_New(self->nrows, self->ncols, DOUBLE);
+  if (!ret) return PyErr_NoMemory();
+
+  int i;
+  for (i=0; i < MAT_LGT(self); i++)
+    MAT_BUFD(ret)[i] = creal(MAT_BUFZ(self)[i]);
+
+  return (PyObject *)ret;
+}
+
+static PyObject * matrix_imag(matrix *self) {
+
+  matrix *ret;
+  if (self->id != COMPLEX) {
+    PyObject *a = PyFloat_FromDouble(0);
+    ret = Matrix_NewFromNumber(self->nrows, self->ncols, self->id, a, 2);
+    Py_DECREF(a);
+    if (!ret) return PyErr_NoMemory();
+    
+    return (PyObject *)ret;
+  }
+    
+  if (!(ret = Matrix_New(self->nrows, self->ncols, DOUBLE)))
+    return PyErr_NoMemory();
+
+  int i;
+  for (i=0; i < MAT_LGT(self); i++)
+    MAT_BUFD(ret)[i] = cimag(MAT_BUFZ(self)[i]);
+
+  return (PyObject *)ret;
+}
+
+static char doc_tofile[] =
+    "Writes a matrix to file\n\n"
+    "ARGUMENTS\n"
+    "fo          a Python file object prevously obtained by open()\n\n";
+static PyObject *
+matrix_tofile(matrix *self, PyObject *args, PyObject *kwrds)
+{
+  PyObject *file_obj;
+  FILE *fp;
+  char *kwlist[] = {"fo",  NULL};
+  
+  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O", kwlist, &file_obj)) 
+    return NULL;
+  
+  if (!PyFile_Check(file_obj)) 
+    PY_ERR_TYPE("argument must a file object");
+
+  if (!(fp = PyFile_AsFile(file_obj))) 
+    PY_ERR(PyExc_IOError,"file not open for writing");
+  
+  fwrite(self->buffer, E_SIZE[self->id], MAT_LGT(self), fp);  
+  return Py_BuildValue("");
+}
+
+static char doc_fromfile[] =
+    "Reads a matrix from file\n\n"
+    "ARGUMENTS\n"
+    "fo          a Python file object prevously obtained by open()\n\n";
+static PyObject *
+matrix_fromfile(matrix *self, PyObject *args, PyObject *kwrds)
+{
+  PyObject *file_obj;
+  FILE *fp;
+  char *kwlist[] = {"fo", NULL};
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O", kwlist, &file_obj)) 
+    return NULL;
+
+  if (!PyFile_Check(file_obj)) 
+    PY_ERR_TYPE("argument must a file object");
+  if (!(fp = PyFile_AsFile(file_obj))) 
+    PY_ERR(PyExc_IOError,"file not open for reading");
+  
+  int n = fread(self->buffer, E_SIZE[self->id], MAT_LGT(self), fp);
+
+  if (n < MAT_LGT(self)) 
+    PY_ERR(PyExc_IOError, "could not read entire matrix");
+  return Py_BuildValue("");
+}
+
+static PyObject *
+matrix_getstate(matrix *self)
+{
+  PyObject *list = PyList_New(MAT_LGT(self));
+  PyObject *size = PyTuple_New(2);
+  if (!list || !size) {
+    Py_XDECREF(list); Py_XDECREF(size); return NULL;
+  }
+  
+  PyTuple_SET_ITEM(size, 0, PyInt_FromLong(MAT_NROWS(self)));
+  PyTuple_SET_ITEM(size, 1, PyInt_FromLong(MAT_NCOLS(self)));
+
+  int i;
+  for (i=0; i<MAT_LGT(self); i++) {
+    PyList_SET_ITEM(list, i, num2PyObject[MAT_ID(self)](MAT_BUF(self), i));
+  }
+
+  return Py_BuildValue("NNs", list, size, TC_CHAR[MAT_ID(self)]);
+}
+
+static PyObject *
+matrix_reduce(matrix* self)
+{
+  return Py_BuildValue("ON", self->ob_type, matrix_getstate(self));
+}
+
+static PyMethodDef matrix_methods[] = {
+  {"trans", (PyCFunction)matrix_transpose, METH_NOARGS, 
+   "Returns the matrix transpose"},
+  {"ctrans", (PyCFunction)matrix_ctranspose, METH_NOARGS, 
+   "Returns the matrix conjugate transpose"},
+  {"real", (PyCFunction)matrix_real, METH_NOARGS, 
+   "Returns real part of matrix"},
+  {"imag", (PyCFunction)matrix_imag, METH_NOARGS, 
+   "Returns imaginary part of matrix"},
+  {"tofile", (PyCFunction)matrix_tofile, METH_VARARGS|METH_KEYWORDS,
+   doc_tofile},
+  {"fromfile", (PyCFunction)matrix_fromfile, METH_VARARGS|METH_KEYWORDS, 
+   doc_fromfile},
+  {"__reduce__", (PyCFunction)matrix_reduce, METH_NOARGS,
+   "__reduce__() -> (cls, state)"},
+  {NULL}  /* Sentinel */
+};
+
+static PyObject *
+matrix_get_size(matrix *self, void *closure)
+{
+  PyObject *t = PyTuple_New(2);
+  
+  PyTuple_SET_ITEM(t, 0, PyInt_FromLong(self->nrows));
+  PyTuple_SET_ITEM(t, 1, PyInt_FromLong(self->ncols));
+  
+  return t;
+}
+
+static PyObject * matrix_get_typecode(matrix *self, void *closure)
+{
+  return PyString_FromStringAndSize(TC_CHAR[self->id], 1);
+}
+
+
+static void matrix_free_array_struct(void *a_struct, void *descr)
+{
+  free(((PyArrayInterface *)a_struct)->shape);
+  free(((PyArrayInterface *)a_struct)->strides);
+  free(a_struct);
+}
+
+static PyObject * matrix_array_struct(matrix *self, void *closure) {
+  
+  PyArrayInterface *a = malloc(sizeof(PyArrayInterface));
+  if (!a) return PyErr_NoMemory();
+
+  a->shape = malloc(2*sizeof(int_t));
+  a->strides = malloc(2*sizeof(int_t));
+  if (!a->shape || !a->strides) {
+    free(a->shape); free(a->strides); free(a);
+    return PyErr_NoMemory();
+  }
+  
+  a->version = 2;
+  a->nd = 2;
+  a->typekind = PY_ARRAY_TC[self->id];
+  a->itemsize = E_SIZE[self->id];
+  a->flags = 0x001 + 0x002 + 0x100 + 0x200 + 0x400;
+  a->shape[0] = self->nrows;
+  a->shape[1] = self->ncols;
+  a->strides[0] = E_SIZE[self->id];
+  a->strides[1] = self->nrows*E_SIZE[self->id];
+  a->data = self->buffer;
+
+  return (PyObject *) PyCObject_FromVoidPtrAndDesc((void *) a, 
+      "CVXOPT ARRAY STRUCT", matrix_free_array_struct);  
+
+}
+
+static PyObject * matrix_get_T(matrix *self, void *closure)
+{
+  return matrix_transpose(self);
+}
+
+static PyObject * matrix_get_H(matrix *self, void *closure)
+{
+  return matrix_ctranspose(self);
+}
+
+static PyGetSetDef matrix_getsets[] = {
+  {"size", (getter) matrix_get_size, NULL, "matrix dimensions"}, 
+  {"typecode", (getter) matrix_get_typecode, NULL, "typecode character"},
+  {"__array_struct__", (getter) matrix_array_struct, NULL,
+   "C object implementing the NumPy array protocol"},
+  {"T", (getter) matrix_get_T, NULL, "transpose"},
+  {"H", (getter) matrix_get_H, NULL, "conjugate transpose"},
+  {NULL}  /* Sentinel */
+};
+
+PyTypeObject matrix_tp = {
+	PyObject_HEAD_INIT(NULL)
+	0,
+	"cvxopt.base.matrix",
+	sizeof(matrix),
+	0,
+	(destructor)matrix_dealloc,	        /* tp_dealloc */
+	0,	               	                /* tp_print */
+	0,					/* tp_getattr */
+	0,					/* tp_setattr */
+	0,					/* tp_compare */
+	(reprfunc)matrix_repr,	                /* tp_repr */
+	&matrix_as_number,			/* tp_as_number */
+	0,	                                /* tp_as_sequence */
+	&matrix_as_mapping,   	                /* tp_as_mapping */
+	0,					/* tp_hash */
+	0,					/* tp_call */
+	(reprfunc)matrix_str,			/* tp_str */
+	0,		                        /* tp_getattro */
+	0,			                /* tp_setattro */
+	0,			                /* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | 
+	Py_TPFLAGS_CHECKTYPES,                  /* tp_flags */
+	0,					/* tp_doc */
+	0,					/* tp_traverse */
+	0,					/* tp_clear */
+	0,	      		                /* tp_richcompare */
+	0,					/* tp_weaklistoffset */
+	(getiterfunc)matrix_iter,		/* tp_iter */
+	0,	       	                        /* tp_iternext */
+	matrix_methods,		                /* tp_methods */
+	0,			        	/* tp_members */
+	matrix_getsets,			        /* tp_getset */
+	0,		                        /* tp_base */
+	0,					/* tp_dict */
+	0,					/* tp_descr_get */
+	0,					/* tp_descr_set */
+	0,					/* tp_dictoffset */
+	0,                                      /* tp_init */
+	0,              			/* tp_alloc */
+	matrix_new,				/* tp_new */
+	0,           				/* tp_free */
+};
+
+/**************************************************************************/
+
+static PyObject *
+matrix_add_generic(PyObject *self, PyObject *other, int inplace) 
+{
+  if (!(Matrix_Check(self) || PY_NUMBER(self)) || 
+      !(Matrix_Check(other) || PY_NUMBER(other))) {
+    Py_INCREF(Py_NotImplemented);
+    return Py_NotImplemented;
+  }
+
+  int id_self = get_id(self, (Matrix_Check(self) ? 0 : 1));
+  int id_other = get_id(other, (Matrix_Check(other) ? 0 : 1));
+  int id = MAX(id_self,id_other);    
+
+  if (inplace && (id != id_self || (MAT_LGT(self)==1 && 
+	      (Matrix_Check(other) && MAT_LGT(other)!=1))))
+      PY_ERR_TYPE("invalid inplace operation");
+
+  /* first operand is a scalar */
+  if (PY_NUMBER(self) || (Matrix_Check(self) && MAT_LGT(self)==1)) 
+  {          
+    number n;     
+    if (!inplace) { 
+      convert_num[id](&n,self,(Matrix_Check(self) ? 0 : 1),0);
+      
+      matrix *ret = Matrix_NewFromMatrix((matrix *)other, id);
+      if (!ret) return PyErr_NoMemory();
+
+      int lgt = MAT_LGT(ret), int1 = 1, int0 = 0;
+      axpy[id](&lgt, &One[id], &n, &int0, ret->buffer, &int1);
+      return (PyObject *)ret;
+    }
+    else {
+      convert_num[id](&n,other,(Matrix_Check(other) ? 0 : 1),0);
+
+      int int1 = 1, int0 = 0;
+      axpy[id](&int1, &One[id], &n, &int0, MAT_BUF(self), &int1);
+      
+      Py_INCREF(self);
+      return self;
+    }    
+  }
+  /* second operand is a scalar */
+  else if (PY_NUMBER(other) || (Matrix_Check(other) && 
+	  MAT_LGT(other)==1))       
+  {
+    number n;
+    convert_num[id](&n,other,(Matrix_Check(other) ? 0 : 1),0);
+    
+    if (!inplace) {      
+      matrix *ret = Matrix_NewFromMatrix((matrix *)self, id);
+      if (!ret) return PyErr_NoMemory();
+
+      int lgt = MAT_LGT(self), int1 = 1, int0 = 0;
+      axpy[id](&lgt, &One[id], &n, &int0, ret->buffer, &int1);
+
+      return (PyObject *)ret;
+    }
+    else {
+      int lgt = MAT_LGT(self), int1 = 1, int0 = 0;
+      axpy[id](&lgt, &One[id], &n, &int0, MAT_BUF(self), &int1);
+      
+      Py_INCREF(self);
+      return self;
+    }    
+  }
+  else { /* adding two matrices */     
+    if (MAT_NROWS(self) != MAT_NROWS(other) ||
+	MAT_NCOLS(self) != MAT_NCOLS(other))
+      PY_ERR_TYPE("incompatible dimensions");
+    
+    void *other_coerce = convert_mtx_alloc((matrix *)other, id);
+    if (!other_coerce) return PyErr_NoMemory();
+
+    if (!inplace) {
+      matrix *ret = Matrix_NewFromMatrix((matrix *)self, id);
+      if (!ret) return PyErr_NoMemory();
+            
+      int lgt = MAT_LGT(self), int1 = 1;
+      axpy[id](&lgt, &One[id], other_coerce, &int1, MAT_BUF(ret), &int1); 
+
+      if (MAT_BUF(other) != other_coerce) { free(other_coerce); }
+      return (PyObject *)ret;
+    } 
+    else {
+      int lgt = MAT_LGT(self), int1 = 1;
+      axpy[id](&lgt, &One[id], other_coerce, &int1, MAT_BUF(self), &int1); 
+      
+      if (MAT_BUF(other) != other_coerce) { free(other_coerce); }      
+
+      Py_INCREF(self);
+      return self;      
+    }
+  }
+}
+
+PyObject * matrix_add(PyObject *self, PyObject *other) 
+{
+  return matrix_add_generic(self, other, 0);
+}
+
+static PyObject * matrix_iadd(PyObject *self,PyObject *other)
+{  
+  return matrix_add_generic(self, other, 1);
+}
+
+static PyObject *
+matrix_sub_generic(PyObject *self, PyObject *other, int inplace) 
+{
+  if (!(Matrix_Check(self) || PY_NUMBER(self)) || 
+      !(Matrix_Check(other) || PY_NUMBER(other))) {
+    Py_INCREF(Py_NotImplemented);
+    return Py_NotImplemented;
+  }
+
+  int id_self = get_id(self, (Matrix_Check(self) ? 0 : 1));
+  int id_other = get_id(other, (Matrix_Check(other) ? 0 : 1));
+  int id = MAX(id_self,id_other);    
+  
+  if (inplace && (id != id_self || (MAT_LGT(self)==1 && 
+	      (Matrix_Check(other) && MAT_LGT(other)!=1))))
+      PY_ERR_TYPE("invalid inplace operation");
+
+  /* first operand is a scalar */
+  if (PY_NUMBER(self) || (Matrix_Check(self) && MAT_LGT(self)==1)) 
+  {          
+
+    number n;    
+    if (!inplace) {      
+      convert_num[id](&n,self,(Matrix_Check(self) ? 0 : 1),0);
+      
+      matrix *ret = Matrix_NewFromMatrix((matrix *)other, id);
+      if (!ret) return PyErr_NoMemory();
+
+      int lgt = MAT_LGT(ret), int1 = 1, int0 = 0;
+      scal[id](&lgt, &MinusOne[id], ret->buffer, &int1);
+      axpy[id](&lgt, &One[id], &n, &int0, ret->buffer, &int1);
+      return (PyObject *)ret;
+    }
+    else {       
+      convert_num[id](&n,other,(Matrix_Check(other) ? 0 : 1),0);
+
+      int int1 = 1, int0 = 0;
+      axpy[id](&int1, &MinusOne[id], &n, &int0, MAT_BUF(self), &int1);
+      
+      Py_INCREF(self);
+      return self;      
+    }    
+  }
+  /* second operand is a scalar */
+  else if (PY_NUMBER(other) || (Matrix_Check(other) &&  MAT_LGT(other)==1)) 
+  {
+    number n;
+    convert_num[id](&n,other,(Matrix_Check(other) ? 0 : 1),0);
+    
+    if (!inplace) {      
+      matrix *ret = Matrix_NewFromMatrix((matrix *)self, id);
+      if (!ret) return PyErr_NoMemory();
+
+      int lgt = MAT_LGT(self), int1 = 1, int0 = 0;
+      axpy[id](&lgt, &MinusOne[id], &n, &int0, ret->buffer, &int1);
+
+      return (PyObject *)ret;
+    }
+    else {
+      int lgt = MAT_LGT(self), int1 = 1, int0 = 0;
+      axpy[id](&lgt, &MinusOne[id], &n, &int0, MAT_BUF(self), &int1);
+      
+      Py_INCREF(self);
+      return self;
+    }    
+  }
+  else { /* subtracting two matrices */     
+    if (MAT_NROWS(self) != MAT_NROWS(other) ||
+	MAT_NCOLS(self) != MAT_NCOLS(other))
+      PY_ERR_TYPE("incompatible dimensions");
+    
+    void *other_coerce = convert_mtx_alloc((matrix *)other, id);
+    if (!other_coerce) return PyErr_NoMemory();
+
+    if (!inplace) {
+      matrix *ret = Matrix_NewFromMatrix((matrix *)self, id);
+      if (!ret) return PyErr_NoMemory();
+            
+      int lgt = MAT_LGT(self), int1 = 1;
+      axpy[id](&lgt, &MinusOne[id], other_coerce, &int1, MAT_BUF(ret), &int1); 
+
+      if (MAT_BUF(other) != other_coerce) { free(other_coerce); }
+      return (PyObject *)ret;
+    } 
+    else {
+      int lgt = MAT_LGT(self), int1 = 1;
+      axpy[id](&lgt,&MinusOne[id],other_coerce,&int1,MAT_BUF(self),&int1); 
+            
+      if (MAT_BUF(other) != other_coerce) { free(other_coerce); }      
+      
+      Py_INCREF(self);
+      return self;      
+    }
+  }
+}
+
+PyObject * matrix_sub(PyObject *self, PyObject *other) 
+{
+  return matrix_sub_generic(self, other, 0);
+}
+
+static PyObject * matrix_isub(PyObject *self,PyObject *other)
+{
+  return matrix_sub_generic(self, other, 1);
+}
+
+static PyObject * 
+matrix_mul_generic(PyObject *self, PyObject *other, int inplace) 
+{
+
+  if (!(Matrix_Check(self) || PY_NUMBER(self)) || 
+      !(Matrix_Check(other) || PY_NUMBER(other))) {
+    Py_INCREF(Py_NotImplemented);
+    return Py_NotImplemented;
+  }
+
+  int id_self = get_id(self, (Matrix_Check(self) ? 0 : 1));
+  int id_other = get_id(other, (Matrix_Check(other) ? 0 : 1));
+  int id = MAX(id_self,id_other);    
+
+  if (inplace && (id != id_self || (MAT_LGT(self)==1 && 
+	      (Matrix_Check(other) && MAT_LGT(other)!=1)) ||
+	  (MAT_LGT(self)>1 && (Matrix_Check(other) && MAT_LGT(other)>1))) )
+    PY_ERR_TYPE("invalid inplace operation");
+
+  /* first operand is a scalar */
+  if (PY_NUMBER(self) || (Matrix_Check(self) && MAT_LGT(self)==1)) 
+  {          
+    number n;
+    if (!inplace) {
+      convert_num[id](&n,self,(Matrix_Check(self) ? 0 : 1),0);
+    
+      matrix *ret = Matrix_NewFromMatrix((matrix *)other, id);      
+      if (!ret) return PyErr_NoMemory();
+
+      int lgt = MAT_LGT(ret), int1 = 1;
+      scal[id](&lgt, &n, ret->buffer, &int1);
+      return (PyObject *)ret;
+    }
+    else {
+      convert_num[id](&n,other,(Matrix_Check(other) ? 0 : 1),0);
+
+      int int1 = 1;
+      scal[id](&int1, &n, MAT_BUF(self), &int1);
+
+      Py_INCREF(self);
+      return self;
+    }    
+  }
+  /* second operand is a scalar */
+  else if (PY_NUMBER(other) || (Matrix_Check(other) && 
+	  MAT_LGT(other)==1))       
+  {
+    number n;
+    convert_num[id](&n,other,(Matrix_Check(other) ? 0 : 1),0);
+    
+    if (!inplace) {      
+      matrix *ret = Matrix_NewFromMatrix((matrix *)self, id); 
+      if (!ret) return PyErr_NoMemory();
+
+      int lgt = MAT_LGT(self), int1 = 1;
+      scal[id](&lgt, &n, ret->buffer, &int1);
+      return (PyObject *)ret;
+    }
+    else {
+      int lgt = MAT_LGT(self), int1 = 1;
+      scal[id](&lgt, &n, MAT_BUF(self), &int1);
+
+      Py_INCREF(self);
+      return self;
+    }    
+  }
+  else { /* multiplying two matrices */       
+    if (MAT_NCOLS(self) != MAT_NROWS(other)) 
+      PY_ERR_TYPE("incompatible dimensions");
+    
+    int m = MAT_NROWS(self), n = MAT_NCOLS(other), k = MAT_NCOLS(self);
+    
+    int ldA = MAX(1,MAT_NROWS(self));
+    int ldB = MAX(1,MAT_NROWS(other));
+    int ldC = MAX(1,MAT_NROWS(self));
+    char transA='N', transB='N';
+
+    void *self_coerce = convert_mtx_alloc((matrix *)self, id);
+    if (!self_coerce) return PyErr_NoMemory();
+
+    void *other_coerce = convert_mtx_alloc((matrix *)other, id);
+    if (!other_coerce) { 
+      if (MAT_ID(self) != id) { free(self_coerce); }
+      return PyErr_NoMemory(); 
+    }
+
+    matrix *c = Matrix_New(m, n, id);
+    if (!c) {
+      if (MAT_ID(self) != id)  { free(self_coerce); }
+      if (MAT_ID(other) != id) { free(other_coerce); }
+      return PyErr_NoMemory(); 
+    }
+      
+    gemm[id](&transA, &transB, &m, &n, &k, &One[id], self_coerce, 
+	&ldA, other_coerce, &ldB, &Zero[id], MAT_BUF(c), &ldC);
+
+    if (MAT_ID(self) != id)  { free(self_coerce); }
+    if (MAT_ID(other) != id) { free(other_coerce); }      
+    return (PyObject *)c;
+  }
+}
+
+static PyObject * matrix_mul(PyObject *self, PyObject *other) 
+{
+  return matrix_mul_generic(self, other, 0);
+}
+
+static PyObject * matrix_imul(PyObject *self,PyObject *other)
+{
+  return matrix_mul_generic(self, other, 1);
+}
+
+static PyObject * 
+matrix_div_generic(PyObject *self, PyObject *other, int inplace) 
+{
+  if (!((Matrix_Check(other) && MAT_LGT(other)==1) || PY_NUMBER(other))) {
+    Py_INCREF(Py_NotImplemented);
+    return Py_NotImplemented;
+  }
+
+  int id_self = get_id(self, (Matrix_Check(self) ? 0 : 1));
+  int id_other = get_id(other, (Matrix_Check(other) ? 0 : 1));
+  int id = MAX(id_self,id_other);    
+
+  number n;
+  convert_num[id](&n,other,(Matrix_Check(other) ? 0 : 1),0);
+    
+  if (!inplace) {      
+    matrix *ret = Matrix_NewFromMatrix((matrix *)self, id); 
+    if (!ret) return PyErr_NoMemory();
+
+    int lgt = MAT_LGT(ret);
+    if (div_array[id](ret->buffer, n, lgt)) { Py_DECREF(ret); return NULL; }
+    return (PyObject *)ret;
+  }
+  else {
+    if (id != id_self) PY_ERR_TYPE("invalid inplace operation");
+  
+    if (div_array[id](MAT_BUF(self), n, MAT_LGT(self)))  
+      return NULL; 
+    
+    Py_INCREF(self);
+    return self;
+  }    
+}
+
+static PyObject * matrix_div(PyObject *self, PyObject *other) 
+{
+  return matrix_div_generic(self, other, 0);
+}
+
+static PyObject * matrix_idiv(PyObject *self,PyObject *other)
+{
+  return matrix_div_generic(self, other, 1);
+}
+
+static PyObject *
+matrix_rem_generic(PyObject *self, PyObject *other, int inplace) 
+{
+  if (!((Matrix_Check(other) && MAT_LGT(other)==1) || PY_NUMBER(other))) {
+    Py_INCREF(Py_NotImplemented);
+    return Py_NotImplemented;
+  }
+
+  int id_self = get_id(self, (Matrix_Check(self) ? 0 : 1));
+  int id_other = get_id(other, (Matrix_Check(other) ? 0 : 1));
+  int id = MAX(id_self,id_other);    
+
+  if (id == COMPLEX) PY_ERR(PyExc_NotImplementedError, "complex modulo");  
+  
+  number n;
+  convert_num[id](&n,other,(Matrix_Check(other) ? 0 : 1),0);
+  
+  if (!inplace) {      
+    matrix *ret = Matrix_NewFromMatrix((matrix *)self, id); 
+    if (!ret) return PyErr_NoMemory();
+    
+    int lgt = MAT_LGT(ret);
+    if (mtx_rem[id](ret->buffer, n, lgt)) { Py_DECREF(ret); return NULL; }
+    return (PyObject *)ret;
+  }
+  else {
+    void *ptr = convert_mtx_alloc((matrix *)self, id);
+    if (!ptr) return PyErr_NoMemory();
+    
+    int lgt = MAT_LGT(self);
+    if (mtx_rem[id](ptr,n,lgt)) { free(ptr); return NULL; }
+    
+    free_convert_mtx_alloc(self, ptr, id);
+    Py_INCREF(self);
+    return self;
+  }      
+}
+
+static PyObject * matrix_rem(PyObject *self, PyObject *other)
+{
+  return matrix_rem_generic(self, other, 0);
+}
+
+static PyObject * matrix_irem(PyObject *self, PyObject *other)
+{
+  return matrix_rem_generic(self, other, 1);
+}
+
+static PyObject * matrix_neg(matrix *self)
+{
+  matrix *x = Matrix_NewFromMatrix(self,self->id);
+  if (!x) return PyErr_NoMemory();
+  
+  int n = MAT_LGT(x), int1 = 1;
+  scal[x->id](&n, &MinusOne[x->id], x->buffer, &int1);
+  
+  return (PyObject *)x;
+}
+
+static PyObject * matrix_pos(matrix *self)
+{
+  matrix *x = Matrix_NewFromMatrix(self, self->id);
+  if (!x) return PyErr_NoMemory();
+  
+  return (PyObject *)x;
+}
+
+static PyObject * matrix_abs(matrix *self)
+{ 
+  matrix *ret = Matrix_New(self->nrows, self->ncols,
+      (self->id == COMPLEX ? DOUBLE : self->id));
+
+  if (!ret) return PyErr_NoMemory();
+
+  mtx_abs[self->id](MAT_BUF(self), MAT_BUF(ret), MAT_LGT(self));
+  return (PyObject *)ret;
+}
+
+static PyObject * matrix_pow(PyObject *self, PyObject *other) 
+{
+  if (!PY_NUMBER(other)) PY_ERR_TYPE("exponent must be a number");
+  
+  number val;
+  int id = MAX(DOUBLE, MAX(MAT_ID(self), get_id(other, 1)));
+  convert_num[id](&val, other, 1, 0); 
+  matrix *Y = Matrix_NewFromMatrix((matrix *)self, id);
+  if (!Y) return PyErr_NoMemory();
+
+  int i;
+  for (i=0; i<MAT_LGT(Y); i++) {
+    if (id == DOUBLE) {
+      if ((MAT_BUFD(Y)[i] == 0.0 && val.d < 0.0) || 
+	  (MAT_BUFD(Y)[i] < 0.0 && val.d < 1.0 && val.d > 0.0)) {
+	Py_DECREF(Y);
+	PY_ERR(PyExc_ValueError, "domain error");
+      }
+
+
+      MAT_BUFD(Y)[i] = pow(MAT_BUFD(Y)[i], val.d);
+    } else {
+      if (MAT_BUFZ(Y)[i] == 0.0 && (cimag(val.z) != 0.0 || creal(val.z)<0.0)) {
+	Py_DECREF(Y);
+	PY_ERR(PyExc_ValueError, "domain error");
+      }
+      MAT_BUFZ(Y)[i] = cpow(MAT_BUFZ(Y)[i], val.z);
+    }    
+  }
+  
+  return (PyObject *)Y;
+}
+
+
+static PyNumberMethods matrix_as_number = {
+	(binaryfunc)matrix_add,	/*nb_add*/
+	(binaryfunc)matrix_sub,	/*nb_subtract*/
+	(binaryfunc)matrix_mul,	/*nb_multiply*/
+	(binaryfunc)matrix_div, /*nb_divide*/
+	(binaryfunc)matrix_rem, /*nb_remainder*/
+	0,	                /*nb_divmod*/
+	(ternaryfunc)matrix_pow, /*nb_power*/
+	(unaryfunc)matrix_neg,	/*nb_negative*/
+	(unaryfunc)matrix_pos,	/*nb_positive*/
+	(unaryfunc)matrix_abs,	/*nb_absolute*/
+	0,	                /*nb_nonzero*/
+	0,	                /*nb_invert*/
+	0,	                /*nb_lshift*/
+	0,	                /*nb_rshift*/
+	0,	                /*nb_and*/
+	0,	                /*nb_xor*/
+	0,	                /*nb_or*/
+	0,		        /*nb_coerce*/
+	0,	                /*nb_int*/
+	0,	                /*nb_long*/
+	0,                      /*nb_float*/
+	0,	                /*nb_oct*/
+	0, 	                /*nb_hex*/
+	(binaryfunc)matrix_iadd,/*nb_inplace_add*/
+	(binaryfunc)matrix_isub,/*nb_inplace_subtract*/
+	(binaryfunc)matrix_imul,/*nb_inplace_multiply*/
+	(binaryfunc)matrix_idiv,/*nb_inplace_divide*/
+	(binaryfunc)matrix_irem,/*nb_inplace_remainder*/
+	0,			/*nb_inplace_power*/
+	0,			/*nb_inplace_lshift*/
+	0,			/*nb_inplace_rshift*/
+	0,			/*nb_inplace_and*/
+	0,			/*nb_inplace_xor*/
+	0,			/*nb_inplace_or*/
+	0,	                /*nb_floor_divide*/
+	0,	                /*nb_true_divide*/
+	0,			/*nb_inplace_floor_divide*/
+	0,			/*nb_inplace_true_divide*/
+};
+
+
+/*********************** Iterator **************************/
+
+typedef struct {
+  PyObject_HEAD
+  long index;
+  matrix *mObj;   
+} matrixiter;
+
+static PyTypeObject matrixiter_tp;
+
+#define MatrixIter_Check(O) PyObject_TypeCheck(O, &matrixiter_tp)
+
+static PyObject *
+matrix_iter(matrix *obj)
+{
+  matrixiter *it;
+  
+  if (!Matrix_Check(obj)) {
+    PyErr_BadInternalCall();
+    return NULL;
+  }
+
+  it = PyObject_GC_New(matrixiter, &matrixiter_tp);
+  if (!it) return NULL;
+
+  matrixiter_tp.tp_iter = PyObject_SelfIter;
+  matrixiter_tp.tp_getattro = PyObject_GenericGetAttr;
+
+  Py_INCREF(obj);
+  it->index = 0;
+  it->mObj = obj;
+  PyObject_GC_Track(it);
+
+  return (PyObject *)it;
+}
+
+static void
+matrixiter_dealloc(matrixiter *it)
+{
+  PyObject_GC_UnTrack(it);
+  Py_XDECREF(it->mObj);
+  PyObject_GC_Del(it);
+}
+
+static int
+matrixiter_traverse(matrixiter *it, visitproc visit, void *arg)
+{
+  if (it->mObj == NULL)
+    return 0;
+
+  return visit((PyObject *)(it->mObj), arg);
+}
+
+static PyObject *
+matrixiter_next(matrixiter *it)
+{
+  assert(MatrixIter_Check(it));
+  if (it->index >= MAT_LGT(it->mObj))
+    return NULL;
+  
+  return num2PyObject[it->mObj->id](it->mObj->buffer, it->index++);
+}
+
+static PyTypeObject matrixiter_tp = {
+        PyObject_HEAD_INIT(NULL)
+	0,					/* ob_size */
+	"matrixiter",			        /* tp_name */
+	sizeof(matrixiter),      		/* tp_basicsize */
+	0,					/* tp_itemsize */
+	(destructor)matrixiter_dealloc,		/* tp_dealloc */
+	0,					/* tp_print */
+	0,					/* tp_getattr */
+	0,					/* tp_setattr */
+	0,					/* tp_compare */
+	0,					/* tp_repr */
+	0,					/* tp_as_number */
+	0,					/* tp_as_sequence */
+	0,					/* tp_as_mapping */
+	0,					/* tp_hash */
+	0,					/* tp_call */
+	0,					/* tp_str */
+	0,                      		/* tp_getattro */
+	0,					/* tp_setattro */
+	0,					/* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
+	0,					/* tp_doc */
+	(traverseproc)matrixiter_traverse,	/* tp_traverse */
+	0,					/* tp_clear */
+	0,					/* tp_richcompare */
+	0,					/* tp_weaklistoffset */
+	0,                  			/* tp_iter */
+	(iternextfunc)matrixiter_next,		/* tp_iternext */
+	0,					/* tp_methods */
+};
+
+
+
+PyObject * matrix_log(matrix *self, PyObject *args, PyObject *kwrds)
+{
+  PyObject *A;
+
+  if (!PyArg_ParseTuple(args, "O", &A)) return NULL;
+
+  if (PyInt_Check(A) || PyFloat_Check(A)) {
+    double f = PyFloat_AsDouble(A);
+    if (f>0.0)
+      return Py_BuildValue("d",log(f));
+    else 
+      PY_ERR(PyExc_ValueError, "domain error");
+  }
+  else if (PyComplex_Check(A)) {
+    number n;
+    convert_num[COMPLEX](&n, A, 1, 0);
+    
+    if (n.z == 0) PY_ERR(PyExc_ValueError, "domain error");
+
+    n.z = clog(n.z);
+    return num2PyObject[COMPLEX](&n, 0);    
+  }
+    
+  else if (Matrix_Check(A)  && (MAT_ID(A) == INT || MAT_ID(A) == DOUBLE)) {
+    if (MAT_LGT(A) == 0) 
+      return (PyObject *)Matrix_New(MAT_NROWS(A),MAT_NCOLS(A),DOUBLE);
+
+    double val = (MAT_ID(A) == INT ? MAT_BUFI(A)[0] : MAT_BUFD(A)[0]);
+
+    int i;      
+    for (i=1; i<MAT_LGT(A); i++) {
+      if (MAT_ID(A) == INT)
+	val = MIN(val,(MAT_BUFI(A)[i]));
+      else
+	val = MIN(val,(MAT_BUFD(A)[i]));
+    }
+
+    if (val > 0.0) {	
+      matrix *ret = Matrix_New(MAT_NROWS(A), MAT_NCOLS(A), DOUBLE);
+      if (!ret) return PyErr_NoMemory();
+      
+      for (i=0; i<MAT_LGT(A); i++)
+	MAT_BUFD(ret)[i] = log((MAT_ID(A)== INT ? 
+		MAT_BUFI(A)[i] : MAT_BUFD(A)[i]));
+
+      return (PyObject *)ret;
+    } 
+    else PY_ERR(PyExc_ValueError, "domain error");
+      
+  }
+  else if (Matrix_Check(A) && MAT_ID(A) == COMPLEX) {
+    matrix *ret = Matrix_New(MAT_NROWS(A), MAT_NCOLS(A), COMPLEX);
+    if (!ret) return PyErr_NoMemory();
+
+    int i;
+    for (i=0; i<MAT_LGT(A); i++) {
+      if (MAT_BUFZ(A)[i] == 0) {
+	Py_DECREF(ret);
+	PY_ERR(PyExc_ValueError, "domain error");
+      }
+      MAT_BUFZ(ret)[i] = clog(MAT_BUFZ(A)[i]);    
+    }
+    return (PyObject *)ret;
+  }
+  else PY_ERR_TYPE("argument must a be a number or dense matrix");
+}
+
+PyObject * matrix_exp(matrix *self, PyObject *args, PyObject *kwrds)
+{
+  PyObject *A;
+
+  if (!PyArg_ParseTuple(args, "O", &A)) return NULL;
+
+  if (PyInt_Check(A) || PyFloat_Check(A)) 
+    return Py_BuildValue("d",exp(PyFloat_AsDouble(A)));
+
+  else if (PyComplex_Check(A)) {
+    number n;
+    convert_num[COMPLEX](&n, A, 1, 0);
+    n.z = cexp(n.z);
+    return num2PyObject[COMPLEX](&n, 0);    
+  }
+    
+  else if (Matrix_Check(A)) {
+    matrix *ret = Matrix_New(MAT_NROWS(A),MAT_NCOLS(A),
+	(MAT_ID(A) == COMPLEX ? COMPLEX : DOUBLE));
+    if (!ret) return PyErr_NoMemory();
+      
+    int i;
+    if (MAT_ID(ret) == DOUBLE) 
+      for (i=0; i<MAT_LGT(ret); i++)
+	MAT_BUFD(ret)[i] = exp(MAT_ID(A) == DOUBLE ? MAT_BUFD(A)[i] :
+	    MAT_BUFI(A)[i]);
+    else 
+      for (i=0; i<MAT_LGT(ret); i++)
+	MAT_BUFZ(ret)[i] = cexp(MAT_BUFZ(A)[i]);
+
+    return (PyObject *)ret;
+  }
+  else PY_ERR_TYPE("argument must a be a number or dense matrix");
+}
+
+PyObject * matrix_sqrt(matrix *self, PyObject *args, PyObject *kwrds)
+{
+  PyObject *A;
+
+  if (!PyArg_ParseTuple(args, "O", &A)) return NULL;
+
+  if (PyInt_Check(A) || PyFloat_Check(A)) {
+    double f = PyFloat_AsDouble(A);
+    if (f >= 0.0)
+      return Py_BuildValue("d",sqrt(f));
+    else PY_ERR(PyExc_ValueError, "domain error");
+  }
+  else if (PyComplex_Check(A)) {
+    number n;
+    convert_num[COMPLEX](&n, A, 1, 0);
+    n.z = csqrt(n.z);
+    return num2PyObject[COMPLEX](&n, 0);    
+  }  
+  else if (Matrix_Check(A) && (MAT_ID(A) == INT || MAT_ID(A) == DOUBLE)) {
+    if (MAT_LGT(A) == 0) 
+      return (PyObject *)Matrix_New(MAT_NROWS(A),MAT_NCOLS(A),DOUBLE);
+
+    double val = (MAT_ID(A) == INT ? MAT_BUFI(A)[0] : MAT_BUFD(A)[0]);
+
+    int i;      
+    for (i=1; i<MAT_LGT(A); i++) {
+      if (MAT_ID(A) == INT)
+	val = MIN(val,(MAT_BUFI(A)[i]));
+      else
+	val = MIN(val,(MAT_BUFD(A)[i]));
+    }
+
+    if (val >= 0.0) {	
+      matrix *ret = Matrix_New(MAT_NROWS(A), MAT_NCOLS(A), DOUBLE);
+      if (!ret) return PyErr_NoMemory();
+      
+      for (i=0; i<MAT_LGT(A); i++)
+	MAT_BUFD(ret)[i] = sqrt((MAT_ID(A)== INT ? 
+		MAT_BUFI(A)[i] : MAT_BUFD(A)[i]));
+
+      return (PyObject *)ret;
+      
+    } 
+    else PY_ERR(PyExc_ValueError, "domain error");
+  }
+  else if (Matrix_Check(A) && MAT_ID(A) == COMPLEX) {
+    matrix *ret = Matrix_New(MAT_NROWS(A), MAT_NCOLS(A), COMPLEX);
+    if (!ret) return PyErr_NoMemory();
+
+    int i;
+    for (i=0; i<MAT_LGT(A); i++) 
+      MAT_BUFZ(ret)[i] = csqrt(MAT_BUFZ(A)[i]);    
+
+    return (PyObject *)ret;
+  }
+  else PY_ERR_TYPE("argument must a be a number or dense matrix");
+}
+
+PyObject * matrix_cos(matrix *self, PyObject *args, PyObject *kwrds)
+{
+  PyObject *A;
+
+  if (!PyArg_ParseTuple(args, "O", &A)) return NULL;
+
+  if (PyInt_Check(A) || PyFloat_Check(A)) 
+    return Py_BuildValue("d",cos(PyFloat_AsDouble(A)));
+
+  else if (PyComplex_Check(A)) {
+    number n;
+    convert_num[COMPLEX](&n, A, 1, 0);
+    n.z = ccos(n.z);
+    return num2PyObject[COMPLEX](&n, 0);    
+  }
+    
+  else if (Matrix_Check(A)) {
+    matrix *ret = Matrix_New(MAT_NROWS(A),MAT_NCOLS(A),
+	(MAT_ID(A) == COMPLEX ? COMPLEX : DOUBLE));
+    if (!ret) return PyErr_NoMemory();
+      
+    int_t i;
+    if (MAT_ID(ret) == DOUBLE) 
+      for (i=0; i<MAT_LGT(ret); i++)
+	MAT_BUFD(ret)[i] = cos(MAT_ID(A) == DOUBLE ? MAT_BUFD(A)[i] :
+	    MAT_BUFI(A)[i]);
+    else 
+      for (i=0; i<MAT_LGT(ret); i++)
+	MAT_BUFZ(ret)[i] = ccos(MAT_BUFZ(A)[i]);
+
+    return (PyObject *)ret;
+  }
+  else PY_ERR_TYPE("argument must a be a number or dense matrix");
+}
+
+PyObject * matrix_sin(matrix *self, PyObject *args, PyObject *kwrds)
+{
+  PyObject *A;
+
+  if (!PyArg_ParseTuple(args, "O", &A)) return NULL;
+
+  if (PyInt_Check(A) || PyFloat_Check(A)) 
+    return Py_BuildValue("d",sin(PyFloat_AsDouble(A)));
+
+  else if (PyComplex_Check(A)) {
+    number n;
+    convert_num[COMPLEX](&n, A, 1, 0);
+    n.z = csin(n.z);
+    return num2PyObject[COMPLEX](&n, 0);    
+  }
+    
+  else if (Matrix_Check(A)) {
+    matrix *ret = Matrix_New(MAT_NROWS(A),MAT_NCOLS(A),
+	(MAT_ID(A) == COMPLEX ? COMPLEX : DOUBLE));
+    if (!ret) return PyErr_NoMemory();
+      
+    int_t i;
+    if (MAT_ID(ret) == DOUBLE) 
+      for (i=0; i<MAT_LGT(ret); i++)
+	MAT_BUFD(ret)[i] = sin(MAT_ID(A) == DOUBLE ? MAT_BUFD(A)[i] :
+	    MAT_BUFI(A)[i]);
+    else 
+      for (i=0; i<MAT_LGT(ret); i++)
+	MAT_BUFZ(ret)[i] = csin(MAT_BUFZ(A)[i]);
+
+    return (PyObject *)ret;
+  }
+  else PY_ERR_TYPE("argument must a be a number or dense matrix");
+}
+
+PyObject * matrix_elem_mul(matrix *self, PyObject *args, PyObject *kwrds)
+{
+  matrix *A, *B;
+
+  if (!PyArg_ParseTuple(args, "OO", &A, &B)) return NULL;
+
+  if (!Matrix_Check(A) || !Matrix_Check(B) || MAT_ID(A) != MAT_ID(B))
+    PY_ERR_TYPE("arguments must be matrices of same type");
+
+  if (MAT_NROWS(A) != MAT_NROWS(B) || MAT_NCOLS(A) != MAT_NCOLS(B))
+    PY_ERR_TYPE("arguments must have same dimensions");
+
+  matrix *ret = Matrix_New(MAT_NROWS(A), MAT_NCOLS(A), MAT_ID(A));
+  if (!ret) return PyErr_NoMemory();
+
+  int i;
+  for (i=0; i<MAT_LGT(A); i++) {
+    switch (MAT_ID(A)) {
+    case INT: MAT_BUFI(ret)[i] = MAT_BUFI(A)[i]*MAT_BUFI(B)[i]; break;
+    case DOUBLE: MAT_BUFD(ret)[i] = MAT_BUFD(A)[i]*MAT_BUFD(B)[i]; break;
+    case COMPLEX: MAT_BUFZ(ret)[i] = MAT_BUFZ(A)[i]*MAT_BUFZ(B)[i]; break;    
+    }    
+  }
+  
+  return (PyObject *)ret;
+}
+
+PyObject * matrix_elem_div(matrix *self, PyObject *args, PyObject *kwrds)
+{
+  matrix *A, *B;
+
+  if (!PyArg_ParseTuple(args, "OO", &A, &B)) return NULL;
+
+  if (!Matrix_Check(A) || !Matrix_Check(B) || MAT_ID(A) != MAT_ID(B))
+    PY_ERR_TYPE("arguments must be matrices of same type");
+
+  if (MAT_NROWS(A) != MAT_NROWS(B) || MAT_NCOLS(A) != MAT_NCOLS(B))
+    PY_ERR_TYPE("arguments must have same dimensions");
+
+  matrix *ret = Matrix_New(MAT_NROWS(A), MAT_NCOLS(A), MAT_ID(A));
+  if (!ret) return PyErr_NoMemory();
+
+  int i;
+  for (i=0; i<MAT_LGT(A); i++) {
+    switch (MAT_ID(A)) {
+    case INT: 
+      if (MAT_BUFI(B)[i] == 0) goto divzero;
+      MAT_BUFI(ret)[i] = MAT_BUFI(A)[i]/MAT_BUFI(B)[i]; break;
+    case DOUBLE: 
+      if (MAT_BUFD(B)[i] == 0.0) goto divzero;
+      MAT_BUFD(ret)[i] = MAT_BUFD(A)[i]/MAT_BUFD(B)[i]; break;
+    case COMPLEX: 
+      if (MAT_BUFZ(B)[i] == 0.0) goto divzero;
+      MAT_BUFZ(ret)[i] = MAT_BUFZ(A)[i]/MAT_BUFZ(B)[i]; break;    
+    }    
+  }
+  
+  return (PyObject *)ret;
+
+ divzero:
+  Py_DECREF(ret);
+  PY_ERR(PyExc_ArithmeticError, "division by zero");
+}
+
diff --git a/src/C/dsdp.c b/src/C/dsdp.c
new file mode 100644
index 0000000..0f120d9
--- /dev/null
+++ b/src/C/dsdp.c
@@ -0,0 +1,437 @@
+/*
+ * This file is part of CVXOPT version 0.8.2.
+ * Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+ */
+
+#include "cvxopt.h"
+#include "misc.h"
+#include "dsdp5.h"
+#include "math.h"
+
+PyDoc_STRVAR(dsdp__doc__,"Interface to DSDP version 5.8.\n\n"
+    "Software for Semidefinite Programming.\n\n"
+    "Three control parameters can be modified by making an entry in \n"
+    "dictionary dsdp.options:\n"
+    "    options['DSDP_Monitor']: set to k in order to show \n"
+    "        progress after every kth iteration (default: 0). \n"
+    "    options['DSDP_MaxIts']:  maximum number of iterations\n"
+    "    options['DSDP_GapTolerance']: the relative tolerance used\n"
+    "        in the exit condition (default: 1e-5).\n\n"
+    "DSDSP is available from www-unix.mcs.anl.gov/DSDP.");
+
+static  PyObject *dsdp_module;
+
+static char doc_dsdp[] = 
+    "Solves a semidefinite program using DSDP.\n\n"
+    "(status, x, r, zl, zs) = sdp(c, Gl=None, hl=None, Gs=None, hs=None"
+    ",\n"
+    "                             gamma=1e8, beta=1e7)"
+    "\n\n"
+    "PURPOSE\n"
+    "Solves the SDP\n\n"
+    "    minimize    c'*x + gamma*r\n"
+    "    subject to  Gl*x <= hl + r\n"
+    "                mat(Gs[k]*x) <= hs[k] + r*I, k=1,...,L\n"
+    "                -beta <= x <= beta,  r >= 0\n\n"
+    "and its dual\n\n"
+    "    maximize    -hl'*zl - sum_k tr(hs[k]*zs[k]) - beta*||zb||_1\n"
+    "    subject to  Gl'*zl + sum_k Gs[k]'*vec(zs[k]) + zb + c = 0\n"
+    "                sum(zl) + sum_k tr(zs[k]) <= gamma \n"
+    "                zl >= 0,  zs[k] >=0, k=1,...,L. \n\n"
+    "For an mxm matrix y, vec(y) denotes the m^2-vector with the\n"
+    "entries of y stored columnwise.   mat(y) is the inverse\n"
+    "operation.\n\n"
+    "ARGUMENTS\n"
+    "c         n by 1 dense 'd' matrix\n\n" 
+    "Gl        ml by n dense or sparse 'd' matrixi.  The default\n"
+    "          value is a matrix with zero rows.\n\n"
+    "hl        ml by 1 dense 'd' matrix.  The default value is a\n"
+    "          vector of length zero.\n\n"
+    "Gs        list of L dense or sparse 'd' matrices.  If the kth\n"
+    "          linear matrix inequality has size mk, then Gs[k] is a\n"
+    "          matrix of size mk**2 by n, and mat(Gs[k][:,i]) is the\n"
+    "          coefficient of the ith variable i in inequality k.\n"
+    "          Only the lower triangular entries in mat(Gs[k][:,i])\n"
+    "          are accessed.  The default value of Gs is an empty list."
+    "\n\n"
+    "hs        list of L square dense 'd' matrices.  hs[k] is the\n"
+    "          righthand side in the kth linear matrix inequality.\n"
+    "          Only the lower triangular entries of hs[k] are\n"
+    "          accessed.  The default value of hs is an empty list.\n\n"
+    "beta      positive double\n\n"
+    "gamma     positive double\n\n"
+    "status    the DSDP solution status: 'DSDP_PDFEASIBLE', \n"
+    "          'DSDP_UNBOUNDED', 'DSDP_INFEASIBLE', or\n"
+    "          'DSDP_UNKNOWN'.\n\n"
+    "x         the primal solution, as a dense 'd' matrix of size\n"
+    "          n by 1\n\n"
+    "r         the optimal value of the variable r\n\n"
+    "zl        the dual solution as a dense 'd' matrix of size\n"
+    "          ml by 1\n\n"
+    "zs        the dual solution as a list of L square dense 'd'\n"
+    "          matrices.  Each matrix represents a symmetric matrix\n"
+    "          in unpacked lower triangular format.";
+
+
+typedef struct {     /* symmetric matrix X in DSDP packed storage */
+    int n;           /* order of X */
+    char issparse;
+    double *val;     /* lower triangular nonzeros of X.  Stored in row 
+                      * major order as an n*(n+1)/2-array if X is dense,
+                      * and in arbitrary order if X is sparse.*/
+    int *ind;        /* NULL if X is dense; otherwise, the indices of 
+                      *	the elements of val in the n*(n+1)/2 array of
+                      *	the lower triangular entries of X stored 
+                      *	rowwise. */
+    int nnz;         /* length of val */
+} dsdp_matrix;
+
+extern void dcopy_(int *n, double *x, int *incx, double *y, int *incy);
+
+static PyObject* solvesdp(PyObject *self, PyObject *args, 
+    PyObject *kwrds)
+{
+    matrix *c, *hl=NULL, *hk, *x=NULL, *zl=NULL, *zsk=NULL;
+    PyObject *Gl=NULL, *Gs=NULL, *hs=NULL, *Gk, *t=NULL, *zs=NULL,
+        *param, *key, *value;
+    int i, j, k, n, ml, l, mk, nnz, *lp_colptr=NULL, *lp_rowind=NULL,
+      incx, incy, lngth, maxm;
+    int_compat pos=0;
+    double *lp_values=NULL, *zlvals=NULL, *zk=NULL, r, beta=-1.0, 
+        gamma=-1.0, tol;
+    dsdp_matrix **lmis=NULL;
+    div_t qr;
+    DSDP sdp;
+    LPCone lpcone; 
+    SDPCone sdpcone; 
+    DSDPTerminationReason info;
+    DSDPSolutionType status;
+    char *keystr, err_str[100];
+    char *kwlist[] = {"c", "Gl", "hl", "Gs", "hs", "gamma", "beta", 
+        NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|OOOOdd", kwlist, 
+        &c, &Gl, &hl, &Gs, &hs, &gamma, &beta)) return NULL;
+
+
+
+    if (!Matrix_Check(c) || MAT_NCOLS(c) != 1 || MAT_ID(c) != DOUBLE)
+        PY_ERR_TYPE("c must be a dense 'd' matrix with one column");
+    n = MAT_NROWS(c);
+
+    if (Gl && ((!Matrix_Check(Gl) && !SpMatrix_Check(Gl)) || 
+        X_NCOLS(Gl) != n || X_ID(Gl) != DOUBLE))
+        PY_ERR_TYPE("invalid type or dimensions for Gl");
+    ml = Gl ? X_NROWS(Gl) : 0;
+    if ((!hl && ml) || (hl && (!Matrix_Check(hl) || MAT_NCOLS(hl) != 1 
+        || MAT_NROWS(hl) != ml || MAT_ID(hl) != DOUBLE)))
+        PY_ERR_TYPE("invalid type or dimensions for hl");
+
+    if (Gs && !PyList_Check(Gs)) PY_ERR_TYPE("Gs must be a list");
+    l = Gs ? PyList_Size(Gs) : 0;
+    if (hs && !PyList_Check(hs)) PY_ERR_TYPE("hs must be a list");
+    if ((!hs && l) || (hs && PyList_Size(hs) != l))
+        PY_ERR_TYPE("Gs and hs must be lists of equal length");
+    for (maxm=0, k=0; k<l; k++) {
+        Gk = PyList_GetItem(Gs, k); 
+        hk = (matrix *) PyList_GetItem(hs, k); 
+        if ((!Matrix_Check(Gk) && !SpMatrix_Check(Gk)) || 
+            X_ID(Gk) != DOUBLE)
+            PY_ERR_TYPE("Gs must be a list of 'd' matrices with n "
+                "columns");
+        if (!Matrix_Check(hk) || MAT_ID(hk) != DOUBLE ||
+            ((mk = MAT_NCOLS(hk)) != MAT_NROWS(hk)))
+            PY_ERR_TYPE("hs must be a list of square dense 'd' "
+                "matrices");
+        if (X_NROWS(Gk) != mk*mk || X_NCOLS(Gk) != n)
+            PY_ERR_TYPE("incompatible dimensions for elements of Gs");
+        maxm = MAX(mk, maxm);
+    }
+
+    if (DSDPCreate(n, &sdp) || DSDPCreateLPCone(sdp, &lpcone) || 
+        DSDPCreateSDPCone(sdp, l, &sdpcone)){ 
+        t = PyErr_NoMemory();
+        goto done;
+    }
+
+    if (!(param = PyObject_GetAttrString(dsdp_module, "options")) ||
+        !PyDict_Check(param)){
+	PyErr_SetString(PyExc_AttributeError, "missing dsdp.options "
+            " dictionary");
+	t = NULL;
+	goto done;
+    }
+    while (PyDict_Next(param, &pos, &key, &value))
+	if ((keystr = PyString_AsString(key))){
+	    if (!strcmp(keystr, "DSDP_Monitor")){
+		if (!PyInt_Check(value)) {
+                    sprintf(err_str, "invalid value for integer "
+			"DSDP parameter: DSDP_Monitor");
+		    PyErr_SetString(PyExc_ValueError, err_str);
+		    t = NULL;
+		    Py_DECREF(param);
+		    goto done;
+		}
+		else 
+		    DSDPSetStandardMonitor(sdp, PyInt_AsLong(value)); 
+	    }
+	    if (!strcmp(keystr, "DSDP_MaxIts")){
+		if (!PyInt_Check(value) || 
+                    (k = PyInt_AsLong(value)) < 0) {
+                    sprintf(err_str, "invalid value for nonnegative "
+                        "integer DSDP parameter: DSDP_MaxIts");
+		    PyErr_SetString(PyExc_ValueError, err_str);
+		    t = NULL;
+		    Py_DECREF(param);
+		    goto done;
+		}
+		else 
+		    DSDPSetMaxIts(sdp, k); 
+            }
+	    if (!strcmp(keystr, "DSDP_GapTolerance")){
+		if ((!PyFloat_Check(value) && !PyInt_Check(value)) || 
+                    (tol = PyFloat_AsDouble(value)) <= 0.0) {
+                    sprintf(err_str, "invalid value for float "
+                        "DSDP parameter: DSDP_GapTolerance");
+		    PyErr_SetString(PyExc_ValueError, err_str);
+		    t = NULL;
+		    Py_DECREF(param);
+		    goto done;
+		}
+		else 
+		    DSDPSetGapTolerance(sdp, tol); 
+           }
+        }
+    Py_DECREF(param);
+
+    if (gamma > 0) DSDPSetPenaltyParameter(sdp, gamma); 
+    if (beta > 0) DSDPSetYBounds(sdp, -beta, beta); 
+
+    /* cost function */
+    for (k=0; k<n; k++) DSDPSetDualObjective(sdp, k+1, -MAT_BUFD(c)[k]);
+
+    /* linear inequalities: store [Gl, hl] in CCS format */
+    nnz = ml ? ml + (Matrix_Check(Gl) ? ml*n : SP_NNZ(Gl)) : 0;
+    if (!(lp_colptr = (int *) calloc(n+2, sizeof(int))) ||
+        !(lp_rowind = (int *) calloc(nnz, sizeof(int))) ||
+        !(lp_values = (double *) calloc(nnz, sizeof(double)))){
+        t = PyErr_NoMemory();
+        goto done;
+    }
+    lp_colptr[0] = 0;
+    if (ml){
+	if (Matrix_Check(Gl)){
+            memcpy(lp_values, MAT_BUFD(Gl), ml*n*sizeof(double));
+            for (k=0; k<n; k++){
+                for (j=0; j<ml; j++) lp_rowind[ml*k+j] = j;
+                lp_colptr[k+1] = lp_colptr[k] + ml;
+            }
+        }
+        else {
+            memcpy(lp_values, SP_VALD(Gl), SP_NNZ(Gl)*sizeof(double));
+            for (k=0; k<n; k++){
+                for (j=SP_COL(Gl)[k]; j<SP_COL(Gl)[k+1]; j++)
+                    lp_rowind[j] = (int) SP_ROW(Gl)[j];
+                lp_colptr[k+1] = lp_colptr[k] + (int) (SP_COL(Gl)[k+1] -
+                    SP_COL(Gl)[k]);
+            }
+        }
+        memcpy(lp_values+lp_colptr[n], MAT_BUFD(hl), ml*sizeof(double));
+        for (k=0; k<ml; k++) lp_rowind[lp_colptr[n]+k] = k;
+        lp_colptr[n+1] = lp_colptr[n] + ml;
+    }
+    if (LPConeSetData2(lpcone, ml, lp_colptr, lp_rowind, lp_values)){
+        t = PyErr_NoMemory();
+        goto done;
+    }
+    /* LPConeView(lpcone); */
+
+    /* linear matrix inequalities: store mat(hs[k]), mat(Gs[k][:,i]) 
+     * as an lx(n+1) array of dsdp matrices. */
+    if (!(lmis = (dsdp_matrix **) calloc(l, sizeof(dsdp_matrix *)))){
+        t = PyErr_NoMemory();
+        goto done;
+    }
+    for (k=0; k<l; k++) lmis[k] = NULL;
+    for (k=0; k<l; k++){
+        Gk = PyList_GetItem(Gs, k); 
+        hk = (matrix *) PyList_GetItem(hs, k); 
+        if (!(lmis[k] = (dsdp_matrix *) calloc(n+1, 
+            sizeof(dsdp_matrix)))){ 
+            t = PyErr_NoMemory();
+            goto done;
+        }
+
+	/* lmis[k][0] is hs[k] as a dsdp matrix */
+        mk = MAT_NROWS(hk); 
+        lmis[k][0].n = mk;
+        lmis[k][0].issparse = 0;
+        if (!(lmis[k][0].val = (double *) calloc(mk*(mk+1)/2, 
+            sizeof(double)))){
+            t = PyErr_NoMemory();
+            goto done;
+        }
+        lmis[k][0].ind = NULL;
+        lmis[k][0].nnz = mk*(mk+1)/2;
+        for (j=0; j<mk; j++){
+	    lngth = j+1;  incx = mk;  incy = 1;
+            dcopy_(&lngth, MAT_BUFD(hk)+j, &incx, 
+                lmis[k][0].val+j*(j+1)/2, &incy); 
+        }
+
+        /* lmis[k][i+1] is mat(Gs[k][i]) as a dsdp matrix */
+        for (i=0; i<n; i++){
+            lmis[k][i+1].n = mk;
+            if (Matrix_Check(Gk)){
+                lmis[k][i+1].issparse = 0;
+                if (!(lmis[k][i+1].val = (double *) calloc(mk*(mk+1)/2, 
+                    sizeof(double)))){
+                    t = PyErr_NoMemory();
+                    goto done;
+                }
+                lmis[k][i+1].ind = NULL;
+                lmis[k][i+1].nnz = mk*(mk+1)/2;
+                for (j=0; j<mk; j++){
+                    lngth = j+1;  incx = mk;  incy = 1;
+                    dcopy_(&lngth, MAT_BUFD(Gk)+i*mk*mk+j, &incx, 
+                        lmis[k][i+1].val+j*(j+1)/2, &incy);
+                }
+            } else {
+                lmis[k][i+1].issparse = 1;
+                /* nnz is number of lower triangular nonzeros in 
+                 * Gk[:,i] */
+                for (nnz=0, j=SP_COL(Gk)[i]; j<SP_COL(Gk)[i+1]; j++){
+                    qr = div(SP_ROW(Gk)[j], mk); 
+                    if (qr.quot <= qr.rem) nnz++;
+                }
+                lmis[k][i+1].nnz = nnz;
+                if (!(lmis[k][i+1].val = (double *) calloc(nnz, 
+                    sizeof(double))) || !(lmis[k][i+1].ind = (int *) 
+                    calloc(nnz, sizeof(int)))){
+                    t = PyErr_NoMemory();
+                    goto done;
+                }
+                /* lmis[k][i+1].val, lmis[k][i+1].ind are the lower 
+                 * triangular nonzeros/indices of Gk[:,i].  The indices
+		 * refer to the postions in the lower triangular part 
+		 * stored in row major order as an mk*(mk+1)/2 array. */
+                for (nnz=0, j=SP_COL(Gk)[i]; j<SP_COL(Gk)[i+1]; j++){
+                    qr = div(SP_ROW(Gk)[j], mk); 
+                    if (qr.quot <= qr.rem){
+                        lmis[k][i+1].val[nnz] = SP_VALD(Gk)[j];
+                        lmis[k][i+1].ind[nnz] = qr.rem*(qr.rem+1)/2 + 
+                            qr.quot; 
+                        nnz++;
+                    } 
+                }
+            } 
+        }
+    }
+    for (k=0; k<l; k++) for(i=0; i<n+1; i++){
+        if (lmis[k][i].issparse){
+            SDPConeSetASparseVecMat(sdpcone, k, i, lmis[k][i].n, 1.0, 0,
+                lmis[k][i].ind, lmis[k][i].val, lmis[k][i].nnz);
+        }
+        else {
+            SDPConeSetADenseVecMat(sdpcone, k, i, lmis[k][i].n, 1.0, 
+                lmis[k][i].val, lmis[k][i].nnz);
+        }
+        /* SDPConeViewDataMatrix(sdpcone, k, i);  */
+    }
+
+    DSDPSetup(sdp);
+    if (DSDPSolve(sdp)){
+	PyErr_SetString(PyExc_ArithmeticError, "DSDP error");
+        t = NULL;
+	goto done;
+    }
+    DSDPStopReason(sdp, &info);
+    if (info != DSDP_CONVERGED){
+        PyErr_SetObject(PyExc_ArithmeticError, Py_BuildValue("i",info));
+        t = NULL;
+        goto done;
+    }
+
+    if (!(zs = PyList_New(l)) || !(x = (matrix *) Matrix_New(n, 1, 
+        DOUBLE)) || !(zl = (matrix *) Matrix_New(ml, 1, DOUBLE)) || 
+        !(zk = (double *) calloc(maxm*(maxm+1)/2, sizeof(double))) || 
+        !(t = PyTuple_New(5))) { 
+        Py_XDECREF(x);  Py_XDECREF(zl);  Py_XDECREF(zs);  Py_XDECREF(t);
+        t = PyErr_NoMemory();
+        goto done;
+    }
+    DSDPGetSolutionType(sdp, &status);
+
+    switch (status){
+        case DSDP_PDFEASIBLE:
+            PyTuple_SET_ITEM(t, 0, (PyObject *) 
+                PyString_FromString("DSDP_PDFEASIBLE"));
+	    break;
+        case DSDP_UNBOUNDED:
+            PyTuple_SET_ITEM(t, 0, (PyObject *) 
+                PyString_FromString("DSDP_UNBOUNDED"));
+	    break;
+        case DSDP_INFEASIBLE:
+            PyTuple_SET_ITEM(t, 0, (PyObject *) 
+                PyString_FromString("DSDP_INFEASIBLE"));
+	    break;
+        case DSDP_PDUNKNOWN:
+            PyTuple_SET_ITEM(t, 0, (PyObject *) 
+                PyString_FromString("DSDP_UNKNOWN"));
+	    break;
+    }
+
+    DSDPGetY(sdp, MAT_BUFD(x), n);
+    PyTuple_SET_ITEM(t, 1, (PyObject *) x);
+
+    DSDPGetR(sdp, &r);
+    PyTuple_SET_ITEM(t, 2, Py_BuildValue("d", r));
+
+    DSDPComputeX(sdp);
+    LPConeGetXArray(lpcone, &zlvals, &k);
+    memcpy(MAT_BUFD(zl), zlvals, ml*sizeof(double));
+    PyTuple_SET_ITEM(t, 3, (PyObject *) zl);
+
+    for (k=0; k<l; k++){
+        hk = (matrix *) PyList_GetItem(hs, k); 
+        mk = MAT_NROWS(hk); 
+        if (!(zsk = (matrix *) Matrix_New(mk, mk, DOUBLE))){
+            Py_XDECREF(x);  Py_XDECREF(zl);  Py_XDECREF(zs);  
+            Py_XDECREF(t);
+            t = PyErr_NoMemory();
+            goto done;
+        }
+        SDPConeComputeX(sdpcone, k, mk, zk, maxm*(maxm+1)/2);
+        for (j=0; j<mk; j++){
+            lngth=j+1;  incx=1;  incy=mk;
+            dcopy_(&lngth, zk+j*(j+1)/2, &incx, MAT_BUFD(zsk)+j, &incy);
+        }
+        PyList_SetItem(zs, k, (PyObject *) zsk);
+    }
+    PyTuple_SET_ITEM(t, 4, (PyObject *) zs);
+
+    done:
+        free(lp_colptr);  free(lp_rowind);  free(lp_values);  free(zk);
+        DSDPDestroy(sdp);  
+        if (lmis) for (k=0; k<l; k++){ 
+            if (lmis[k]) for (i=0; i<n+1; i++){ 
+                if (lmis[k][i].issparse) free(lmis[k][i].ind); 
+                free(lmis[k][i].val); 
+            } 
+        } 
+        free(lmis); 
+        return t;
+}
+
+static PyMethodDef dsdp_functions[] = {
+  {"sdp", (PyCFunction) solvesdp, METH_VARARGS|METH_KEYWORDS, doc_dsdp},
+  {NULL}  /* Sentinel */
+};
+
+PyMODINIT_FUNC initdsdp(void)
+{
+    dsdp_module = Py_InitModule3("cvxopt.dsdp", dsdp_functions, 
+        dsdp__doc__);
+    PyModule_AddObject(dsdp_module, "options", PyDict_New());
+    if (import_cvxopt() < 0) return;
+}
diff --git a/src/C/fftw.c b/src/C/fftw.c
new file mode 100644
index 0000000..65feadd
--- /dev/null
+++ b/src/C/fftw.c
@@ -0,0 +1,290 @@
+/*
+ * This file is part of CVXOPT version 0.8.2.
+ * Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+ */
+
+#include "cvxopt.h"
+#include "misc.h"
+#include <fftw3.h>
+
+PyDoc_STRVAR(fftw__doc__,
+    "Interface to the FFTW3 library.\n");
+
+extern void zscal_(int *n, complex *alpha, complex *x, int *incx);
+extern void dscal_(int *n, double *alpha, double *x, int *incx);
+        
+static char doc_dft[] = 
+    "DFT of a matrix,  X := dft(X)\n\n" 
+    "PURPOSE\n"
+    "Computes the DFT of a dense matrix X column by column.\n\n"
+    "ARGUMENTS\n"
+    "X         A dense matrix of typecode 'z'.";
+
+
+static PyObject *dft(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+  matrix *X;
+  char *kwlist[] = {"X", NULL};
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O", kwlist, &X)) 
+    return NULL;
+
+  if (!(Matrix_Check(X) && MAT_ID(X) == COMPLEX))     
+    PY_ERR(PyExc_ValueError, "X must be a dense matrix with type 'z'");
+
+  int m = X->nrows, n = X->ncols; 
+  if (m == 0) return Py_BuildValue("");
+
+  fftw_plan p = fftw_plan_many_dft(1, &m, n, 
+      X->buffer, &m, 1, m,
+      X->buffer, &m, 1, m,
+      FFTW_FORWARD, FFTW_ESTIMATE);
+
+  fftw_execute(p);   
+  fftw_destroy_plan(p);  
+  return Py_BuildValue("");
+}
+
+static char doc_idft[] = 
+    "IDFT of a matrix,  X := idft(X)\n\n" 
+    "PURPOSE\n"
+    "Computes the inverse DFT of a dense matrix X column by column.\n\n"
+    "ARGUMENTS\n"
+    "X         A dense matrix of typecode 'z'.";
+
+static PyObject *idft(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+  matrix *X;
+  char *kwlist[] = {"X", NULL};
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O", kwlist, &X)) 
+    return NULL;
+
+  if (!(Matrix_Check(X) && MAT_ID(X) == COMPLEX))     
+    PY_ERR(PyExc_ValueError, "X must be a dense matrix with type 'z'");
+
+  int m = X->nrows, n = X->ncols; 
+  if (m == 0) return Py_BuildValue("");
+
+  fftw_plan p = fftw_plan_many_dft(1, &m, n, 
+      X->buffer, &m, 1, m,
+      X->buffer, &m, 1, m,
+      FFTW_BACKWARD, FFTW_ESTIMATE);
+  
+  fftw_execute(p); 
+  
+  number a;
+  a.z = 1.0/m;
+  int mn = m*n, ix = 1;
+  zscal_(&mn, &a.z, MAT_BUFZ(X), &ix);
+  
+  fftw_destroy_plan(p);
+  return Py_BuildValue("");  
+}
+
+static char doc_dct[] = 
+    "DCT of a matrix.\n"
+    "X := dct(X, type=2)\n\n" 
+    "PURPOSE\n"
+    "Computes the DCT of a dense matrix X column by column.\n\n"
+    "ARGUMENTS\n"
+    "X         A dense matrix of typecode 'd'.\n\n"
+    "type      integer from 1 to 4; chooses either DCT-I, DCT-II, \n"
+    "          DCT-III or DCT-IV.";
+
+static PyObject *dct(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+  matrix *X;
+  int type = 2;
+  char *kwlist[] = {"X", "type", NULL};
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|i", kwlist, &X, &type)) 
+    return NULL;
+
+  if (!(Matrix_Check(X) && MAT_ID(X) == DOUBLE))     
+    PY_ERR(PyExc_ValueError, "X must be a dense matrix with type 'd'");
+   
+  int m = X->nrows, n = X->ncols;
+  if (m == 0) return Py_BuildValue("");
+
+  fftw_r2r_kind kind;
+  switch(type) {
+  case 1: 
+    kind = FFTW_REDFT00; 
+    if (m <= 1) PY_ERR(PyExc_ValueError, "m must be greater than 1 for DCT-I");
+    break;
+  case 2: kind = FFTW_REDFT10; break;
+  case 3: kind = FFTW_REDFT01; break;
+  case 4: kind = FFTW_REDFT11; break;
+  default: PY_ERR(PyExc_ValueError, "type must be between 1 and 4");
+  }
+  fftw_plan p = fftw_plan_many_r2r(1, &m, n, 
+      X->buffer, &m, 1, m,
+      X->buffer, &m, 1, m,
+      &kind, FFTW_ESTIMATE);
+
+  fftw_execute(p);   
+  fftw_destroy_plan(p);  
+  return Py_BuildValue("");
+}
+
+static char doc_idct[] = 
+    "IDCT of a matrix.\n"
+    "X := idct(X, type=2)\n\n" 
+    "PURPOSE\n"
+    "Computes the IDCT of a dense matrix X column by column.\n\n"
+    "ARGUMENTS\n"
+    "X         A dense matrix of typecode 'd'.\n\n"
+    "type      integer from 1 to 4; chooses the inverse transform for\n"
+    "          either DCT-I, DCT-II, DCT-III or DCT-IV.";
+
+static PyObject *idct(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+  matrix *X;
+  int type = 2;
+  char *kwlist[] = {"X", "type", NULL};
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|i", kwlist, &X, &type)) 
+    return NULL;
+
+  if (!(Matrix_Check(X) && MAT_ID(X) == DOUBLE))     
+    PY_ERR(PyExc_ValueError, "X must be a dense matrix with type 'd'");
+   
+  int m = X->nrows, n = X->ncols;
+  if (m == 0) return Py_BuildValue("");
+
+  fftw_r2r_kind kind;
+  switch(type) {
+  case 1: kind = FFTW_REDFT00; 
+    if (m <= 1) PY_ERR(PyExc_ValueError, "m must be greater than 1 for DCT-I");
+    break;
+  case 2: kind = FFTW_REDFT01; break;
+  case 3: kind = FFTW_REDFT10; break;
+  case 4: kind = FFTW_REDFT11; break;
+  default: PY_ERR(PyExc_ValueError, "type must be between 1 and 4");
+  }
+  fftw_plan p = fftw_plan_many_r2r(1, &m, n, 
+      X->buffer, &m, 1, m,
+      X->buffer, &m, 1, m,
+      &kind, FFTW_ESTIMATE);
+
+  fftw_execute(p);   
+  
+  double a = 1.0/(type == 1 ? MAX(1,2*(m-1)) : 2*m);
+  int mn = m*n, ix = 1;
+  dscal_(&mn, &a, MAT_BUFD(X), &ix);
+
+  fftw_destroy_plan(p);  
+  return Py_BuildValue("");
+}
+
+static char doc_dst[] = 
+    "DST of a matrix.\n"
+    "X := dst(X, type=1)\n\n" 
+    "PURPOSE\n"
+    "Computes the DST of a dense matrix X column by column.\n\n"
+    "ARGUMENTS\n"
+    "X         A dense matrix of typecode 'd'.\n\n"
+    "type      integer from 1 to 4; chooses either DST-I, DST-II, \n"
+    "          DST-III or DST-IV.";
+
+static PyObject *dst(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+  matrix *X;
+  int type = 1;
+  char *kwlist[] = {"X", "type", NULL};
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|i", kwlist, &X, &type)) 
+    return NULL;
+
+  if (!(Matrix_Check(X) && MAT_ID(X) == DOUBLE))     
+    PY_ERR(PyExc_ValueError, "X must be a dense matrix with type 'd'");
+   
+  int m = X->nrows, n = X->ncols;
+  if (m == 0) return Py_BuildValue("");
+
+  fftw_r2r_kind kind;
+  switch(type) {
+  case 1: kind = FFTW_RODFT00; break;
+  case 2: kind = FFTW_RODFT10; break;
+  case 3: kind = FFTW_RODFT01; break;
+  case 4: kind = FFTW_RODFT11; break;
+  default: PY_ERR(PyExc_ValueError, "type must be between 1 and 4");
+  }
+  fftw_plan p = fftw_plan_many_r2r(1, &m, n, 
+      X->buffer, &m, 1, m,
+      X->buffer, &m, 1, m,
+      &kind, FFTW_ESTIMATE);
+
+  fftw_execute(p);   
+  fftw_destroy_plan(p);  
+  return Py_BuildValue("");
+}
+
+static char doc_idst[] = 
+    "IDST of a matrix.\n"
+    "X := idst(X, type=1)\n\n" 
+    "PURPOSE\n"
+    "Computes the IDST of a dense matrix X column by column.\n\n"
+    "ARGUMENTS\n"
+    "X         A dense matrix of typecode 'd'.\n\n"
+    "type      integer from 1 to 4; chooses the inverse transform for\n"
+    "          either DST-I, DST-II, DST-III or DST-IV.";
+
+static PyObject *idst(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+  matrix *X;
+  int type = 1;
+  char *kwlist[] = {"X", "type", NULL};
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|i", kwlist, &X, &type)) 
+    return NULL;
+
+  if (!(Matrix_Check(X) && MAT_ID(X) == DOUBLE))     
+    PY_ERR(PyExc_ValueError, "X must be a dense matrix with type 'd'");
+   
+  int m = X->nrows, n = X->ncols;
+  if (m == 0) return Py_BuildValue("");
+
+  fftw_r2r_kind kind;
+  switch(type) {
+  case 1: kind = FFTW_RODFT00; break;
+  case 2: kind = FFTW_RODFT01; break;
+  case 3: kind = FFTW_RODFT10; break;
+  case 4: kind = FFTW_RODFT11; break;
+  default: PY_ERR(PyExc_ValueError, "type must be between 1 and 4");
+  }
+  fftw_plan p = fftw_plan_many_r2r(1, &m, n, 
+      X->buffer, &m, 1, m,
+      X->buffer, &m, 1, m,
+      &kind, FFTW_ESTIMATE);
+
+  fftw_execute(p);   
+  
+  double a = 1.0/(type == 1 ? MAX(1,2*(m+1)) : 2*m);
+  int mn = m*n, ix = 1;
+  dscal_(&mn, &a, MAT_BUFD(X), &ix);
+
+  fftw_destroy_plan(p);  
+  return Py_BuildValue("");
+}
+
+static PyMethodDef fftw_functions[] = {
+    {"dft", (PyCFunction) dft, METH_VARARGS|METH_KEYWORDS, doc_dft},
+    {"idft", (PyCFunction) idft, METH_VARARGS|METH_KEYWORDS, doc_idft},
+    {"dct", (PyCFunction) dct, METH_VARARGS|METH_KEYWORDS, doc_dct},
+    {"idct", (PyCFunction) idct, METH_VARARGS|METH_KEYWORDS, doc_idct},
+    {"dst", (PyCFunction) dst, METH_VARARGS|METH_KEYWORDS, doc_dst},
+    {"idst", (PyCFunction) idst, METH_VARARGS|METH_KEYWORDS, doc_idst},
+    {NULL}  /* Sentinel */
+};
+
+
+PyMODINIT_FUNC initfftw(void)
+{
+  PyObject *m;
+
+  m = Py_InitModule3("cvxopt.fftw", fftw_functions, fftw__doc__);
+
+  if (import_cvxopt() < 0) return;
+}
diff --git a/src/C/glpk.c b/src/C/glpk.c
new file mode 100644
index 0000000..d05dd31
--- /dev/null
+++ b/src/C/glpk.c
@@ -0,0 +1,358 @@
+/*
+ * This file is part of CVXOPT version 0.8.2.
+ * Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+ */
+
+#include "cvxopt.h"
+#include "glpk.h"
+
+#define err_dbl_mtrx(s) {PyErr_SetString(PyExc_TypeError, \
+    s " must be a matrix with typecode 'd'"); \
+    return NULL;}
+
+#define err_p_int(s) {PyErr_SetString(PyExc_ValueError, \
+    s " must be a positive integer"); \
+    return NULL;}
+
+PyDoc_STRVAR(glpk__doc__,
+    "Interface to the simplex algorithm in GLPK.\n\n" 
+    "The GLPK control parameters have the default values listed in \n"
+    "the GLPK documentation, except for 'LPX_K_PRESOL', which is set\n"
+    "to 1 and cannot be modified.  The other parameters can be\n"
+    "modified by making an entry in the dictionary glpk.options.\n"
+    "For example, the command glpk.options['LPX_K_MSGLEV'] = 0 turns\n"
+    "off the printed output during execution of glpk.simplex().\n"
+    "See the documentation at www.gnu.org/software/glpk/glpk.html for\n"
+    "the list of GLPK control parameters and their default values.");
+
+static PyObject *glpk_module;
+
+typedef struct {
+    char  name[20];
+    int   idx;
+    char  type;
+}   param_tuple;
+
+static const param_tuple GLPK_PARAM_LIST[] = { 
+    {"LPX_K_MSGLEV", 300, 'i'},
+    {"LPX_K_SCALE",  301, 'i'},
+    {"LPX_K_DUAL",   302, 'i'},
+    {"LPX_K_PRICE",  303, 'i'},
+    {"LPX_K_RELAX",  304, 'f'},
+    {"LPX_K_TOLBND", 305, 'f'},
+    {"LPX_K_TOLDJ",  306, 'f'},
+    {"LPX_K_TOLPIV", 307, 'f'},
+    {"LPX_K_ROUND",  308, 'i'},
+    {"LPX_K_OBJLL",  309, 'f'},
+    {"LPX_K_OBJUL",  310, 'f'},
+    {"LPX_K_ITLIM",  311, 'i'},
+    {"LPX_K_ITCNT",  312, 'i'},
+    {"LPX_K_TMLIM",  313, 'f'},
+    {"LPX_K_OUTFRQ", 314, 'i'},
+    {"LPX_K_OUTDLY", 315, 'f'},
+    {"LPX_K_BRANCH", 316, 'i'},
+    {"LPX_K_BTRACK", 317, 'i'},
+    {"LPX_K_TOLINT", 318, 'f'},
+    {"LPX_K_TOLOBJ", 319, 'f'},
+    {"LPX_K_MPSINFO",320, 'i'},
+    {"LPX_K_MPSOBJ", 321, 'i'},
+    {"LPX_K_MPSORIG",322, 'i'},
+    {"LPX_K_MPSWIDE",323, 'i'},
+    {"LPX_K_MPSFREE",324, 'i'},
+    {"LPX_K_MPSSKIP",325, 'i'},
+    {"LPX_K_LPTORIG",326, 'i'},
+    {"LPX_K_PRESOL", 327, 'i'}
+}; /* 28 paramaters */
+
+
+static int get_param_idx(char *str, int *idx, char *type) 
+{
+    int i;
+
+    for (i=0; i<28; i++) {
+        if (!strcmp(GLPK_PARAM_LIST[i].name, str)) {
+            *idx =  GLPK_PARAM_LIST[i].idx; 
+            *type = GLPK_PARAM_LIST[i].type; 
+            return 1;
+        }
+    }
+    return 0;  
+}
+
+
+static char doc_simplex[] = 
+    "Solves a linear program using GLPK.\n\n"
+    "(status, x, z, y) = solvelp(c, G, h, A, b)\n"
+    "(status, x, z) = solvelp(c, G, h)\n\n"
+    "PURPOSE\n"
+    "(status, x, z, y) = solvelp(c, G, h, A, b) solves the pair\n"
+    "of primal and dual LPs\n\n"
+    "    minimize    c'*x            maximize    -h'*z + b'*y\n"
+    "    subject to  G*x <= h        subject to  G'*z + A'*y + c = 0\n"
+    "                A*x = b                     z >= 0.\n\n"
+    "(status, x, z) = solvelp(c, G, h) solves the pair of primal\n"
+    "and dual LPs\n\n"
+    "    minimize    c'*x            maximize    -h'*z \n"
+    "    subject to  G*x <= h        subject to  G'*z + c = 0\n"
+    "                                            z >= 0.\n\n"
+    "ARGUMENTS\n"
+    "c            nx1 dense 'd' matrix with n>=1\n\n" 
+    "G            mxn dense or sparse 'd' matrix with m>=1\n\n"
+    "h            mx1 dense 'd' matrix\n\n"
+    "A            pxn dense or sparse 'd' matrix with p>=0\n\n"
+    "b            px1 dnese 'd' matrix\n\n"
+    "status       'optimal', 'primal infeasible', 'dual infeasible' \n"
+    "             or 'unknown'\n\n"
+    "x            if status is 'optimal', a primal optimal solution;\n"
+    "             None otherwise\n\n"
+    "z,y          if status is 'optimal', the dual optimal solution;\n"
+    "             None otherwise";
+
+
+static PyObject *simplex(PyObject *self, PyObject *args, 
+    PyObject *kwrds)
+{
+    matrix *c, *h, *b=NULL, *x=NULL, *z=NULL, *y=NULL;
+    PyObject *G, *A=NULL, *t=NULL, *param, *key, *value;
+    LPX *lp;
+    int m, n, p, i, j, k, nnz, nnzmax, *rn=NULL, *cn=NULL, param_id;
+    int_compat pos=0;    
+    double *a=NULL, val;
+    char param_type, err_str[100], *keystr;
+    char *kwlist[] = {"c", "G", "h", "A", "b", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|OO", kwlist, &c,
+        &G, &h, &A, &b)) return NULL;
+
+    if ((Matrix_Check(G) && MAT_ID(G) != DOUBLE) || 
+        (SpMatrix_Check(G) && SP_ID(G) != DOUBLE) ||
+        (!Matrix_Check(G) && !SpMatrix_Check(G))){
+        PyErr_SetString(PyExc_TypeError, "G must be a 'd' matrix");
+        return NULL;
+    }
+    if ((m = Matrix_Check(G) ? MAT_NROWS(G) : SP_NROWS(G)) <= 0) 
+        err_p_int("m");
+    if ((n = Matrix_Check(G) ? MAT_NCOLS(G) : SP_NCOLS(G)) <= 0) 
+        err_p_int("n");
+
+    if (!Matrix_Check(h) || h->id != DOUBLE) err_dbl_mtrx("h");
+    if (h->nrows != m || h->ncols != 1){
+        PyErr_SetString(PyExc_ValueError, "incompatible dimensions");
+        return NULL;
+    }
+
+    if (A){
+        if ((Matrix_Check(A) && MAT_ID(A) != DOUBLE) || 
+            (SpMatrix_Check(A) && SP_ID(A) != DOUBLE) ||
+            (!Matrix_Check(A) && !SpMatrix_Check(A))){
+                PyErr_SetString(PyExc_ValueError, "A must be a dense "
+                    "'d' matrix or a general sparse matrix");
+                return NULL;
+	}
+        if ((p = Matrix_Check(A) ? MAT_NROWS(A) : SP_NROWS(A)) < 0)
+            err_p_int("p");
+        if ((Matrix_Check(A) ? MAT_NCOLS(A) : SP_NCOLS(A)) != n){
+            PyErr_SetString(PyExc_ValueError, "incompatible "
+                "dimensions");
+            return NULL;
+	}
+    }
+    else p = 0;
+
+    if (b && (!Matrix_Check(b) || b->id != DOUBLE)) err_dbl_mtrx("b");
+    if ((b && (b->nrows != p || b->ncols != 1)) || (!b && p !=0 )){
+        PyErr_SetString(PyExc_ValueError, "incompatible dimensions");
+        return NULL;
+    }
+
+    lp = lpx_create_prob();
+    lpx_add_rows(lp, m+p);
+    lpx_add_cols(lp, n);
+
+    for (i=0; i<n; i++){
+        lpx_set_obj_coef(lp, i+1, MAT_BUFD(c)[i]);
+        lpx_set_col_bnds(lp, i+1, LPX_FR, 0.0, 0.0);
+    }
+    for (i=0; i<m; i++)
+        lpx_set_row_bnds(lp, i+1, LPX_UP, 0.0, MAT_BUFD(h)[i]);     
+    for (i=0; i<p; i++)
+        lpx_set_row_bnds(lp, i+m+1, LPX_FX, MAT_BUFD(b)[i], 
+            MAT_BUFD(b)[i]);     
+
+    nnzmax = (SpMatrix_Check(G) ? SP_NNZ(G) : m*n ) + 
+        ((A && SpMatrix_Check(A)) ? SP_NNZ(A) : p*n);
+    a = (double *) calloc(nnzmax+1, sizeof(double));
+    rn = (int *) calloc(nnzmax+1, sizeof(int));
+    cn = (int *) calloc(nnzmax+1, sizeof(int));
+    if (!a || !rn || !cn){
+        free(a);  free(rn);  free(cn);  lpx_delete_prob(lp);
+        return PyErr_NoMemory();
+    }
+
+    nnz = 0;
+    if (SpMatrix_Check(G)) {
+        for (j=0; j<n; j++) for (k=SP_COL(G)[j]; k<SP_COL(G)[j+1]; k++)
+            if ((val = SP_VALD(G)[k]) != 0.0){
+                a[1+nnz] = val;
+                rn[1+nnz] = SP_ROW(G)[k]+1;
+                cn[1+nnz] = j+1;
+                nnz++;
+            }
+    }
+    else for (j=0; j<n; j++) for (i=0; i<m; i++)
+        if ((val = MAT_BUFD(G)[i+j*m]) != 0.0){
+            a[1+nnz] = val;
+            rn[1+nnz] = i+1;
+            cn[1+nnz] = j+1;
+            nnz++;
+        }
+
+    if (A && SpMatrix_Check(A)){
+        for (j=0; j<n; j++) for (k=SP_COL(A)[j]; k<SP_COL(A)[j+1]; k++)
+            if ((val = SP_VALD(A)[k]) != 0.0){
+                a[1+nnz] = val;
+                rn[1+nnz] = m+SP_ROW(A)[k]+1;
+                cn[1+nnz] = j+1;
+                nnz++;
+            }
+    }
+    else for (j=0; j<n; j++) for (i=0; i<p; i++)
+        if ((val = MAT_BUFD(A)[i+j*p]) != 0.0){
+            a[1+nnz] = val;
+            rn[1+nnz] = m+i+1;
+            cn[1+nnz] = j+1;
+            nnz++;
+        }
+
+    lpx_load_matrix(lp, nnz, rn, cn, a);
+    free(rn);  free(cn);  free(a);
+
+    if (!(t = PyTuple_New(A ? 4 : 3))){
+        lpx_delete_prob(lp);
+        return PyErr_NoMemory();
+    }
+
+    if (!(param = PyObject_GetAttrString(glpk_module, "options"))
+        || !PyDict_Check(param)){
+            lpx_delete_prob(lp);
+            PyErr_SetString(PyExc_AttributeError, 
+                "missing glpk.options dictionary");
+            return NULL; 
+    }
+    
+    while (PyDict_Next(param, &pos, &key, &value))
+        if ((keystr = PyString_AsString(key)) && get_param_idx(keystr, 
+            &param_id, &param_type)){
+	    if (param_type == 'i'){
+	        if (!PyInt_Check(value)){
+                    sprintf(err_str, "invalid value for integer "
+                        "GLPK parameter: %-.20s", keystr);
+                    PyErr_SetString(PyExc_ValueError, err_str); 
+	            lpx_delete_prob(lp);
+	            Py_DECREF(param);
+                    return NULL;
+	        }
+                if (!strcmp("LPX_K_PRESOL", keystr) &&
+                    PyInt_AS_LONG(value) != 1){
+                    PyErr_Warn(PyExc_UserWarning, "ignoring value of "
+                        "GLPK parameter 'LPX_K_PRESOL'");
+                }
+                else lpx_set_int_parm(lp, param_id, 
+                    PyInt_AS_LONG(value));
+	    } 
+	    else { 
+	        if (!PyInt_Check(value) && !PyFloat_Check(value)){
+                    sprintf(err_str, "invalid value for floating point "
+                        "GLPK parameter: %-.20s", keystr);
+                    PyErr_SetString(PyExc_ValueError, err_str); 
+	            lpx_delete_prob(lp);
+	            Py_DECREF(param);
+                    return NULL;
+	        }
+	        lpx_set_real_parm(lp, param_id, 
+                    PyFloat_AsDouble(value));
+	    } 
+    }
+    lpx_set_int_parm(lp, LPX_K_PRESOL, 1);
+    Py_DECREF(param);
+
+    switch (lpx_simplex(lp)){
+
+        case LPX_E_OK:
+
+            x = (matrix *) Matrix_New(n,1,DOUBLE);
+            z = (matrix *) Matrix_New(m,1,DOUBLE);
+            if (A) y = (matrix *) Matrix_New(p,1,DOUBLE);
+            if (!x || !z || (A && !y)){
+                Py_XDECREF(x);
+                Py_XDECREF(z);
+                Py_XDECREF(y);
+                Py_XDECREF(t);
+                lpx_delete_prob(lp);
+                return PyErr_NoMemory();
+            }
+
+            PyTuple_SET_ITEM(t, 0, (PyObject *) 
+                PyString_FromString("optimal"));
+
+            for (i=0; i<n; i++) 
+                MAT_BUFD(x)[i] = lpx_get_col_prim(lp, i+1);
+            PyTuple_SET_ITEM(t, 1, (PyObject *) x);
+
+            for (i=0; i<m; i++) 
+                MAT_BUFD(z)[i] = -lpx_get_row_dual(lp, i+1);
+            PyTuple_SET_ITEM(t, 2, (PyObject *) z);
+
+            if (A){
+                for (i=0; i<p; i++) 
+                    MAT_BUFD(y)[i] = -lpx_get_row_dual(lp, m+i+1);
+                PyTuple_SET_ITEM(t, 3, (PyObject *) y);
+            }
+
+            lpx_delete_prob(lp);
+            return (PyObject *) t;
+
+        case LPX_E_NOPFS: 
+
+            PyTuple_SET_ITEM(t, 0, (PyObject *) 
+                PyString_FromString("primal infeasible"));
+            break;
+    
+        case LPX_E_NODFS:
+
+            PyTuple_SET_ITEM(t, 0, (PyObject *) 
+                PyString_FromString("dual infeasible"));
+            break;
+
+        default:
+
+            PyTuple_SET_ITEM(t, 0, (PyObject *) 
+                PyString_FromString("unknown"));
+    }
+
+    lpx_delete_prob(lp);
+
+    PyTuple_SET_ITEM(t, 1, Py_BuildValue(""));
+    PyTuple_SET_ITEM(t, 2, Py_BuildValue(""));
+    if (A) PyTuple_SET_ITEM(t, 3, Py_BuildValue(""));
+
+    return (PyObject *) t;
+}
+
+
+static PyMethodDef glpk_functions[] = {
+    {"solvelp", (PyCFunction) simplex, METH_VARARGS|METH_KEYWORDS, 
+        doc_simplex},
+    {NULL}  /* Sentinel */
+};
+
+
+PyMODINIT_FUNC initglpk(void)
+{
+    glpk_module = Py_InitModule3("cvxopt.glpk", glpk_functions, 
+        glpk__doc__);
+
+    PyModule_AddObject(glpk_module, "options", PyDict_New());
+
+    if (import_cvxopt() < 0) return;
+}
diff --git a/src/C/lapack.c b/src/C/lapack.c
new file mode 100644
index 0000000..469f694
--- /dev/null
+++ b/src/C/lapack.c
@@ -0,0 +1,5088 @@
+/*
+ * This file is part of CVXOPT version 0.8.2.
+ * Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+ */
+
+#include "Python.h"
+#include "cvxopt.h"
+#include "misc.h"
+
+#define err_lapack { PyErr_SetObject( (info < 0) ? PyExc_ValueError :\
+    PyExc_ArithmeticError, Py_BuildValue("i",info) ); \
+    return NULL;}
+
+PyDoc_STRVAR(lapack__doc__, "Interface to the LAPACK library.\n\n"
+    "Double-precision real and complex LAPACK routines for solving\n"
+    "sets of linear equations, linear least-squares and least-norm\n"
+    "problems, symmetric and Hermitian eigenvalue problems, and \n"
+    "singular value decomposition.\n\n"
+    "For more details, see the LAPACK Users' Guide at \n"
+    "www.netlib.org/lapack/lug/lapack_lug.html.\n\n"
+    "Double and complex matrices and vectors are stored in CVXOPT \n"
+    "matrices using the conventional BLAS storage schemes, with the\n"
+    "CVXOPT matrix buffers interpreted as one-dimensional arrays.\n"
+    "For each matrix argument X, an additional integer argument offsetX\n"
+    "specifies the start of the array, i.e., the pointer \n"
+    "X->buffer + offsetX is passed to the LAPACK function.  The other\n"
+    "arguments (dimensions and options) have the same meaning as in\n"
+    "the LAPACK definition.  Default values of the dimension arguments\n"
+    "are derived from the CVXOPT matrix sizes.\n"
+    "If a routine from the LAPACK library returns with a positive \n"
+    "'info' value, an ArithmeticError is raised.  If it returns with \n"
+    "a negative 'info' value, a ValueError is raised.  In both cases\n"
+    "the value of 'info' is returned as an argument to the exception.");
+
+
+/* LAPACK prototypes */
+extern int ilaenv_(int  *ispec, char **name, char **opts, int *n1, 
+    int *n2, int *n3, int *n4);
+
+extern void dgetrf_(int *m, int *n, double *A, int *lda, int *ipiv, 
+    int *info);
+extern void zgetrf_(int *m, int *n, complex *A, int *lda, int *ipiv, 
+    int *info);
+extern void dgetrs_(char *trans, int *n, int *nrhs, double *A, int *lda,
+    int *ipiv, double *B, int *ldb, int *info);
+extern void zgetrs_(char *trans, int *n, int *nrhs, complex *A, int *lda, 
+    int *ipiv, complex *B, int *ldb, int *info);
+extern void dgetri_(int *n, double *A, int *lda, int *ipiv, double *work, 
+    int *lwork, int *info);
+extern void zgetri_(int *n, complex *A, int *lda, int *ipiv, complex *work,
+    int *lwork, int *info);
+extern void dgesv_(int *n, int *nrhs, double *A, int *lda, int *ipiv, 
+    double *B, int *ldb, int *info);
+extern void zgesv_(int *n, int *nrhs, complex *A, int *lda, int *ipiv, 
+    complex *B, int *ldb, int *info);
+
+extern void dgbtrf_(int *m, int *n, int *kl, int *ku, double *AB, 
+    int *ldab, int *ipiv, int *info);
+extern void zgbtrf_(int *m, int *n, int *kl, int *ku, complex *AB, 
+    int *ldab, int *ipiv, int *info);
+extern void dgbtrs_(char *trans, int *n, int *kl, int *ku, int *nrhs,
+    double *AB, int *ldab, int *ipiv, double *B, int *ldB, int *info);
+extern void zgbtrs_(char *trans, int *n, int *kl, int *ku, int *nrhs,
+    complex *AB, int *ldab, int *ipiv, complex *B, int *ldB, int *info);
+extern void dgbsv_(int *n, int *kl, int *ku, int *nrhs, double *ab, 
+    int *ldab, int *ipiv, double *b, int *ldb, int *info);
+extern void zgbsv_(int *n, int *kl, int *ku, int *nrhs, complex *ab, 
+    int *ldab, int *ipiv, complex *b, int *ldb, int *info);
+
+extern void dgttrf_(int *n, double *dl, double *d, double *du, 
+    double *du2, int *ipiv, int *info);
+extern void zgttrf_(int *n, complex *dl, complex *d, complex *du, 
+    complex *du2, int *ipiv, int *info);
+extern void dgttrs_(char *trans, int *n, int *nrhs, double *dl, double *d,
+    double *du, double *du2, int *ipiv, double *B, int *ldB, int *info);
+extern void zgttrs_(char *trans, int *n, int *nrhs, complex *dl, 
+    complex *d, complex *du, complex *du2, int *ipiv, complex *B, 
+    int *ldB, int *info);
+extern void dgtsv_(int *n, int *nrhs, double *dl, double *d, double *du,
+    double *B, int *ldB, int *info);
+extern void zgtsv_(int *n, int *nrhs, complex *dl, complex *d, complex *du,
+    complex *B, int *ldB, int *info);
+
+extern void dpotrf_(char *uplo, int *n, double *A, int *lda, int *info);
+extern void zpotrf_(char *uplo, int *n, complex *A, int *lda, int *info);
+extern void dpotrs_(char *uplo, int *n, int *nrhs, double *A, int *lda, 
+    double *B, int *ldb, int *info);
+extern void zpotrs_(char *uplo, int *n, int *nrhs, complex *A, int *lda, 
+    complex *B, int *ldb, int *info);
+extern void dpotri_(char *uplo, int *n, double *A, int *lda, int *info);
+extern void zpotri_(char *uplo, int *n, complex *A, int *lda, int *info);
+extern void dposv_(char *uplo, int *n, int *nrhs, double *A, int *lda, 
+    double *B, int *ldb, int *info);
+extern void zposv_(char *uplo, int *n, int *nrhs, complex *A, int *lda, 
+    complex *B, int *ldb, int *info);
+
+extern void dpbtrf_(char *uplo, int *n, int *kd, double *AB, int *ldab,
+    int *info);
+extern void zpbtrf_(char *uplo, int *n, int *kd, complex *AB, int *ldab,
+    int *info);
+extern void dpbtrs_(char *uplo, int *n, int *kd, int *nrhs, double *AB,
+    int *ldab, double *B, int *ldb, int *info);
+extern void zpbtrs_(char *uplo, int *n, int *kd, int *nrhs, complex *AB,
+    int *ldab, complex *B, int *ldb, int *info);
+extern void dpbsv_(char *uplo, int *n, int *kd, int *nrhs, double *A,
+    int *lda, double *B, int *ldb, int *info);
+extern void zpbsv_(char *uplo, int *n, int *kd, int *nrhs, complex *A,
+    int *lda, complex *B, int *ldb, int *info);
+
+extern void dpttrf_(int *n, double *d, double *e, int *info);
+extern void zpttrf_(int *n, double *d, complex *e, int *info);
+extern void dpttrs_(int *n, int *nrhs, double *d, double *e, double *B,
+    int *ldB, int *info);
+extern void zpttrs_(char *uplo, int *n, int *nrhs, double *d, complex *e, 
+    complex *B, int *ldB, int *info);
+extern void dptsv_(int *n, int *nrhs, double *d, double *e, double *B,
+    int *ldB, int *info);
+extern void zptsv_(int *n, int *nrhs, double *d, complex *e, complex *B,
+    int *ldB, int *info);
+
+extern void dsytrf_(char *uplo, int *n, double *A, int *lda, int *ipiv, 
+    double *work, int *lwork, int *info);
+extern void zsytrf_(char *uplo, int *n, complex *A, int *lda, int *ipiv, 
+    complex *work, int *lwork, int *info);
+extern void zhetrf_(char *uplo, int *n, complex *A, int *lda, int *ipiv,
+    complex *work, int *lwork, int *info);
+extern void dsytrs_(char *uplo, int *n, int *nrhs, double *A, int *lda, 
+    int *ipiv, double *B, int *ldb, int *info);
+extern void zsytrs_(char *uplo, int *n, int *nrhs, complex *A, int *lda, 
+    int *ipiv, complex *B, int *ldb, int *info);
+extern void zhetrs_(char *uplo, int *n, int *nrhs, complex *A, int *lda, 
+    int *ipiv, complex *B, int *ldb, int *info);
+extern void dsytri_(char *uplo, int *n, double *A, int *lda, int *ipiv,
+    double *work, int *info);
+extern void zsytri_(char *uplo, int *n, complex *A, int *lda, int *ipiv,
+    complex *work, int *info);
+extern void zhetri_(char *uplo, int *n, complex *A, int *lda, int *ipiv,
+    complex *work, int *info);
+extern void dsysv_(char *uplo, int *n, int *nrhs, double *A, int *lda, 
+    int *ipiv, double *B, int *ldb, double *work, int *lwork,
+    int *info);
+extern void zsysv_(char *uplo, int *n, int *nrhs, complex *A, int *lda, 
+    int *ipiv, complex *B, int *ldb, complex *work, int *lwork, int *info);
+extern void zhesv_(char *uplo, int *n, int *nrhs, complex *A, int *lda, 
+    int *ipiv, complex *B, int *ldb, complex *work, int *lwork, int *info);
+
+extern void dtrtrs_(char *uplo, char *trans, char *diag, int *n, int *nrhs,
+    double  *a, int *lda, double *b, int *ldb, int *info);
+extern void ztrtrs_(char *uplo, char *trans, char *diag, int *n, int *nrhs,
+    complex  *a, int *lda, complex *b, int *ldb, int *info);
+extern void dtrtri_(char *uplo, char *diag, int *n, double  *a, int *lda, 
+    int *info);
+extern void ztrtri_(char *uplo, char *diag, int *n, complex  *a, int *lda, 
+    int *info);
+extern void dtbtrs_(char *uplo, char *trans, char *diag, int *n, int *kd,
+    int *nrhs, double *ab, int *ldab, double *b, int *ldb, int *info);
+extern void ztbtrs_(char *uplo, char *trans, char *diag, int *n, int *kd,
+    int *nrhs, complex *ab, int *ldab, complex *b, int *ldb, int *info);
+
+extern void dgels_(char *trans, int *m, int *n, int *nrhs, double *a, 
+    int *lda, double *b, int *ldb, double *work, int *lwork, int *info);
+extern void zgels_(char *trans, int *m, int *n, int *nrhs, complex *a, 
+    int *lda, complex *b, int *ldb, complex *work, int *lwork, int *info);
+extern void dgeqrf_(int *m, int *n, double *a, int *lda, double *tau,
+    double *work, int *lwork, int *info);         
+extern void zgeqrf_(int *m, int *n, complex *a, int *lda, complex *tau,
+    complex *work, int *lwork, int *info);         
+extern void dormqr_(char *side, char *trans, int *m, int *n, int *k,
+    double *a, int *lda, double *tau, double *c, int *ldc, double *work,
+    int *lwork, int *info);
+extern void zunmqr_(char *side, char *trans, int *m, int *n, int *k,
+    complex *a, int *lda, complex *tau, complex *c, int *ldc, 
+    complex *work, int *lwork, int *info);
+
+extern void dsyev_(char *jobz, char *uplo, int *n, double *A, int *lda, 
+    double *W, double *work, int *lwork, int *info);
+extern void zheev_(char *jobz, char *uplo, int *n, complex *A, int *lda,
+    double *W, complex *work, int *lwork, double *rwork, int *info);
+extern void dsyevx_(char *jobz, char *range, char *uplo, int *n, double *A,
+    int *lda, double *vl, double *vu, int *il, int *iu, double *abstol, 
+    int *m, double *W, double *Z, int *ldz, double *work, int *lwork, 
+    int *iwork, int *ifail, int *info);
+extern void zheevx_(char *jobz, char *range, char *uplo, int *n, 
+    complex *A, int *lda, double *vl, double *vu, int *il, int *iu, 
+    double *abstol, int *m, double *W, complex *Z, int *ldz, complex *work,
+    int *lwork, double *rwork, int *iwork, int *ifail, int *info);
+extern void dsyevd_(char *jobz, char *uplo, int *n, double *A, int *ldA, 
+    double *W, double *work, int *lwork, int *iwork, int *liwork, 
+    int *info); 
+extern void zheevd_(char *jobz, char *uplo, int *n, complex *A, int *ldA, 
+    double *W, complex *work, int *lwork, double *rwork, int *lrwork, 
+    int *iwork, int *liwork, int *info); 
+extern void dsyevr_(char *jobz, char *range, char *uplo, int *n, double *A,
+    int *ldA, double *vl, double *vu, int *il, int *iu, double *abstol, 
+    int *m, double *W, double *Z, int *ldZ, int *isuppz, double *work, 
+    int *lwork, int *iwork, int *liwork, int *info); 
+extern void zheevr_(char *jobz, char *range, char *uplo, int *n, 
+    complex *A, int *ldA, double *vl, double *vu, int *il, int *iu, 
+    double *abstol, int *m, double *W, complex *Z, int *ldZ, int *isuppz, 
+    complex *work, int *lwork, double *rwork, int *lrwork, int *iwork, 
+    int *liwork, int *info); 
+
+extern void dsygv_(int *itype, char *jobz, char *uplo, int *n, double *A, 
+    int *lda, double *B, int *ldb, double *W, double *work, int *lwork, 
+    int *info);
+extern void zhegv_(int *itype, char *jobz, char *uplo, int *n, complex *A, 
+    int *lda, complex *B, int *ldb, double *W, complex *work, int *lwork, 
+    double *rwork, int *info);
+
+extern void dgesvd_(char *jobu, char *jobvt, int *m, int *n, double *A,
+    int *ldA, double *S, double *U, int *ldU, double *Vt, int *ldVt,
+    double *work, int *lwork, int *info);
+extern void dgesdd_(char *jobz, int *m, int *n, double *A, int *ldA,
+    double *S, double *U, int *ldU, double *Vt, int *ldVt, double *work, 
+    int *lwork, int *iwork, int *info);
+extern void zgesvd_(char *jobu, char *jobvt, int *m, int *n, complex *A,
+    int *ldA, double *S, complex *U, int *ldU, complex *Vt, int *ldVt,
+    complex *work, int *lwork, double *rwork, int *info);
+extern void zgesdd_(char *jobz, int *m, int *n, complex *A, int *ldA,
+    double *S, complex *U, int *ldU, complex *Vt, int *ldVt, complex *work,
+    int *lwork, double *rwork, int *iwork, int *info);
+
+
+static char doc_getrf[] = 
+    "LU factorization of a general real or complex m by n matrix.\n\n"
+    "getrf(A, ipiv, m=A.size[0], n=A.size[1], ldA=max(1,A.size[0]),\n"
+    "      offsetA=0)\n\n"
+    "PURPOSE\n"
+    "On exit, A is replaced with L, U in the factorization P*A = L*U\n"
+    "and ipiv contains the permutation:\n"
+    "P = P_min{m,n} * ... * P2 * P1 where Pi interchanges rows i and\n"
+    "ipiv[i] of A (using the Fortran convention, i.e., the first row\n"
+    "is numbered 1).\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "ipiv      'i' matrix of length at least min(m,n)\n\n"
+    "m         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,m).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer"; 
+
+static PyObject* getrf(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *ipiv; 
+    int m=-1, n=-1, ldA=0, oA=0, info; 
+    char *kwlist[] = {"A", "ipiv", "m", "n", "ldA", "offsetA", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiii", kwlist, 
+        &A, &ipiv, &m, &n, &ldA, &oA)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(ipiv) || ipiv ->id != INT) err_int_mtrx("ipiv");
+    if (m < 0) m = A->nrows;
+    if (n < 0) n = A->ncols;
+    if (m == 0 || n == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,m)) err_ld("ldA");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + m > len(A)) err_buf_len("A");
+    if (len(ipiv) < MIN(n,m)) err_buf_len("ipiv");
+
+#if (SIZEOF_INT < SIZEOF_LONG)			
+    int *ipiv_ptr = malloc(MIN(m,n)*sizeof(int));	
+    if (!ipiv_ptr) return PyErr_NoMemory(); 
+#else 
+    int *ipiv_ptr = MAT_BUFI(ipiv);		
+#endif						
+
+    switch (MAT_ID(A)) {
+        case DOUBLE: 
+            dgetrf_(&m, &n, MAT_BUFD(A)+oA, &ldA, ipiv_ptr, &info);
+            break;
+
+        case COMPLEX:
+            zgetrf_(&m, &n, MAT_BUFZ(A)+oA, &ldA, ipiv_ptr, &info);
+            break;
+
+        default:
+#if (SIZEOF_INT < SIZEOF_LONG)			
+            free(ipiv_ptr);
+#endif
+            err_invalid_id;
+    }
+
+#if (SIZEOF_INT < SIZEOF_LONG) 
+    int i;  for (i=0; i<MIN(m,n); i++) MAT_BUFI(ipiv)[i] = ipiv_ptr[i];
+    free(ipiv_ptr); 
+#endif 
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_getrs[] = 
+    "Solves a general real or complex set of linear equations,\n"
+    "given the LU factorization computed by getrf() or gesv().\n\n"
+    "getrs(A, ipiv, B, trans='N', n=A.size[0], nrhs=B.size[1],\n"
+    "      ldA = max(1,A.size[0]), ldB=max(1,B.size[0]), offsetA=0,\n"
+    "      offsetB=0)\n\n"
+    "PURPOSE\n"
+    "If trans is 'N', solves A*X = B.\n"
+    "If trans is 'T', solves A^T*X = B.\n"
+    "If trans is 'C', solves A^H*X = B.\n"
+    "On entry, A and ipiv contain the LU factorization of an n by n\n"
+    "matrix A as computed by getrf() or gesv().  On exit B is replaced\n"
+    "by the solution X.\n\n"  
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "ipiv      'i' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "trans     'N', 'T' or 'C'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer.  If negative, the default value is\n"
+    "           used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "ldB       positive integer.  ldB >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* getrs(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B, *ipiv; 
+    int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; 
+    char trans='N';
+    char *kwlist[] = {"A", "ipiv", "B", "trans", "n", "nrhs", "ldA", 
+        "ldB", "offsetA", "offsetB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ciiiiii", kwlist,
+        &A, &ipiv, &B, &trans, &n, &nrhs, &ldA, &ldB, &oA, &oB)) 
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids;
+    if (trans != 'N' && trans != 'T' && trans != 'C')
+        err_char("trans", "'N', 'T', 'C'");
+    if (n < 0){
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1, n)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+    if (len(ipiv) < n) err_buf_len("ipiv");
+
+#if (SIZEOF_INT < SIZEOF_LONG)			
+    int *ipiv_ptr = malloc(n*sizeof(int));	
+    if (!ipiv_ptr) return PyErr_NoMemory();	
+    int i;  for (i=0; i<n; i++) ipiv_ptr[i] = MAT_BUFI(ipiv)[i];
+#else 
+    int *ipiv_ptr = MAT_BUFI(ipiv);		
+#endif						
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            if (trans == 'C') trans = 'T';
+            dgetrs_(&trans, &n, &nrhs, MAT_BUFD(A)+oA, &ldA, ipiv_ptr, 
+                MAT_BUFD(B)+oB, &ldB, &info);
+            break;
+
+        case COMPLEX:
+            zgetrs_(&trans, &n, &nrhs, MAT_BUFZ(A)+oA, &ldA, ipiv_ptr, 
+                MAT_BUFZ(B)+oB, &ldB, &info);
+            break;
+    
+	default:
+#if (SIZEOF_INT < SIZEOF_LONG)			
+            free(ipiv_ptr);
+#endif
+            err_invalid_id;
+    }
+
+#if (SIZEOF_INT < SIZEOF_LONG) 
+    free(ipiv_ptr); 
+#endif 
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_getri[] = 
+    "Inverse of a real or complex matrix.\n\n"
+    "getri(A, ipiv, n=A.size[0], ldA = max(1,A.size[0]), offsetA=0)\n\n"
+    "PURPOSE\n"
+    "Computes the inverse of real or complex matrix of order n.  On\n"
+    "entry, A and ipiv contain the LU factorization, as returned by\n"
+    "gesv() or getrf().  On exit A is replaced by the inverse.\n\n" 
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "ipiv      'i' matrix\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer";
+
+static PyObject* getri(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *ipiv; 
+    int n=-1, ldA=0, oA=0, info, lwork; 
+    void *work; 
+    number wl;
+    char *kwlist[] = {"A", "ipiv", "n", "ldA", "offsetA", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iii", kwlist, &A,
+        &ipiv, &n, &ldA, &oA)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv");
+    if (n < 0){
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (n == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (len(ipiv) < n) err_buf_len("ipiv");
+
+#if (SIZEOF_INT < SIZEOF_LONG)
+    int *ipiv_ptr = malloc(n*sizeof(int));
+    if (!ipiv_ptr) return PyErr_NoMemory();
+    int i;  for (i=0; i<n; i++) ipiv_ptr[i] = MAT_BUFI(ipiv)[i];
+#else 
+    int *ipiv_ptr = MAT_BUFI(ipiv);
+#endif
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            lwork = -1;
+            dgetri_(&n, NULL, &ldA, NULL, &wl.d, &lwork, &info);
+            lwork = (int) wl.d;
+            if (!(work = (void *) calloc(lwork, sizeof(double)))) {
+#if (SIZEOF_INT < SIZEOF_LONG)
+                free(ipiv_ptr);
+#endif
+                return PyErr_NoMemory();
+            }
+            dgetri_(&n, MAT_BUFD(A)+oA, &ldA, ipiv_ptr, (double *) work,
+                &lwork, &info);
+            free(work);
+            break;
+
+        case COMPLEX:
+            lwork = -1;
+            zgetri_(&n, NULL, &ldA, NULL, &wl.z, &lwork, &info);
+            lwork = (int) creal(wl.z);
+            if (!(work = (void *) calloc(lwork, sizeof(complex)))){
+#if (SIZEOF_INT < SIZEOF_LONG)
+                free(ipiv_ptr);
+#endif
+                return PyErr_NoMemory();
+            }
+            zgetri_(&n, MAT_BUFZ(A)+oA, &ldA, ipiv_ptr, 
+                (complex *) work, &lwork, &info);
+            free(work);
+            break;
+
+        default:
+#if (SIZEOF_INT < SIZEOF_LONG)			
+            free(ipiv_ptr);
+#endif
+            err_invalid_id;
+    }
+
+#if (SIZEOF_INT < SIZEOF_LONG) 
+    free(ipiv_ptr); 
+#endif 
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_gesv[] = 
+    "Solves a general real or complex set of linear equations.\n\n"
+    "dgesv(A, B, ipiv=None, n=A.size[0], nrhs=B.size[1], \n"
+    "      ldA=max(1,A.size[0]), ldB=max(1,B.size[0]), offsetA=0, \n"
+    "      offsetB=0)\n\n"
+    "PURPOSE\n"
+    "Solves A*X=B with A n by n real or complex.\n"
+    "If ipiv is provided, then on exit A is overwritten with the details\n"
+    "of the LU factorization, and ipiv contains the permutation matrix.\n"
+    "If ipiv is not provided, then gesv() does not return the \n"
+    "factorization and does not modify A.  On exit B is replaced with\n"
+    "the solution X.\n\n"
+    "ARGUMENTS.\n"
+    "A         'd' or 'z' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "ipiv      'i' matrix of length at least n\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "ldB       positive integer.  ldB >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer\n\n" 
+    "offsetA   nonnegative integer";
+
+static PyObject* gesv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B, *ipiv=NULL; 
+    int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info, k; 
+    void *Ac=NULL;
+    int *ipivc=NULL;
+    static char *kwlist[] = {"A", "B", "ipiv", "n", "nrhs", "ldA", 
+        "ldB", "offsetA", "offsetB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Oiiiiii", kwlist, 
+        &A, &B, &ipiv, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids;
+    if (ipiv && (!Matrix_Check(ipiv) || ipiv->id != INT)) 
+        err_int_mtrx("ipiv");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1, n)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+    if (ipiv && len(ipiv) < n) err_buf_len("ipiv");
+
+    if (ipiv) {
+#if (SIZEOF_INT < SIZEOF_LONG)			
+        if (!(ipivc = (int *) calloc(n, sizeof(int))))
+            return PyErr_NoMemory();	
+#else 
+        ipivc = MAT_BUFI(ipiv);		
+#endif						    
+    }
+    else if (!(ipivc = (int *) calloc(n, sizeof(int))))
+        return PyErr_NoMemory();
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            if (ipiv) 
+                dgesv_(&n, &nrhs, MAT_BUFD(A)+oA, &ldA, ipivc,
+                    MAT_BUFD(B)+oB, &ldB, &info);
+            else {
+                if (!(Ac = (void *) calloc(n*n, sizeof(double)))){
+                    free(ipivc);  
+                    return PyErr_NoMemory();
+                }
+                for (k=0; k<n; k++) memcpy((double *) Ac + k*n, 
+                    MAT_BUFD(A)+oA+k*ldA, n*sizeof(double));
+                dgesv_(&n, &nrhs, (double *) Ac, &n, ipivc, 
+                    MAT_BUFD(B)+oB, &ldB, &info);
+                free(Ac);
+            }
+            break;
+
+        case COMPLEX:
+            if (ipiv) 
+                zgesv_(&n, &nrhs, MAT_BUFZ(A)+oA, &ldA, ipivc,
+                    MAT_BUFZ(B)+oB, &ldB, &info);
+            else {
+                if (!(Ac = (void *) calloc(n*n, sizeof(complex)))){
+                    free(ipivc);  
+                    return PyErr_NoMemory();
+                }
+                for (k=0; k<n; k++) memcpy((complex *) Ac + k*n, 
+                    MAT_BUFZ(A)+oA+k*ldA, n*sizeof(complex));
+                zgesv_(&n, &nrhs, (complex *) Ac, &n, ipivc, 
+                    MAT_BUFZ(B)+oB, &ldB, &info);
+                free(Ac);
+            }
+            break;
+
+        default:
+            if (ipiv){
+#if (SIZEOF_INT < SIZEOF_LONG) 
+                free(ipivc); 
+#endif 
+            }
+            else free(ipivc);
+            err_invalid_id;
+    }
+
+    if (ipiv){
+#if (SIZEOF_INT < SIZEOF_LONG) 
+        for (k=0; k<n; k++) MAT_BUFI(ipiv)[k] = ipivc[k];
+        free(ipivc); 
+#endif 
+    }
+    else free(ipivc);
+    
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_gbtrf[] = 
+    "LU factorization of a real or complex m by n band matrix.\n\n"
+    "gbtrf(A, m, kl, ipiv, n=A.size[1], ku=A.size[0]-2*kl-1,\n"
+    "      ldA=max(1,A.size[0]), offsetA=0)\n\n"
+    "PURPOSE\n"
+    "Computes the LU factorization of an m by n band matrix with kl\n"
+    "subdiagonals and ku superdiagonals.  On entry, the diagonals are\n"
+    "stored in rows kl+1 to 2*kl+ku+1 of the array A, in the BLAS format\n"
+    "for general band matrices.   On exit A and ipiv contains the\n"
+    "factorization.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "m         nonnegative integer\n\n"
+    "kl        nonnegative integer.\n\n"  
+    "ipiv      'i' matrix of length at least min(m,n)\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ku        nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= 2*kl+ku+1.  If zero, the\n"
+    "          default value is used.\n\n"
+    "offsetA   nonnegative integer"; 
+
+static PyObject* gbtrf(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *ipiv; 
+    int m, kl, n=-1, ku=-1, ldA=0, oA=0, info; 
+    char *kwlist[] = {"A", "m", "kl", "ipiv", "n", "ku", "ldA", "offsetA", 
+        NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OiiO|iiii", kwlist, 
+        &A, &m, &kl, &ipiv, &n, &ku, &ldA, &oA)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (m < 0) err_nn_int("m");
+    if (kl < 0) err_nn_int("kl");
+    if (n < 0) n = A->ncols;
+    if (m == 0 || n == 0) return Py_BuildValue("");
+    if (ku < 0) ku = A->nrows - 2*kl - 1;
+    if (ku < 0) err_nn_int("kl");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < 2*kl + ku + 1) err_ld("ldA");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + 2*kl + ku + 1 > len(A)) err_buf_len("A");
+    if (!Matrix_Check(ipiv) || ipiv ->id != INT) err_int_mtrx("ipiv");
+    if (len(ipiv) < MIN(n,m)) err_buf_len("ipiv");
+
+#if (SIZEOF_INT < SIZEOF_LONG)			
+    int *ipiv_ptr = malloc(MIN(m,n)*sizeof(int));	
+    if (!ipiv_ptr) return PyErr_NoMemory(); 
+#else 
+    int *ipiv_ptr = MAT_BUFI(ipiv);		
+#endif						
+
+    switch (MAT_ID(A)) {
+        case DOUBLE: 
+            dgbtrf_(&m, &n, &kl, &ku, MAT_BUFD(A)+oA, &ldA, ipiv_ptr, 
+                &info);
+            break;
+
+        case COMPLEX:
+            zgbtrf_(&m, &n, &kl, &ku, MAT_BUFZ(A)+oA, &ldA, ipiv_ptr, 
+                &info);
+            break;
+
+        default:
+#if (SIZEOF_INT < SIZEOF_LONG)			
+            free(ipiv_ptr);
+#endif
+            err_invalid_id;
+    }
+
+#if (SIZEOF_INT < SIZEOF_LONG) 
+    int i;  for (i=0; i<MIN(m,n); i++) MAT_BUFI(ipiv)[i] = ipiv_ptr[i];
+    free(ipiv_ptr); 
+#endif 
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_gbtrs[] = 
+    "Solves a real or complex set of linear equations with a banded\n"
+    "coefficient matrix, given the LU factorization computed by gbtrf()\n" 
+    "or gbsv().\n\n"
+    "gbtrs(A, kl, ipiv, B, trans='N', n=A.size[1], ku=A.size[0]-2*kl-1,\n"
+    "      nrhs=B.size[1], ldA=max(1,AB.size[0]), ldB=max(1,B.size[0]),\n"
+    "      offsetA=0, offsetB=0)\n\n"
+    "PURPOSE\n"
+    "If trans is 'N', solves A*X = B.\n"
+    "If trans is 'T', solves A^T*X = B.\n"
+    "If trans is 'C', solves A^H*X = B.\n"
+    "On entry, A and ipiv contain the LU factorization of an n by n\n"
+    "band matrix A as computed by getrf() or gbsv().  On exit B is\n"
+    "replaced by the solution X.\n\n"  
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "kl        nonnegative integer\n\n"
+    "ipiv      'i' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "trans     'N', 'T' or 'C'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ku        nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= 2*kl+ku+1.  If zero, the\n"
+    "          default value is used.\n\n"
+    "ldB       positive integer.  ldB >= max(1,n).  If zero, the default\n"
+    "          default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* gbtrs(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B, *ipiv; 
+    int kl, n=-1, ku=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; 
+    char trans='N';
+    char *kwlist[] = {"A", "kl", "ipiv", "B", "trans", "n", "ku", "nrhs",
+        "ldA", "ldB", "offsetA", "offsetB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OiOO|ciiiiiii", kwlist,
+        &A, &kl, &ipiv, &B, &trans, &n, &ku, &nrhs, &ldA, &ldB, &oA, 
+        &oB)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids;
+    if (trans != 'N' && trans != 'T' && trans != 'C')
+        err_char("trans", "'N', 'T', 'C'");
+    if (kl < 0) err_nn_int("kl");
+    if (ku < 0) ku = A->nrows - 2*kl - 1;
+    if (ku < 0) err_nn_int("kl");
+    if (n < 0) n = A->ncols;
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < 2*kl+ku+1) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1, n)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + 2*kl + ku + 1 > len(A)) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+    if (len(ipiv) < n) err_buf_len("ipiv");
+
+#if (SIZEOF_INT < SIZEOF_LONG)			
+    int *ipiv_ptr = malloc(n*sizeof(int));	
+    if (!ipiv_ptr) return PyErr_NoMemory();	
+    int i;  for (i=0; i<n; i++) ipiv_ptr[i] = MAT_BUFI(ipiv)[i];
+#else 
+    int *ipiv_ptr = MAT_BUFI(ipiv);		
+#endif						
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            if (trans == 'C') trans = 'T';
+            dgbtrs_(&trans, &n, &kl, &ku, &nrhs, MAT_BUFD(A)+oA, &ldA, 
+                ipiv_ptr, MAT_BUFD(B)+oB, &ldB, &info);
+            break;
+
+        case COMPLEX:
+            zgbtrs_(&trans, &n, &kl, &ku, &nrhs, MAT_BUFZ(A)+oA, &ldA, 
+                ipiv_ptr, MAT_BUFZ(B)+oB, &ldB, &info);
+            break;
+    
+	default:
+#if (SIZEOF_INT < SIZEOF_LONG)			
+            free(ipiv_ptr);
+#endif
+            err_invalid_id;
+    }
+
+#if (SIZEOF_INT < SIZEOF_LONG) 
+    free(ipiv_ptr); 
+#endif 
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_gbsv[] = 
+    "Solves a real or complex set of linear equations with a banded\n"
+    "coefficient matrix.\n\n"
+    "gbsv(A, kl, B, ipiv=None, ku=None, n=A.size[1], nrhs=B.size[1],\n"
+    "     ldA=max(1,A.size[0]), ldB=max(1,B.size[0]), offsetA=0, \n"
+    "     offsetB=0)\n\n"
+    "PURPOSE\n"
+    "Solves A*X=B with A an n by n real or complex band matrix with kl\n"
+    "subdiagonals and ku superdiagonals.\n"
+    "If ipiv is provided, then on entry the kl+ku+1 diagonals of the\n"
+    "matrix are stored in rows kl+1 to 2*kl+ku+1 of A, in the BLAS\n"
+    "format for general band matrices.  On exit, A and ipiv contain the\n"
+    "details of the factorization.  If ipiv is not provided, then on\n"
+    "entry the diagonals of the matrix are stored in rows 1 to kl+ku+1 \n"
+    "of A, and gbsv() does not return the factorization and does not\n"
+    "modify A.  On exit B is replaced with solution X.\n\n"
+    "ARGUMENTS.\n"
+    "A         'd' or 'z' banded matrix\n\n"
+    "kl        nonnegative integer\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "ipiv      'i' matrix of length at least n\n\n"
+    "ku        nonnegative integer.  If negative, the default value is\n"
+    "          used.  The default value is A.size[0]-kl-1 if ipiv is\n"
+    "          not provided, and A.size[0]-2*kl-1 otherwise.\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= kl+ku+1 if ipiv is not provided\n"
+    "          and ldA >= 2*kl+ku+1 if ipiv is provided.  If zero, the\n"
+    "          default value is used.\n\n"
+    "ldB       positive integer.  ldB >= max(1,n).  If zero, the default\n"
+    "          default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n" 
+    "offsetB   nonnegative integer";
+
+
+static PyObject* gbsv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B, *ipiv=NULL; 
+    void *Ac;
+    int kl, ku=-1, n=-1, nrhs=-1, ldA=0, oA=0, ldB=0, oB=0, info, k; 
+    int *ipivc=NULL;
+    static char *kwlist[] = {"A", "kl", "B", "ipiv", "ku", "n", "nrhs",  
+        "ldA", "ldB", "oA", "oB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OiO|Oiiiiiii", kwlist, 
+        &A, &kl, &B, &ipiv, &ku, &n, &nrhs, &ldA, &ldB, &oA, &oB)) 
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids;
+    if (ipiv && (!Matrix_Check(ipiv) || ipiv->id != INT)) 
+        err_int_mtrx("ipiv");
+    if (n < 0) n = A->ncols;
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (kl < 0) err_nn_int("kl");
+    if (ku < 0) ku = A->nrows - kl - 1 - (ipiv ? kl : 0);
+    if (ku < 0) err_nn_int("ku");
+    if (ldA == 0) ldA = MAX(1, A->nrows);
+    if (ldA < ( ipiv ? 2*kl+ku+1 : kl+ku+1)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1,n)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA");  
+    if (oA + (n-1)*ldA + (ipiv ? 2*kl+ku+1 : kl+ku+1) > len(A)) 
+        err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+    if (ipiv && len(ipiv) < n) err_buf_len("ipiv");
+
+    if (ipiv) {
+#if (SIZEOF_INT < SIZEOF_LONG)			
+        if (!(ipivc = (int *) calloc(n, sizeof(int))))
+            return PyErr_NoMemory();	
+#else 
+        ipivc = MAT_BUFI(ipiv);		
+#endif						    
+    }
+    else if (!(ipivc = (int *) calloc(n, sizeof(int))))
+        return PyErr_NoMemory();
+
+    switch (MAT_ID(A)) {
+        case DOUBLE:
+            if (ipiv) 
+                dgbsv_(&n, &kl, &ku, &nrhs, MAT_BUFD(A)+oA, &ldA, ipivc,
+                    MAT_BUFD(B)+oB, &ldB, &info);
+            else {
+                if (!(Ac = (void *) calloc((2*kl+ku+1)*n, 
+                    sizeof(double)))){
+                    free(ipivc); 
+                    return PyErr_NoMemory();
+                }
+                for (k=0; k<n; k++) 
+                    memcpy((double *) Ac + kl + k*(2*kl+ku+1),  
+                        MAT_BUFD(A) + oA + k*ldA, 
+                        (kl+ku+1)*sizeof(double)); 
+                ldA = 2*kl+ku+1;
+                dgbsv_(&n, &kl, &ku, &nrhs, (double *) Ac, &ldA, ipivc,
+                    MAT_BUFD(B)+oB, &ldB, &info);
+                free(Ac);
+            }
+            break;
+    
+        case COMPLEX:
+            if (ipiv) 
+                zgbsv_(&n, &kl, &ku, &nrhs, MAT_BUFZ(A)+oA, &ldA, ipivc,
+                    MAT_BUFZ(B)+oB, &ldB, &info);
+            else {
+                if (!(Ac = (void *) calloc((2*kl+ku+1)*n, 
+                    sizeof(complex)))){
+                    free(ipivc);
+                    return PyErr_NoMemory();
+                }
+                for (k=0; k<n; k++) 
+                    memcpy((complex *) Ac + kl + k*(2*kl+ku+1),  
+                        MAT_BUFZ(A) + oA + k*ldA, 
+                        (kl+ku+1)*sizeof(complex)); 
+                ldA = 2*kl+ku+1;
+                zgbsv_(&n, &kl, &ku, &nrhs, (complex *) Ac, &ldA, ipivc,
+                    MAT_BUFZ(B)+oB, &ldB, &info);
+                free(Ac);
+            }
+            break;
+
+        default:
+            if (ipiv){
+#if (SIZEOF_INT < SIZEOF_LONG) 
+                free(ipivc); 
+#endif 
+            }
+            else free(ipivc);
+            err_invalid_id;
+    }
+
+    if (ipiv){
+#if (SIZEOF_INT < SIZEOF_LONG) 
+        for (k=0; k<n; k++) MAT_BUFI(ipiv)[k] = ipivc[k];
+        free(ipivc); 
+#endif 
+    }
+    else free(ipivc);
+    
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_gttrf[] = 
+    "LU factorization of a real or complex tridiagonal matrix.\n\n"
+    "gttrf(dl, d, du, du2, ipiv, n=len(d)-offsetd, offsetdl=0, offsetd=0,"
+    "\n"
+    "      offsetdu=0)\n\n"
+    "PURPOSE\n"
+    "Factors an n by n real or complex tridiagonal matrix A as A = P*L*U."
+    "\n  A is specified by its lower diagonal dl, diagonal d, and upper\n"
+    "diagonal du.  On exit dl, d, du, du2 and ipiv contain the details\n"
+    "of the factorization.\n\n"
+    "ARGUMENTS.\n"
+    "dl        'd' or 'z' matrix\n\n"
+    "d         'd' or 'z' matrix.  Must have the same type as dl.\n\n"
+    "du        'd' or 'z' matrix.  Must have the same type as dl.\n\n"
+    "du2       'd' or 'z' matrix of length at least n-2.  Must have the\n"
+    "           same type as dl.\n\n"
+    "ipiv      'i' matrix of length at least n\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "offsetdl  nonnegative integer\n\n" 
+    "offsetd   nonnegative integer\n\n" 
+    "offsetdu  nonnegative integer"; 
+
+static PyObject* gttrf(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *dl, *d, *du, *du2, *ipiv; 
+    int n=-1, odl=0, od=0, odu=0, info; 
+    static char *kwlist[] = {"dl", "d", "du", "du2", "ipiv", "n", 
+        "offsetdl", "offsetd", "offsetdu", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOOOO|iiii", kwlist, 
+        &dl, &d, &du, &du2, &ipiv, &n, &odl, &od, &odu)) 
+        return NULL;
+
+    if (!Matrix_Check(dl)) err_mtrx("dl");
+    if (!Matrix_Check(d)) err_mtrx("d");
+    if (!Matrix_Check(du)) err_mtrx("du");
+    if (!Matrix_Check(du2)) err_mtrx("du");
+    if ((MAT_ID(dl) != MAT_ID(d)) || (MAT_ID(dl) != MAT_ID(du)) || 
+        (MAT_ID(dl) != MAT_ID(du2))) err_conflicting_ids;
+    if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv");
+    if (od < 0) err_nn_int("offsetd");
+    if (n < 0) n = len(d) - od;
+    if (n < 0) err_buf_len("d");
+    if (n == 0) return Py_BuildValue("");
+    if (odl < 0) err_nn_int("offsetdl");
+    if (odl + n - 1  > len(dl)) err_buf_len("dl");
+    if (od + n > len(d)) err_buf_len("d");
+    if (odu < 0) err_nn_int("offsetdu");
+    if (odu + n - 1  > len(du)) err_buf_len("du");
+    if (n - 2  > len(du2)) err_buf_len("du2");
+    if (len(ipiv) < n) err_buf_len("ipiv");
+    if (n > len(ipiv)) err_buf_len("ipiv");
+
+#if (SIZEOF_INT < SIZEOF_LONG)			
+    int *ipiv_ptr = malloc(n*sizeof(int));	
+    if (!ipiv_ptr) return PyErr_NoMemory(); 
+#else 
+    int *ipiv_ptr = MAT_BUFI(ipiv);		
+#endif						
+
+    switch (MAT_ID(dl)){
+        case DOUBLE:
+            dgttrf_(&n, MAT_BUFD(dl)+odl, MAT_BUFD(d)+od, MAT_BUFD(du)+odu,
+                MAT_BUFD(du2), ipiv_ptr, &info);
+            break;
+
+        case COMPLEX:
+            zgttrf_(&n, MAT_BUFZ(dl)+odl, MAT_BUFZ(d)+od, MAT_BUFZ(du)+odu,
+                MAT_BUFZ(du2), ipiv_ptr, &info);
+            break;
+
+        default:
+#if (SIZEOF_INT < SIZEOF_LONG)			
+            free(ipiv_ptr);
+#endif
+            err_invalid_id;
+    }
+
+#if (SIZEOF_INT < SIZEOF_LONG) 
+    int i;  for (i=0; i<n; i++) MAT_BUFI(ipiv)[i] = ipiv_ptr[i];
+    free(ipiv_ptr); 
+#endif 
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_gttrs[] = 
+    "Solves a real or complex tridiagonal set of linear equations, \n"
+    "given the LU factorization computed by gttrf().\n\n"
+    "gttrs(dl, d, du, du2, ipiv, B, trans='N', n=len(d)-offsetd,\n"
+    "      nrhs=B.size[1], ldB=max(1,B.size[0]), offsetdl=0, offsetd=0,\n"
+    "      offsetdu=0, offsetB=0)\n\n"
+    "PURPOSE\n"
+    "If trans is 'N', solves A*X=B.\n"
+    "If trans is 'T', solves A^T*X=B.\n"
+    "If trans is 'C', solves A^H*X=B.\n"
+    "On entry, dl, d, du, du2 and ipiv contain the LU factorization of \n"
+    "an n by n tridiagonal matrix A as computed by gttrf().  On exit B\n"
+    "is replaced by the solution X.\n\n"
+    "ARGUMENTS.\n"
+    "dl        'd' or 'z' matrix\n\n"
+    "d         'd' or 'z' matrix.  Must have the same type as dl.\n\n"
+    "du        'd' or 'z' matrix.  Must have the same type as dl.\n\n"
+    "du2       'd' or 'z' matrix.  Must have the same type as dl.\n\n"
+    "ipiv      'i' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type oas dl.\n\n"
+    "trans     'N', 'T' or 'C'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldB       positive integer.  ldB >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetdl  nonnegative integer\n\n" 
+    "offsetd   nonnegative integer\n\n" 
+    "offsetdu  nonnegative integer\n\n" 
+    "offsetB   nonnegative integer"; 
+
+static PyObject* gttrs(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *dl, *d, *du, *du2, *ipiv, *B; 
+    char trans='N';
+    int n=-1, nrhs=-1, ldB=0, odl=0, od=0, odu=0, oB=0, info; 
+    static char *kwlist[] = {"dl", "d", "du", "du2", "ipiv", "B", "trans",
+        "n", "nrhs", "ldB", "offsetdl", "offsetd", "offsetdu", "offsetB",
+        NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOOOOO|ciiiiiii", 
+        kwlist, &dl, &d, &du, &du2, &ipiv, &B, &trans, &n, &nrhs, &ldB, 
+        &odl, &od, &odu, &oB)) return NULL;
+
+    if (!Matrix_Check(dl)) err_mtrx("dl");
+    if (!Matrix_Check(d)) err_mtrx("d");
+    if (!Matrix_Check(du)) err_mtrx("du");
+    if (!Matrix_Check(du2)) err_mtrx("du");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if ((MAT_ID(dl) != MAT_ID(d)) || (MAT_ID(dl) != MAT_ID(du)) || 
+        (MAT_ID(dl) != MAT_ID(du2)) || (MAT_ID(dl) != MAT_ID(B))) 
+        err_conflicting_ids;
+    if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv");
+    if (trans != 'N' && trans != 'T' && trans != 'C')
+        err_char("trans", "'N', 'T', 'C'");
+    if (od < 0) err_nn_int("offsetd");
+    if (n < 0) n = len(d) - od;
+    if (n < 0) err_buf_len("d");
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1, n)) err_ld("ldB");
+    if (odl < 0) err_nn_int("offsetdl");
+    if (odl + n - 1  > len(dl)) err_buf_len("dl");
+    if (od + n > len(d)) err_buf_len("d");
+    if (odu < 0) err_nn_int("offsetdu");
+    if (odu + n - 1  > len(du)) err_buf_len("du");
+    if (n - 2  > len(du2)) err_buf_len("du2");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+    if (n > len(ipiv)) err_buf_len("ipiv");
+
+#if (SIZEOF_INT < SIZEOF_LONG)			
+    int *ipiv_ptr = malloc(n*sizeof(int));	
+    if (!ipiv_ptr) return PyErr_NoMemory(); 
+    int i;  for (i=0; i<n; i++) ipiv_ptr[i] = MAT_BUFI(ipiv)[i];
+#else 
+    int *ipiv_ptr = MAT_BUFI(ipiv);		
+#endif						
+
+    switch (MAT_ID(dl)){
+        case DOUBLE:
+            dgttrs_(&trans, &n, &nrhs, MAT_BUFD(dl)+odl, MAT_BUFD(d)+od,
+                MAT_BUFD(du)+odu, MAT_BUFD(du2), ipiv_ptr, 
+                MAT_BUFD(B)+oB, &ldB, &info);
+            break;
+
+        case COMPLEX:
+            zgttrs_(&trans, &n, &nrhs, MAT_BUFZ(dl)+odl, MAT_BUFZ(d)+od,
+                MAT_BUFZ(du)+odu, MAT_BUFZ(du2), ipiv_ptr, 
+                MAT_BUFZ(B)+oB, &ldB, &info);
+            break;
+
+        default:
+#if (SIZEOF_INT < SIZEOF_LONG)			
+            free(ipiv_ptr);
+#endif
+            err_invalid_id;
+    }
+
+#if (SIZEOF_INT < SIZEOF_LONG) 
+    free(ipiv_ptr); 
+#endif 
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_gtsv[] = 
+    "Solves a real or complex set of linear equations with a tridiagonal\n"
+    "coefficient matrix.\n\n"
+    "gtsv(dl, d, du, B, n=len(d)-offsetd, nrhs=B.size[1], \n"
+    "     ldB=max(1,B.size[0]), offsetdl=0, offsetd=0, offsetdu=0, \n"
+    "     offsetB=0)\n\n"
+    "PURPOSE\n"
+    "Solves A*X=B with A n by n real or complex and tridiagonal.\n"
+    "A is specified by its lower diagonal dl, diagonal d and upper \n"
+    "diagonal du.  On exit B is overwritten with the solution, and dl,\n"
+    "d, du are overwritten with the elements of the upper triangular\n"
+    "matrix in the LU factorization of A.\n\n"
+    "ARGUMENTS.\n"
+    "dl        'd' or 'z' matrix\n\n"
+    "d         'd' or 'z' matrix.  Must have the same type as dl.\n\n"
+    "du        'd' or 'z' matrix.  Must have the same type as dl.\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as dl.\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldB       positive integer.  ldB >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetdl  nonnegative integer\n\n" 
+    "offsetd   nonnegative integer\n\n" 
+    "offsetdu  nonnegative integer\n\n" 
+    "offsetB   nonnegative integer";
+
+static PyObject* gtsv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *dl, *d, *du, *B; 
+    int n=-1, nrhs=-1, ldB=0, odl=0, od=0, odu=0, oB=0, info; 
+    static char *kwlist[] = {"dl", "d", "du", "B", "n", "nrhs", "ldB", 
+        "offsetdl", "offsetd", "offsetdu", "offsetB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOOO|iiiiiii", kwlist, 
+        &dl, &d, &du, &B, &n, &nrhs, &ldB, &odl, &od, &odu, &oB)) 
+        return NULL;
+
+    if (!Matrix_Check(dl)) err_mtrx("dl");
+    if (!Matrix_Check(d)) err_mtrx("d");
+    if (!Matrix_Check(du)) err_mtrx("du");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if ((MAT_ID(dl) != MAT_ID(B)) || (MAT_ID(dl) != MAT_ID(d)) || 
+        (MAT_ID(dl) != MAT_ID(du)) || (MAT_ID(dl) != MAT_ID(B))) 
+        err_conflicting_ids;
+    if (od < 0) err_nn_int("offsetd");
+    if (n < 0) n = len(d) - od;
+    if (n < 0) err_buf_len("d");
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (odl < 0) err_nn_int("offsetdl");
+    if (odl + n - 1  > len(dl)) err_buf_len("dl");
+    if (od + n > len(d)) err_buf_len("d");
+    if (odu < 0) err_nn_int("offsetdu");
+    if (odu + n - 1  > len(du)) err_buf_len("du");
+    if (oB < 0) err_nn_int("offsetB");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1, n)) err_ld("ldB");
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+
+    switch (MAT_ID(dl)){
+        case DOUBLE:
+            dgtsv_(&n, &nrhs, MAT_BUFD(dl)+odl, MAT_BUFD(d)+od,
+                MAT_BUFD(du)+odu, MAT_BUFD(B)+oB, &ldB, &info);
+            break;
+
+        case COMPLEX:
+            zgtsv_(&n, &nrhs, MAT_BUFZ(dl)+odl, MAT_BUFZ(d)+od,
+                MAT_BUFZ(du)+odu, MAT_BUFZ(B)+oB, &ldB, &info);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_potrf[] = 
+    "Cholesky factorization of a real symmetric or complex Hermitian\n"
+    "positive definite matrix.\n\n"
+    "potrf(A, uplo='L', n=A.size[0], ldA = max(1,A.size[0]), offsetA=0)"
+    "\n\n"
+    "PURPOSE\n"
+    "Factors A as A=L*L^T or A = L*L^H, where A is n by n, real\n"
+    "symmetric or complex Hermitian, and positive definite.\n"
+    "On exit, if uplo='L', the lower triangular part of A is replaced\n"
+    "by L.  If uplo='U', the upper triangular part is replaced by L^T\n"
+    "or L^H.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer";
+
+static PyObject* potrf(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A; 
+    int n=-1, ldA=0, oA=0, info; 
+    char uplo='L';
+    char *kwlist[] = {"A", "uplo", "n", "ldA", "offsetA", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|ciii", kwlist, &A,
+        &uplo, &n, &ldA, &oA))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A is not square");
+            return NULL;
+        }
+    }
+    if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'");
+    if (n == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1, A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (oA < 0) err_nn_int("offsetA"); 
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            dpotrf_(&uplo, &n, MAT_BUFD(A)+oA, &ldA, &info);
+	    break;
+
+        case COMPLEX:
+            zpotrf_(&uplo, &n, MAT_BUFZ(A)+oA, &ldA, &info);
+	    break;
+
+	default:
+	    err_invalid_id;
+    }
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_potrs[] = 
+    "Solves a real symmetric or complex Hermitian positive definite set\n"
+    "of linear equations, given the Cholesky factorization computed by\n"
+    "potrf() or posv().\n\n"
+    "potrs(A, B, uplo='L', n=A.size[0], nrhs=B.size[1],\n"
+    "      ldA=max(1,A.size[0]), ldB=max(1,B.size[0]), offsetA=0,\n"
+    "      offsetB=0)\n\n"
+    "PURPOSE\n"
+    "Solves A*X = B where A is n by n, real symmetric or complex\n"
+    "Hermitian and positive definite, and B is n by nrhs.\n"
+    "On entry, A contains the Cholesky factor, as returned by posv() or\n"
+    "potrf().  On exit B is replaced by the solution X.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "ldB       positive integer.  ldB >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* potrs(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B; 
+    int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; 
+    char uplo='L';
+    char *kwlist[] = {"A", "B", "uplo", "n", "nrhs", "ldA", "ldB", 
+        "offsetA", "offsetB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciiiiii", kwlist, 
+        &A, &B, &uplo, &n, &nrhs, &ldA, &ldB, &oA, &oB))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids;
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0) n = A->nrows;
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1,n)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            dpotrs_(&uplo, &n, &nrhs, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB,
+                &ldB, &info);
+            break;
+
+        case COMPLEX:
+            zpotrs_(&uplo, &n, &nrhs, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB,
+                &ldB, &info);
+	    break;
+
+        default:
+	    err_invalid_id;
+    }
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_potri[] = 
+    "Inverse of a real symmetric or complex Hermitian positive definite\n" 
+    "matrix.\n\n"
+    "potri(A, uplo='L', n=A.size[0], ldA=max(1,A.size[0]), offsetA=0)\n\n"
+    "PURPOSE\n"
+    "Computes the inverse of a real symmetric or complex Hermitian\n"
+    "positive definite matrix of order n.  On entry, A contains the\n"
+    "Cholesky factor, as returned by posv() or potrf().  On exit it is\n"
+    "replaced by the inverse.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer";
+
+static PyObject* potri(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A; 
+    int n=-1, ldA=0, oA=0, info; 
+    char uplo='L';
+    char *kwlist[] = {"A", "uplo", "n", "ldA", "offsetA", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|ciii", kwlist, 
+        &A, &uplo, &n, &ldA, &oA)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0) n = A->nrows;
+    if (n == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            dpotri_(&uplo, &n, MAT_BUFD(A)+oA, &ldA, &info);
+            break;
+
+        case COMPLEX:
+            zpotri_(&uplo, &n, MAT_BUFZ(A)+oA, &ldA, &info);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_posv[] = 
+    "Solves a real symmetric or complex Hermitian positive definite set\n"
+    "of linear equations.\n\n"
+    "posv(A, B, uplo='L', n=A.size[0], nrhs=B.size[1], \n"
+    "     ldA=max(1,A.size[0]), ldB=max(1,B.size[0]), offsetA=0, \n"
+    "     offsetB=0)\n\n"
+    "PURPOSE\n"
+    "Solves A*X = B with A n by n, real symmetric or complex Hermitian,\n"
+    "and positive definite, and B n by nrhs.\n"
+    "On exit, if uplo is 'L',  the lower triangular part of A is\n"
+    "replaced by L.  If uplo is 'U', the upper triangular part is\n"
+    "replaced by L^H.  B is replaced by the solution.\n\n"
+    "ARGUMENTS.\n"
+    "A         'd' or 'z' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "ldB       positive integer.  ldB >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* posv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B; 
+    int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; 
+    char uplo='L';
+    char *kwlist[] = {"A", "B", "uplo", "n", "nrhs", "ldA", "ldB", 
+        "offsetA", "offsetB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciiiiii", kwlist, 
+        &A, &B, &uplo, &n, &nrhs, &ldA, &ldB, &oA, &oB))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids;
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0) n = A->nrows;
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1, n)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");  
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            dposv_(&uplo, &n, &nrhs, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB,
+                &ldB, &info);
+            break;
+
+        case COMPLEX:
+            zposv_(&uplo, &n, &nrhs, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB,
+                &ldB, &info);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_pbtrf[] = 
+    "Cholesky factorization of a real symmetric or complex Hermitian\n"
+    "positive definite band matrix.\n\n"
+    "pbtrf(A, uplo='L', n=A.size[1], kd=A.size[0]-1, ldA=max(1,A.size[0]),"
+    "\n"
+    "      offsetA=0)\n\n"
+    "PURPOSE\n"
+    "Factors A as A=L*L^T or A = L*L^H, where A is an n by n real\n"
+    "symmetric or complex Hermitian positive definite band matrix with\n"
+    "kd subdiagonals and kd superdiagonals.  A is stored in the BLAS \n"
+    "format for symmetric band matrices.  On exit, A contains the\n"
+    "Cholesky factor in the BLAS format for triangular band matrices.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         nonnegative integer. If negative, the default value is\n"
+    "          used.\n\n"
+    "kd        nonnegative integer. If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= kd+1.  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer";
+
+static PyObject* pbtrf(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A; 
+    int n=-1, kd=-1, ldA=0, oA=0, info; 
+    char uplo='L';
+    char *kwlist[] = {"A", "uplo", "n", "kd", "ldA", "offsetA", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|ciiii", kwlist, &A,
+        &uplo, &n, &kd, &ldA, &oA))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (n < 0) n = A->ncols;
+    if (n == 0) return Py_BuildValue("");
+    if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'");
+    if (kd < 0) kd = A->nrows - 1;
+    if (kd < 0) err_nn_int("kd");
+    if (ldA == 0) ldA = MAX(1, A->nrows);
+    if (ldA < kd+1) err_ld("ldA");
+    if (oA < 0) err_nn_int("offsetA"); 
+    if (oA + (n-1)*ldA + kd + 1 > len(A)) err_buf_len("A");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            dpbtrf_(&uplo, &n, &kd, MAT_BUFD(A)+oA, &ldA, &info);
+            break;
+
+        case COMPLEX:
+            zpbtrf_(&uplo, &n, &kd, MAT_BUFZ(A)+oA, &ldA, &info);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_pbtrs[] = 
+    "Solves a real symmetric or complex Hermitian positive definite set\n"
+    "of linear equations with a banded coefficient matrix, given the\n"
+    "Cholesky factorization computed by pbtrf() or pbsv().\n\n"
+    "pbtrs(A, B, uplo='L', n=A.size[1], kd=A.size[0]-1, nrhs=B.size[1],\n"
+    "      ldA=max(1,A.size[0]), ldB=max(1,B.size[0]), offsetA=0,\n"
+    "      offsetB=0)\n\n"
+    "PURPOSE\n"
+    "Solves A*X = B where A is an n by n real symmetric or complex \n"
+    "Hermitian positive definite band matrix with kd subdiagonals and kd\n"
+    "superdiagonals, and B is n by nrhs.  A contains the Cholesky factor\n"
+    "of A, as returned by pbtrf() or pbtrs().  On exit, B is replaced by\n"
+    "the solution X.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix.\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         nonnegative integer. If negative, the default value is\n"
+    "          used.\n\n"
+    "kd        nonnegative integer. If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer. If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= kd+1.  If zero, the default\n"
+    "          value is used.\n\n"
+    "ldB       positive integer.  ldB >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* pbtrs(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B; 
+    int n=-1, kd=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; 
+    char uplo='L';
+    char *kwlist[] = {"A", "B", "uplo", "n", "kd", "nrhs", "ldA", "ldB",
+        "offsetA", "offsetB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciiiiiii", kwlist, 
+        &A, &B, &uplo, &n, &kd, &nrhs, &ldA, &ldB, &oA, oB))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids;
+    if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'");
+    if (n < 0) n = A->ncols;
+    if (kd < 0) kd = A->nrows - 1;
+    if (kd < 0) err_nn_int("kd");
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < kd+1) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1,n)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA"); 
+    if (oA + (n-1)*ldA + kd + 1 > len(A)) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            dpbtrs_(&uplo, &n, &kd, &nrhs, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(B)+oB, &ldB, &info);
+            break;
+
+        case COMPLEX:
+            zpbtrs_(&uplo, &n, &kd, &nrhs, MAT_BUFZ(A)+oA, &ldA, 
+                MAT_BUFZ(B)+oB, &ldB, &info);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_pbsv[] = 
+    "Solves a real symmetric or complex Hermitian positive definite set\n"
+    "of linear equations with a banded coefficient matrix.\n\n"
+    "pbsv(A, B, uplo='L', n=A.size[1], kd=A.size[0]-1, nrhs=B.size[1],\n"
+    "     ldA=MAX(1,A.size[0]), ldB=max(1,B.size[0]), offsetA=0,\n"
+    "     offsetB=0)\n\n"
+    "PURPOSE\n"
+    "Solves A*X = B where A is an n by n real symmetric or complex\n"
+    "Hermitian positive definite band matrix with kd subdiagonals and kd\n"
+    "superdiagonals, and B is n by nrhs.\n"
+    "On entry, A contains A in the BLAS format for symmetric band\n"
+    "matrices.  On exit, A is replaced with the Cholesky factors, stored\n"
+    "in the BLAS format for triangular band matrices.  B is replaced\n"
+    "by the solution X.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix.\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         nonnegative integer. If negative, the default value is\n"
+    "          used.\n\n"
+    "kd        nonnegative integer. If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer. If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= kd+1.  If zero, the default\n"
+    "          value is used.\n\n"
+    "ldB       positive integer.  ldB >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* pbsv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B; 
+    int n=-1, kd=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; 
+    char uplo='L';
+    char *kwlist[] = {"A", "B", "uplo", "n", "kd", "nrhs", "ldA", "ldB",
+        "offsetA", "offsetB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciiiiiii", kwlist, 
+        &A, &B, &uplo, &n, &kd, &nrhs, &ldA, &ldB, &oA, oB))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids;
+    if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'");
+    if (n < 0) n = A->ncols;
+    if (kd < 0) kd = A->nrows - 1;
+    if (kd < 0) err_nn_int("kd");
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < kd+1) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1,n)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA"); 
+    if (oA + (n-1)*ldA + kd + 1 > len(A)) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            dpbsv_(&uplo, &n, &kd, &nrhs, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(B)+oB, &ldB, &info);
+            break;
+
+        case COMPLEX:
+            zpbsv_(&uplo, &n, &kd, &nrhs, MAT_BUFZ(A)+oA, &ldA, 
+                MAT_BUFZ(B)+oB, &ldB, &info);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_pttrf[] = 
+    "Cholesky factorization of a real symmetric or complex Hermitian\n"
+    "positive definite tridiagonal matrix.\n\n"
+    "pttrf(d, e, n=len(d)-offsetd, offsetd=0, offsete=0)\n\n"
+    "PURPOSE\n"
+    "Factors A  as A = L*D*L^T or A = L*D*L^H where A is n by n, real\n"
+    "symmetric or complex Hermitian, positive definite, and tridiagonal.\n"
+    "On entry, d is the subdiagonal of A and e is the diagonal.  On \n"
+    "exit, d contains the diagonal of D and e contains the subdiagonal\n"
+    "of the unit bidiagonal matrix L.\n\n"
+    "ARGUMENTS.\n"
+    "d         'd' matrix\n\n"
+    "e         'd' or 'z' matrix.\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "offsetd   nonnegative integer\n\n" 
+    "offsete   nonnegative integer";
+
+static PyObject* pttrf(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *d, *e; 
+    int n=-1, od=0, oe=0, info; 
+    static char *kwlist[] = {"d", "e", "n", "offsetd", "offsete", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iii", kwlist, &d, 
+        &e, &n, &od, &oe)) return NULL;
+
+    if (!Matrix_Check(d)) err_mtrx("d");
+    if (MAT_ID(d) != DOUBLE) err_type("d");
+    if (!Matrix_Check(e)) err_mtrx("e");
+    if (od < 0) err_nn_int("offsetd");
+    if (n < 0) n = len(d) - od;
+    if (n < 0) err_buf_len("d");
+    if (od + n > len(d)) err_buf_len("d");
+    if (n == 0) return Py_BuildValue("");
+    if (oe < 0) err_nn_int("offsete");
+    if (oe + n - 1  > len(e)) err_buf_len("e");
+
+    switch (MAT_ID(e)){
+        case DOUBLE:
+            dpttrf_(&n, MAT_BUFD(d)+od, MAT_BUFD(e)+oe, &info);
+            break;
+
+        case COMPLEX:
+            zpttrf_(&n, MAT_BUFD(d)+od, MAT_BUFZ(e)+oe, &info);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_pttrs[] = 
+    "Solves a real symmetric or complex Hermitian positive definite set\n"
+    "of linear equations with a tridiagonal coefficient matrix, given \n"
+    "the factorization computed by pttrf().\n\n"
+    "pttrs(d, e, B, uplo='L', n=len(d)-offsetd, nrhs=B.size[1],\n"
+    "      ldB=max(1,B.size[0], offsetd=0, offsete=0, offsetB=0)\n\n"
+    "PURPOSE\n"
+    "Solves A*X=B with A n by n real or complex Hermitian positive\n"
+    "definite and tridiagonal, and B n by nrhs.  On entry, d and e\n"
+    "contain the Cholesky factorization L*D*L^T or L*D*L^H, for example,\n"
+    "as returned by pttrf().  The argument d is the diagonal of the \n"
+    "diagonal matrix D.  The argument uplo only matters in the complex\n"
+    "case.  If uplo = 'L', then e is the subdiagonal of L.  If uplo='U',\n"
+    "e is the superdiagonal of L^H.  On exit B is overwritten with the\n"
+    "solution X. \n\n"
+    "ARGUMENTS.\n"
+    "d         'd' matrix\n\n"
+    "e         'd' or 'z' matrix.\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as e.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldB       positive integer.  ldB >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetd   nonnegative integer\n\n" 
+    "offsete   nonnegative integer\n\n" 
+    "offsetB   nonnegative integer";
+
+static PyObject* pttrs(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *d, *e, *B; 
+    char uplo='L';
+    int n=-1, nrhs=-1, ldB=0, od=0, oe=0, oB=0, info; 
+    static char *kwlist[] = {"d", "e", "B", "uplo", "n", "nrhs", "ldB", 
+        "offsetd", "offsete", "offsetB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ciiiiii", kwlist, 
+        &d, &e, &B, &uplo, &n, &nrhs, &ldB, &od, &oe, &oB)) return NULL;
+
+    if (!Matrix_Check(d)) err_mtrx("d");
+    if (MAT_ID(d) != DOUBLE) err_type("d");
+    if (!Matrix_Check(e)) err_mtrx("e");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(e) != MAT_ID(B)) err_conflicting_ids;
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (od < 0) err_nn_int("offsetd");
+    if (n < 0) n = len(d) - od;
+    if (n < 0) err_buf_len("d");
+    if (od + n > len(d)) err_buf_len("d");
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (oe < 0) err_nn_int("offsete");
+    if (oe + n - 1  > len(e)) err_buf_len("e");
+    if (oB < 0) err_nn_int("offsetB");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1, n)) err_ld("ldB");
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+
+    switch (MAT_ID(e)){
+        case DOUBLE:
+            dpttrs_(&n, &nrhs, MAT_BUFD(d)+od, MAT_BUFD(e)+oe, 
+                MAT_BUFD(B)+oB, &ldB, &info);
+            break;
+
+        case COMPLEX:
+            zpttrs_(&uplo, &n, &nrhs, MAT_BUFD(d)+od, MAT_BUFZ(e)+oe, 
+                MAT_BUFZ(B)+oB, &ldB, &info);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_ptsv[] = 
+    "Solves a real symmetric or complex Hermitian positive definite set\n"
+    "of linear equations with a tridiagonal coefficient matrix.\n\n"
+    "ptsv(d, e, B, n=len(d)-offsetd, nrhs=B.size[1], ldB=max(1,B.size[0],"
+    "\n"
+    "     offsetd=0, offsete=0, offsetB=0)\n\n"
+    "PURPOSE\n"
+    "Solves A*X=B with A n by n real or complex Hermitian positive\n"
+    "definite and tridiagonal.  A is specified by its diagonal d and\n"
+    "subdiagonal e.  On exit B is overwritten with the solution, and d\n"
+    "and e are overwritten with the elements of Cholesky factorization\n"
+    "of A.\n\n"
+    "ARGUMENTS.\n"
+    "d         'd' matrix\n\n"
+    "e         'd' or 'z' matrix.\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as e.\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldB       positive integer.  ldB >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetd   nonnegative integer\n\n" 
+    "offsete   nonnegative integer\n\n" 
+    "offsetB   nonnegative integer";
+
+static PyObject* ptsv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *d, *e, *B; 
+    int n=-1, nrhs=-1, ldB=0, od=0, oe=0, oB=0, info; 
+    static char *kwlist[] = {"d", "e", "B", "n", "nrhs", "ldB", "offsetd", 
+        "offsete", "offsetB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|iiiiii", kwlist, 
+        &d, &e, &B, &n, &nrhs, &ldB, &od, &oe, &oB)) return NULL;
+
+    if (!Matrix_Check(d)) err_mtrx("d");
+    if (MAT_ID(d) != DOUBLE) err_type("d");
+    if (!Matrix_Check(e)) err_mtrx("e");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(e) != MAT_ID(B)) err_conflicting_ids;
+    if (od < 0) err_nn_int("offsetd");
+    if (n < 0) n = len(d) - od;
+    if (n < 0) err_buf_len("d");
+    if (od + n > len(d)) err_buf_len("d");
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (oe < 0) err_nn_int("offsete");
+    if (oe + n - 1  > len(e)) err_buf_len("e");
+    if (oB < 0) err_nn_int("offsetB");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1, n)) err_ld("ldB");
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+
+    switch (MAT_ID(e)){
+        case DOUBLE:
+            dptsv_(&n, &nrhs, MAT_BUFD(d)+od, MAT_BUFD(e)+oe, 
+                MAT_BUFD(B)+oB, &ldB, &info);
+            break;
+
+        case COMPLEX:
+            zptsv_(&n, &nrhs, MAT_BUFD(d)+od, MAT_BUFZ(e)+oe, 
+                MAT_BUFZ(B)+oB, &ldB, &info);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_sytrf[] = 
+    "LDL^T factorization of a real or complex symmetric matrix.\n\n"
+    "sytrf(A, ipiv, uplo='L', n=A.size[0], ldA=max(1,A.size[0]))\n\n"
+    "PURPOSE\n"
+    "Computes the LDL^T factorization of a real or complex symmetric\n"
+    "n by n matrix  A.  On exit, A and ipiv contain the details of the\n"
+    "factorization.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "ipiv      'i' matrix of length at least n\n\n" 
+    "uplo      'L' or 'U'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer";
+
+static PyObject* sytrf(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *ipiv; 
+    void *work; 
+    number wl;
+    int n=-1, ldA=0, oA=0, info, lwork;
+    char uplo='L';
+    char *kwlist[] = {"A", "ipiv", "uplo", "n", "ldA", "offsetA", NULL};
+    
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciii", kwlist,
+        &A, &ipiv, &uplo, &n, &ldA, &oA)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (n == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (oA < 0) err_nn_int("offsetA");  
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (len(ipiv) < n) err_buf_len("ipiv");
+
+#if (SIZEOF_INT < SIZEOF_LONG)			
+    int *ipiv_ptr = malloc(n*sizeof(int));	
+    if (!ipiv_ptr) return PyErr_NoMemory();			
+#else 
+    int *ipiv_ptr = MAT_BUFI(ipiv);		
+#endif						
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            lwork = -1;
+            dsytrf_(&uplo, &n, NULL, &ldA, NULL, &wl.d, &lwork, &info);
+            lwork = (int) wl.d;
+            if (!(work = (void *) calloc(lwork, sizeof(double)))){
+#if (SIZEOF_INT < SIZEOF_LONG)			
+                free(ipiv_ptr);
+#endif						
+                return PyErr_NoMemory();
+            }
+            dsytrf_(&uplo, &n, MAT_BUFD(A)+oA, &ldA, ipiv_ptr, 
+                (double *) work, &lwork, &info);
+            free(work);   
+            break;
+
+        case COMPLEX:
+            lwork = -1;
+            zsytrf_(&uplo, &n, NULL, &ldA, NULL, &wl.z, &lwork, &info);
+            lwork = (int) creal(wl.z);
+            if (!(work = (void *) calloc(lwork, sizeof(complex)))){
+#if (SIZEOF_INT < SIZEOF_LONG)			
+                free(ipiv_ptr);
+#endif						
+                return PyErr_NoMemory();
+            }
+            zsytrf_(&uplo, &n, MAT_BUFZ(A)+oA, &ldA, ipiv_ptr, 
+                (complex *) work, &lwork, &info);
+            free(work);   
+            break;
+
+        default:
+#if (SIZEOF_INT < SIZEOF_LONG) 
+            free(ipiv_ptr); 
+#endif 
+            err_invalid_id;
+    }
+
+#if (SIZEOF_INT < SIZEOF_LONG) 
+    int i;  for (i=0; i<n; i++)  MAT_BUFI(ipiv)[i] = ipiv_ptr[i];
+    free(ipiv_ptr); 
+#endif 
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_hetrf[] = 
+    "LDL^H factorization of a real symmetric or complex Hermitian matrix."
+    "\n\n"
+    "hetrf(A, ipiv, uplo='L', n=A.size[0], ldA=max(1,A.size[0]))\n\n"
+    "PURPOSE\n"
+    "Computes the LDL^H factorization of a real symmetric or complex\n"
+    "Hermitian n by n matrix  A.  On exit, A and ipiv contain the\n"
+    "details of the factorization.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "ipiv      'i' matrix of length at least n\n\n" 
+    "uplo      'L' or 'U'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,n).  If zero, the default\n"
+    "          default value is used.\n\n"
+    "offsetA   nonnegative integer";
+
+static PyObject* hetrf(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *ipiv; 
+    void *work; 
+    number wl;
+    int n=-1, ldA=0, oA=0, info, lwork;
+    char uplo='L';
+    char *kwlist[] = {"A", "ipiv", "uplo", "n", "ldA", "offsetA", NULL};
+    
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciii", kwlist,
+        &A, &ipiv, &uplo, &n, &ldA, &oA)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (n == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (oA < 0) err_nn_int("offsetA");  
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (len(ipiv) < n) err_buf_len("ipiv");
+
+#if (SIZEOF_INT < SIZEOF_LONG)			
+    int *ipiv_ptr = malloc(n*sizeof(int));	
+    if (!ipiv_ptr) return PyErr_NoMemory();			
+#else 
+    int *ipiv_ptr = MAT_BUFI(ipiv);		
+#endif						
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            lwork = -1;
+            dsytrf_(&uplo, &n, NULL, &ldA, NULL, &wl.d, &lwork, &info);
+            lwork = (int) wl.d;
+            if (!(work = (void *) calloc(lwork, sizeof(double)))){
+#if (SIZEOF_INT < SIZEOF_LONG)			
+                free(ipiv_ptr);
+#endif						
+                return PyErr_NoMemory();
+            }
+            dsytrf_(&uplo, &n, MAT_BUFD(A)+oA, &ldA, ipiv_ptr, 
+                (double *) work, &lwork, &info);
+            free(work);   
+            break;
+
+        case COMPLEX:
+            lwork = -1;
+            zhetrf_(&uplo, &n, NULL, &ldA, NULL, &wl.z, &lwork, &info);
+            lwork = (int) creal(wl.z);
+            if (!(work = (void *) calloc(lwork, sizeof(complex)))){
+#if (SIZEOF_INT < SIZEOF_LONG)			
+                free(ipiv_ptr);
+#endif						
+                return PyErr_NoMemory();
+            }
+            zhetrf_(&uplo, &n, MAT_BUFZ(A)+oA, &ldA, ipiv_ptr, 
+                (complex *) work, &lwork, &info);
+            free(work);   
+            break;
+
+        default:
+#if (SIZEOF_INT < SIZEOF_LONG) 
+            free(ipiv_ptr); 
+#endif 
+            err_invalid_id;
+    }
+
+#if (SIZEOF_INT < SIZEOF_LONG) 
+    int i;  for (i=0; i<n; i++)  MAT_BUFI(ipiv)[i] = ipiv_ptr[i];
+    free(ipiv_ptr); 
+#endif 
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_sytrs[] = 
+    "Solves a real or complex symmetric set of linear equations,\n"
+    "given the LDL^T factorization computed by sytrf() or sysv().\n\n"
+    "sytrs(A, ipiv, B, uplo='L', n=A.size[0], nrhs=B.size[1],\n"
+    "      ldA=max(1,A.size[0]), ldB=max(1,B.size[0]), offsetA=0,\n"
+    "      offsetB=0)\n\n"
+    "PURPOSE\n"
+    "Solves A*X = B where A is real or complex symmetric and n by n,\n"
+    "and B is n by nrhs.  On entry, A and ipiv contain the\n"
+    "factorization of A as returned by sytrf() or sysv().  On exit, B is\n"
+    "replaced by the solution.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "ipiv      'i' matrix \n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "ldB       nonnegative integer.  ldB >= max(1,n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* sytrs(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B, *ipiv; 
+    int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; 
+    char uplo='L';
+    char *kwlist[] = {"A", "ipiv", "B", "uplo", "n", "nrhs", "ldA", "ldB",
+        "offsetA", "offsetB", NULL};
+    
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ciiiiii", kwlist,
+        &A, &ipiv, &B, &uplo, &n, &nrhs, &ldA, &ldB, &oA, &oB)) 
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids;
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (nrhs < 0) nrhs = B->ncols; 
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1,n)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+    if (len(ipiv) < n) err_buf_len("ipiv");
+
+#if (SIZEOF_INT < SIZEOF_LONG)			
+    int *ipiv_ptr = malloc(n*sizeof(int));	
+    if (!ipiv_ptr) return PyErr_NoMemory();			
+    int i;  for (i=0; i<n; i++) ipiv_ptr[i] = MAT_BUFI(ipiv)[i];
+#else 
+    int *ipiv_ptr = MAT_BUFI(ipiv);		
+#endif						
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            dsytrs_(&uplo, &n, &nrhs, MAT_BUFD(A)+oA, &ldA, ipiv_ptr, 
+                MAT_BUFD(B)+oB, &ldB, &info);
+            break;
+
+	case COMPLEX:
+            zsytrs_(&uplo, &n, &nrhs, MAT_BUFZ(A)+oA, &ldA, ipiv_ptr, 
+                MAT_BUFZ(B)+oB, &ldB, &info);
+            break;
+
+	default:
+#if (SIZEOF_INT < SIZEOF_LONG) 
+            free(ipiv_ptr); 
+#endif 
+	    err_invalid_id;
+    }
+
+#if (SIZEOF_INT < SIZEOF_LONG) 
+    free(ipiv_ptr); 
+#endif 
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_hetrs[] = 
+    "Solves a real symmetric or complex Hermitian set of linear\n"
+    "equations, given the LDL^H factorization computed by hetrf() or " 
+    "hesv().\n\n"
+    "hetrs(A, ipiv, B, uplo='L', n=A.size[0], nrhs=B.size[1],\n"
+    "      ldA=max(1,A.size[0]), ldB=max(1,B.size[0]), offsetA=0,\n"
+    "      offsetB=0)\n\n"
+    "PURPOSE\n"
+    "Solves A*X = B where A is real symmetric or complex Hermitian\n"
+    "and n by n, and B is n by nrhs.  On entry, A and ipiv contain\n"
+    "the factorization of A as returned by hetrf or hesv.  On exit, B\n"
+    "is replaced by the solution.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "ipiv      'i' matrix \n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'U' or 'L'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "ldB       positive integer.  ldB >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* hetrs(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B, *ipiv; 
+    int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; 
+    char uplo='L';
+    char *kwlist[] = {"A", "ipiv", "B", "uplo", "n", "nrhs", "ldA", "ldB", 
+        "offsetA", "offsetB", NULL};
+    
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ciiiiii", kwlist,
+        &A, &ipiv, &B, &uplo, &n, &nrhs, &ldA, &ldB, &oA, &oB)) 
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids;
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (nrhs < 0) nrhs = B->ncols; 
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1,n)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+    if (len(ipiv) < n) err_buf_len("ipiv");
+
+#if (SIZEOF_INT < SIZEOF_LONG)			
+    int *ipiv_ptr = malloc(n*sizeof(int));	
+    if (!ipiv_ptr) return PyErr_NoMemory();			
+    int i;  for (i=0; i<n; i++) ipiv_ptr[i] = MAT_BUFI(ipiv)[i];
+#else 
+    int *ipiv_ptr = MAT_BUFI(ipiv);		
+#endif						
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            dsytrs_(&uplo, &n, &nrhs, MAT_BUFD(A)+oA, &ldA, 
+                ipiv_ptr, MAT_BUFD(B)+oB, &ldB, &info);
+            break;
+
+	case COMPLEX:
+            zhetrs_(&uplo, &n, &nrhs, MAT_BUFZ(A)+oA, &ldA, 
+                ipiv_ptr, MAT_BUFZ(B)+oB, &ldB, &info);
+            break;
+
+	default:
+#if (SIZEOF_INT < SIZEOF_LONG) 
+            free(ipiv_ptr); 
+#endif 
+	    err_invalid_id;
+    }
+
+#if (SIZEOF_INT < SIZEOF_LONG) 
+    free(ipiv_ptr); 
+#endif 
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_sytri[] = 
+    "Inverse of a real or complex symmetric matrix.\n\n"
+    "sytri(A, ipiv, uplo='L', n=A.size[0], ldA=max(1,A.size[0]),\n"
+    "      offsetA=0)\n\n"
+    "PURPOSE\n"
+    "Computes the inverse of a real or complex symmetric matrix of\n"
+    "order n.  On entry, A and ipiv contain the LDL^T factorization,\n"
+    "as returned by sysv() or sytrf().  On exit A is replaced by the\n"
+    "inverse.  \n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "ipiv      'i' matrix \n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer";
+
+static PyObject* sytri(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *ipiv; 
+    int n=-1, ldA=0, oA=0, info; 
+    char uplo='L';
+    void *work; 
+    char *kwlist[] = {"A", "ipiv", "uplo", "n", "ldA", "offsetA", NULL};
+    
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciii", kwlist,
+        &A, &ipiv, &uplo, &n, &ldA, &oA)) 
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (n == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (len(ipiv) < n) err_buf_len("ipiv");
+
+#if (SIZEOF_INT < SIZEOF_LONG)			
+    int *ipiv_ptr = malloc(n*sizeof(int));	
+    if (!ipiv_ptr) return PyErr_NoMemory();			
+    int i;  for (i=0; i<n; i++) ipiv_ptr[i] = MAT_BUFI(ipiv)[i];
+#else 
+    int *ipiv_ptr = MAT_BUFI(ipiv);		
+#endif						
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            if (!(work = (void *) calloc(n, sizeof(double)))) {
+#if (SIZEOF_INT < SIZEOF_LONG)
+                free(ipiv_ptr);
+#endif
+                return PyErr_NoMemory();
+            }
+            dsytri_(&uplo, &n, MAT_BUFD(A)+oA, &ldA, ipiv_ptr, 
+                (double *) work, &info);
+            free(work);
+            break;
+
+	case COMPLEX:
+            if (!(work = (void *) calloc(2*n, sizeof(complex)))){
+#if (SIZEOF_INT < SIZEOF_LONG)
+                free(ipiv_ptr);
+#endif
+                return PyErr_NoMemory();
+            }
+            zsytri_(&uplo, &n, MAT_BUFZ(A)+oA, &ldA, ipiv_ptr, 
+                (complex *) work, &info);
+            free(work);
+            break;
+
+        default:
+#if (SIZEOF_INT < SIZEOF_LONG)
+            free(ipiv_ptr);
+#endif
+            err_invalid_id;
+    }
+
+#if (SIZEOF_INT < SIZEOF_LONG) 
+    free(ipiv_ptr); 
+#endif 
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_hetri[] = 
+    "Inverse of a real symmetric or complex Hermitian matrix.\n\n"
+    "hetri(A, ipiv, uplo='L', n=A.size[0], ldA=max(1,A.size[0]),\n"
+    "      offsetA=0)\n\n"
+    "PURPOSE\n"
+    "Computes the inverse of a real symmetric or complex Hermitian\n"
+    "matrix of order n.  On entry, A and ipiv contain the LDL^T\n"
+    "factorization, as returned by hesv() or hetrf().  On exit A is\n"
+    "replaced by the inverse. \n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "ipiv      'i' matrix \n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer";
+
+static PyObject* hetri(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *ipiv; 
+    int n=-1, ldA=0, oA=0, info; 
+    char uplo='L';
+    void *work; 
+    char *kwlist[] = {"A", "ipiv", "uplo", "n", "ldA", "offsetA", NULL};
+    
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciii", kwlist,
+        &A, &ipiv, &uplo, &n, &ldA, &oA)) 
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (n == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (len(ipiv) < n) err_buf_len("ipiv");
+
+#if (SIZEOF_INT < SIZEOF_LONG)			
+    int *ipiv_ptr = malloc(n*sizeof(int));	
+    if (!ipiv_ptr) return PyErr_NoMemory();			
+    int i;  for (i=0; i<n; i++) ipiv_ptr[i] = MAT_BUFI(ipiv)[i];
+#else 
+    int *ipiv_ptr = MAT_BUFI(ipiv);		
+#endif						
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            if (!(work = (void *) calloc(n, sizeof(double)))){
+#if (SIZEOF_INT < SIZEOF_LONG)
+                free(ipiv_ptr);
+#endif
+                return PyErr_NoMemory();
+            }
+            dsytri_(&uplo, &n, MAT_BUFD(A)+oA, &ldA, ipiv_ptr, 
+                (double *) work, &info);
+            free(work);
+            break;
+
+        case COMPLEX:
+            if (!(work = (void *) calloc(n, sizeof(complex)))){
+#if (SIZEOF_INT < SIZEOF_LONG)
+                free(ipiv_ptr);
+#endif
+                return PyErr_NoMemory();
+            }
+            zhetri_(&uplo, &n, MAT_BUFZ(A)+oA, &ldA, ipiv_ptr, 
+                (complex *) work, &info);
+            free(work);
+            break;
+
+        default:
+#if (SIZEOF_INT < SIZEOF_LONG)
+            free(ipiv_ptr);
+#endif
+            err_invalid_id;
+    }
+
+#if (SIZEOF_INT < SIZEOF_LONG) 
+    free(ipiv_ptr); 
+#endif 
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_sysv[] = 
+    "Solves a real or complex symmetric set of linear equations.\n\n"
+    "sysv(A, B, ipiv=None, uplo='L', n=A.size[0], nrhs=B.size[1],\n"
+    "     ldA = max(1,A.size[0]), ldB = max(1,B.size[0]),\n"
+    "     offsetA=0, offsetB=0)\n\n"
+    "PURPOSE\n"
+    "Solves A*X = B where A is real or complex symmetric and n by n.\n"
+    "If ipiv is provided, then on exit A and ipiv contain the details\n"
+    "of the LDL^T factorization of A.  If ipiv is not provided, then\n"
+    "the factorization is not returned and A is not modified.  On\n"
+    "exit, B contains the solution.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "ipiv      'i' matrix of length at least n\n\n" 
+    "uplo      'L' or 'U'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "ldB       positive integer.  ldB >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* sysv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B, *ipiv=NULL; 
+    int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info, lwork, k,
+        *ipivc=NULL; 
+    void *work=NULL, *Ac=NULL;
+    number wl;
+    char uplo='L';
+    char *kwlist[] = {"A", "B", "ipiv", "uplo", "n", "nrhs", "ldA", 
+        "ldB", "offsetA", "offsetB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ociiiiii", kwlist,
+        &A, &B, &ipiv, &uplo, &n, &nrhs, &ldA, &ldB, &oA, &oB))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids;
+    if (ipiv && (!Matrix_Check(ipiv) || ipiv->id != INT)) 
+        err_int_mtrx("ipiv");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1, n)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+    if (ipiv && len(ipiv) < n) err_buf_len("ipiv");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            lwork = -1;
+            dsytrf_(&uplo, &n, NULL, &ldA, NULL, &wl.d, &lwork, &info);
+            lwork = (int) wl.d;
+            if (!(work = (void *) calloc(lwork, sizeof(double))))
+                return PyErr_NoMemory();
+            if (ipiv) {
+#if (SIZEOF_INT < SIZEOF_LONG)			
+                if (!(ipivc = (int *) calloc(n, sizeof(int)))){	
+                    free(work); 
+                    return PyErr_NoMemory();
+                }
+                for (k=0; k<n; k++) ipivc[k] = MAT_BUFI(ipiv)[k];
+#else 
+                ipivc = MAT_BUFI(ipiv);		
+#endif						
+                dsysv_(&uplo, &n, &nrhs, MAT_BUFD(A)+oA, &ldA, ipivc, 
+                    MAT_BUFD(B)+oB, &ldB, (double *) work, &lwork, 
+                    &info);
+#if (SIZEOF_INT < SIZEOF_LONG) 
+		for (k=0; k<n; k++) MAT_BUFI(ipiv)[k] = ipivc[k];
+                free(ipivc); 
+#endif 
+	    }
+            else {
+                ipivc = (int *) calloc(n, sizeof(int));
+                Ac = (void *) calloc(n*n, sizeof(double));
+                if (!ipivc || !Ac){
+                    free(work);  free(ipivc);  free(Ac);
+                    return PyErr_NoMemory();
+                }
+                for (k=0; k<n; k++) 
+                    memcpy((double *) Ac + k*n, MAT_BUFD(A) + oA + k*ldA, 
+                        n*sizeof(double));
+                dsysv_(&uplo, &n, &nrhs, (double *) Ac, &n, ipivc, 
+                    MAT_BUFD(B)+oB, &ldB, work, &lwork, &info);
+                free(ipivc); free(Ac);
+            }
+            free(work);   
+            break;
+
+        case COMPLEX:
+            lwork = -1;
+            zsytrf_(&uplo, &n, NULL, &ldA, NULL, &wl.z, &lwork, &info);
+            lwork = (int) creal(wl.z);
+            if (!(work = (void *) calloc(lwork, sizeof(complex))))
+                return PyErr_NoMemory();
+            if (ipiv) {
+#if (SIZEOF_INT < SIZEOF_LONG)			
+                if (!(ipivc = (int *) calloc(n, sizeof(int)))){	
+                    free(work);
+                    return PyErr_NoMemory();			
+                }
+                for (k=0; k<n; k++) ipivc[k] = MAT_BUFI(ipiv)[k];
+#else 
+                ipivc = MAT_BUFI(ipiv);		
+#endif
+                zsysv_(&uplo, &n, &nrhs, MAT_BUFZ(A)+oA, &ldA, ipivc, 
+                    MAT_BUFZ(B)+oB, &ldB, (complex *) work, &lwork, &info);
+#if (SIZEOF_INT < SIZEOF_LONG) 
+                for (k=0; k<n; k++) MAT_BUFI(ipiv)[k] = ipivc[k];
+                free(ipivc); 
+#endif 
+            }
+            else {
+                ipivc = (int *) calloc(n, sizeof(int));
+                Ac = (void *) calloc(n*n, sizeof(complex));
+                if (!ipivc || !Ac){
+                    free(work);  free(ipivc);  free(Ac);
+                    return PyErr_NoMemory();
+                }
+                for (k=0; k<n; k++) 
+                    memcpy((complex *) Ac + k*n, MAT_BUFZ(A) + oA + k*ldA, 
+                        n*sizeof(complex));
+                zsysv_(&uplo, &n, &nrhs, (complex *) Ac, &n, ipivc, 
+                    MAT_BUFZ(B)+oB, &ldB, work, &lwork, &info);
+                free(ipivc);  free(Ac);    
+            }
+            free(work);   
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_hesv[] = 
+    "Solves a real symmetric or complex Hermitian set of linear\n"
+    "equations.\n\n"
+    "herv(A, B, ipiv=None, uplo='L', n=A.size[0], nrhs=B.size[1],\n"
+    "     ldA = max(1,A.size[0]), ldB = max(1,B.size[0]), offsetA=0,\n"
+    "     offsetB=0)\n\n"
+    "PURPOSE\n"
+    "Solves A*X=B where A is real symmetric or complex Hermitian and\n"
+    "n by n.  If ipiv is provided, then on exit A and ipiv contain\n"
+    "the details of the LDL^H factorization of A.  If ipiv is not\n"
+    "provided, then the factorization is not returned and A is not\n"
+    "modified.  On exit, B contains the solution.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "ipiv      'i' matrix of length at least n\n\n" 
+    "uplo      'U' or 'L'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "ldB       positive integer.  ldB >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* hesv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B, *ipiv=NULL; 
+    int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info, lwork, k,
+        *ipivc=NULL; 
+    void *work=NULL, *Ac=NULL;
+    number wl;
+    char uplo='L';
+    char *kwlist[] = {"A", "B", "ipiv", "uplo", "n", "nrhs", "ldA", "ldB", 
+        "offsetA", "offsetB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ociiiiii", kwlist,
+        &A, &B, &ipiv, &uplo, &n, &nrhs, &ldA, &ldB, &oA, &oB))
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids;
+    if (ipiv && (!Matrix_Check(ipiv) || ipiv->id != INT)) 
+        err_int_mtrx("ipiv");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1, n)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+    if (ipiv && len(ipiv) < n) err_buf_len("ipiv");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            lwork = -1;
+            dsytrf_(&uplo, &n, NULL, &ldA, NULL, &wl.d, &lwork, &info);
+            lwork = (int) wl.d;
+            if (!(work = (void *) calloc(lwork, sizeof(double))))
+                return PyErr_NoMemory();
+            if (ipiv) {
+#if (SIZEOF_INT < SIZEOF_LONG)			
+                if (!(ipivc = (int *) calloc(n,sizeof(int)))){	
+                    free(work);  
+                    return PyErr_NoMemory();			
+                }
+                int i; for (i=0; i<n; i++) ipivc[i] = MAT_BUFI(ipiv)[i];
+#else 
+                ipivc = MAT_BUFI(ipiv);		
+#endif
+                dsysv_(&uplo, &n, &nrhs, MAT_BUFD(A)+oA, &ldA, ipivc, 
+                    MAT_BUFD(B)+oB, &ldB, (double *) work, &lwork, 
+                    &info);
+#if (SIZEOF_INT < SIZEOF_LONG) 
+                for (i=0; i<n; i++) MAT_BUFI(ipiv)[i] = ipivc[i];
+                free(ipivc); 
+#endif 
+            }
+            else {
+                ipivc = (int *) calloc(n, sizeof(int));
+                Ac = (void *) calloc(n*n, sizeof(double));
+                if (!ipivc || !Ac){
+                    free(work);  free(ipivc);  free(Ac);
+                    return PyErr_NoMemory();
+                }
+                for (k=0; k<n; k++) 
+                    memcpy((double *) Ac + k*n, MAT_BUFD(A) + oA + k*ldA, 
+                        n*sizeof(double));
+                dsysv_(&uplo, &n, &nrhs, (double *) Ac, &n, ipivc, 
+                    MAT_BUFD(B)+oB, &ldB, work, &lwork, &info);
+                free(ipivc);  free(Ac); 
+            }
+            free(work);   
+            break;
+
+        case COMPLEX:
+            lwork = -1;
+            zhetrf_(&uplo, &n, NULL, &ldA, NULL, &wl.z, &lwork, &info);
+            lwork = (int) creal(wl.z);
+            if (!(work = (void *) calloc(lwork, sizeof(complex))))
+                return PyErr_NoMemory();
+            if (ipiv) {
+#if (SIZEOF_INT < SIZEOF_LONG)			
+                if (!(ipivc = (int *) calloc(n,sizeof(int)))){ 	
+                    free(work);
+                    return PyErr_NoMemory();			
+                }
+                for (k=0; k<n; k++) ipivc[k] = MAT_BUFI(ipiv)[k];
+#else 
+                ipivc = MAT_BUFI(ipiv);		
+#endif
+                zhesv_(&uplo, &n, &nrhs, MAT_BUFZ(A)+oA, &ldA, ipivc, 
+                    MAT_BUFZ(B)+oB, &ldB, (complex *) work, &lwork, &info);
+#if (SIZEOF_INT < SIZEOF_LONG) 
+                for (k=0; k<n; k++) MAT_BUFI(ipiv)[k] = ipivc[k];
+                free(ipivc); 
+#endif 
+            }
+            else {
+                ipivc = (int *) calloc(n, sizeof(int));
+                Ac = (void *) calloc(n*n, sizeof(complex));
+                if (!ipivc || !Ac){
+                    free(work);  free(ipivc);  free(Ac);
+                    return PyErr_NoMemory();
+                }
+                for (k=0; k<n; k++) 
+                    memcpy((complex *) Ac + k*n, MAT_BUFZ(A) + oA + k*ldA, 
+                        n*sizeof(complex));
+                zhesv_(&uplo, &n, &nrhs, (complex *) Ac, &n, ipivc, 
+                    MAT_BUFZ(B)+oB, &ldB, work, &lwork, &info);
+                free(ipivc);  free(Ac); 
+            }
+            free(work);   
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_trtrs[] =
+    "Solution of a triangular set of equations with multiple righthand\n"
+    "sides.\n\n"
+    "trtrs(A, B, uplo='L', trans='N', diag='N', n=A.size[0],\n"
+    "      nrhs=B.size[1], ldA=max(1,A.size[0]), ldB=max(1,B.size[0]),\n"
+    "      offsetA=0, offsetB=0)\n\n"
+    "PURPOSE\n"   
+    "If trans is 'N', solves A*X = B.\n"
+    "If trans is 'T', solves A^T*X = B.\n"
+    "If trans is 'C', solves A^H*X = B.\n"
+    "B is n by nrhs and A is triangular of order n.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "trans     'N', 'T' or 'C'\n\n"
+    "diag      'N' or 'U'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n" 
+    "ldB       positive integer.  ldB >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* trtrs(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B;
+    int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info;
+    char uplo='L', trans='N', diag='N';
+    char *kwlist[] = {"A", "B", "uplo", "trans", "diag", "n", "nrhs", 
+        "ldA", "ldB", "offsetA", "offsetB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccciiiiii", kwlist, 
+        &A, &B, &uplo, &trans, &diag, &n, &nrhs, &ldA, &ldB, &oA, &oB)) 
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids;
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (diag != 'N' && diag != 'U') err_char("diag", "'N', 'U'");
+    if (trans != 'N' && trans != 'T' && trans != 'C') 
+        err_char("trans", "'N', 'T', 'C'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (A->nrows != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1,n)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB"); 
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            if (trans == 'C') trans = 'T';
+            dtrtrs_(&uplo, &trans, &diag, &n, &nrhs, MAT_BUFD(A)+oA, 
+                &ldA, MAT_BUFD(B)+oB, &ldB, &info);
+            break;
+
+        case COMPLEX:
+            ztrtrs_(&uplo, &trans, &diag, &n, &nrhs, MAT_BUFZ(A)+oA, 
+                &ldA, MAT_BUFZ(B)+oB, &ldB, &info);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_trtri[] =
+    "Inverse of a triangular matrix.\n\n"
+    "trtri(A, uplo='L', diag='N', n=A.size[0], ldA=max(1,A.size[0]),\n" 
+    "      offsetA=0)\n\n"
+    "PURPOSE\n"   
+    "Computes the inverse of a triangular matrix of order n.\n"
+    "On exit, A is replaced with its inverse.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "diag      'N' or 'U'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n" 
+    "offsetA   nonnegative integer";
+
+static PyObject* trtri(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A;
+    int n=-1, ldA=0, oA=0, info;
+    char uplo='L', diag='N';
+    char *kwlist[] = {"A", "uplo", "diag", "n", "ldA", "offsetA", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|cciii", kwlist, 
+        &A, &uplo, &diag, &n, &ldA, &oA)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (diag != 'N' && diag != 'U') err_char("diag", "'N', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (A->nrows != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (n == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            dtrtri_(&uplo, &diag, &n, MAT_BUFD(A)+oA, &ldA, &info);
+            break;
+
+        case COMPLEX:
+            ztrtri_(&uplo, &diag, &n, MAT_BUFZ(A)+oA, &ldA, &info);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_tbtrs[] =
+    "Solution of a triangular set of equations with banded coefficient\n"
+    "matrix.\n\n"
+    "tbtrs(A, B, uplo='L', trans='N', diag='N', n=A.size[1], \n"
+    "      kd=A.size[0]-1, nrhs=B.size[1], ldA=max(1,A.size[0]),\n"
+    "      ldB=max(1,B.size[0]), offsetA=0, offsetB=0)\n\n"
+    "PURPOSE\n"   
+    "If trans is 'N', solves A*X = B.\n"
+    "If trans is 'T', solves A^T*X = B.\n"
+    "If trans is 'C', solves A^H*X = B.\n"
+    "B is n by nrhs and A is a triangular band matrix of order n with kd\n"
+    "subdiagonals (uplo is 'L') or superdiagonals (uplo is 'U').\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "trans     'N', 'T' or 'C'\n\n"
+    "diag      'N' or 'U'\n\n"
+    "n         nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "kd        nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "nrhs      nonnegative integer.  If negative, the default value is\n"
+    "          used.\n\n"
+    "ldA       positive integer.  ldA >= kd+1.  If zero, the default\n"
+    "          value is used.\n\n" 
+    "ldB       positive integer.  ldB >= max(1,n).  If zero, the default\n"
+    "          value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* tbtrs(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B;
+    char uplo='L', trans='N', diag='N';
+    int n=-1, kd=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info;
+    char *kwlist[] = {"A", "B", "uplo", "trans", "diag", "n", "kd", "nrhs",
+        "ldA", "ldB", "offsetA", "offsetB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccciiiiiii", kwlist, 
+        &A, &B, &uplo, &trans, &diag, &n, &kd, &nrhs, &ldA, &ldB, &oA, 
+        &oB)) 
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids;
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (diag != 'N' && diag != 'U') err_char("diag", "'N', 'U'");
+    if (trans != 'N' && trans != 'T' && trans != 'C') 
+        err_char("trans", "'N', 'T', 'C'");
+    if (n < 0) n = A->ncols;
+    if (kd < 0) kd = A->nrows - 1;
+    if (kd < 0) err_nn_int("kd");
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < kd+1) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1,n)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + kd + 1 > len(A)) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB"); 
+    if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            if (trans == 'C') trans = 'T';
+            dtbtrs_(&uplo, &trans, &diag, &n, &kd, &nrhs, MAT_BUFD(A)+oA, 
+                &ldA, MAT_BUFD(B)+oB, &ldB, &info);
+            break;
+
+        case COMPLEX:
+            ztbtrs_(&uplo, &trans, &diag, &n, &kd, &nrhs, MAT_BUFZ(A)+oA, 
+                &ldA, MAT_BUFZ(B)+oB, &ldB, &info);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_gels[] = 
+    "Solves least-squares and least-norm problems with full rank\n"
+    "matrices.\n\n"
+    "gels(A, B, trans='N', m=A.size[0], n=A.size[1], nrhs=B.size[1],\n"
+    "     ldA=max(1,A.size[0]), ldB=max(1,B.size[0]), offsetA=0,\n"
+    "     offsetB=0)\n\n"
+    "PURPOSE\n" 
+    "1. If trans is 'N' and A and B are real/complex:\n"
+    "- if m >= n: minimizes ||A*X - B||_F.\n" 
+    "- if m < n: minimizes ||X||_F subject to A*X = B.\n\n" 
+    "2. If trans is 'N' or 'C' and A and B are real:\n"
+    "- if m >= n: minimizes ||X||_F subject to A^T*X = B.\n"
+    "- if m < n: minimizes ||X||_F subject to A^T*X = B.\n\n"
+    "3. If trans is 'C' and A and B are complex:\n"
+    "- if m >= n: minimizes ||X||_F subject to A^H*X = B.\n"
+    "- if m < n: minimizes ||X||_F subject to A^H*X = B.\n\n"
+    "A is an m by n matrix.  B has nrhs columns.  On exit, B is\n"
+    "replaced with the solution, and A is replaced with the details\n"
+    "of its QR or LQ factorization.\n\n"
+    "Note that gels does not check whether A has full rank.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "trans     'N', 'T' or 'C' if A is real.  'N' or 'C' if A is\n"
+    "          complex.\n\n"
+    "m         integer.  If negative, the default value is used.\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "nrhs      integer.  If negative, the default value is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,m).  If zero, the\n"
+    "          default value is used.\n\n"
+    "ldB       nonnegative integer.  ldB >= max(1,m,n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* gels(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B; 
+    int m=-1, n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info, lwork; 
+    void *work; 
+    number wl;
+    char trans='N';
+    char *kwlist[] = {"A", "B", "trans", "m", "n", "nrhs", "ldA", "ldB",
+        "offsetA", "offsetB", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciiiiiii", 
+        kwlist, &A, &B, &trans, &m, &n, &nrhs, &ldA, &ldB, &oA, &oB)) 
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B)) err_mtrx("B");
+    if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids;
+    if (trans != 'N' && trans != 'T' && trans != 'C')
+        err_char("trans", "'N', 'T', 'C'");
+    if (m < 0) m = A->nrows;
+    if (n < 0) n = A->ncols;
+    if (nrhs < 0) nrhs = B->ncols;
+    if (m == 0 || n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,m)) err_ld("ldA"); 
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(MAX(1,n),m)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA");  
+    if (oA + (n-1)*ldA + m > len(A)) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (nrhs-1)*ldB + ((trans == 'N') ? m : n) > len(B))
+        err_buf_len("B");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            if (trans == 'C') trans = 'T';
+            lwork = -1;
+            dgels_(&trans, &m, &n, &nrhs, NULL, &ldA, NULL, &ldB, &wl.d,
+                &lwork, &info);
+            lwork = (int) wl.d;
+            if (!(work = (void *) calloc(lwork, sizeof(double))))
+                return PyErr_NoMemory();
+            dgels_(&trans, &m, &n, &nrhs, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(B)+oB, &ldB, (double *) work, &lwork, &info);
+            free(work);
+	    break;
+
+        case COMPLEX:
+            if (trans == 'T') err_char("trans", "'N', 'C'");
+            lwork = -1;
+            zgels_(&trans, &m, &n, &nrhs, NULL, &ldA, NULL, &ldB, &wl.z,
+                &lwork, &info);
+            lwork = (int) creal(wl.z);
+            if (!(work = (void *) calloc(lwork, sizeof(complex))))
+                return PyErr_NoMemory();
+            zgels_(&trans, &m, &n, &nrhs, MAT_BUFZ(A)+oA, &ldA, 
+                MAT_BUFZ(B)+oB, &ldB, (complex *) work, &lwork, &info);
+            free(work);
+	    break;
+
+        default:
+	    err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_geqrf[] = 
+    "QR factorization.\n\n"
+    "geqrf(A, tau, m=A.size[0], n=A.size[1], ldA=max(1,A.size[0]),\n"
+    "      offsetA=0)\n\n"
+    "PURPOSE\n" 
+    "QR factorization of an m by n real or complex matrix A:\n"
+    "A = Q*R = [Q1 Q2] * [R1; 0] if m >= n\n" 
+    "A = Q*R = Q * [R1 R2] if m <= n,\n"
+    "where Q is m by m and orthogonal/unitary and R is m by n with R1\n"
+    "upper triangular.  On exit, R is stored in the upper triangular\n"
+    "part of A.  Q is stored as a product of k=min(m,n) elementary\n"
+    "reflectors.  The parameters of the reflectors are stored in the\n"
+    "first k entries of tau and in the lower triangular part of the\n"
+    "first k columns of A.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "tau       'd' or 'z' matrix of length at least min(m,n).  Must\n"
+    "          have the same type as A.\n\n"
+    "m         integer.  If negative, the default value is used.\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,m).  If zero, the\n"
+    "          default value is used.\n\n"
+    "offsetA   nonnegative integer";
+
+static PyObject* geqrf(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *tau; 
+    int m=-1, n=-1, ldA=0, oA=0, info, lwork; 
+    void *work; 
+    number wl;
+    char *kwlist[] = {"A", "tau", "m", "n", "ldA", "offsetA", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiii", kwlist, 
+        &A, &tau, &m, &n, &ldA, &oA)) 
+        return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(tau)) err_mtrx("tau");
+    if (MAT_ID(A) != MAT_ID(tau)) err_conflicting_ids;
+    if (m < 0) m = A->nrows;
+    if (n < 0) n = A->ncols;
+    if (m == 0 || n == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,m)) err_ld("ldA"); 
+    if (oA < 0) err_nn_int("offsetA");  
+    if (oA + (n-1)*ldA + m > len(A)) err_buf_len("A");
+    if (len(tau) < MIN(m,n)) err_buf_len("tau");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            lwork = -1;
+            dgeqrf_(&m, &n, NULL, &ldA, NULL, &wl.d, &lwork, &info);
+            lwork = (int) wl.d;
+            if (!(work = (void *) calloc(lwork, sizeof(double))))
+                return PyErr_NoMemory();
+            dgeqrf_(&m, &n, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(tau), 
+                (double *) work, &lwork, &info);
+            free(work);
+	    break;
+
+        case COMPLEX:
+            lwork = -1;
+            zgeqrf_(&m, &n, NULL, &ldA, NULL, &wl.z, &lwork, &info);
+            lwork = (int) creal(wl.z);
+            if (!(work = (void *) calloc(lwork, sizeof(complex))))
+                return PyErr_NoMemory();
+            zgeqrf_(&m, &n, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(tau), 
+                (complex *) work, &lwork, &info);
+            free(work);
+	    break;
+
+        default:
+	    err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_ormqr[] = 
+    "Product with a real orthogonal matrix.\n\n"
+    "ormqr(A, tau, C, side='L', trans='N', m=C.size[0], n=C.size[1],\n"
+    "      k=min(A.size), ldA=max(1,A.size[0]), ldC=max(1,C.size[0]),\n"
+    "      offsetA=0, offsetC=0)\n\n"
+    "PURPOSE\n" 
+    "Computes\n"
+    "C := Q*C   if side = 'L' and trans = 'N'.\n"
+    "C := Q^T*C if side = 'L' and trans = 'T'.\n"
+    "C := C*Q   if side = 'R' and trans = 'N'.\n"
+    "C := C*Q^T if side = 'R' and trans = 'T'.\n"
+    "C is m by n and Q is a square orthogonal matrix computed by geqrf."
+    "\n"
+    "Q is defined as a product of k elementary reflectors, stored as\n"
+    "the first k columns of A and the first k entries of tau.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' matrix\n\n"
+    "tau       'd' matrix of length at least k\n\n"
+    "C         'd' matrix\n\n"
+    "side      'L' or 'R'\n\n"
+    "trans     'N' or 'T'\n\n"
+    "m         integer.  If negative, the default value is used.\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "k         integer.  If negative, the default value is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,m) if side = 'L'\n"
+    "          and ldA >= max(1,n) if side = 'R'.  If zero, the\n"
+    "          default value is used.\n\n"
+    "ldC       nonnegative integer.  ldC >= max(1,m).  If zero, the\n"
+    "          default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* ormqr(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *tau, *C; 
+    int m=-1, n=-1, k=-1, ldA=0, ldC=0, oA=0, oC=0, info, lwork; 
+    void *work; 
+    number wl;
+    char side='L', trans='N';
+    char *kwlist[] = {"A", "tau", "C", "side", "trans", "m", "n", "k", 
+        "ldA", "ldC", "offsetA", "offsetC", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cciiiiiii", 
+        kwlist, &A, &tau, &C, &side, &trans, &m, &n, &k, &ldA, &ldC, 
+        &oA, &oC)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(tau)) err_mtrx("tau");
+    if (!Matrix_Check(C)) err_mtrx("C");
+    if (MAT_ID(A) != MAT_ID(tau) || MAT_ID(A) != MAT_ID(C)) 
+        err_conflicting_ids;
+    if (side != 'L' && side != 'R') err_char("side", "'L', 'R'");
+    if (trans != 'N' && trans != 'T') err_char("trans", "'N', 'T'");
+    if (m < 0) m = C->nrows;
+    if (n < 0) n = C->ncols;
+    if (k < 0) k = MIN(A->nrows, A->ncols);
+    if (m == 0 || n == 0 || k == 0) return Py_BuildValue("");
+    if (k > ((side == 'L') ? m : n)) err_ld("k");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < ((side == 'L') ? MAX(1,m) : MAX(1,n))) err_ld("ldA"); 
+    if (ldC == 0) ldC = MAX(1,C->nrows);
+    if (ldC < MAX(1,m)) err_ld("ldC");
+    if (oA < 0) err_nn_int("offsetA");  
+    if (oA + (k-1)*ldA + ((side == 'L' ) ? m : n) > len(A)) 
+        err_buf_len("A");
+    if (oC < 0) err_nn_int("offsetC");
+    if (oC + (n-1)*ldC + m > len(C)) err_buf_len("C");
+    if (len(tau) < k) err_buf_len("tau");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            lwork = -1;
+            dormqr_(&side, &trans, &m, &n, &k, NULL, &ldA, NULL, NULL,
+                &ldC, &wl.d, &lwork, &info);
+            lwork = (int) wl.d;
+            if (!(work = (void *) calloc(lwork, sizeof(double))))
+                return PyErr_NoMemory();
+            dormqr_(&side, &trans, &m, &n, &k, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(tau), MAT_BUFD(C)+oC, &ldC, (double *) work, 
+                &lwork, &info);
+            free(work);
+	    break;
+
+        default:
+	    err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_unmqr[] = 
+    "Product with a real or complex orthogonal matrix.\n\n"
+    "ormqr(A, tau, C, side='L', trans='N', m=C.size[0], n=C.size[1],\n"
+    "      k=min(A.size), ldA=max(1,A.size[0]), ldC=max(1,C.size[0]),\n"
+    "      offsetA=0, offsetC=0)\n\n"
+    "PURPOSE\n" 
+    "Computes\n"
+    "C := Q*C   if side = 'L' and trans = 'N'.\n"
+    "C := Q^T*C if side = 'L' and trans = 'T'.\n"
+    "C := Q^H*C if side = 'L' and trans = 'C'.\n"
+    "C := C*Q   if side = 'R' and trans = 'N'.\n"
+    "C := C*Q^T if side = 'R' and trans = 'T'.\n"
+    "C := C*Q^H if side = 'R' and trans = 'C'.\n"
+    "C is m by n and Q is a square orthogonal/unitary matrix computed\n"
+    "by geqrf.  Q is defined as a product of k elementary reflectors,\n"
+    "stored as the first k columns of A and the first k entries of tau."
+    "\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "tau       'd' or 'z' matrix of length at least k.  Must have the\n"
+    "          same type as A.\n\n"
+    "C         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "side      'L' or 'R'\n\n"
+    "trans     'N', 'T' or 'C'n\n"
+    "m         integer.  If negative, the default value is used.\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "k         integer.  If negative, the default value is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,m) if side = 'L'\n"
+    "          and ldA >= max(1,n) if side = 'R'.  If zero, the\n"
+    "          default value is used.\n\n"
+    "ldC       nonnegative integer.  ldC >= max(1,m).  If zero, the\n"
+    "          default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* unmqr(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *tau, *C; 
+    int m=-1, n=-1, k=-1, ldA=0, ldC=0, oA=0, oC=0, info, lwork; 
+    void *work; 
+    number wl;
+    char side='L', trans='N';
+    char *kwlist[] = {"A", "tau", "C", "side", "trans", "m", "n", "k", 
+        "ldA", "ldC", "offsetA", "offsetC", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cciiiiiii", 
+        kwlist, &A, &tau, &C, &side, &trans, &m, &n, &k, &ldA, &ldC, 
+        &oA, &oC)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(tau)) err_mtrx("tau");
+    if (!Matrix_Check(C)) err_mtrx("C");
+    if (MAT_ID(A) != MAT_ID(tau) || MAT_ID(A) != MAT_ID(C)) 
+        err_conflicting_ids;
+    if (side != 'L' && side != 'R') err_char("side", "'L', 'R'");
+    if (trans != 'N' && trans != 'T' && trans != 'C') 
+        err_char("trans", "'N', 'T', 'C'");
+    if (m < 0) m = C->nrows;
+    if (n < 0) n = C->ncols;
+    if (k < 0) k = MIN(A->nrows, A->ncols);
+    if (m == 0 || n == 0 || k == 0) return Py_BuildValue("");
+    if (k > ((side == 'L') ? m : n)) err_ld("k");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < ((side == 'L') ? MAX(1,m) : MAX(1,n))) err_ld("ldA"); 
+    if (ldC == 0) ldC = MAX(1,C->nrows);
+    if (ldC < MAX(1,m)) err_ld("ldC");
+    if (oA < 0) err_nn_int("offsetA");  
+    if (oA + (k-1)*ldA + ((side == 'L' ) ? m : n) > len(A)) 
+        err_buf_len("A");
+    if (oC < 0) err_nn_int("offsetC");
+    if (oC + (n-1)*ldC + m > len(C)) err_buf_len("C");
+    if (len(tau) < k) err_buf_len("tau");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            if (trans == 'C') trans = 'T';
+            lwork = -1;
+            dormqr_(&side, &trans, &m, &n, &k, NULL, &ldA, NULL, NULL,
+                &ldC, &wl.d, &lwork, &info);
+            lwork = (int) wl.d;
+            if (!(work = (void *) calloc(lwork, sizeof(double))))
+                return PyErr_NoMemory();
+            dormqr_(&side, &trans, &m, &n, &k, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(tau), MAT_BUFD(C)+oC, &ldC, (double *) work, 
+                &lwork, &info);
+            free(work);
+	    break;
+
+        case COMPLEX:
+            if (trans == 'T') err_char("trans", "'N', 'C'");
+            lwork = -1;
+            zunmqr_(&side, &trans, &m, &n, &k, NULL, &ldA, NULL, NULL,
+                &ldC, &wl.z, &lwork, &info);
+            lwork = (int) creal(wl.z);
+            if (!(work = (void *) calloc(lwork, sizeof(complex))))
+                return PyErr_NoMemory();
+            zunmqr_(&side, &trans, &m, &n, &k, MAT_BUFZ(A)+oA, &ldA, 
+                MAT_BUFZ(tau), MAT_BUFZ(C)+oC, &ldC, (complex *) work, 
+                &lwork, &info);
+            free(work);
+	    break;
+
+        default:
+	    err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+static char doc_syev[] = 
+    "Eigenvalue decomposition of a real symmetric matrix.\n\n"
+    "syev(A, W, jobz='N', uplo='L', n=A.size[0], "
+    "ldA = max(1,A.size[0]),\n"
+    "     offsetA=0, offsetW=0)\n\n"
+    "PURPOSE\n"
+    "Returns eigenvalues/vectors of a real symmetric nxn matrix A.\n"
+    "On exit, W contains the eigenvalues in ascending order.  If jobz\n"
+    "is 'V', the (normalized) eigenvectors are also computed and\n"
+    "returned in A.  If jobz is 'N', only the eigenvalues are\n"
+    "computed, and the content of A is destroyed.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' matrix\n\n"
+    "W         'd' matrix of length at least n\n\n"
+    "jobz      'N' or 'V'\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* syev(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *W; 
+    int n=-1, ldA=0, oA=0, oW=0, info, lwork; 
+    double *work; 
+    number wl; 
+    char uplo='L', jobz='N';
+    char *kwlist[] = {"A", "W", "jobz", "uplo", "n", "ldA", "offsetA", 
+        "offsetW", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cciiii", kwlist,
+        &A, &W, &jobz, &uplo, &n, &ldA, &oA, &oW)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(W) || MAT_ID(W) != DOUBLE) err_dbl_mtrx("W");
+    if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (n == 0) return Py_BuildValue("i",0);
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oW < 0) err_nn_int("offsetW");
+    if (oW + n > len(W)) err_buf_len("W");
+
+    switch (MAT_ID(A)){
+	case DOUBLE:
+	    lwork=-1;
+	    dsyev_(&jobz, &uplo, &n, NULL, &ldA, NULL, &wl.d, &lwork, 
+                &info);
+	    lwork = (int) wl.d;
+	    if (!(work = calloc(lwork, sizeof(double))))
+		return PyErr_NoMemory();
+	    dsyev_(&jobz, &uplo, &n, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(W)+oW, work, &lwork, &info);
+	    free(work);   
+	    break;
+
+        default:
+	    err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_heev[] = 
+    "Eigenvalue decomposition of a real symmetric or complex Hermitian"
+    "\nmatrix.\n\n"
+    "heev(A, W, jobz='N', uplo='L', n=A.size[0], "
+    "ldA = max(1,A.size[0]),\n"
+    "     offsetA=0, offsetW=0)\n\n"
+    "PURPOSE\n"
+    "Returns eigenvalues/vectors of a real symmetric or complex\n"
+    "Hermitian nxn matrix A.  On exit, W contains the eigenvalues in\n"
+    "ascending order.  If jobz is 'V', the (normalized) eigenvectors\n"
+    "are also computed and returned in A.  If jobz is 'N', only the\n"
+    "eigenvalues are computed, and the content of A is destroyed.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "W         'd' matrix of length at least n\n\n"
+    "jobz      'N' or 'V'\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* heev(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *W; 
+    int n=-1, ldA=0, oA=0, oW=0, info, lwork; 
+    double *rwork=NULL;
+    void *work=NULL; 
+    number wl; 
+    char uplo='L', jobz='N';
+    char *kwlist[] = {"A", "W", "jobz", "uplo", "n", "ldA", "offsetA", 
+        "offsetW", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cciiii", kwlist,
+        &A, &W, &jobz, &uplo, &n, &ldA, &oA, &oW)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(W) || MAT_ID(W) != DOUBLE) err_dbl_mtrx("W");
+    if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (n == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oW < 0) err_nn_int("offsetW");
+    if (oW + n > len(W)) err_buf_len("W");
+    switch (MAT_ID(A)){
+	case DOUBLE:
+	    lwork=-1;
+	    dsyev_(&jobz, &uplo, &n, NULL, &ldA, NULL, &wl.d, &lwork, 
+                &info);
+	    lwork = (int) wl.d;
+	    if (!(work = (void *) calloc(lwork, sizeof(double))))
+		return PyErr_NoMemory();
+	    dsyev_(&jobz, &uplo, &n, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(W)+oW, (double *) work, &lwork, &info);
+	    free(work);   
+	    break;
+
+        case COMPLEX:
+	    lwork=-1;
+	    zheev_(&jobz, &uplo, &n, NULL, &ldA, NULL, &wl.z, &lwork,
+                NULL, &info);
+	    lwork = (int) creal(wl.z);
+	    work = (void *) calloc(lwork, sizeof(complex));
+	    rwork = (double *) calloc(3*n-2, sizeof(double));
+	    if (!work || !rwork){
+		free(work);  free(rwork);
+		return PyErr_NoMemory();
+	    }
+	    zheev_(&jobz, &uplo, &n, MAT_BUFZ(A)+oA, &ldA, 
+		MAT_BUFD(W)+oW,  (complex *) work, &lwork, rwork, 
+		&info);
+	    free(work);  free(rwork);
+	    break;
+
+        default:
+	    err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_syevx[] = 
+    "Computes selected eigenvalues and eigenvectors of a real symmetric"
+    "\nmatrix (expert driver).\n\n"
+    "m = syevx(A, W, jobz='N', range='A', uplo='L', vl=0.0, vu=0.0, \n"
+    "          il=1, iu=1, Z=None, n=A.size[0], ldA=max(1,A.size[0]),\n"
+    "          ldZ=None, abstol=0.0, offsetA=0, offsetW=0,\n"
+    "          offsetZ=0)\n\n"
+    "PURPOSE\n"
+    "Computes selected eigenvalues/vectors of a real symmetric n by n\n"
+    "matrix A.\n"
+    "If range is 'A', all eigenvalues are computed.\n"
+    "If range is 'V', all eigenvalues in the interval (vl,vu] are\n"
+    "computed.\n"
+    "If range is 'I', all eigenvalues il through iu are computed\n"
+    "(sorted in ascending order with 1 <= il <= iu <= n).\n"
+    "If jobz is 'N', only the eigenvalues are returned in W.\n"
+    "If jobz is 'V', the eigenvectors are also returned in Z.\n"  
+    "On exit, the content of A is destroyed.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' matrix\n\n"  
+    "W         'd' matrix of length at least n.  On exit, contains\n"
+    "          the computed eigenvalues in ascending order.\n\n"
+    "jobz      'N' or 'V'\n\n"
+    "range     'A', 'V' or 'I'\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "vl,vu     doubles.  Only required when range is 'V'.\n\n"
+    "il,iu     integers.  Only required when range is 'I'.\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "Z         'd' matrix.  Only required when jobz is 'V'.  If range\n"
+    "          is 'A' or 'V', Z must have at least n columns.  If\n"
+    "          range is 'I', Z must have at least iu-il+1 columns.\n"
+    "          On exit the first m columns of Z contain the computed\n"
+    "          (normalized) eigenvectors.\n\n"
+    "abstol    double.  Absolute error tolerance for eigenvalues.\n"
+    "          If nonpositive, the LAPACK default value is used.\n\n"
+    "ldZ       nonnegative integer.  ldZ >= 1 if jobz is 'N' and\n"
+    "          ldZ >= max(1,n) if jobz is 'V'.  The default value\n"
+    "          is 1 if jobz is 'N' and max(1,Z.size[0]) if jobz ='V'.\n"
+    "          If zero, the default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetW   nonnegative integer\n\n"
+    "offsetZ   nonnegative integer\n\n"
+    "m         the number of eigenvalues computed";
+
+static PyObject* syevx(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *W, *Z=NULL; 
+    int n=-1, ldA=0, ldZ=0, il=1, iu=1, oA=0, oW=0, oZ=0, info, lwork,
+        *iwork, m, *ifail=NULL; 
+    double *work, vl=0.0, vu=0.0, abstol=0.0; 
+    double wl;
+    char uplo='L', jobz='N', range='A';
+    char *kwlist[] = {"A", "W", "jobz", "range", "uplo", "vl", "vu", 
+	"il", "iu", "Z", "n", "ldA", "ldZ", "abstol", "offsetA", 
+        "offsetW", "offsetZ", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cccddiiOiiidiii",
+        kwlist, &A, &W, &jobz, &range, &uplo, &vl, &vu, &il, &iu, &Z,
+	&n, &ldA, &ldZ, &abstol, &oA, &oW, &oZ)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(W) || MAT_ID(W) != DOUBLE) err_dbl_mtrx("W");
+    if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'");
+    if (range != 'A' && range != 'V' && range != 'I') 
+	err_char("range", "'A', 'V', 'I'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (n == 0) return Py_BuildValue("i",0);
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (range == 'V' && vl >= vu){
+        PyErr_SetString(PyExc_ValueError, "vl must be less than vu");
+        return NULL;
+    }
+    if (range == 'I' && (il < 1 || il > iu || iu > n)){
+        PyErr_SetString(PyExc_ValueError, "il and iu must satisfy "
+            "1 <= il <= iu <= n");
+        return NULL;
+    }
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oW < 0) err_nn_int("offsetW");
+    if (oW + n > len(W)) err_buf_len("W");
+    if (jobz == 'V'){
+        if (!Z || !Matrix_Check(Z) || MAT_ID(Z) != DOUBLE) 
+            err_dbl_mtrx("Z");
+        if (ldZ == 0) ldZ = MAX(1,Z->nrows);
+        if (ldZ < MAX(1,n)) err_ld("ldZ");
+        if (oZ < 0) err_nn_int("offsetZ");
+        if (oZ + ((range == 'I') ? iu-il : n-1)*ldZ + n > len(Z)) 
+	    err_buf_len("Z"); 
+    } else {
+        if (ldZ == 0) ldZ = 1;
+        if (ldZ < 1) err_ld("ldZ");
+    }
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+	    lwork = -1;
+	    dsyevx_(&jobz, &range, &uplo, &n, NULL, &ldA, &vl, &vu, &il,
+                &iu, &abstol, &m, NULL, NULL, &ldZ, &wl, &lwork, NULL,
+	       	NULL, &info);
+	    lwork = (int) wl;
+	    work = (double *) calloc(lwork, sizeof(double));
+	    iwork = (int *) calloc(5*n, sizeof(int));
+	    if (jobz == 'V') ifail = (int *) calloc(n, sizeof(int));
+	    if (!work || !iwork || (jobz == 'V' && !ifail)){
+		free(work); free(iwork); free(ifail);
+	        return PyErr_NoMemory();
+	    }
+	    dsyevx_(&jobz, &range, &uplo, &n, MAT_BUFD(A)+oA, &ldA, &vl,
+                &vu, &il, &iu, &abstol, &m, MAT_BUFD(W)+oW, 
+		(jobz == 'V') ? MAT_BUFD(Z)+oZ : NULL,  &ldZ, work, 
+		&lwork, iwork, ifail, &info);
+	    free(work);   free(iwork);   free(ifail);   
+            break;
+
+        default:
+	    err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("i", m);
+}
+
+
+static char doc_heevx[] = 
+    "Computes selected eigenvalues and eigenvectors of a real symmetric"
+    "\nor complex Hermitian matrix (expert driver).\n\n"
+    "m = syevx(A, W, jobz='N', range='A', uplo='L', vl=0.0, vu=0.0, \n"
+    "          il=1, iu=1, Z=None, n=A.size[0], \n"
+    "          ldA = max(1,A.size[0]), ldZ=None, abstol=0.0, \n"
+    "          offsetA=0, offsetW=0, offsetZ=0)\n\n"
+    "PURPOSE\n"
+    "Computes selected eigenvalues/vectors of a real symmetric or\n"
+    "complex Hermitian n by n matrix A.\n"
+    "If range is 'A', all eigenvalues are computed.\n"
+    "If range is 'V', all eigenvalues in the interval (vl,vu] are\n"
+    "computed.\n"
+    "If range is 'I', all eigenvalues il through iu are computed\n"
+    "(sorted in ascending order with 1 <= il <= iu <= n).\n"
+    "If jobz is 'N', only the eigenvalues are returned in W.\n"
+    "If jobz is 'V', the eigenvectors are also returned in Z.\n"  
+    "On exit, the content of A is destroyed.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"  
+    "W         'd' matrix of length at least n.  On exit, contains\n"
+    "          the computed eigenvalues in ascending order.\n\n"
+    "jobz      'N' or 'V'\n\n"
+    "range     'A', 'V' or 'I'\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "vl,vu     doubles.  Only required when range is 'V'.\n\n"
+    "il,iu     integers.  Only required when range is 'I'.\n\n"
+    "Z         'd' or 'z' matrix.  Must have the same type as A.\n"
+    "          Z is only required when jobz is 'V'.  If range is 'A'\n"
+    "          or 'V', Z must have at least n columns.  If range is\n"
+    "          'I', Z must have at least iu-il+1 columns.  On exit\n"
+    "          the first m columns of Z contain the computed\n"
+    "          (normalized) eigenvectors.\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "ldZ       nonnegative integer.  ldZ >= 1 if jobz is 'N' and\n"
+    "          ldZ >= max(1,n) if jobz is 'V'.  The default value\n"
+    "          is 1 if jobz is 'N' and max(1,Z.size[0]) if jobz ='V'.\n"
+    "          If zero, the default value is used.\n\n"
+    "abstol    double.  Absolute error tolerance for eigenvalues.\n"
+    "          If nonpositive, the LAPACK default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetW   nonnegative integer\n\n"
+    "offsetZ   nonnegative integer\n\n"
+    "m         the number of eigenvalues computed";
+
+static PyObject* heevx(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *W, *Z=NULL; 
+    int n=-1, ldA=0, ldZ=0, il=1, iu=1, oA=0, oW=0, oZ=0, info, lwork,
+        *iwork, m, *ifail=NULL; 
+    double vl=0.0, vu=0.0, abstol=0.0, *rwork; 
+    number wl;
+    void *work;
+    char uplo='L', jobz='N', range='A';
+    char *kwlist[] = {"A", "W", "jobz", "range", "uplo", "vl", "vu",
+	"il", "iu", "Z", "n", "ldA", "ldZ", "abstol", "offsetA", 
+        "offsetW", "offsetZ", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cccddiiOiiidiii",
+        kwlist, &A, &W, &jobz, &range, &uplo, &vl, &vu, &il, &iu, &Z, 
+	&n, &ldA, &ldZ, &abstol, &oA, &oW, &oZ)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(W) || MAT_ID(W) != DOUBLE) err_dbl_mtrx("W");
+    if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'");
+    if (range != 'A' && range != 'V' && range != 'I') 
+	err_char("range", "'A', 'V', 'I'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (n == 0) return Py_BuildValue("i",0);
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (range == 'V' && vl >= vu){
+        PyErr_SetString(PyExc_ValueError, "vl must be less than vu");
+        return NULL;
+    }
+    if (range == 'I' && (il < 1 || il > iu || iu > n)){
+        PyErr_SetString(PyExc_ValueError, "il and iu must satisfy "
+            "1 <= il <= iu <= n");
+        return NULL;
+    }
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oW < 0) err_nn_int("offsetW");
+    if (oW + n > len(W)) err_buf_len("W");
+    if (jobz == 'V'){
+        if (!Z || !Matrix_Check(Z)) err_mtrx("Z");
+	if (MAT_ID(Z) != MAT_ID(A)) err_conflicting_ids; 
+        if (ldZ == 0) ldZ = MAX(1,Z->nrows);
+        if (ldZ < MAX(1,n)) err_ld("ldZ");
+        if (oZ < 0) err_nn_int("offsetZ");
+        if (oZ + ((range == 'I') ? iu-il : n-1)*ldZ + n > len(Z)) 
+	    err_buf_len("Z"); 
+    } else {
+        if (ldZ == 0) ldZ = 1;
+        if (ldZ < 1) err_ld("ldZ");
+    }
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+	    lwork = -1;
+	    dsyevx_(&jobz, &range, &uplo, &n, NULL, &ldA, &vl, &vu, &il,
+                &iu, &abstol, &m, NULL, NULL, &ldZ, &wl.d, &lwork, NULL,
+	       	NULL, &info);
+	    lwork = (int) wl.d;
+	    work = (void *) calloc(lwork, sizeof(double));
+	    iwork = (int *) calloc(5*n, sizeof(int));
+	    if (jobz == 'V') ifail = (int *) calloc(n, sizeof(int));
+	    if (!work || !iwork || (jobz == 'V' && !ifail)){
+		free(work); free(iwork); free(ifail);
+	        return PyErr_NoMemory();
+	    }
+	    dsyevx_(&jobz, &range, &uplo, &n, MAT_BUFD(A)+oA, &ldA, &vl,
+                &vu, &il, &iu, &abstol, &m, MAT_BUFD(W)+oW, 
+		(jobz == 'V') ? MAT_BUFD(Z)+oZ : NULL,  &ldZ, 
+		(double *) work, &lwork, iwork, ifail, &info);
+	    free(work);  free(iwork);  free(ifail);   
+            break;
+
+	case COMPLEX:
+	    lwork = -1;
+	    zheevx_(&jobz, &range, &uplo, &n, NULL, &ldA, &vl, &vu, &il,
+                &iu, &abstol, &m, NULL, NULL, &ldZ, &wl.z, &lwork, NULL,
+	       	NULL, NULL, &info);
+	    lwork = (int) creal(wl.z);
+	    work = (void *) calloc(lwork, sizeof(complex));
+	    rwork = (double *) calloc(7*n, sizeof(double));
+	    iwork = (int *) calloc(5*n, sizeof(int));
+	    if (jobz == 'V') ifail = (int *) calloc(n, sizeof(int));
+	    if (!work || !rwork || !iwork || (jobz == 'V' && !ifail)){
+		free(work); free(rwork); free(iwork); free(ifail);
+	        return PyErr_NoMemory();
+	    }
+	    zheevx_(&jobz, &range, &uplo, &n, MAT_BUFZ(A)+oA, &ldA, &vl,
+                &vu, &il, &iu, &abstol, &m, MAT_BUFD(W)+oW, 
+		(jobz == 'V') ? MAT_BUFZ(Z)+oZ : NULL,  &ldZ, 
+		(complex *) work, &lwork, rwork, iwork, ifail, &info);
+	    free(work);  free(rwork);  free(iwork);  free(ifail);   
+            break;
+
+        default:
+	    err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("i", m);
+}
+
+
+static char doc_syevd[] = 
+    "Eigenvalue decomposition of a real symmetric matrix\n"
+    "(divide-and-conquer driver).\n\n"
+    "syevd(A, W, jobz='N', uplo='L', n=A.size[0], "
+    "ldA = max(1,A.size[0]),\n"
+    "      offsetA=0, offsetW=0)\n\n"
+    "PURPOSE\n"
+    "Returns  eigenvalues/vectors of a real symmetric nxn matrix A.\n"
+    "On exit, W contains the eigenvalues in ascending order.\n"
+    "If jobz is 'V', the (normalized) eigenvectors are also computed\n"
+    "and returned in A.  If jobz is 'N', only the eigenvalues are\n"
+    "computed, and the content of A is destroyed.\n"
+    "\n\nARGUMENTS\n"
+    "A         'd' matrix\n\n"
+    "W         'd' matrix of length at least n.  On exit, contains\n"
+    "          the computed eigenvalues in ascending order.\n\n"
+    "jobz      'N' or 'V'\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* syevd(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *W; 
+    int n=-1, ldA=0, oA=0, oW=0, info, lwork, liwork, *iwork, iwl; 
+    double *work=NULL, wl; 
+    char uplo='L', jobz='N';
+    char *kwlist[] = {"A", "W", "jobz", "uplo", "n", "ldA", "offsetA", 
+        "offsetW", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cciiii", kwlist,
+        &A, &W, &jobz, &uplo, &n, &ldA, &oA, &oW)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(W) || W->id != DOUBLE) err_dbl_mtrx("W");
+    if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (n == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oW < 0) err_nn_int("offsetW");
+    if (oW + n > len(W)) err_buf_len("W");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            lwork = -1;
+            liwork = -1;
+            dsyevd_(&jobz, &uplo, &n, NULL, &ldA, NULL, &wl, &lwork, 
+                &iwl, &liwork, &info);
+            lwork = (int) wl;
+            liwork = iwl;
+            work = (double *) calloc(lwork, sizeof(double));
+            iwork = (int *) calloc(liwork, sizeof(int));
+            if (!work || !iwork){
+                free(work);  free(iwork);
+                return PyErr_NoMemory();
+            }
+	    dsyevd_(&jobz, &uplo, &n, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(W)+oW, work, &lwork, iwork, &liwork, &info);
+            free(work);  free(iwork);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_heevd[] = 
+    "Eigenvalue decomposition of a real symmetric or complex Hermitian"
+    "\nmatrix (divide-and-conquer driver).\n\n"
+    "heevd(A, W, jobz='N', uplo='L', n=A.size[0], "
+    "ldA = max(1,A.size[0]),\n"
+    "      offsetA=0, offsetW=0)\n\n"
+    "PURPOSE\n"
+    "Returns  eigenvalues/vectors of a real symmetric or complex\n"
+    "Hermitian n by n matrix A.  On exit, W contains the eigenvalues\n"
+    "in ascending order.  If jobz is 'V', the (normalized) eigenvectors"
+    "\nare also computed and returned in A.  If jobz is 'N', only the\n"
+    "eigenvalues are computed, and the content of A is destroyed.\n"
+    "\n\nARGUMENTS\n"
+    "A         'd' matrix\n\n"
+    "W         'd' matrix of length at least n.  On exit, contains\n"
+    "          the computed eigenvalues in ascending order.\n\n"
+    "jobz      'N' or 'V'\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* heevd(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *W; 
+    int n=-1, ldA=0, oA=0, oW=0, info, lwork, liwork, *iwork, iwl, 
+	lrwork; 
+    double *rwork, rwl;
+    number wl;
+    void *work;
+    char uplo='L', jobz='N';
+    char *kwlist[] = {"A", "W", "jobz", "uplo", "n", "ldA", "offsetA", 
+        "offsetW", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cciiii", kwlist,
+        &A, &W, &jobz, &uplo, &n, &ldA, &oA, &oW)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(W) || W->id != DOUBLE) err_dbl_mtrx("W");
+    if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (n == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oW < 0) err_nn_int("offsetW");
+    if (oW + n > len(W)) err_buf_len("W");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            lwork = -1;
+            liwork = -1;
+            dsyevd_(&jobz, &uplo, &n, NULL, &ldA, NULL, &wl.d, &lwork, 
+                &iwl, &liwork, &info);
+            lwork = (int) wl.d;
+            liwork = iwl;
+            work = (void *) calloc(lwork, sizeof(double));
+            iwork = (int *) calloc(liwork, sizeof(int));
+            if (!work || !iwork){
+                free(work);  free(iwork);
+                return PyErr_NoMemory();
+            }
+            dsyevd_(&jobz, &uplo, &n, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(W)+oW, (double *) work, &lwork, iwork, &liwork,
+                &info);
+            free(work);   free(iwork);
+            break;
+
+        case COMPLEX:
+            lwork = -1;
+            liwork = -1;
+            lrwork = -1;
+            zheevd_(&jobz, &uplo, &n, NULL, &ldA, NULL, &wl.z, &lwork, 
+                &rwl, &lrwork, &iwl, &liwork, &info);
+            lwork = (int) wl.d;
+            lrwork = (int) rwl;
+            liwork = iwl;
+            work = (void *) calloc(lwork, sizeof(complex));
+            rwork = (double *) calloc(lrwork, sizeof(double));
+            iwork = (int *) calloc(liwork, sizeof(int));
+            if (!work || !rwork || !iwork){
+                free(work);  free(rwork);  free(iwork);
+                return PyErr_NoMemory();
+            }
+            zheevd_(&jobz, &uplo, &n, MAT_BUFZ(A)+oA, &ldA, 
+                MAT_BUFD(W)+oW, (complex *) work, &lwork, rwork,
+                &lrwork, iwork, &liwork, &info);
+            free(work);  free(rwork);  free(iwork);
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_syevr[] = 
+    "Computes selected eigenvalues and eigenvectors of a real symmetric"
+    "\n"
+    "matrix (RRR driver).\n\n"
+    "m = syevr(A, W, jobz='N', range='A', uplo='L', vl=0.0, vu=0.0, \n"
+    "          il=1, iu=1, Z=None, n=A.size[0], ldA=max(1,A.size[0]),\n"
+    "          ldZ=None, abstol=0.0, offsetA=0, offsetW=0, offsetZ=0)\n"
+    "\n" 
+    "PURPOSE\n"
+    "Computes selected eigenvalues/vectors of a real symmetric n by n\n"
+    "matrix A.\n"
+    "If range is 'A', all eigenvalues are computed.\n"
+    "If range is 'V', all eigenvalues in the interval (vl,vu] are\n"
+    "computed.\n"
+    "If range is 'I', all eigenvalues il through iu are computed\n"
+    "(sorted in ascending order with 1 <= il <= iu <= n).\n"
+    "If jobz is 'N', only the eigenvalues are returned in W.\n"
+    "If jobz is 'V', the eigenvectors are also returned in Z.\n"  
+    "On exit, the content of A is destroyed.\n"
+    "syevr is usually the fastest of the four eigenvalue routines.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' matrix\n\n"  
+    "W         'd' matrix of length at least n.  On exit, contains\n"
+    "          the computed eigenvalues in ascending order.\n\n"
+    "jobz      'N' or 'V'\n\n"
+    "range     'A', 'V' or 'I'\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "vl,vu     doubles.  Only required when range is 'V'.\n\n"
+    "il,iu     integers.  Only required when range is 'I'.\n\n"
+    "Z         'd' matrix.  Only required when jobz = 'V'.\n"
+    "          If range is 'A' or 'V', Z must have at least n columns."
+    "\n"
+    "          If range is 'I', Z must have at least iu-il+1 columns.\n"
+    "          On exit the first m columns of Z contain the computed\n"
+    "          (normalized) eigenvectors.\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).\n"
+    "          If zero, the default value is used.\n\n"
+    "ldZ       nonnegative integer.  ldZ >= 1 if jobz is 'N' and\n"
+    "          ldZ >= max(1,n) if jobz is 'V'.  The default value\n"
+    "          is 1 if jobz is 'N' and max(1,Z.size[0]) if jobz ='V'.\n"
+    "          If zero, the default value is used.\n\n"
+    "abstol    double.  Absolute error tolerance for eigenvalues.\n"
+    "          If nonpositive, the LAPACK default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetW   nonnegative integer\n\n"
+    "offsetZ   nonnegative integer\n\n"
+    "m         the number of eigenvalues computed";
+
+static PyObject* syevr(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *W, *Z=NULL; 
+    int n=-1, ldA=0, ldZ=0, il=1, iu=1, oA=0, oW=0, oZ=0, info, lwork,
+        *iwork=NULL, liwork, m, *isuppz=NULL, iwl; 
+    double *work=NULL, vl=0.0, vu=0.0, abstol=0.0, wl; 
+    char uplo='L', jobz='N', range='A';
+    char *kwlist[] = {"A", "W", "jobz", "range", "uplo", "vl", "vu",
+	"il", "iu", "Z", "n", "ldA", "ldZ", "abstol", "offsetA", 
+        "offsetW", "offsetZ", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cccddiiOiiidiii",
+        kwlist, &A, &W, &jobz, &range, &uplo, &vl, &vu, &il, &iu, &Z,
+	&n, &ldA, &ldZ, &abstol, &oA, &oW, &oZ)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A"); 
+    if (!Matrix_Check(W) || MAT_ID(W) != DOUBLE) err_dbl_mtrx("W");
+    if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'");
+    if (range != 'A' && range != 'V' && range != 'I') 
+	err_char("range", "'A', 'V', 'I'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (n == 0) return Py_BuildValue("i",0);
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (range == 'V' && vl >= vu){
+        PyErr_SetString(PyExc_ValueError, "vl must be less than vu");
+        return NULL;
+    }
+    if (range == 'I' && (il < 1 || il > iu || iu > n)){
+        PyErr_SetString(PyExc_ValueError, "il and iu must satisfy "
+            "1 <= il <= iu <= n");
+        return NULL;
+    }
+    if (jobz == 'V'){
+        if (!Z || !Matrix_Check(Z) || MAT_ID(Z) != DOUBLE) 
+            err_dbl_mtrx("Z");
+        if (ldZ == 0) ldZ = MAX(1,Z->nrows);
+        if (ldZ < MAX(1,n)) err_ld("ldZ");
+    } else {
+        if (ldZ == 0) ldZ = 1;
+        if (ldZ < 1) err_ld("ldZ");
+    }
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oW < 0) err_nn_int("offsetW");
+    if (oW + n > len(W)) err_buf_len("W");
+    if (jobz == 'V'){
+        if (oZ < 0) err_nn_int("offsetZ");
+        if (oZ + ((range == 'I') ? iu-il : n-1)*ldZ + n > len(Z)) 
+	    err_buf_len("Z"); 
+    }
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            lwork = -1;
+            liwork = -1;
+            dsyevr_(&jobz, &range, &uplo, &n, NULL, &ldA, &vl, &vu, &il,
+                &iu, &abstol, &m, NULL, NULL, &ldZ, NULL, &wl, &lwork, 
+                &iwl, &liwork, &info);
+            lwork = (int) wl;
+            liwork = iwl;
+            work = (void *) calloc(lwork, sizeof(double));
+            iwork = (int *) calloc(liwork, sizeof(int));
+            if (jobz == 'V') 
+                isuppz = (int *) calloc(2*MAX(1, (range == 'I') ? 
+                   iu-il+1 : n), sizeof(int));
+            if (!work  || !iwork || (jobz == 'V' && !isuppz)){
+                free(work);  free(iwork);  free(isuppz);
+                return PyErr_NoMemory();
+            }
+            dsyevr_(&jobz, &range, &uplo, &n, MAT_BUFD(A)+oA, &ldA, &vl,
+                &vu, &il, &iu, &abstol, &m, MAT_BUFD(W)+oW,
+                (jobz == 'V') ? MAT_BUFD(Z)+oZ : NULL,  &ldZ, 
+                (jobz == 'V') ? isuppz : NULL, work, &lwork, iwork, 
+                &liwork, &info);
+            free(work);   free(iwork);   free(isuppz);   
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("i",m);
+}
+
+
+static char doc_heevr[] = 
+    "Computes selected eigenvalues and eigenvectors of a real symmetric"
+    "\nor complex Hermitian matrix (RRR driver).\n\n"
+    "m = syevr(A, W, jobz='N', range='A', uplo='L', vl=0.0, vu=0.0, \n"
+    "          il=1, iu=1, Z=None, n=A.size[0], ldA=max(1,A.size[0]),\n"
+    "          ldZ=None, abstol=0.0, offsetA=0, offsetW=0, offsetZ=0)\n"
+    "\n"
+    "PURPOSE\n"
+    "Computes selected eigenvalues/vectors of a real symmetric or\n"
+    "complex Hermitian n by n matrix A.\n"
+    "If range is 'A', all eigenvalues are computed.\n"
+    "If range is 'V', all eigenvalues in the interval (vl,vu] are\n"
+    "computed.\n"
+    "If range is 'I', all eigenvalues il through iu are computed\n"
+    "(sorted in ascending order with 1 <= il <= iu <= n).\n"
+    "If jobz is 'N', only the eigenvalues are returned in W.\n"
+    "If jobz is 'V', the eigenvectors are also returned in Z.\n"  
+    "On exit, the content of A is destroyed.\n"
+    "syevr is usually the fastest of the four eigenvalue routines.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"  
+    "W         'd' matrix of length at least n.  On exit, contains\n"
+    "          the computed eigenvalues in ascending order.\n\n"
+    "jobz      'N' or 'V'\n\n"
+    "range     'A', 'V' or 'I'\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "vl,vu     doubles.  Only required when range is 'V'.\n\n"
+    "il,iu     integers.  Only required when range is 'I'.\n\n"
+    "Z         'd' or 'z' matrix.  Must have the same type as A.\n"
+    "          Only required when jobz = 'V'.  If range is 'A' or\n"
+    "          'V', Z must have at least n columns.  If range is 'I',\n"
+    "          Z must have at least iu-il+1 columns.  On exit the\n"
+    "          first m columns of Z contain the computed (normalized)\n"
+    "          eigenvectors.\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).\n"
+    "          If zero, the default value is used.\n\n"
+    "ldZ       nonnegative integer.  ldZ >= 1 if jobz is 'N' and\n"
+    "          ldZ >= max(1,n) if jobz is 'V'.  The default value\n"
+    "          is 1 if jobz is 'N' and max(1,Z.size[0]) if jobz ='V'.\n"
+    "          If zero, the default value is used.\n\n"
+    "abstol    double.  Absolute error tolerance for eigenvalues.\n"
+    "          If nonpositive, the LAPACK default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetW   nonnegative integer\n\n"
+    "offsetZ   nonnegative integer\n\n"
+    "m         the number of eigenvalues computed";
+
+static PyObject* heevr(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *W, *Z=NULL; 
+    int n=-1, ldA=0, ldZ=0, il=1, iu=1, oA=0, oW=0, oZ=0, info, 
+        lwork, *iwork, liwork, lrwork, m, *isuppz=NULL, iwl; 
+    double vl=0.0, vu=0.0, abstol=0.0, *rwork, rwl; 
+    void *work;
+    number wl;
+    char uplo='L', jobz='N', range='A';
+    char *kwlist[] = {"A", "W", "jobz", "range", "uplo", "vl", "vu",
+	"il", "iu", "Z", "n", "ldA", "ldZ", "abstol", "offsetA", 
+        "offsetW", "offsetZ", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cccddiiOiiidiii",
+        kwlist, &A, &W, &jobz, &range, &uplo, &vl, &vu, &il, &iu, &Z,
+	&n, &ldA, &ldZ, &abstol, &oA, &oW, &oZ)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A"); 
+    if (!Matrix_Check(W) || MAT_ID(W) != DOUBLE) err_dbl_mtrx("W");
+    if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'");
+    if (range != 'A' && range != 'V' && range != 'I') 
+	err_char("range", "'A', 'V', 'I'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+    }
+    if (n == 0) return Py_BuildValue("i",0);
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (range == 'V' && vl >= vu){
+        PyErr_SetString(PyExc_ValueError, "vl must be less than vu");
+        return NULL;
+    }
+    if (range == 'I' && (il < 1 || il > iu || iu > n)){
+        PyErr_SetString(PyExc_ValueError, "il and iu must satisfy "
+            "1 <= il <= iu <= n");
+        return NULL;
+    }
+    if (jobz == 'V'){
+        if (!Z || !Matrix_Check(Z)) err_mtrx("Z");
+	if (MAT_ID(Z) != MAT_ID(A)) err_conflicting_ids; 
+        if (ldZ == 0) ldZ = MAX(1,Z->nrows);
+        if (ldZ < MAX(1,n)) err_ld("ldZ");
+    } else {
+        if (ldZ == 0) ldZ = 1;
+        if (ldZ < 1) err_ld("ldZ");
+    }
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oW < 0) err_nn_int("offsetW");
+    if (oW + n > len(W)) err_buf_len("W");
+    if (jobz == 'V'){
+        if (oZ < 0) err_nn_int("offsetZ");
+        if (oZ + ((range == 'I') ? iu-il : n-1)*ldZ + n > len(Z)) 
+	    err_buf_len("Z"); 
+    }
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            lwork = -1;
+            liwork = -1;
+            dsyevr_(&jobz, &range, &uplo, &n, NULL, &ldA, &vl, &vu, &il,
+                &iu, &abstol, &m, NULL, NULL, &ldZ, NULL, &wl.d, &lwork,
+                &iwl, &liwork, &info);
+            lwork = (int) wl.d;
+            liwork = iwl;
+            work = (void *) calloc(lwork, sizeof(double));
+            iwork = (int *) calloc(liwork, sizeof(int));
+            if (jobz == 'V') 
+                isuppz = (int *) calloc(2*MAX(1, (range == 'I') ? 
+                   iu-il+1 : n), sizeof(int));
+            if (!work  || !iwork || (jobz == 'V' && !isuppz)){
+                free(work);  free(iwork);  free(isuppz);
+                return PyErr_NoMemory();
+            }
+            dsyevr_(&jobz, &range, &uplo, &n, MAT_BUFD(A)+oA, &ldA, &vl,
+                &vu, &il, &iu, &abstol, &m, MAT_BUFD(W)+oW,
+                (jobz == 'V') ? MAT_BUFD(Z)+oZ : NULL,  &ldZ, 
+                (jobz == 'V') ? isuppz : NULL, (double *) work, &lwork,
+	       	iwork, &liwork, &info);
+            free(work);   free(iwork);   free(isuppz);   
+            break;
+
+	case COMPLEX:
+            lwork = -1;
+            liwork = -1;
+	    lrwork = -1;
+            zheevr_(&jobz, &range, &uplo, &n, NULL, &ldA, &vl, &vu, &il,
+                &iu, &abstol, &m, NULL, NULL, &ldZ, NULL, &wl.z, &lwork,
+                &rwl, &lrwork, &iwl, &liwork, &info);
+            lwork = (int) creal(wl.z);
+	    lrwork = (int) rwl;
+            liwork = iwl;
+            work = (void *) calloc(lwork, sizeof(complex));
+            rwork = (double *) calloc(lrwork, sizeof(double));
+            iwork = (int *) calloc(liwork, sizeof(int));
+            if (jobz == 'V') 
+                isuppz = (int *) calloc(2*MAX(1, (range == 'I') ? 
+                   iu-il+1 : n), sizeof(int));
+            if (!work  || !rwork || !iwork || (jobz == 'V' && !isuppz)){
+                free(work);  free(rwork);  free(iwork);  free(isuppz);
+                return PyErr_NoMemory();
+            }
+            zheevr_(&jobz, &range, &uplo, &n, MAT_BUFZ(A)+oA, &ldA, &vl,
+                &vu, &il, &iu, &abstol, &m, MAT_BUFD(W)+oW,
+                (jobz == 'V') ? MAT_BUFZ(Z)+oZ : NULL,  &ldZ, 
+                (jobz == 'V') ? isuppz : NULL, (complex *) work, &lwork,
+	       	rwork, &lrwork, iwork, &liwork, &info);
+            free(work);   free(rwork); free(iwork);   free(isuppz);   
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("i",m);
+}
+
+
+static char doc_sygv[] = 
+    "Generalized symmetric-definite eigenvalue decomposition with real"
+    "\n" 
+    "matrices.\n\n"
+    "sygv(A, B, W, itype=1, jobz='N', uplo='L', n=A.size[0], \n"
+    "     ldA = max(1,A.size[0]), ldB = max(1,B.size[0]), offsetA=0, \n"
+    "     offsetB=0, offsetW=0)\n\n"
+    "PURPOSE\n"
+    "Returns eigenvalues/vectors of a real generalized \n"
+    "symmetric-definite eigenproblem of order n, with B positive \n"
+    "definite. \n"
+    "1. If itype is 1: A*x = lambda*B*x.\n"
+    "2. If itype is 2: A*Bx = lambda*x.\n"
+    "3. If itype is 3: B*Ax = lambda*x.\n\n"
+    "On exit, W contains the eigenvalues in ascending order.  If jobz\n"
+    "is 'V', the matrix of eigenvectors Z is also computed and\n"
+    "returned in A, normalized as follows: \n"
+    "1. If itype is 1: Z^T*A*Z = diag(W), Z^T*B*Z = I\n"
+    "2. If itype is 2: Z^T*A^{-1}*Z = diag(W)^{-1}, Z^T*B*Z = I\n"
+    "3. If itype is 3: Z^T*A*Z = diag(W), Z^T*B^{-1}*Z = I.\n\n"
+    "If jobz is 'N', only the eigenvalues are computed, and the\n"
+    "contents of A is destroyed.   On exit, the matrix B is replaced\n"
+    "by its Cholesky factor.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' matrix\n\n"
+    "B         'd' matrix\n\n"
+    "W         'd' matrix of length at least n\n\n"
+    "itype     integer 1, 2, or 3\n\n"
+    "jobz      'N' or 'V'\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "ldB       nonnegative integer.  ldB >= max(1,n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* sygv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B, *W; 
+    int n=-1, itype=1, ldA=0, ldB=0, oA=0, oB=0, oW=0, info, lwork; 
+    double *work; 
+    number wl; 
+    char uplo='L', jobz='N';
+    char *kwlist[] = {"A", "B", "W", "itype", "jobz", "uplo", "n", 
+        "ldA", "ldB", "offsetA", "offsetB", "offsetW", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|icciiiiii", 
+        kwlist, &A, &B, &W, &itype, &jobz, &uplo, &n, &ldA, &ldB, &oA, 
+        &oB, &oW)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B) || MAT_ID(B) != MAT_ID(A)) err_conflicting_ids;
+    if (!Matrix_Check(W) || MAT_ID(W) != DOUBLE) err_dbl_mtrx("W");
+    if (itype != 1 && itype != 2 && itype != 3)
+        err_char("itype", "1, 2, 3");
+    if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+        if (A->nrows != n || A->ncols != n){
+            PyErr_SetString(PyExc_TypeError, "B must have the same "
+                "dimension as A");
+            return NULL;
+	}
+    }
+    if (n == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1,n)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (n-1)*ldB + n > len(B)) err_buf_len("B");
+    if (oW < 0) err_nn_int("offsetW");
+    if (oW + n > len(W)) err_buf_len("W");
+
+    switch (MAT_ID(A)){
+	case DOUBLE:
+            lwork=-1;
+            dsygv_(&itype, &jobz, &uplo, &n, NULL, &ldA, NULL, &ldB,
+                NULL, &wl.d, &lwork, &info);
+            lwork = (int) wl.d;
+            if (!(work = calloc(lwork, sizeof(double))))
+                return PyErr_NoMemory();
+            dsygv_(&itype, &jobz, &uplo, &n, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(B)+oB, &ldB, MAT_BUFD(W)+oW, work, &lwork, 
+                &info);
+            free(work);   
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_hegv[] = 
+    "Generalized symmetric-definite eigenvalue decomposition with\n"
+    "real or complex matrices.\n\n"
+    "hegv(A, B, W, itype=1, jobz='N', uplo='L', n=A.size[0], \n"
+    "     ldA = max(1,A.size[0]), ldB = max(1,B.size[0]), offsetA=0, \n"
+    "     offsetB=0, offsetW=0)\n\n"
+    "PURPOSE\n"
+    "Returns eigenvalues/vectors of a real or complex generalized\n"
+    "symmetric-definite eigenproblem of order n, with B positive\n"
+    "definite. \n"
+    "1. If itype is 1: A*x = lambda*B*x.\n"
+    "2. If itype is 2: A*Bx = lambda*x.\n"
+    "3. If itype is 3: B*Ax = lambda*x.n\n\n"
+    "On exit, W contains the eigenvalues in ascending order.  If jobz\n"
+    "is 'V', the matrix of eigenvectors Z is also computed and \n"
+    "returned in A, normalized as follows: \n"
+    "1. If itype is 1: Z^H*A*Z = diag(W), Z^H*B*Z = I\n"
+    "2. If itype is 2: Z^H*A^{-1}*Z = diag(W), Z^H*B*Z = I\n"
+    "3. If itype is 3: Z^H*A*Z = diag(W), Z^H*B^{-1}*Z = I.\n\n"
+    "If jobz is 'N', only the eigenvalues are computed, and the \n"
+    "contents of A is destroyed.   On exit, the matrix B is replaced\n"
+    "by its Cholesky factor.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"
+    "B         'd' or 'z' matrix.  Must have the same type as A.\n\n"
+    "W         'd' matrix of length at least n\n\n"
+    "itype     integer 1, 2, or 3\n\n"
+    "jobz      'N' or 'V'\n\n"
+    "uplo      'L' or 'U'\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "ldB       nonnegative integer.  ldB >= max(1,n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* hegv(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *B, *W; 
+    int n=-1, itype=1, ldA=0, ldB=0, oA=0, oB=0, oW=0, info, lwork; 
+    double *rwork=NULL;
+    void *work=NULL; 
+    number wl; 
+    char uplo='L', jobz='N';
+    char *kwlist[] = {"A", "B", "W", "itype", "jobz", "uplo", "n", 
+        "ldA", "offsetA", "offsetB", "offsetW", NULL};
+    int ispec=1, n2=-1, n3=-1, n4=-1;
+    char *name = "zhetrd", *uplol = "L", *uplou = "U";
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|icciiiii", 
+        kwlist, &A, &B, &W, &itype, &jobz, &uplo, &n, &ldA, &ldB, &oA, 
+        &oB, &oW)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A");
+    if (!Matrix_Check(B) || MAT_ID(B) != MAT_ID(A)) err_conflicting_ids;
+    if (!Matrix_Check(W) || MAT_ID(W) != DOUBLE) err_dbl_mtrx("W");
+    if (itype != 1 && itype != 2 && itype != 3)
+        err_char("itype", "1, 2, 3");
+    if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'");
+    if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'");
+    if (n < 0){ 
+        n = A->nrows;
+        if (n != A->ncols){
+            PyErr_SetString(PyExc_TypeError, "A must be square");
+            return NULL;
+        }
+        if (A->nrows != n || A->ncols != n){
+            PyErr_SetString(PyExc_TypeError, "B must have the same "
+                "dimension as A");
+            return NULL;
+	}
+    }
+    if (n == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,n)) err_ld("ldA");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1,n)) err_ld("ldB");
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (n-1)*ldB + n > len(B)) err_buf_len("B");
+    if (oW < 0) err_nn_int("offsetW");
+    if (oW + n > len(W)) err_buf_len("W");
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            lwork=-1;
+            dsygv_(&itype, &jobz, &uplo, &n, NULL, &ldA, NULL, &ldB,
+                NULL, &wl.d, &lwork, &info);
+            lwork = (int) wl.d;
+            if (!(work = calloc(lwork, sizeof(double))))
+                return PyErr_NoMemory();
+            dsygv_(&itype, &jobz, &uplo, &n, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(B)+oB, &ldB, MAT_BUFD(W)+oW, work, &lwork, 
+                &info);
+            free(work);   
+            break;
+
+        case COMPLEX:
+#if 0       
+            /* zhegv does not handle lwork=-1 correctly */
+            lwork=-1;
+            zhegv_(&itype, &jobz, &uplo, &n, NULL, &n, NULL, &n, NULL, 
+                &wl.z, &lwork, NULL, &info);
+            lwork = (int) creal(wl.z);
+#endif
+            /* replaces call to zhegv with lwork=-1 */
+            lwork = n * (1 + ilaenv_(&ispec, &name, (uplo == 'L') ?  
+                &uplol : &uplou, &n, &n2, &n3, &n4));
+	    
+            work = (void *) calloc(lwork, sizeof(complex));
+            rwork = (double *) calloc(3*n-2, sizeof(double));
+            if (!work || !rwork){
+                free(work);  free(rwork);
+                return PyErr_NoMemory();
+            }	
+            zhegv_(&itype, &jobz, &uplo, &n, MAT_BUFZ(A)+oA, &ldA, 
+                MAT_BUFZ(B)+oB, &ldB, MAT_BUFD(W)+oW, (complex *) work, 
+                &lwork, rwork, &info);
+            free(work);  free(rwork);
+            break;
+
+        default:
+	    err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_gesvd[] = 
+    "Singular value decomposition of a real or complex matrix.\n\n"
+    "gesvd(A, S, jobu='N', jobvt='N', U=None, Vt=None, m=A.size[0],\n"
+    "      n=A.size[1], ldA=max(1,A.size[0]), ldU=None, ldVt=None,\n"
+    "      offsetA=0, offsetS=0, offsetU=0, offsetVt=0)\n\n"
+    "PURPOSE\n"
+    "Computes singular values and, optionally, singular vectors of a \n"
+    "real or complex m by n matrix A.\n\n"
+    "The argument jobu controls how many left singular vectors are\n"
+    "computed: \n\n"
+    "'N': no left singular vectors are computed.\n"
+    "'A': all left singular vectors are computed and returned as\n"
+    "     columns of U.\n"
+    "'S': the first min(m,n) left singular vectors are computed and\n"
+    "     returned as columns of U.\n"
+    "'O': the first min(m,n) left singular vectors are computed and\n"
+    "     returned as columns of A.\n\n"
+    "The argument jobvt controls how many right singular vectors are\n"
+    "computed:\n\n"
+    "'N': no right singular vectors are computed.\n"
+    "'A': all right singular vectors are computed and returned as\n"
+    "     rows of Vt.\n"
+    "'S': the first min(m,n) right singular vectors are computed and\n"
+    "     returned as rows of Vt.\n"
+    "'O': the first min(m,n) right singular vectors are computed and\n"
+    "     returned as rows of A.\n"
+    "Note that the (conjugate) transposes of the right singular \n"
+    "vectors are returned in Vt or A.\n\n"
+    "On exit (in all cases), the contents of A are destroyed.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"  
+    "S         'd' matrix of length at least min(m,n).  On exit, \n"
+    "          contains the computed singular values in descending\n"
+    "          order.\n\n"
+    "jobu      'N', 'A', 'S' or 'O'\n\n"
+    "jobvt     'N', 'A', 'S' or 'O'\n\n"
+    "U         'd' or 'z' matrix.  Must have the same type as A.\n"
+    "          Not referenced if jobu is 'N' or 'O'.  If jobu is 'A',\n"
+    "          a matrix with at least m columns.   If jobu is 'S', a\n"
+    "          matrix with at least min(m,n) columns.\n"
+    "          On exit (with jobu 'A' or 'S'), the columns of U\n"
+    "          contain the computed left singular vectors.\n\n"
+    "Vt        'd' or 'z' matrix.  Must have the same type as A.\n"
+    "          Not referenced if jobvt is 'N' or 'O'.  If jobvt is \n"
+    "          'A' or 'S', a matrix with at least n columns.\n"
+    "          On exit (with jobvt 'A' or 'S'), the rows of Vt\n"
+    "          contain the computed right singular vectors, or, in\n"
+    "          the complex case, their complex conjugates.\n\n"
+    "m         integer.  If negative, the default value is used.\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,m).\n"
+    "          If zero, the default value is used.\n\n"
+    "ldU       nonnegative integer.\n"
+    "          ldU >= 1 if jobu is 'N' or 'O'.\n"
+    "          ldU >= max(1,m) if jobu is 'A' or 'S'.\n"
+    "          The default value is max(1,U.size[0]) if jobu is 'A' \n"
+    "          or 'S', and 1 otherwise.\n"
+    "          If zero, the default value is used.\n\n"
+    "ldVt      nonnegative integer.\n"
+    "          ldVt >= 1 if jobvt is 'N' or 'O'.\n"
+    "          ldVt >= max(1,n) if jobvt is 'A'.  \n"
+    "          ldVt >= max(1,min(m,n)) if ldVt is 'S'.\n"
+    "          The default value is max(1,Vt.size[0]) if jobvt is 'A'\n"
+    "          or 'S', and 1 otherwise.\n" 
+    "          If zero, the default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetS   nonnegative integer\n\n"
+    "offsetU   nonnegative integer\n\n"
+    "offsetVt  nonnegative integer";
+
+static PyObject* gesvd(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *S, *U=NULL, *Vt=NULL; 
+    int m=-1, n=-1, ldA=0, ldU=0, ldVt=0, oA=0, oS=0, oU=0, oVt=0, info,
+       	lwork; 
+    double *rwork=NULL; 
+    void *work=NULL;
+    number wl;
+    char jobu='N', jobvt='N'; 
+    char *kwlist[] = {"A", "S", "jobu", "jobvt", "U", "Vt", "m", "n", 
+	"ldA", "ldU", "ldVt", "offsetA", "offsetS", "offsetU", 
+        "offsetVt", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccOOiiiiiiiii",
+        kwlist, &A, &S, &jobu, &jobvt, &U, &Vt, &m, &n, &ldA, &ldU, 
+        &ldVt, &oA, &oS, &oU, &oVt)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A"); 
+    if (!Matrix_Check(S) || MAT_ID(S) != DOUBLE) err_dbl_mtrx("S");
+    if (jobu != 'N' && jobu != 'A' && jobu != 'O' && jobu != 'S') 
+        err_char("jobu", "'N', 'A', 'S', 'O'");
+    if (jobvt != 'N' && jobvt != 'A' && jobvt != 'O' && jobvt != 'S') 
+        err_char("jobvt", "'N', 'A', 'S', 'O'");
+    if (jobu == 'O' && jobvt == 'O') {
+        PyErr_SetString(PyExc_ValueError, "'jobu' and 'jobvt' cannot "
+            "both be 'O'");
+        return NULL;
+    }
+    if (m < 0) m = A->nrows;
+    if (n < 0) n = A->ncols;
+    if (m == 0 || n == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,m)) err_ld("ldA");
+    if (jobu == 'A' || jobu == 'S'){
+        if (!U || !Matrix_Check(U)) err_mtrx("U");
+        if (MAT_ID(U) != MAT_ID(A)) err_conflicting_ids; 
+        if (ldU == 0) ldU = MAX(1,U->nrows);
+        if (ldU < MAX(1,m)) err_ld("ldU");
+    } else {
+        if (ldU == 0) ldU = 1;
+        if (ldU < 1) err_ld("ldU");
+    }
+    if (jobvt == 'A' || jobvt == 'S'){
+        if (!Vt || !Matrix_Check(Vt)) err_mtrx("Vt");
+	if (MAT_ID(Vt) != MAT_ID(A)) err_conflicting_ids; 
+        if (ldVt == 0) ldVt = MAX(1,Vt->nrows);
+        if (ldVt < ((jobvt == 'A') ?  MAX(1,n) : MAX(1,MIN(m,n)))) 
+            err_ld("ldVt");
+    } else {
+        if (ldVt == 0) ldVt = 1;
+        if (ldVt < 1) err_ld("ldVt");
+    }
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + m > len(A)) err_buf_len("A");
+    if (oS < 0) err_nn_int("offsetS");
+    if (oS + MIN(m,n) > len(S)) err_buf_len("S");
+    if (jobu == 'A' || jobu == 'S'){
+        if (oU < 0) err_nn_int("offsetU");
+        if (oU + ((jobu == 'A') ? m-1 : MIN(m,n)-1)*ldU + m > len(U)) 
+            err_buf_len("U"); 
+    }
+    if (jobvt == 'A' || jobvt == 'S'){
+        if (oVt < 0) err_nn_int("offsetVt");
+        if (oVt + (n-1)*ldVt + ((jobvt == 'A') ? n : MIN(m,n)) > 
+            len(Vt)) err_buf_len("Vt"); 
+    }
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            lwork = -1;
+            dgesvd_(&jobu, &jobvt, &m, &n, NULL, &ldA, NULL, NULL, 
+                &ldU, NULL, &ldVt, &wl.d, &lwork, &info);
+            lwork = (int) wl.d;
+            if (!(work = (void *) calloc(lwork, sizeof(double)))){
+                free(work);  
+                return PyErr_NoMemory();
+            }
+            dgesvd_(&jobu, &jobvt, &m, &n, MAT_BUFD(A)+oA, &ldA, 
+                MAT_BUFD(S)+oS,  (jobu == 'A' || jobu == 'S') ? 
+		MAT_BUFD(U)+oU : NULL, &ldU, (jobvt == 'A' || 
+                jobvt == 'S') ?  MAT_BUFD(Vt)+oVt : NULL, &ldVt, 
+		(double *) work, &lwork, &info);
+            free(work);   
+            break;
+
+	case COMPLEX:
+            lwork = -1;
+            zgesvd_(&jobu, &jobvt, &m, &n, NULL, &ldA, NULL, NULL, 
+                &ldU, NULL, &ldVt, &wl.z, &lwork, NULL, &info);
+            lwork = (int) creal(wl.z);
+            work = (void *) calloc(lwork, sizeof(complex));
+            rwork = (double *) calloc(5*MIN(m,n), sizeof(double));
+	    if (!work || !rwork){ 
+                free(work);  free(rwork);
+                return PyErr_NoMemory();
+            }
+            zgesvd_(&jobu, &jobvt, &m, &n, MAT_BUFZ(A)+oA, &ldA, 
+                MAT_BUFD(S)+oS, (jobu == 'A' || jobu == 'S') ? 
+                MAT_BUFZ(U)+oU : NULL,  &ldU, (jobvt == 'A' || 
+                jobvt == 'S') ? MAT_BUFZ(Vt)+oVt : NULL, &ldVt, 
+                (complex *) work, &lwork, rwork, &info);
+            free(work);   free(rwork); 
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static char doc_gesdd[] = 
+    "Singular value decomposition of a real or complex matrix\n"
+    "(divide-and-conquer driver).\n\n"
+    "gesdd(A, S, jobz='N', U=None, V=None, m=A.size[0], n=A.size[1], \n"
+    "      ldA=max(1,A.size[0]), ldU=None, ldVt=None, offsetA=0, \n"
+    "      offsetS=0, offsetU=0, offsetVt=0)\n\n"
+    "PURPOSE\n"
+    "Computes singular values and, optionally, singular vectors of a \n"
+    "real or complex m by n matrix A.  The argument jobz controls how\n"
+    "many singular vectors are computed:\n\n"
+    "'N': no singular vectors are computed.\n"
+    "'A': all m left singular vectors are computed and returned as\n"
+    "     columns of U;  all n right singular vectors are computed \n"
+    "     and returned as rows of Vt.\n"
+    "'S': the first min(m,n) left and right singular vectors are\n"
+    "     computed and returned as columns of U and rows of Vt.\n"
+    "'O': if m>=n, the first n left singular vectors are returned as\n"
+    "     columns of A and the n right singular vectors are returned\n"
+    "     as rows of Vt.  If m<n, the m left singular vectors are\n"
+    "     returned as columns of U and the first m right singular\n"
+    "     vectors are returned as rows of A.\n\n"
+    "Note that the (conjugate) transposes of the right singular \n"
+    "vectors are returned in Vt or A.\n\n"
+    "On exit (in all cases), the contents of A are destroyed.\n\n"
+    "ARGUMENTS\n"
+    "A         'd' or 'z' matrix\n\n"  
+    "S         'd' matrix of length at least min(m,n).  On exit, \n"
+    "          contains the computed singular values in descending\n"
+    "          order.\n\n"
+    "jobz      'N', 'A', 'S' or 'O'\n\n"
+    "U         'd' or 'z' matrix.  Must have the same type as A.\n"
+    "          Not referenced if jobz is 'N' or jobz is 'O' and m>=n.\n"
+    "          If jobz is 'A' or jobz is 'O' and m<n, a matrix with\n"
+    "          at least m columns.   If jobz is 'S', a matrix with at\n"
+    "          least min(m,n) columns.  On exit (except when jobz is\n"
+    "          'N' or jobz is 'O' and m>=n), contains the computed\n"
+    "          left singular vectors stored columnwise.\n\n"
+    "Vt        'd' or 'z' matrix.  Must have the same type as A.\n"
+    "          Not referenced if jobz is 'N' or jobz is 'O' and m<n.\n"
+    "          If jobz is 'A' or 'S' or jobz is 'O' and m>=n, a\n"
+    "          matrix with at least n columns.   On exit (except when\n"
+    "          jobz is 'N' or jobz is 'O' and m<n), the rows of Vt\n"
+    "          contain the computed right singular vectors, or, in\n"
+    "          the complex case, their complex conjugates.\n\n"
+    "m         integer.  If negative, the default value is used.\n\n"
+    "n         integer.  If negative, the default value is used.\n\n"
+    "ldA       nonnegative integer.  ldA >= max(1,m).\n"
+    "          If zero, the default value is used.\n\n"
+    "ldU       nonnegative integer.\n"
+    "          ldU >= 1 if jobz is 'N' or 'O'.\n"
+    "          ldU >= max(1,m) if jobz is 'S' or 'A' or jobz is 'O'\n"
+    "          and m<n.  The default value is max(1,U.size[0]) if\n"
+    "          jobz is 'S' or 'A' or jobz is'O' and m<n, and 1\n"
+    "          otherwise.\n\n"
+    "ldVt      nonnegative integer.\n"
+    "          ldVt >= 1 if jobz is 'N'.\n"
+    "          ldVt >= max(1,n) if jobz is 'A' or jobz is 'O' and \n"
+    "          m>=n.  \n"
+    "          ldVt >= max(1,min(m,n)) if ldVt is 'S'.\n"
+    "          The default value is max(1,Vt.size[0]) if jobvt is 'A'\n"
+    "          or 'S' or jobvt is 'O' and m>=n, and 1 otherwise.\n" 
+    "          If zero, the default value is used.\n\n"
+    "offsetA   nonnegative integer\n\n"
+    "offsetS   nonnegative integer\n\n"
+    "offsetU   nonnegative integer\n\n"
+    "offsetVt  nonnegative integer";
+
+static PyObject* gesdd(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *A, *S, *U=NULL, *Vt=NULL; 
+    int m=-1, n=-1, ldA=0, ldU=0, ldVt=0, oA=0, oS=0, oU=0, oVt=0, info,
+       	*iwork=NULL, lwork; 
+    double *rwork=NULL; 
+    void *work=NULL;
+    number wl;
+    char jobz='N';
+    char *kwlist[] = {"A", "S", "jobz", "U", "Vt", "m", "n", "ldA", 
+	"ldU", "ldVt", "offsetA", "offsetS", "offsetU", "offsetVt", 
+        NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cOOiiiiiiiii",
+        kwlist, &A, &S, &jobz, &U, &Vt, &m, &n, &ldA, &ldU, &ldVt, &oA,
+       	&oS, &oU, &oVt)) return NULL;
+
+    if (!Matrix_Check(A)) err_mtrx("A"); 
+    if (!Matrix_Check(S) || MAT_ID(S) != DOUBLE) err_dbl_mtrx("S");
+    if (jobz != 'A' && jobz != 'S' && jobz != 'O' && jobz != 'N') 
+        err_char("jobz", "'A', 'S', 'O', 'N'");
+    if (m < 0) m = A->nrows;
+    if (n < 0) n = A->ncols;
+    if (m == 0 || n == 0) return Py_BuildValue("");
+    if (ldA == 0) ldA = MAX(1,A->nrows);
+    if (ldA < MAX(1,m)) err_ld("ldA");
+    if (jobz == 'A' || jobz == 'S' || (jobz == 'O' && m<n)){
+        if (!U || !Matrix_Check(U)) err_mtrx("U");
+        if (MAT_ID(U) != MAT_ID(A)) err_conflicting_ids; 
+        if (ldU == 0) ldU = MAX(1,U->nrows);
+        if (ldU < MAX(1,m)) err_ld("ldU");
+    } else {
+        if (ldU == 0) ldU = 1;
+        if (ldU < 1) err_ld("ldU");
+    }
+    if (jobz == 'A' || jobz == 'S' || (jobz == 'O' && m>=n)){
+        if (!Vt || !Matrix_Check(Vt)) err_mtrx("Vt");
+	if (MAT_ID(Vt) != MAT_ID(A)) err_conflicting_ids; 
+        if (ldVt == 0) ldVt = MAX(1,Vt->nrows);
+        if (ldVt < ((jobz == 'A' || jobz == 'O') ?  MAX(1,n) : 
+            MAX(1,MIN(m,n)))) err_ld("ldVt");
+    } else {
+        if (ldVt == 0) ldVt = 1;
+        if (ldVt < 1) err_ld("ldVt");
+    }
+    if (oA < 0) err_nn_int("offsetA");
+    if (oA + (n-1)*ldA + m > len(A)) err_buf_len("A");
+    if (oS < 0) err_nn_int("offsetS");
+    if (oS + MIN(m,n) > len(S)) err_buf_len("S");
+    if (jobz == 'A' || jobz == 'S' || (jobz == 'O' && m<n)){
+        if (oU < 0) err_nn_int("offsetU");
+        if (oU + ((jobz == 'A' || jobz == 'O') ? m-1 : MIN(m,n)-1)*ldU 
+            + m > len(U)) 
+	    err_buf_len("U"); 
+    }
+    if (jobz == 'A' || jobz == 'S' || (jobz == 'O' && m>=n)){
+        if (oVt < 0) err_nn_int("offsetVt");
+        if (oVt + (n-1)*ldVt + ((jobz == 'A' || jobz == 'O') ? n : 
+            MIN(m,n)) > len(Vt)) err_buf_len("Vt"); 
+    }
+
+    switch (MAT_ID(A)){
+        case DOUBLE:
+            lwork = -1;
+            dgesdd_(&jobz, &m, &n, NULL, &ldA, NULL, NULL, &ldU, NULL, 
+                &ldVt, &wl.d, &lwork, NULL, &info);
+            lwork = (int) wl.d;
+            work = (void *) calloc(lwork, sizeof(double));
+            iwork = (int *) calloc(8*MIN(m,n), sizeof(int));
+	    if (!work || !iwork){
+                free(work);  free(iwork);
+                return PyErr_NoMemory();
+            }
+            dgesdd_(&jobz, &m, &n, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(S)+oS,
+                (jobz == 'A' || jobz == 'S' || (jobz == 'O' && m<n)) ?
+                MAT_BUFD(U)+oU : NULL, &ldU, (jobz == 'A' || 
+                jobz == 'S' || (jobz == 'O'  && m>=n)) ? 
+                MAT_BUFD(Vt)+oVt : NULL, &ldVt, (double *) work, &lwork,
+                iwork, &info);
+            free(work);   free(iwork);
+            break;
+
+	case COMPLEX:
+            lwork = -1;
+            zgesdd_(&jobz, &m, &n, NULL, &ldA, NULL, NULL, &ldU, NULL, 
+                &ldVt, &wl.z, &lwork, NULL, NULL, &info);
+            lwork = (int) creal(wl.z);
+            work = (void *) calloc(lwork, sizeof(complex));
+            iwork = (int *) calloc(8*MIN(m,n), sizeof(int));
+            rwork = (double *) calloc( (jobz == 'N') ? 7*MIN(m,n) :
+                5*MIN(m,n)*(MIN(m,n)+1), sizeof(double));
+	    if (!work || !iwork || !rwork){ 
+                free(work);  free(iwork); free(rwork);
+                return PyErr_NoMemory();
+            }
+            zgesdd_(&jobz, &m, &n, MAT_BUFZ(A)+oA, &ldA, MAT_BUFD(S)+oS,
+                (jobz == 'A' || jobz == 'S' || (jobz == 'O' && m<n)) ? 
+		MAT_BUFZ(U)+oU : NULL,  &ldU, (jobz == 'A' || 
+                jobz == 'S' || (jobz == 'O' && m>=n)) ? 
+                MAT_BUFZ(Vt)+oVt : NULL, &ldVt, (complex *) work, 
+                &lwork, rwork, iwork, &info);
+            free(work);  free(iwork); free(rwork); 
+            break;
+
+        default:
+            err_invalid_id;
+    }
+
+    if (info) err_lapack
+    else return Py_BuildValue("");
+}
+
+
+static PyMethodDef lapack_functions[] = {
+{"getrf", (PyCFunction) getrf, METH_VARARGS|METH_KEYWORDS, doc_getrf},
+{"getrs", (PyCFunction) getrs, METH_VARARGS|METH_KEYWORDS, doc_getrs},
+{"getri", (PyCFunction) getri, METH_VARARGS|METH_KEYWORDS, doc_getri},
+{"gesv",  (PyCFunction) gesv,  METH_VARARGS|METH_KEYWORDS, doc_gesv},
+{"gbtrf", (PyCFunction) gbtrf, METH_VARARGS|METH_KEYWORDS, doc_gbtrf},
+{"gbtrs", (PyCFunction) gbtrs, METH_VARARGS|METH_KEYWORDS, doc_gbtrs},
+{"gbsv",  (PyCFunction) gbsv,  METH_VARARGS|METH_KEYWORDS, doc_gbsv},
+{"gttrf", (PyCFunction) gttrf, METH_VARARGS|METH_KEYWORDS, doc_gttrf},
+{"gttrs", (PyCFunction) gttrs, METH_VARARGS|METH_KEYWORDS, doc_gttrs},
+{"gtsv",  (PyCFunction) gtsv,  METH_VARARGS|METH_KEYWORDS, doc_gtsv},
+{"potrf", (PyCFunction) potrf, METH_VARARGS|METH_KEYWORDS, doc_potrf},
+{"potrs", (PyCFunction) potrs, METH_VARARGS|METH_KEYWORDS, doc_potrs},
+{"potri", (PyCFunction) potri, METH_VARARGS|METH_KEYWORDS, doc_potri},
+{"posv",  (PyCFunction) posv,  METH_VARARGS|METH_KEYWORDS, doc_posv},
+{"pbtrf", (PyCFunction) pbtrf, METH_VARARGS|METH_KEYWORDS, doc_pbtrf},
+{"pbtrs", (PyCFunction) pbtrs, METH_VARARGS|METH_KEYWORDS, doc_pbtrs},
+{"pbsv",  (PyCFunction) pbsv,  METH_VARARGS|METH_KEYWORDS, doc_pbsv},
+{"pttrf", (PyCFunction) pttrf, METH_VARARGS|METH_KEYWORDS, doc_pttrf},
+{"pttrs", (PyCFunction) pttrs, METH_VARARGS|METH_KEYWORDS, doc_pttrs},
+{"ptsv",  (PyCFunction) ptsv,  METH_VARARGS|METH_KEYWORDS, doc_ptsv},
+{"sytrs", (PyCFunction) sytrs, METH_VARARGS|METH_KEYWORDS, doc_sytrs},
+{"hetrs", (PyCFunction) hetrs, METH_VARARGS|METH_KEYWORDS, doc_hetrs},
+{"sytrf", (PyCFunction) sytrf, METH_VARARGS|METH_KEYWORDS, doc_sytrf},
+{"hetrf", (PyCFunction) hetrf, METH_VARARGS|METH_KEYWORDS, doc_hetrf},
+{"sytri", (PyCFunction) sytri, METH_VARARGS|METH_KEYWORDS, doc_sytri},
+{"sysv",  (PyCFunction) sysv,  METH_VARARGS|METH_KEYWORDS, doc_sysv},
+{"hetri", (PyCFunction) hetri, METH_VARARGS|METH_KEYWORDS, doc_hetri},
+{"hesv",  (PyCFunction) hesv,  METH_VARARGS|METH_KEYWORDS, doc_hesv},
+{"trtrs", (PyCFunction) trtrs, METH_VARARGS|METH_KEYWORDS, doc_trtrs},
+{"trtri", (PyCFunction) trtri, METH_VARARGS|METH_KEYWORDS, doc_trtri},
+{"tbtrs", (PyCFunction) tbtrs, METH_VARARGS|METH_KEYWORDS, doc_tbtrs},
+{"gels",  (PyCFunction) gels,  METH_VARARGS|METH_KEYWORDS, doc_gels},
+{"geqrf", (PyCFunction) geqrf, METH_VARARGS|METH_KEYWORDS, doc_geqrf},
+{"ormqr", (PyCFunction) ormqr, METH_VARARGS|METH_KEYWORDS, doc_ormqr},
+{"unmqr", (PyCFunction) unmqr, METH_VARARGS|METH_KEYWORDS, doc_unmqr},
+{"syev",  (PyCFunction) syev,  METH_VARARGS|METH_KEYWORDS, doc_syev},
+{"heev",  (PyCFunction) heev,  METH_VARARGS|METH_KEYWORDS, doc_heev},
+{"syevx", (PyCFunction) syevx, METH_VARARGS|METH_KEYWORDS, doc_syevx},
+{"heevx", (PyCFunction) heevx, METH_VARARGS|METH_KEYWORDS, doc_heevx},
+{"sygv",  (PyCFunction) sygv,  METH_VARARGS|METH_KEYWORDS, doc_sygv},
+{"hegv",  (PyCFunction) hegv,  METH_VARARGS|METH_KEYWORDS, doc_hegv},
+{"syevd", (PyCFunction) syevd, METH_VARARGS|METH_KEYWORDS, doc_syevd},
+{"heevd", (PyCFunction) heevd, METH_VARARGS|METH_KEYWORDS, doc_heevd},
+{"syevr", (PyCFunction) syevr, METH_VARARGS|METH_KEYWORDS, doc_syevr},
+{"heevr", (PyCFunction) heevr, METH_VARARGS|METH_KEYWORDS, doc_heevr},
+{"gesvd", (PyCFunction) gesvd, METH_VARARGS|METH_KEYWORDS, doc_gesvd},
+{"gesdd", (PyCFunction) gesdd, METH_VARARGS|METH_KEYWORDS, doc_gesdd},
+{NULL}  /* Sentinel */
+};
+
+PyMODINIT_FUNC initlapack(void)
+{
+  PyObject *m;
+
+  m = Py_InitModule3("cvxopt.lapack", lapack_functions, lapack__doc__);
+
+  if (import_cvxopt() < 0) return;
+}
diff --git a/src/C/misc.h b/src/C/misc.h
new file mode 100644
index 0000000..fb8a9fb
--- /dev/null
+++ b/src/C/misc.h
@@ -0,0 +1,85 @@
+/*
+ * This file is part of CVXOPT version 0.8.2.
+ * Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+ */
+
+#ifndef __MISC__
+#define __MISC__
+
+#define PY_NUMBER(O) (PyInt_Check(O) || PyFloat_Check(O) || PyComplex_Check(O))
+
+#ifndef NO_ANSI99_COMPLEX
+typedef union {
+  double d;
+  int_t i;
+  complex z;
+} number;
+#endif
+
+#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
+#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
+
+#define PY_ERR(E,str) { PyErr_SetString(E, str); return NULL; }
+#define PY_ERR_INT(E,str) { PyErr_SetString(E, str); return -1; }
+#define PY_ERR_TYPE(str) PY_ERR(PyExc_TypeError, str)
+
+/* Python style cyclic wrap-around for indices*/
+#define CWRAP(i,m) (i >= 0 ? i : m+i)
+#define OUT_RNG(i, dim) (i < -dim || i >= dim)
+
+
+#define VALID_TC_MAT(t) (t=='i' || t=='d' || t=='z') 
+#define VALID_TC_SP(t)  (t=='d' || t=='z') 
+#define TC2ID(c) (c=='i' ? 0 : (c=='d' ? 1 : 2)) 
+
+#define X_ID(O)    (Matrix_Check(O) ? MAT_ID(O)    : SP_ID(O))
+#define X_NROWS(O) (Matrix_Check(O) ? MAT_NROWS(O) : SP_NROWS(O))
+#define X_NCOLS(O) (Matrix_Check(O) ? MAT_NCOLS(O) : SP_NCOLS(O))
+
+#define TypeCheck_CObject(O,str,errstr) { \
+    char *descr = PyCObject_GetDesc(O);   \
+    if (!descr || strcmp(descr,str)) PY_ERR(PyExc_TypeError,errstr); }
+
+
+#define len(x) (Matrix_Check(x) ? MAT_LGT(x) : SP_LGT(x))
+
+#define err_mtrx(s) PY_ERR_TYPE(s " must be a matrix") 
+
+#define err_bool(s) PY_ERR_TYPE(s " must be True or False")
+
+#define err_conflicting_ids { \
+    PY_ERR_TYPE("conflicting types for matrix arguments"); }
+
+#define err_invalid_id {PY_ERR_TYPE( \
+	"matrix arguments must have type 'd' or 'z'") }
+
+#define err_nz_int(s) PY_ERR_TYPE(s " must be a nonzero integer") 
+
+#define err_nn_int(s) PY_ERR_TYPE(s " must be a nonnegative integer") 
+
+#define err_buf_len(s) PY_ERR_TYPE("length of " s " is too small")
+
+#define err_type(s) PY_ERR_TYPE("incompatible type for " s)
+
+#define err_p_int(s) { \
+    PY_ERR(PyExc_ValueError, s " must be a positive integer") }
+
+#define err_char(s1,s2) { \
+    PY_ERR(PyExc_ValueError, "possible values of " s1 " are: " s2) }
+
+#define err_ld(s) { \
+    PY_ERR(PyExc_ValueError, "illegal value of " s) }
+
+#define err_int_mtrx(s) { \
+    PY_ERR_TYPE(s " must be a matrix with typecode 'i'") }
+
+#define err_dbl_mtrx(s) { \
+    PY_ERR_TYPE(s " must be a matrix with typecode 'd'") }
+
+#define err_CO(s) PY_ERR_TYPE(s " is not a CObject") 
+
+
+#define err_msk_noparam "missing options dictionary"
+
+
+#endif
diff --git a/src/C/mosek.c b/src/C/mosek.c
new file mode 100644
index 0000000..6900da3
--- /dev/null
+++ b/src/C/mosek.c
@@ -0,0 +1,778 @@
+/*
+ * This file is part of CVXOPT version 0.8.2.
+ * Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+ */
+
+
+#include "cvxopt.h"
+#include "misc.h"
+#include "mosek.h"
+
+PyDoc_STRVAR(mosek__doc__,
+"Interface to the LP and QP solvers in MOSEK.\n\n" 
+"The MOSEK control parameters have the default values listed in \n"
+"the MOSEK documentation at\n"
+"  http://www.mosek.com/products/3/tools/doc/html/tools/node22.html.\n"
+"They can be modified by making an entry in the dictionary\n"
+"mosek.options.  For example, the command\n"
+"  mosek.options['MSK_IPAR_LOG']=0\n"
+"turns off the printed output during execution of mosek.solvelp().");
+
+static PyObject *mosek_module;
+
+static void MSKAPI printstr(void *handle, char str[])
+{
+  printf("%s",str);
+} /* printstr */
+
+static char doc_mosek_solvelp[] = 
+    "Solves a linear program using MOSEK.\n\n"
+    "(prosta, solsta, x, z, y) = solvelp(c, G, h, A, b)\n"
+    "(prosta, solsta, x, z) = solvelp(c, G, h)\n\n"
+    "PURPOSE\n"
+    "(prosta, solsta, x, z, y) = solvelp(c, G, h, A, b) solves the pair\n"
+    "of primal and dual LPs\n\n"
+    "    minimize    c'*x            maximize    -h'*z + b'*y\n"
+    "    subject to  G*x <= h        subject to  G'*z + A'*y + c = 0\n"
+    "                A*x = b                     z >= 0.\n\n"
+    "(prosta, solsta, x, z) = solvelp(c, G, h) solves the pair of\n"
+    "primal and dual LPs\n\n"
+    "    minimize    c'*x            maximize    -h'*z \n"
+    "    subject to  G*x <= h        subject to  G'*z + c = 0\n"
+    "                                            z >= 0.\n\n"
+    "ARGUMENTS\n"
+    "c         nx1 'd' matrix with n>=1\n\n" 
+    "G         mxn 'd' or nonsymmetric sparse matrix with m>=1\n\n"
+    "h         mx1 'd' matrix\n\n"
+    "A         pxn 'd' or nonsymmetric sparse matrix with p>=0\n\n"
+    "b         px1 'd' matrix\n\n"
+    "prosta    the problem status string returned by MOSEK\n\n"
+    "solsta    the solution status string returned by MOSEK\n\n"
+    "x         the primal solution\n\n"
+    "z,y       the dual solution.";
+
+static PyObject *
+mosek_solvelp(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *c, *h, *b=NULL, *x=NULL, *z=NULL, *yu=NULL, *yl=NULL;
+    PyObject *G, *A=NULL, *t=NULL;
+    int m, n, p, i, j, k, nnz=0, nnzmax;
+    char *kwlist[] = {"c", "G", "h", "A", "b", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|OO", kwlist, &c,
+        &G, &h, &A, &b)) return NULL;
+
+    if (!((Matrix_Check(G) && MAT_ID(G) == DOUBLE) || 
+	    (SpMatrix_Check(G) && SP_ID(G) == DOUBLE))) {
+      PY_ERR(PyExc_ValueError, "G must be a dense or sparse matrix"
+	  " with typecode 'd'");
+        return NULL;
+    }
+    if ((m = Matrix_Check(G) ? MAT_NROWS(G) : SP_NROWS(G)) <= 0) 
+        err_p_int("m");
+    if ((n = Matrix_Check(G) ? MAT_NCOLS(G) : SP_NCOLS(G)) <= 0) 
+        err_p_int("n");
+
+    if (!Matrix_Check(h) || h->id != DOUBLE) 
+        err_dbl_mtrx("h");
+    if (h->nrows != m || h->ncols != 1){
+        PyErr_SetString(PyExc_ValueError, "incompatible dimensions");
+        return NULL;
+    }
+
+    if (A){
+      if (!((Matrix_Check(A) && MAT_ID(A) == DOUBLE) || 
+	      (SpMatrix_Check(A) && SP_ID(A) == DOUBLE))) {
+	PyErr_SetString(PyExc_ValueError, "A must be a dense "
+                    "or sparse matrix with typecode 'd'");
+                return NULL;
+	}
+        if ((p = Matrix_Check(A) ? MAT_NROWS(A) : SP_NROWS(A)) < 0)
+            err_p_int("p");
+        if ((Matrix_Check(A) ? MAT_NCOLS(A) : SP_NCOLS(A)) != n){
+            PyErr_SetString(PyExc_ValueError, "incompatible "
+                "dimensions");
+            return NULL;
+	}
+    }
+    else p = 0;
+    if (b && (!Matrix_Check(b) || b->id != DOUBLE)) 
+        err_dbl_mtrx("b");
+    if ((b && (b->nrows != p || b->ncols != 1)) || (!b && p !=0 )){
+        PyErr_SetString(PyExc_ValueError, "incompatible dimensions");
+        return NULL;
+    }
+
+
+    /* Setting up MOSEK environment */
+    nnzmax = (SpMatrix_Check(G) ? SP_NNZ(G) : m*n ) + 
+        ((A && SpMatrix_Check(A)) ? SP_NNZ(A) : p*n);
+
+    int *bkc, *bkx, *ptrb, *ptre, *sub; 
+    bkc  = malloc((m+p)*sizeof(int));
+    bkx  = malloc(n*sizeof(int));
+    ptrb = malloc(n*sizeof(int));
+    ptre = malloc(n*sizeof(int));
+    sub  = malloc(nnzmax*sizeof(int));
+
+    double *blc, *buc, *blx, *bux, *val;
+    blc = malloc((m+p)*sizeof(double));
+    buc = malloc((m+p)*sizeof(double));
+    blx = malloc(n*sizeof(double));
+    bux = malloc(n*sizeof(double));
+    val = malloc(nnzmax*sizeof(double));
+
+    int r;
+    MSKenv_t  env;
+    MSKtask_t task;
+    
+    /* Make mosek environment. */
+    r = MSK_makeenv(&env,NULL,NULL,NULL,NULL); 
+    if (!bkc || !blc || !buc || !bkx || !blx || !buc ||
+	!ptrb || !ptre || !sub || !val || r!=MSK_RES_OK) {
+      free(bkc); free(bkx); free(ptrb); free(ptre); free(sub); 
+      free(blc); free(buc); free(blx); free(bux); free(val);
+      return PyErr_NoMemory();
+    }
+
+    /* Directs the env log stream to the user
+       specified procedure 'printstr'. */
+    MSK_linkfunctoenvstream(env,MSK_STREAM_LOG,NULL,printstr);
+    
+    /* Initialize the environment. */   
+    r = MSK_initenv(env);
+    if (r!=MSK_RES_OK) {
+      free(bkc); free(bkx); free(ptrb); free(ptre); free(sub); 
+      free(blc); free(buc); free(blx); free(bux); free(val);
+      return PyErr_NoMemory();
+    }
+
+    /* Make the optimization task. */
+    r = MSK_maketask(env, (m+p), n, &task);
+    if (r!=MSK_RES_OK) {
+      free(bkc); free(bkx); free(ptrb); free(ptre); free(sub); 
+      free(blc); free(buc); free(blx); free(bux); free(val);
+      MSK_deleteenv(&env);
+      return PyErr_NoMemory();
+    }
+      
+    /* Directs the log task stream to the user
+       specified procedure 'printstr'. */    
+    MSK_linkfunctotaskstream(task,MSK_STREAM_LOG,NULL,printstr);
+        
+    /* Define bounds for the constraints
+       
+      -infty  <=  G*x  <=   h
+         b    <=  A*x  <=   b
+    */
+    
+    for (i=0; i<m; i++) {
+      bkc[i] =  MSK_BK_UP;  
+      blc[i] = -MSK_INFINITY;
+      buc[i] =  MAT_BUFD(h)[i];
+    }
+    
+    for (i=0; i<p; i++) {
+      bkc[m+i] = MSK_BK_FX;  
+      blc[m+i] = MAT_BUFD(b)[i];
+      buc[m+i] = MAT_BUFD(b)[i];
+    }
+
+    /* bounds on the variables (none) */
+    for (i=0; i<n; i++) {
+      bkx[i] =  MSK_BK_FR;		  
+      blx[i] = -MSK_INFINITY;
+      bux[i] =  MSK_INFINITY;
+    }
+    
+    /* constraint matrix */       
+    for (j=0; j<n; j++) {
+      
+      if (SpMatrix_Check(G)) {
+	for (k=SP_COL(G)[j]; k<SP_COL(G)[j+1]; k++) {
+	  val[nnz]   = SP_VALD(G)[k];
+	  sub[nnz++] = SP_ROW(G)[k];
+	}
+      }
+      else {
+	for (k=0; k<m; k++) {
+	  if (MAT_BUFD(G)[j*m+k] != 0.0) {
+	    val[nnz]   = MAT_BUFD(G)[j*m+k];
+	    sub[nnz++] = k;
+	  }
+	}
+      }
+
+      if (A) {
+	if (SpMatrix_Check(A)) {
+	  for (k=SP_COL(A)[j]; k<SP_COL(A)[j+1]; k++) {
+	    val[nnz]   = SP_VALD(A)[k];
+	    sub[nnz++] = m+SP_ROW(A)[k];
+	  }
+	}
+	else {
+	  for (k=0; k<p; k++) {
+	    if (MAT_BUFD(A)[j*p+k] != 0.0) {
+	      val[nnz]   = MAT_BUFD(A)[j*p+k];
+	      sub[nnz++] = m+k;
+	    }
+	  }
+	}	
+      }
+      
+      ptrb[j] = (j>0 ? ptre[j-1] : 0);
+      ptre[j] = nnz;
+    }
+    
+    r = MSK_inputdata(task,
+	(m+p),n,
+	(m+p),n,
+	MAT_BUFD(c),0.0,
+	ptrb, ptre,
+	sub, val,
+	bkc, blc, buc,
+	bkx, blx, bux);
+    
+    free(bkc); free(blc); free(buc); 
+    free(bkx); free(blx); free(bux); 
+    free(ptrb); free(ptre);
+    free(sub); free(val);
+    
+    MSK_putintparam(task,MSK_IPAR_OBJECTIVE_SENSE,MSK_OBJECTIVE_SENSE_MIN);
+    
+    PyObject *param;
+    if (!(param = PyObject_GetAttrString(mosek_module, "options")) ||
+	!PyDict_Check(param)) {
+      MSK_deletetask(&task);
+      MSK_deleteenv(&env);
+      PY_ERR(PyExc_AttributeError,err_msk_noparam);
+    }
+    
+    PyObject *key, *value;
+    int param_id;
+    int_compat pos = 0;    
+
+    while (PyDict_Next(param, &pos, &key, &value)) {
+      MSK_isintparname(task, PyString_AS_STRING(key), &param_id);
+      if (param_id < MSK_IPAR_SOLUTION_CALLBACK) {
+	if (!PyInt_Check(value)) 
+	{
+	  char err_str[100] = "invalid integer parameter: ";
+	  strncat(err_str, PyString_AS_STRING(key), 100);
+	  MSK_deletetask(&task);
+	  MSK_deleteenv(&env);
+	  Py_DECREF(param);
+	  PY_ERR(PyExc_ValueError,err_str);
+	}
+	  
+	MSK_putintparam(task, param_id, PyInt_AsLong(value)); 
+	continue;
+      } 
+      MSK_isdouparname(task, PyString_AS_STRING(key), &param_id);
+      if (param_id < MSK_DPAR_NONCONVEX_TOL_OPT) {
+	if (!PyInt_Check(value) && !PyFloat_Check(value)) 
+	{
+	  char err_str[100] = "invalid floating point parameter: ";
+	  strncat(err_str, PyString_AS_STRING(key), 100);
+	  MSK_deletetask(&task);
+	  MSK_deleteenv(&env);
+	  Py_DECREF(param);
+	  PY_ERR(PyExc_ValueError,err_str);
+	}
+
+	MSK_putdouparam(task, param_id, PyFloat_AsDouble(value)); 	
+	continue;
+      }      
+    }
+    Py_DECREF(param);
+
+    r = MSK_optimize(task);    
+    if (r==MSK_RES_OK) {
+
+      if (!(t = PyTuple_New(A ? 5 : 4))) {
+	MSK_deletetask(&task);
+	MSK_deleteenv(&env);
+	return PyErr_NoMemory();
+      }
+    
+      x = (matrix *) Matrix_New(n,1,DOUBLE);
+      z = (matrix *) Matrix_New(m,1,DOUBLE);
+      if (A) {
+	yu = (matrix *) Matrix_New(p,1,DOUBLE);
+	yl = (matrix *) Matrix_New(p,1,DOUBLE);
+      }
+      if (!x || !z || (A && (!yu || !yl))){
+	Py_XDECREF(x);
+	Py_XDECREF(z);
+	Py_XDECREF(yu);
+	Py_XDECREF(yl);
+	Py_XDECREF(t);
+	MSK_deletetask(&task);
+	MSK_deleteenv(&env);
+	return PyErr_NoMemory();
+      }
+      
+      char statstr[50];
+      int solsta, prosta;
+      double tmp;
+
+      MSK_getsolutioninf(task, 0, &prosta, &solsta, 
+	  &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp);
+      
+      MSK_prostatostr (task, prosta, statstr);
+      PyTuple_SET_ITEM(t, 0, PyString_FromString(statstr));
+
+      MSK_solstatostr (task, solsta, statstr);
+      PyTuple_SET_ITEM(t, 1, PyString_FromString(statstr));
+
+      MSK_getsolutionslice(task, 0, MSK_SOL_ITEM_XX, 0, n, MAT_BUFD(x));
+      PyTuple_SET_ITEM(t, 2, (PyObject *) x);
+	
+      MSK_getsolutionslice(task, 0, MSK_SOL_ITEM_SUC, 0, m, MAT_BUFD(z));
+      PyTuple_SET_ITEM(t, 3, (PyObject *) z);
+	
+      if (A) {	  
+	MSK_getsolutionslice(task,0,MSK_SOL_ITEM_SUC,m,m+p,MAT_BUFD(yu));
+	MSK_getsolutionslice(task,0,MSK_SOL_ITEM_SLC,m,m+p,MAT_BUFD(yl));
+
+	for (i=0; i<yu->nrows; i++) MAT_BUFD(yu)[i] -= MAT_BUFD(yl)[i];
+
+	Py_DECREF(yl);
+	PyTuple_SET_ITEM(t, 4, (PyObject *) yu);
+      }
+
+      MSK_deletetask(&task);
+      MSK_deleteenv(&env);     
+
+      return (PyObject *) t;
+    } 
+      
+    MSK_deletetask(&task);
+    MSK_deleteenv(&env);
+    t = PyString_FromString("internal mosek error");        
+    return (PyObject *) t;    
+}
+
+static char doc_mosek_solveqp[] = 
+    "Solves a convex quadratic program using MOSEK.\n\n"
+    "(prosta, solsta, x, z, y) = solveqp(P, q, G, h, A, b)\n"
+    "(prosta, solsta, x, z) = solveqp(P, q, G, h)\n\n"
+    "PURPOSE\n"
+    "(prosta, solsta, x, z, y) = solveqp(P, q, G, h, A, b) solves the QP\n\n"
+    "    minimize    (1/2)*x'*P*x + q'*x\n"
+    "    subject to  G*x <= h\n"
+    "                A*x = b\n\n"
+    "and its dual\n\n" 
+    "    maximize    (1/2)*(q+G'*z+A'*y)'*Pinv*(q+G'*z+A'*y) - h'*z - b'*y\n"
+    "    subject to  G*x <= h\n"
+    "                A*x = b\n"
+    "                z >= 0\n"
+    "                (I-P*Pinv)*(q+G'*z+A'*y) = 0\n\n"
+    "where Pinv is the Moore-Penrose pseudoinverse of P.\n\n"
+    "(prosta, solsta, x, z) = solveqp(P, q, G, h) solves the LP\n\n"
+    "    minimize    (1/2)*x'*P*q + q'*x\n"
+    "    subject to  G*x <= h\n\n"
+    "and its dual\n\n"
+    "    maximize    (1/2)*(q+G'*z)'*Pinv*(q+G'*z) - h'*z\n"
+    "    subject to  G*x <= h\n"
+    "                z >= 0\n"
+    "                (I-P*Pinv)*(q+G'*z) = 0\n\n"
+    "where Pinv is the Moore-Penrose pseudoinverse of P.\n\n"
+    "ARGUMENTS\n"
+    "P         nxn 'd' matrix with \n\n" 
+    "q         nx1 'd' matrix with n>=1\n\n" 
+    "G         mxn 'd' or nonsymmetric sparse matrix with m>=0\n\n"
+    "h         mx1 'd' matrix\n\n"
+    "A         pxn 'd' or nonsymmetric sparse matrix with p>=0\n\n"
+    "b         px1 'd' matrix\n\n"
+    "prosta    the problem status string returned by MOSEK\n\n"
+    "solsta    the solution status string returned by MOSEK\n\n"
+    "x         the primal solution\n\n"
+    "z,y       the dual solution.";
+
+static PyObject *
+mosek_solveqp(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    matrix *q, *h=NULL, *b=NULL, *x=NULL, *z=NULL, *yu=NULL, *yl=NULL;
+    PyObject *P, *G=NULL, *A=NULL, *t=NULL;
+    int m, n, p, i, j, k, nnz=0, nnzmax, numqonz;
+    char *kwlist[] = {"P", "q", "G", "h", "A", "b", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|OOOO", kwlist, 
+	    &P, &q, &G, &h, &A, &b)) return NULL;
+
+    if (!(Matrix_Check(P) && MAT_ID(P) == DOUBLE && 
+	    MAT_NCOLS(P) == MAT_NROWS(P)) &&
+        !(SpMatrix_Check(P) && SP_ID(P) == DOUBLE)) {
+      PyErr_SetString(PyExc_ValueError, "P must be a square symmetric"
+	  " sparse or dense matrix with typecode 'd'");
+      return NULL;
+    }
+    
+    if (G && ((Matrix_Check(G) && MAT_ID(G) != DOUBLE) || 
+	    (SpMatrix_Check(G) && SP_ID(G) != DOUBLE))) {
+      PyErr_SetString(PyExc_ValueError, "G must be a sparse or dense"
+	  " matrix with typecode 'd'");
+      return NULL;
+    }
+
+    if (!(SpMatrix_Check(P) && ((G && SpMatrix_Check(G)) || !G) && 
+	    ((A && SpMatrix_Check(A)) || !A)) &&
+	!(Matrix_Check(P) && ((G && Matrix_Check(G)) || !G) && 
+	    ((A && Matrix_Check(A)) || !A))) 
+      PY_ERR(PyExc_ValueError, "P, G and A must all be either sparse"
+	  " or dense matrices");      
+
+    int nP = (Matrix_Check(P) ? MAT_NROWS(P) : SP_NROWS(P));    
+    if (!Matrix_Check(q) || MAT_ID(q) != DOUBLE) 
+      PY_ERR(PyExc_ValueError, "q must be a 'd' matrix");
+
+    if (G) {
+      if ((m = Matrix_Check(G) ? MAT_NROWS(G) : SP_NROWS(G)) < 0)
+        err_nn_int("m");
+      if ((n = Matrix_Check(G) ? MAT_NCOLS(G) : SP_NCOLS(G)) <= 0)
+        err_p_int("n");
+
+      if (!h || !Matrix_Check(h) || h->id != DOUBLE) 
+        err_dbl_mtrx("h");
+      if (h->nrows != m || h->ncols != 1 || nP != n || 
+	  q->nrows != n || q->ncols != 1) {
+        PyErr_SetString(PyExc_ValueError, "incompatible dimensions");
+        return NULL;
+      }
+    } 
+    else {
+      m = 0; n = nP;
+    }
+      
+    if (A) {
+        if ((Matrix_Check(A) && MAT_ID(A) != DOUBLE) || 
+            (SpMatrix_Check(A) && SP_ID(A) != DOUBLE)) {
+                PyErr_SetString(PyExc_ValueError, "A must be a sparse "
+                    "or dense matrix with typecode 'd'");
+                return NULL;
+	}
+        if ((p = Matrix_Check(A) ? MAT_NROWS(A) : SP_NROWS(A)) < 0)
+            err_nn_int("p");
+        if ((Matrix_Check(A) ? MAT_NCOLS(A) : SP_NCOLS(A)) != n){
+            PyErr_SetString(PyExc_ValueError, "incompatible "
+                "dimensions");
+            return NULL;
+	}
+    }
+    else p = 0;
+    if (b && (!Matrix_Check(b) || b->id != DOUBLE)) 
+        err_dbl_mtrx("b");
+    if ((b && (b->nrows != p || b->ncols != 1)) || (!b && p !=0)) {
+        PyErr_SetString(PyExc_ValueError, "incompatible dimensions");
+        return NULL;
+    }
+
+    /* Setting up MOSEK environment */
+    numqonz = (SpMatrix_Check(P) ? SP_NNZ(P) : n*(n+1)/2);
+    nnzmax = ((G && SpMatrix_Check(G)) ? SP_NNZ(G) : m*n ) + 
+      ((A && SpMatrix_Check(A)) ? SP_NNZ(A) : p*n);
+
+    int *bkc, *bkx, *ptrb, *ptre, *sub, *qosubi, *qosubj; 
+    bkc    = malloc((m+p)*sizeof(int));
+    bkx    = malloc(n*sizeof(int));
+    ptrb   = malloc(n*sizeof(int));
+    ptre   = malloc(n*sizeof(int));
+    sub    = malloc(nnzmax*sizeof(int));
+    qosubi = malloc(numqonz*sizeof(int));
+    qosubj = malloc(numqonz*sizeof(int));
+
+    double *blc, *buc, *blx, *bux, *val, *qoval;
+    blc = malloc((m+p)*sizeof(double));
+    buc = malloc((m+p)*sizeof(double));
+    blx = malloc(n*sizeof(double));
+    bux = malloc(n*sizeof(double));
+    val = malloc(nnzmax*sizeof(double));
+    qoval = malloc(numqonz*sizeof(double));
+
+    int r;
+    MSKenv_t  env;
+    MSKtask_t task;
+
+    /* Make mosek environment. */
+    r = MSK_makeenv(&env,NULL,NULL,NULL,NULL); 
+    if (!bkc || !blc || !buc || !bkx || !blx || !buc ||
+	!ptrb || !ptre || !sub || !val || 
+	!qosubi || !qosubj || !qoval || r!=MSK_RES_OK) {
+      free(bkc); free(bkx); free(ptrb); free(ptre); free(sub); 
+      free(blc); free(buc); free(blx); free(bux); free(val);
+      free(qosubi); free(qosubj); free(qoval);
+      return PyErr_NoMemory();
+    }
+
+    /* Directs the env log stream to the user
+       specified procedure 'printstr'. */
+    MSK_linkfunctoenvstream(env,MSK_STREAM_LOG,NULL,printstr);
+    
+    /* Initialize the environment. */   
+    r = MSK_initenv(env);
+    if (r!=MSK_RES_OK) {
+      free(bkc); free(bkx); free(ptrb); free(ptre); free(sub); 
+      free(blc); free(buc); free(blx); free(bux); free(val);
+      free(qosubi); free(qosubj); free(qoval);
+      return PyErr_NoMemory();
+    }
+
+    /* Make the optimization task. */
+    r = MSK_maketask(env, (m+p), n, &task);
+    if (r!=MSK_RES_OK) {
+      free(bkc); free(bkx); free(ptrb); free(ptre); free(sub); 
+      free(blc); free(buc); free(blx); free(bux); free(val);
+      free(qosubi); free(qosubj); free(qoval);
+      MSK_deleteenv(&env);
+      return PyErr_NoMemory();
+    }
+    
+    /* Directs the log task stream to the user
+       specified procedure 'printstr'. */    
+    MSK_linkfunctotaskstream(task,MSK_STREAM_LOG,NULL,printstr);
+
+    /* Setup quadratic term of objective */
+    if (Matrix_Check(P)) {
+      for (j=0, k=0; j<n; j++) 
+	for (i=j; i<n; i++, k++) {
+	  qosubi[k] = i;
+	  qosubj[k] = j;
+	  qoval[k]  = MAT_BUFD(P)[j*n+i];
+	}
+    } else {
+      for (j=0, k=0; j<n; j++) {
+	for (i=SP_COL(P)[j]; i<SP_COL(P)[j+1]; i++, k++) {
+	  qosubi[k] = SP_ROW(P)[k];
+	  qosubj[k] = j;
+	  qoval[k]  = SP_VALD(P)[k];	  
+	}
+      }
+    }
+
+    /* Define bounds for the constraints
+       
+      -infty  <=  G*x  <=   h
+         b    <=  A*x  <=   b
+    */
+    
+    for (i=0; i<m; i++) {
+      bkc[i] =  MSK_BK_UP;  
+      blc[i] = -MSK_INFINITY;
+      buc[i] =  MAT_BUFD(h)[i];
+    }
+    
+    for (i=0; i<p; i++) {
+      bkc[m+i] = MSK_BK_FX;  
+      blc[m+i] = MAT_BUFD(b)[i];
+      buc[m+i] = MAT_BUFD(b)[i];
+    }
+
+    /* bounds on the variables (none) */
+    for (i=0; i<n; i++) {
+      bkx[i] =  MSK_BK_FR;		  
+      blx[i] = -MSK_INFINITY;
+      bux[i] =  MSK_INFINITY;
+    }
+    
+    /* constraint matrix */       
+    for (j=0; j<n; j++) {
+      
+      if (G && SpMatrix_Check(G)) {
+	for (k=SP_COL(G)[j]; k<SP_COL(G)[j+1]; k++) {
+	  val[nnz]   = SP_VALD(G)[k];
+	  sub[nnz++] = SP_ROW(G)[k];
+	}
+      }
+      else {
+	for (k=0; k<m; k++) {
+	  if (MAT_BUFD(G)[j*m+k] != 0.0) {
+	    val[nnz]   = MAT_BUFD(G)[j*m+k];
+	    sub[nnz++] = k;
+	  }
+	}
+      }
+
+      if (A) {
+	if (SpMatrix_Check(A)) {
+	  for (k=SP_COL(A)[j]; k<SP_COL(A)[j+1]; k++) {
+	    val[nnz]   = SP_VALD(A)[k];
+	    sub[nnz++] = m+SP_ROW(A)[k];
+	  }
+	}
+	else {
+	  for (k=0; k<p; k++) {
+	    if (MAT_BUFD(A)[j*p+k] != 0.0) {
+	      val[nnz]   = MAT_BUFD(A)[j*p+k];
+	      sub[nnz++] = m+k;
+	    }
+	  }
+	}	
+      }
+      
+      ptrb[j] = (j>0 ? ptre[j-1] : 0);
+      ptre[j] = nnz;
+    }
+    
+    r = MSK_inputdata(task,
+	(m+p),n,
+	(m+p),n,
+	MAT_BUFD(q),0.0,
+	ptrb, ptre,
+	sub, val,
+	bkc, blc, buc,
+	bkx, blx, bux);
+
+    r = MSK_putqobj (task, numqonz, qosubi, qosubj, qoval); 
+
+    free(bkc); free(blc); free(buc); 
+    free(bkx); free(blx); free(bux); 
+    free(ptrb); free(ptre);
+    free(sub); free(val);
+    free(qosubi); free(qosubj); free(qoval);
+
+    MSK_putintparam(task,MSK_IPAR_OBJECTIVE_SENSE,MSK_OBJECTIVE_SENSE_MIN);
+          
+    PyObject *param;
+    if (!(param = PyObject_GetAttrString(mosek_module, "options")) ||
+	!PyDict_Check(param)) {
+      MSK_deletetask(&task);
+      MSK_deleteenv(&env);
+      PY_ERR(PyExc_AttributeError,err_msk_noparam);
+    }
+    
+    PyObject *key, *value;
+    int param_id;
+    int_compat pos = 0;    
+
+    while (PyDict_Next(param, &pos, &key, &value)) {
+      MSK_isintparname(task, PyString_AS_STRING(key), &param_id);
+      if (param_id < MSK_IPAR_SOLUTION_CALLBACK) {
+	if (!PyInt_Check(value)) 
+	{
+	  char err_str[100] = "invalid integer parameter: ";
+	  strncat(err_str, PyString_AS_STRING(key), 100);
+	  MSK_deletetask(&task);
+	  MSK_deleteenv(&env);
+	  Py_DECREF(param);
+	  PY_ERR(PyExc_ValueError,err_str);
+	}
+	  
+	MSK_putintparam(task, param_id, PyInt_AsLong(value)); 
+	continue;
+      } 
+      MSK_isdouparname(task, PyString_AS_STRING(key), &param_id);
+      if (param_id < MSK_DPAR_NONCONVEX_TOL_OPT) {
+	if (!PyInt_Check(value) && !PyFloat_Check(value)) 
+	{
+	  char err_str[100] = "invalid floating point parameter: ";
+	  strncat(err_str, PyString_AS_STRING(key), 100);
+	  MSK_deletetask(&task);
+	  MSK_deleteenv(&env);
+	  Py_DECREF(param);
+	  PY_ERR(PyExc_ValueError,err_str);
+	}
+
+	MSK_putdouparam(task, param_id, PyFloat_AsDouble(value)); 	
+	continue;
+      }      
+    }
+    Py_DECREF(param);
+
+    r = MSK_optimize(task);    
+    if (r==MSK_RES_OK) {
+
+      if (!(t = PyTuple_New(A ? 5 : 4))) {
+	MSK_deletetask(&task);
+	MSK_deleteenv(&env);
+	return PyErr_NoMemory();
+      }
+    
+      x = (matrix *) Matrix_New(n,1,DOUBLE);
+      z = (matrix *) Matrix_New(m,1,DOUBLE);
+      if (A) {
+	yu = (matrix *) Matrix_New(p,1,DOUBLE);
+	yl = (matrix *) Matrix_New(p,1,DOUBLE);
+      }
+      if (!x || !z || (A && (!yu || !yl))){
+	Py_XDECREF(x);
+	Py_XDECREF(z);
+	Py_XDECREF(yu);
+	Py_XDECREF(yl);
+	Py_XDECREF(t);
+	MSK_deletetask(&task);
+	MSK_deleteenv(&env);
+	return PyErr_NoMemory();
+      }
+      
+      char statstr[50];
+      int solsta, prosta;
+      double tmp;
+
+      MSK_getsolutioninf(task, 0, &prosta, &solsta, 
+	  &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp);
+      
+      MSK_prostatostr (task, prosta, statstr);
+      PyTuple_SET_ITEM(t, 0, PyString_FromString(statstr));
+
+      MSK_solstatostr (task, solsta, statstr);
+      PyTuple_SET_ITEM(t, 1, PyString_FromString(statstr));
+
+      MSK_getsolutionslice(task, 0, MSK_SOL_ITEM_XX, 0, n, MAT_BUFD(x));
+      PyTuple_SET_ITEM(t, 2, (PyObject *) x);
+	
+      MSK_getsolutionslice(task, 0, MSK_SOL_ITEM_SUC, 0, m, MAT_BUFD(z));
+      PyTuple_SET_ITEM(t, 3, (PyObject *) z);
+	
+      if (A) {	  
+	MSK_getsolutionslice(task,0,MSK_SOL_ITEM_SUC,m,m+p,MAT_BUFD(yu));
+	MSK_getsolutionslice(task,0,MSK_SOL_ITEM_SLC,m,m+p,MAT_BUFD(yl));
+
+	for (i=0; i<yu->nrows; i++) MAT_BUFD(yu)[i] -= MAT_BUFD(yl)[i];
+
+	Py_DECREF(yl);
+	PyTuple_SET_ITEM(t, 4, (PyObject *) yu);
+      }
+
+      MSK_deletetask(&task);
+      MSK_deleteenv(&env);     
+
+      return (PyObject *) t;
+    } 
+
+    MSK_deletetask(&task);
+    MSK_deleteenv(&env);
+ 
+    char err_str[50];
+
+    switch (r) {
+    case MSK_RES_ERR_INV_PROBLEM:
+      PY_ERR(PyExc_ValueError,"MOSEK error: probably a non-convex "
+	  "problem was specified");
+      break;
+    default:      
+      sprintf(err_str, "Internal MOSEK error. Error code %i",r);
+      PY_ERR(PyExc_Exception,err_str);
+    }
+   
+}
+
+
+static PyMethodDef mosek_functions[] = {
+  {"solvelp", (PyCFunction) mosek_solvelp, METH_VARARGS|METH_KEYWORDS, 
+   doc_mosek_solvelp},
+ {"solveqp", (PyCFunction) mosek_solveqp, METH_VARARGS|METH_KEYWORDS, 
+   doc_mosek_solveqp}, 
+  {NULL}  /* Sentinel */
+};
+
+PyMODINIT_FUNC
+initmosek(void)
+{
+  mosek_module = Py_InitModule3("cvxopt.mosek", mosek_functions, mosek__doc__);
+
+  PyModule_AddObject(mosek_module, "options", PyDict_New());
+  
+  if (import_cvxopt() < 0)
+    return;
+}
diff --git a/src/C/random.c b/src/C/random.c
new file mode 100644
index 0000000..49c4bca
--- /dev/null
+++ b/src/C/random.c
@@ -0,0 +1,144 @@
+/*
+ * This file is part of CVXOPT version 0.8.2.
+ * Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+ */
+
+#include "cvxopt.h"
+
+#include <complex.h>
+
+#include "misc.h"
+#include "rngs/rngs.h"
+#include "rngs/rvgs.h"
+
+PyDoc_STRVAR(random__doc__,"Random Module.");
+
+static char doc_getseed[] =
+    "Returns the seed value for the random number generator.\n\n"
+    "getseed()";
+static PyObject *
+getseed(PyObject *self) 
+{
+  long seed;
+  GetSeed(&seed);
+
+  return Py_BuildValue("l",seed);
+}
+
+static char doc_setseed[] =
+    "Sets the seed value for the random number generator.\n\n"
+    "setseed(value = 0.0)\n\n"
+    "ARGUMENTS\n"
+    "value     a nonnegative number that specifies the seed value.\n"
+    "          If value is 0, the system clock is used.";
+
+static PyObject *
+setseed(PyObject *self, PyObject *args) 
+{
+  long seed = 0;
+
+  if (!PyArg_ParseTuple(args, "|l", &seed))
+    return NULL;
+
+  if (seed < 0) PY_ERR(PyExc_ValueError, "seed value must be non-negative");
+
+  PutSeed( (seed>0 ? seed : -1));
+  return Py_BuildValue("");
+}
+
+static char doc_normal[] =
+    "Randomly generates a matrix with normally distributed entries.\n\n"
+    "normal(nrows, ncols=1, mean=0, std=1)\n\n"
+    "PURPOSE\n"
+    "Returns a matrix with typecode 'd' and size nrows by ncols, with\n"
+    "its entries randomly generated from a normal distribution with mean\n"
+    "m and standard deviation std.\n\n"
+    "ARGUMENTS\n"
+    "nrows     number of rows\n\n"
+    "ncols     number of columns\n\n"
+    "mean      approximate mean of the distribution\n\n"
+    "std       standard deviation of the distribution";
+static PyObject *
+normal(PyObject *self, PyObject *args, PyObject *kwrds) 
+{
+  matrix *obj;
+  int i, nrows, ncols = 1;
+  double m = 0, s = 1;
+  char *kwlist[] = {"nrows", "ncols", "mean", "std", NULL};
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "i|idd", kwlist, 
+	  &nrows, &ncols, &m, &s)) return NULL;
+
+  if (s < 0.0) PY_ERR(PyExc_ValueError, "std must be non-negative");
+
+  if ((nrows<0) || (ncols<0)) {
+    PyErr_SetString(PyExc_TypeError, "dimensions must be non-negative");
+    return NULL;
+  }
+
+  if (!(obj = Matrix_New(nrows, ncols, DOUBLE)))
+    return PyErr_NoMemory();
+  
+  for (i= 0; i < nrows*ncols; i++)
+    MAT_BUFD(obj)[i] = Normal(m,s);
+  
+  return (PyObject *)obj;
+}
+
+static char doc_uniform[] =
+    "Randomly generates a matrix with uniformly distributed entries.\n\n"
+    "uniform(nrows, ncols=1, a=0, b=1)\n\n"
+    "PURPOSE\n"
+    "Returns a matrix with typecode 'd' and size nrows by ncols, with\n"
+    "its entries randomly generated from a uniform distribution on the\n"
+    "interval (a,b).\n\n"
+    "ARGUMENTS\n"
+    "nrows     number of rows\n\n"
+    "ncols     number of columns\n\n"
+    "a         lower bound\n\n"
+    "b         upper bound";
+
+static PyObject *
+uniform(PyObject *self, PyObject *args, PyObject *kwrds) 
+{
+  matrix *obj;
+  int i, nrows, ncols = 1;
+  double a = 0, b = 1;
+
+  char *kwlist[] = {"nrows", "ncols", "a", "b", NULL};
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "i|idd", kwlist, 
+	  &nrows, &ncols, &a, &b)) return NULL;
+  
+  if (a>b) PY_ERR(PyExc_ValueError, "a must be less than b");
+
+  if ((nrows<0) || (ncols<0)) 
+    PY_ERR_TYPE("dimensions must be non-negative");
+  
+  if (!(obj = (matrix *)Matrix_New(nrows, ncols, DOUBLE)))
+    return PyErr_NoMemory();
+  
+  for (i= 0; i < nrows*ncols; i++)
+    MAT_BUFD(obj)[i] = Uniform(a,b);
+  
+  return (PyObject *)obj;
+}
+
+static PyMethodDef random_functions[] = {
+  {"getseed",(PyCFunction)getseed,METH_NOARGS, doc_getseed},  
+  {"setseed",(PyCFunction)setseed,METH_VARARGS, doc_setseed},  
+  {"normal", (PyCFunction)normal, METH_VARARGS|METH_KEYWORDS, doc_normal},  
+  {"uniform",(PyCFunction)uniform,METH_VARARGS|METH_KEYWORDS, doc_uniform},  
+  {NULL}  /* Sentinel */
+};
+
+PyMODINIT_FUNC
+initrandom(void)
+{
+  PyObject *m;
+
+  m = Py_InitModule3("cvxopt.random", random_functions, random__doc__);
+  
+  if (import_cvxopt() < 0)
+    return;
+}
diff --git a/src/C/rngs/README.cvxopt b/src/C/rngs/README.cvxopt
new file mode 100644
index 0000000..43eab85
--- /dev/null
+++ b/src/C/rngs/README.cvxopt
@@ -0,0 +1,3 @@
+The files in this directory are from the random number generator 
+library by Steve Park & Dave Geyer. 
+See www.cs.wm.edu/~va/software/park/park.html.
diff --git a/src/C/rngs/rngs.c b/src/C/rngs/rngs.c
new file mode 100644
index 0000000..a55f176
--- /dev/null
+++ b/src/C/rngs/rngs.c
@@ -0,0 +1,179 @@
+/* -------------------------------------------------------------------------
+ * This is an ANSI C library for multi-stream random number generation.  
+ * The use of this library is recommended as a replacement for the ANSI C 
+ * rand() and srand() functions, particularly in simulation applications 
+ * where the statistical 'goodness' of the random number generator is 
+ * important.  The library supplies 256 streams of random numbers; use 
+ * SelectStream(s) to switch between streams indexed s = 0,1,...,255.
+ *
+ * The streams must be initialized.  The recommended way to do this is by
+ * using the function PlantSeeds(x) with the value of x used to initialize 
+ * the default stream and all other streams initialized automatically with
+ * values dependent on the value of x.  The following convention is used 
+ * to initialize the default stream:
+ *    if x > 0 then x is the state
+ *    if x < 0 then the state is obtained from the system clock
+ *    if x = 0 then the state is to be supplied interactively.
+ *
+ * The generator used in this library is a so-called 'Lehmer random number
+ * generator' which returns a pseudo-random number uniformly distributed
+ * 0.0 and 1.0.  The period is (m - 1) where m = 2,147,483,647 and the
+ * smallest and largest possible values are (1 / m) and 1 - (1 / m)
+ * respectively.  For more details see:
+ * 
+ *       "Random Number Generators: Good Ones Are Hard To Find"
+ *                   Steve Park and Keith Miller
+ *              Communications of the ACM, October 1988
+ *
+ * Name            : rngs.c  (Random Number Generation - Multiple Streams)
+ * Authors         : Steve Park & Dave Geyer
+ * Language        : ANSI C
+ * Latest Revision : 09-22-98
+ * ------------------------------------------------------------------------- 
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include "rngs.h"
+
+#define MODULUS    2147483647 /* DON'T CHANGE THIS VALUE                  */
+#define MULTIPLIER 48271      /* DON'T CHANGE THIS VALUE                  */
+#define CHECK      399268537  /* DON'T CHANGE THIS VALUE                  */
+#define STREAMS    256        /* # of streams, DON'T CHANGE THIS VALUE    */
+#define A256       22925      /* jump multiplier, DON'T CHANGE THIS VALUE */
+#define DEFAULT    123456789  /* initial seed, use 0 < DEFAULT < MODULUS  */
+      
+static long seed[STREAMS] = {DEFAULT};  /* current state of each stream   */
+static int  stream        = 0;          /* stream index, 0 is the default */
+static int  initialized   = 0;          /* test for stream initialization */
+
+
+   double Random(void)
+/* ----------------------------------------------------------------
+ * Random returns a pseudo-random real number uniformly distributed 
+ * between 0.0 and 1.0. 
+ * ----------------------------------------------------------------
+ */
+{
+  const long Q = MODULUS / MULTIPLIER;
+  const long R = MODULUS % MULTIPLIER;
+        long t;
+
+  t = MULTIPLIER * (seed[stream] % Q) - R * (seed[stream] / Q);
+  if (t > 0) 
+    seed[stream] = t;
+  else 
+    seed[stream] = t + MODULUS;
+  return ((double) seed[stream] / MODULUS);
+}
+
+
+   void PlantSeeds(long x)
+/* ---------------------------------------------------------------------
+ * Use this function to set the state of all the random number generator 
+ * streams by "planting" a sequence of states (seeds), one per stream, 
+ * with all states dictated by the state of the default stream. 
+ * The sequence of planted states is separated one from the next by 
+ * 8,367,782 calls to Random().
+ * ---------------------------------------------------------------------
+ */
+{
+  const long Q = MODULUS / A256;
+  const long R = MODULUS % A256;
+        int  j;
+        int  s;
+
+  initialized = 1;
+  s = stream;                            /* remember the current stream */
+  SelectStream(0);                       /* change to stream 0          */
+  PutSeed(x);                            /* set seed[0]                 */
+  stream = s;                            /* reset the current stream    */
+  for (j = 1; j < STREAMS; j++) {
+    x = A256 * (seed[j - 1] % Q) - R * (seed[j - 1] / Q);
+    if (x > 0)
+      seed[j] = x;
+    else
+      seed[j] = x + MODULUS;
+   }
+}
+
+
+   void PutSeed(long x)
+/* ---------------------------------------------------------------
+ * Use this function to set the state of the current random number 
+ * generator stream according to the following conventions:
+ *    if x > 0 then x is the state (unless too large)
+ *    if x < 0 then the state is obtained from the system clock
+ *    if x = 0 then the state is to be supplied interactively
+ * ---------------------------------------------------------------
+ */
+{
+  char ok = 0;
+
+  if (x > 0)
+    x = x % MODULUS;                       /* correct if x is too large  */
+  if (x < 0)                                 
+    x = ((unsigned long) time((time_t *) NULL)) % MODULUS;              
+  if (x == 0)                                
+    while (!ok) {
+      printf("\nEnter a positive integer seed (9 digits or less) >> ");
+      scanf("%ld", &x);
+      ok = (0 < x) && (x < MODULUS);
+      if (!ok)
+        printf("\nInput out of range ... try again\n");
+    }
+  seed[stream] = x;
+}
+
+
+   void GetSeed(long *x)
+/* ---------------------------------------------------------------
+ * Use this function to get the state of the current random number 
+ * generator stream.                                                   
+ * ---------------------------------------------------------------
+ */
+{
+  *x = seed[stream];
+}
+
+
+   void SelectStream(int index)
+/* ------------------------------------------------------------------
+ * Use this function to set the current random number generator
+ * stream -- that stream from which the next random number will come.
+ * ------------------------------------------------------------------
+ */
+{
+  stream = ((unsigned int) index) % STREAMS;
+  if ((initialized == 0) && (stream != 0))   /* protect against        */
+    PlantSeeds(DEFAULT);                     /* un-initialized streams */
+}
+
+
+   void TestRandom(void)
+/* ------------------------------------------------------------------
+ * Use this (optional) function to test for a correct implementation.
+ * ------------------------------------------------------------------    
+ */
+{
+  long   i;
+  long   x;
+  double u;
+  char   ok = 0;  
+
+  SelectStream(0);                  /* select the default stream */
+  PutSeed(1);                       /* and set the state to 1    */
+  for(i = 0; i < 10000; i++)
+    u = Random();
+  GetSeed(&x);                      /* get the new state value   */
+  ok = (x == CHECK);                /* and check for correctness */
+
+  SelectStream(1);                  /* select stream 1                 */ 
+  PlantSeeds(1);                    /* set the state of all streams    */
+  GetSeed(&x);                      /* get the state of stream 1       */
+  ok = ok && (x == A256);           /* x should be the jump multiplier */    
+  if (ok)
+    printf("\n The implementation of rngs.c is correct.\n\n");
+  else
+    printf("\n\a ERROR -- the implementation of rngs.c is not correct.\n\n");
+}
diff --git a/src/C/rngs/rngs.h b/src/C/rngs/rngs.h
new file mode 100644
index 0000000..4bc7c06
--- /dev/null
+++ b/src/C/rngs/rngs.h
@@ -0,0 +1,19 @@
+/* ----------------------------------------------------------------------- 
+ * Name            : rngs.h  (header file for the library file rngs.c) 
+ * Author          : Steve Park & Dave Geyer
+ * Language        : ANSI C
+ * Latest Revision : 09-22-98
+ * ----------------------------------------------------------------------- 
+ */
+
+#if !defined( _RNGS_ )
+#define _RNGS_
+
+double Random(void);
+void   PlantSeeds(long x);
+void   GetSeed(long *x);
+void   PutSeed(long x);
+void   SelectStream(int index);
+void   TestRandom(void);
+
+#endif
diff --git a/src/C/rngs/rvgs.c b/src/C/rngs/rvgs.c
new file mode 100644
index 0000000..265ade6
--- /dev/null
+++ b/src/C/rngs/rvgs.c
@@ -0,0 +1,218 @@
+/* -------------------------------------------------------------------------- 
+ * This is an ANSI C library for generating random variates from six discrete 
+ * distributions
+ *
+ *      Generator         Range (x)     Mean         Variance
+ *
+ *      Bernoulli(p)      x = 0,1       p            p*(1-p)
+ *      Binomial(n, p)    x = 0,...,n   n*p          n*p*(1-p)
+ *      Equilikely(a, b)  x = a,...,b   (a+b)/2      ((b-a+1)*(b-a+1)-1)/12
+ *      Geometric(p)      x = 0,...     p/(1-p)      p/((1-p)*(1-p))
+ *      Pascal(n, p)      x = 0,...     n*p/(1-p)    n*p/((1-p)*(1-p))
+ *      Poisson(m)        x = 0,...     m            m
+ * 
+ * and seven continuous distributions
+ *
+ *      Uniform(a, b)     a < x < b     (a + b)/2    (b - a)*(b - a)/12 
+ *      Exponential(m)    x > 0         m            m*m
+ *      Erlang(n, b)      x > 0         n*b          n*b*b
+ *      Normal(m, s)      all x         m            s*s
+ *      Lognormal(a, b)   x > 0            see below
+ *      Chisquare(n)      x > 0         n            2*n 
+ *      Student(n)        all x         0  (n > 1)   n/(n - 2)   (n > 2)
+ *
+ * For the a Lognormal(a, b) random variable, the mean and variance are
+ *
+ *                        mean = exp(a + 0.5*b*b)
+ *                    variance = (exp(b*b) - 1) * exp(2*a + b*b)
+ *
+ * Name              : rvgs.c  (Random Variate GeneratorS)
+ * Author            : Steve Park & Dave Geyer
+ * Language          : ANSI C
+ * Latest Revision   : 10-28-98
+ * --------------------------------------------------------------------------
+ */
+
+#include <math.h>
+#include "rngs.h"
+#include "rvgs.h"
+
+
+   long Bernoulli(double p)
+/* ========================================================
+ * Returns 1 with probability p or 0 with probability 1 - p. 
+ * NOTE: use 0.0 < p < 1.0                                   
+ * ========================================================
+ */ 
+{
+  return ((Random() < (1.0 - p)) ? 0 : 1);
+}
+
+   long Binomial(long n, double p)
+/* ================================================================ 
+ * Returns a binomial distributed integer between 0 and n inclusive. 
+ * NOTE: use n > 0 and 0.0 < p < 1.0
+ * ================================================================
+ */
+{ 
+  long i, x = 0;
+
+  for (i = 0; i < n; i++)
+    x += Bernoulli(p);
+  return (x);
+}
+
+   long Equilikely(long a, long b)
+/* ===================================================================
+ * Returns an equilikely distributed integer between a and b inclusive. 
+ * NOTE: use a < b
+ * ===================================================================
+ */
+{
+  return (a + (long) ((b - a + 1) * Random()));
+}
+
+   long Geometric(double p)
+/* ====================================================
+ * Returns a geometric distributed non-negative integer.
+ * NOTE: use 0.0 < p < 1.0
+ * ====================================================
+ */
+{
+  return ((long) (log(1.0 - Random()) / log(p)));
+}
+
+   long Pascal(long n, double p)
+/* ================================================= 
+ * Returns a Pascal distributed non-negative integer. 
+ * NOTE: use n > 0 and 0.0 < p < 1.0
+ * =================================================
+ */
+{ 
+  long i, x = 0;
+
+  for (i = 0; i < n; i++)
+    x += Geometric(p);
+  return (x);
+}
+
+   long Poisson(double m)
+/* ================================================== 
+ * Returns a Poisson distributed non-negative integer. 
+ * NOTE: use m > 0
+ * ==================================================
+ */
+{ 
+  double t = 0.0;
+  long   x = 0;
+
+  while (t < m) {
+    t += Exponential(1.0);
+    x++;
+  }
+  return (x - 1);
+}
+
+   double Uniform(double a, double b)
+/* =========================================================== 
+ * Returns a uniformly distributed real number between a and b. 
+ * NOTE: use a < b
+ * ===========================================================
+ */
+{ 
+  return (a + (b - a) * Random());
+}
+
+   double Exponential(double m)
+/* =========================================================
+ * Returns an exponentially distributed positive real number. 
+ * NOTE: use m > 0.0
+ * =========================================================
+ */
+{
+  return (-m * log(1.0 - Random()));
+}
+
+   double Erlang(long n, double b)
+/* ================================================== 
+ * Returns an Erlang distributed positive real number.
+ * NOTE: use n > 0 and b > 0.0
+ * ==================================================
+ */
+{ 
+  long   i;
+  double x = 0.0;
+
+  for (i = 0; i < n; i++) 
+    x += Exponential(b);
+  return (x);
+}
+
+   double Normal(double m, double s)
+/* ========================================================================
+ * Returns a normal (Gaussian) distributed real number.
+ * NOTE: use s > 0.0
+ *
+ * Uses a very accurate approximation of the normal idf due to Odeh & Evans, 
+ * J. Applied Statistics, 1974, vol 23, pp 96-97.
+ * ========================================================================
+ */
+{ 
+  const double p0 = 0.322232431088;     const double q0 = 0.099348462606;
+  const double p1 = 1.0;                const double q1 = 0.588581570495;
+  const double p2 = 0.342242088547;     const double q2 = 0.531103462366;
+  const double p3 = 0.204231210245e-1;  const double q3 = 0.103537752850;
+  const double p4 = 0.453642210148e-4;  const double q4 = 0.385607006340e-2;
+  double u, t, p, q, z;
+
+  u   = Random();
+  if (u < 0.5)
+    t = sqrt(-2.0 * log(u));
+  else
+    t = sqrt(-2.0 * log(1.0 - u));
+  p   = p0 + t * (p1 + t * (p2 + t * (p3 + t * p4)));
+  q   = q0 + t * (q1 + t * (q2 + t * (q3 + t * q4)));
+  if (u < 0.5)
+    z = (p / q) - t;
+  else
+    z = t - (p / q);
+  return (m + s * z);
+}
+
+   double Lognormal(double a, double b)
+/* ==================================================== 
+ * Returns a lognormal distributed positive real number. 
+ * NOTE: use b > 0.0
+ * ====================================================
+ */
+{
+  return (exp(a + b * Normal(0.0, 1.0)));
+}
+
+   double Chisquare(long n)
+/* =====================================================
+ * Returns a chi-square distributed positive real number. 
+ * NOTE: use n > 0
+ * =====================================================
+ */
+{ 
+  long   i;
+  double z, x = 0.0;
+
+  for (i = 0; i < n; i++) {
+    z  = Normal(0.0, 1.0);
+    x += z * z;
+  }
+  return (x);
+}
+
+   double Student(long n)
+/* =========================================== 
+ * Returns a student-t distributed real number.
+ * NOTE: use n > 0
+ * ===========================================
+ */
+{
+  return (Normal(0.0, 1.0) / sqrt(Chisquare(n) / n));
+}
+
diff --git a/src/C/rngs/rvgs.h b/src/C/rngs/rvgs.h
new file mode 100644
index 0000000..d3768d6
--- /dev/null
+++ b/src/C/rngs/rvgs.h
@@ -0,0 +1,28 @@
+/* ------------------------------------------------------------- 
+ * Name            : rvgs.h (header file for the library rvgs.c)
+ * Author          : Steve Park & Dave Geyer
+ * Language        : ANSI C
+ * Latest Revision : 11-03-96
+ * -------------------------------------------------------------- 
+ */
+
+#if !defined( _RVGS_ )
+#define _RVGS_
+
+long Bernoulli(double p);
+long Binomial(long n, double p);
+long Equilikely(long a, long b);
+long Geometric(double p);
+long Pascal(long n, double p);
+long Poisson(double m);
+
+double Uniform(double a, double b);
+double Exponential(double m);
+double Erlang(long n, double b);
+double Normal(double m, double s);
+double Lognormal(double a, double b);
+double Chisquare(long n);
+double Student(long n);
+
+#endif
+
diff --git a/src/C/sparse.c b/src/C/sparse.c
new file mode 100644
index 0000000..0785ba0
--- /dev/null
+++ b/src/C/sparse.c
@@ -0,0 +1,3992 @@
+/*
+ * This file is part of CVXOPT version 0.8.2.
+ * Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+ */
+
+#define BASE_MODULE
+
+#include "Python.h"
+#include "cvxopt.h"
+#include "misc.h" 
+
+#include <complexobject.h>
+
+#define CONJ(flag, val) (flag == 'C' ? conj(val) : val)
+
+extern PyObject *base_mod;
+
+extern const int  E_SIZE[];
+extern const char TC_CHAR[][2];
+extern const char PRINTOPT[][15];
+extern number One[3], MinusOne[3], Zero[3];
+
+extern void (*write_num[])(void *, int, void *, int) ;
+extern int (*convert_num[])(void *, void *, int, int_t) ;
+extern PyObject * (*num2PyObject[])(void *, int) ;
+extern void (*scal[])(int *, number *, void *, int *) ;
+extern void (*axpy[])(int *, void *, void *, int *, void *, int *) ;
+extern void (*gemm[])(char *, char *, int *, int *, int *, void *, 
+    void *, int *, void *, int *, void *, void *, int *) ;
+extern int (*div_array[])(void *, number, int) ;
+extern int get_id(void *, int ) ;
+
+extern PyTypeObject matrix_tp ;
+extern matrix * Matrix_NewFromMatrix(matrix *, int) ;
+extern matrix * Matrix_NewFromSequence(PyObject *, int) ; 
+extern matrix * Matrix_NewFromArrayStruct(PyObject *, int, int_t *) ;
+extern matrix * Matrix_NewFromNumber(int , int , int , void *, int ) ;
+extern matrix * create_indexlist(int, PyObject *) ; 
+extern matrix * Matrix_New(int, int, int) ;
+extern matrix * dense(spmatrix *) ;  
+extern PyObject * matrix_add(PyObject *, PyObject *) ; 
+extern PyObject * matrix_sub(PyObject *, PyObject *) ; 
+extern void * convert_mtx_alloc(matrix *, int) ;
+
+PyTypeObject spmatrix_tp ;
+spmatrix * SpMatrix_New(int, int, int, int ) ;
+
+extern void (*scal[])(int *, number *, void *, int *) ;
+extern void (*gemm[])(char *, char *, int *, int *, int *, void *, void *, 
+    int *, void *, int *, void *, void *, int *) ;
+extern void (*syrk[])(char *, char *, int *, int *, void *, void *,
+    int *, void *, void *, int *) ;
+
+static int sp_daxpy(number, void *, void *, int, int, int, void **) ;
+static int sp_zaxpy(number, void *, void *, int, int, int, void **) ;
+int (*sp_axpy[])(number, void *, void *, int, int, int, void **) 
+  = { NULL, sp_daxpy, sp_zaxpy };
+
+static int sp_dgemm(char, char, number, void *, void *, number, void *, 
+    int, int, int, int, void **, int, int, int) ; 
+static int sp_zgemm(char, char, number, void *, void *, number, void *, 
+    int, int, int, int, void **, int, int, int) ; 
+int (*sp_gemm[])(char, char, number, void *, void *, number, void *, 
+    int, int, int, int, void **, int, int, int) 
+  = { NULL, sp_dgemm, sp_zgemm };
+
+static int sp_dgemv(char, int, int, number, void *, int, 
+    void *, int, number, void *, int) ;
+static int sp_zgemv(char, int, int, number, void *, int, 
+    void *, int, number, void *, int) ;
+int (*sp_gemv[])(char, int, int, number, void *, int, void *, int,  
+    number, void *, int) = { NULL, sp_dgemv, sp_zgemv } ;
+
+static int sp_dsymv(char, int, number, ccs *, int, void *, int,
+    number, void *, int) ;
+static int sp_zsymv(char, int, number, ccs *, int, void *, int,
+    number, void *, int) ;
+int (*sp_symv[])(char, int, number, ccs *, int, void *, int,
+    number, void *, int) = { NULL, sp_dsymv, sp_zsymv } ;
+
+static int sp_dsyrk(char, char, number, void *, number, 
+    void *, int, int, int, int, void **) ;
+int (*sp_syrk[])(char, char, number, void *, number, 
+    void *, int, int, int, int, void **) = { NULL, sp_dsyrk, NULL };
+
+typedef struct {
+  int_t key, value;
+} int_list;
+
+static int comp_int(const void *x, const void *y) {
+  if (((int_list *)x)->key == ((int_list *)y)->key) 
+    return 0;
+  else
+    return (((int_list *)x)->key > ((int_list *)y)->key ? 1 : -1);
+}
+
+typedef struct {
+  int_t key; double value;
+} double_list;
+
+static int comp_double(const void *x, const void *y) {
+  if (((double_list *)x)->key == ((double_list *)y)->key) 
+    return 0;
+  else
+    return (((double_list *)x)->key > ((double_list *)y)->key ? 1 : -1);
+}
+
+typedef struct {
+  int_t key; complex value;
+} complex_list;
+
+static int comp_complex(const void *x, const void *y) {
+  if (((complex_list *)x)->key == ((complex_list *)y)->key) 
+    return 0;
+  else
+    return (((complex_list *)x)->key > ((complex_list *)y)->key ? 1 : -1);
+}
+
+#define spmatrix_getitem_i(O,i,v) \
+  spmatrix_getitem_ij(O,i%SP_NROWS(O),i/SP_NROWS(O),v)
+#define spmatrix_setitem_i(O,i,v) \
+  spmatrix_setitem_ij(O,i%SP_NROWS(O),i/SP_NROWS(O),v)
+
+#define free_lists_exit(argI,argJ,I,J,ret) { \
+   if (argI && !Matrix_Check(argI)) { Py_XDECREF(I); } \
+    if (argJ && !Matrix_Check(argJ)) { Py_XDECREF(J); } \
+    return ret; }
+
+#define INCR_SP_ROW_IDX(O, j, k) {		\
+    while (((ccs *)O)->colptr[j+1] == k+1) j++;	\
+    k++; }
+
+int 
+convert_array(void *dest, void *src, int dest_id, int src_id, int n) {
+
+  if (dest_id != MAX(dest_id,src_id)) 
+    return -1;
+  
+  int i;
+  if (dest_id == src_id)
+    memcpy(dest, src, n*E_SIZE[dest_id]);
+  else if (dest_id == DOUBLE) {
+    for (i=0; i<n; i++)
+      ((double *)dest)[i] = ((int *)src)[i];
+  } else {
+    if (src_id == INT) {
+      for (i=0; i<n; i++)
+	((complex *)dest)[i] = ((int *)src)[i];
+    } else {
+      for (i=0; i<n; i++)
+	((complex *)dest)[i] = ((double *)src)[i];
+    }
+  }
+  return 0;
+}
+
+ccs * alloc_ccs(int_t nrows, int_t ncols, int nnz, int id) 
+{  
+  ccs *obj = malloc(sizeof(ccs));
+  if (!obj) return NULL;
+
+  obj->nrows = nrows;
+  obj->ncols = ncols;
+  obj->id = id;
+  obj->nzmax = nnz;
+
+  obj->values = malloc(E_SIZE[id]*nnz);
+  obj->colptr = calloc(ncols+1,sizeof(int_t));    
+  obj->rowind = malloc(sizeof(int_t)*nnz);  
+
+  if (!obj->values || !obj->colptr || !obj->rowind) {
+    free(obj->values); free(obj->colptr); free(obj->rowind); free(obj);
+    return NULL;
+  } 
+  
+  return obj;  
+}
+
+void free_ccs(ccs *obj) {
+  free(obj->values);
+  free(obj->rowind);
+  free(obj->colptr);
+  free(obj);
+}
+
+static int
+realloc_ccs(ccs *obj, int nzmax) {
+
+  int_t *rowind;
+  void *values;
+
+  if ((rowind = realloc(obj->rowind, nzmax*sizeof(int_t))))
+    obj->rowind = rowind;
+  else  
+    return 0;
+
+  if ((values = realloc(obj->values, nzmax*E_SIZE[obj->id])))
+    obj->values = values;
+  else 
+    return 0;
+  
+  obj->nzmax = nzmax;
+  return 1;
+}
+
+static ccs * convert_ccs(ccs *src, int id) {
+  
+  if (src->id == id) return src;
+
+  if (id != MAX(id,src->id)) PY_ERR_TYPE("incompatible matrix types");
+    
+  ccs *ret = alloc_ccs(src->nrows,src->ncols,src->nzmax,id);
+  if (!ret) return (ccs *)PyErr_NoMemory();
+  
+  convert_array(ret->values, src->values, id, src->id, src->nzmax);
+  memcpy(ret->rowind, src->rowind, src->nzmax*sizeof(int_t));
+  memcpy(ret->colptr, src->colptr, (src->ncols+1)*sizeof(int_t));
+  return ret;
+}
+
+spmatrix *SpMatrix_NewFromMatrix(matrix *src, int id)
+{
+  spmatrix *A;
+  int nnz = 0, i, j;
+
+  if (id < MAT_ID(src)) PY_ERR_TYPE("illegal type conversion");
+  
+  for (j=0; j<MAT_NCOLS(src); j++) {
+    for (i=0; i<MAT_NROWS(src); i++) {
+
+      number *a = MAT_BUF(src) + (i+j*MAT_NROWS(src))*E_SIZE[MAT_ID(src)];
+      if (((MAT_ID(src) == INT) && (a->i != Zero[INT].i)) ||
+	  ((MAT_ID(src) == DOUBLE) && (a->d != Zero[DOUBLE].d)) ||
+	  ((MAT_ID(src) == COMPLEX) && (a->z != Zero[COMPLEX].z))) 
+	nnz++;
+    }
+  }
+
+  if (!(A = SpMatrix_New(MAT_NROWS(src), MAT_NCOLS(src), nnz, id)))
+    return (spmatrix *)PyErr_NoMemory();
+
+  int cnt = 0;
+  for (j=0; j<MAT_NCOLS(src); j++) {
+    for (i=0; i<MAT_NROWS(src); i++) {
+
+      number a;
+      convert_num[id](&a, src, 0, i+j*MAT_NROWS(src));
+      if (((id == INT) && (a.i != Zero[INT].i)) ||
+	  ((id == DOUBLE) && (a.d != Zero[DOUBLE].d)) ||
+	  ((id == COMPLEX) && (a.z != Zero[COMPLEX].z))) {
+	write_num[id](SP_VAL(A), cnt, &a, 0); 
+	SP_ROW(A)[cnt++] = i;
+	SP_COL(A)[j+1]++;
+      }
+    }
+  }
+
+  for (i=0; i<SP_NCOLS(A); i++)
+    SP_COL(A)[i+1] += SP_COL(A)[i];
+  
+  return A;
+}
+
+spmatrix * sparse_concat(PyObject *L, int id_arg)
+{
+  int m=0, n=0, mk=0, nk=0, i=0, j, id=0, nnz=0;
+  PyObject *col;
+  
+  int single_col = (PyList_GET_SIZE(L) > 0 && 
+      !PyList_Check(PyList_GET_ITEM(L, 0)));
+
+  for (j=0; j<(single_col ? 1 : PyList_GET_SIZE(L)); j++) {
+
+    col = (single_col ? L : PyList_GET_ITEM(L, j));
+    if (!PyList_Check(col))  
+      PY_ERR_TYPE("L must be a list of lists with matrices");
+    
+    mk = 0;
+    for (i=0; i<PyList_GET_SIZE(col); i++) {
+      PyObject *Lij = PyList_GET_ITEM(col, i);
+      if (!Matrix_Check(Lij) && !SpMatrix_Check(Lij) && !PY_NUMBER(Lij)) 
+	PY_ERR_TYPE("invalid type in list");
+
+      int blk_nrows, blk_ncols;
+      if (Matrix_Check(Lij) || SpMatrix_Check(Lij)) {
+	blk_nrows = X_NROWS(Lij); blk_ncols = X_NCOLS(Lij);
+	id = MAX(id, X_ID(Lij));
+      } else {
+	blk_nrows = 1; blk_ncols = 1;
+	id = MAX(id, get_id(Lij,1));
+      }
+
+      if (Matrix_Check(Lij)) {
+	
+	int ik, jk;
+	for (jk=0; jk<MAT_NCOLS(Lij); jk++) {
+	  for (ik=0; ik<MAT_NROWS(Lij); ik++) {
+	
+	    number *a = MAT_BUF(Lij) + 
+	      (ik+jk*MAT_NROWS(Lij))*E_SIZE[MAT_ID(Lij)];
+
+	    if (((MAT_ID(Lij) == INT) && (a->i != Zero[INT].i)) ||
+		((MAT_ID(Lij) == DOUBLE) && (a->d != Zero[DOUBLE].d)) ||
+		((MAT_ID(Lij) == COMPLEX) && (a->z != Zero[COMPLEX].z))) 
+	      nnz++;
+	  }
+	}
+      } else if (SpMatrix_Check(Lij)) {
+	int ik, jk;
+	for (jk=0; jk<SP_NCOLS(Lij); jk++) {
+	  
+	  for (ik=SP_COL(Lij)[jk]; ik<SP_COL(Lij)[jk+1]; ik++) {
+	    if (((SP_ID(Lij) == DOUBLE) && (SP_VALD(Lij)[ik] != 0.0)) ||
+		((SP_ID(Lij) == COMPLEX) && (SP_VALZ(Lij)[ik] != 0.0)))
+	      nnz++;
+	  }
+	}	
+      }
+      else nnz += 1;
+	
+      if (i==0) {
+	nk = blk_ncols; n += nk;
+	mk = blk_nrows; 
+      } else {
+	if (blk_ncols != nk) 
+	  PY_ERR_TYPE("incompatible dimensions of subblocks");
+	mk += blk_nrows;
+      }
+    }
+    if (j==0) 
+      m = mk;
+    else if (m != mk) PY_ERR_TYPE("incompatible dimensions of subblocks");   
+  }
+
+  if ((id_arg >= 0) && (id_arg < id))
+    PY_ERR_TYPE("illegal type conversion");
+
+  id = MAX(DOUBLE, MAX(id, id_arg));    
+  spmatrix *A = SpMatrix_New(m, n, nnz, id);
+  if (!A) return (spmatrix *)PyErr_NoMemory();
+  
+  int ik = 0, jk, cnt = 0;
+  nk = 0;
+  for (j=0; j<(single_col ? 1 : PyList_GET_SIZE(L)); j++) {
+    col = (single_col ? L : PyList_GET_ITEM(L, j));
+      
+    if (PyList_GET_SIZE(col) > 0) {
+	
+      int tmp = (PY_NUMBER(PyList_GET_ITEM(col, 0)) ? 1 :  
+	  X_NCOLS(PyList_GET_ITEM(col, 0)));
+
+      for (jk=0; jk<tmp; jk++) {
+	  
+	mk = 0;
+	int blk_nrows = 0, blk_ncols = 0;
+	for (i=0; i<PyList_GET_SIZE(col); i++) {
+	  
+	  PyObject *Lij = PyList_GET_ITEM(col, i);
+	  
+	  if (Matrix_Check(Lij) || SpMatrix_Check(Lij)) {
+	    blk_nrows = X_NROWS(Lij); blk_ncols = X_NCOLS(Lij);
+	  } else {
+	    blk_nrows = 1; blk_ncols = 1;
+	  }
+
+	  if (Matrix_Check(Lij)) {
+	    for (ik=0; ik<MAT_NROWS(Lij); ik++) {
+	      
+	      number a;
+	      convert_num[id](&a, Lij, 0, ik + jk*MAT_NROWS(Lij));
+
+	      if (((id == DOUBLE) && (a.d != Zero[DOUBLE].d)) ||
+		  ((id == COMPLEX) && (a.z != Zero[COMPLEX].z))) {
+
+		write_num[id](SP_VAL(A), cnt, &a, 0); 
+		SP_ROW(A)[cnt++] = mk + ik;
+		SP_COL(A)[nk+1]++;
+	      }
+	    }
+	  } else if SpMatrix_Check(Lij) { 
+	    
+	    int ik;
+	    for (ik=SP_COL(Lij)[jk]; ik<SP_COL(Lij)[jk+1]; ik++) {
+	      if ((SP_ID(Lij) == DOUBLE) && (SP_VALD(Lij)[ik] != 0.0)) {
+		if (id == DOUBLE) 
+		  SP_VALD(A)[cnt] = SP_VALD(Lij)[ik];
+		else
+		  SP_VALZ(A)[cnt] = SP_VALD(Lij)[ik];
+
+		SP_ROW(A)[cnt++] = mk + SP_ROW(Lij)[ik];
+		SP_COL(A)[nk+1]++;	
+		nnz++;
+	      } 
+	      else if ((SP_ID(Lij) == COMPLEX) && (SP_VALZ(Lij)[ik] != 0.0)) {
+
+		SP_VALZ(A)[cnt] = SP_VALD(Lij)[ik];
+		SP_ROW(A)[cnt++] = mk + SP_ROW(Lij)[ik];
+		SP_COL(A)[nk+1]++;	
+		nnz++;				
+	      }
+	    }
+	  } else {
+
+	    number a;
+	    convert_num[id](&a,	Lij, 1, 0);
+
+	    if (((id == DOUBLE) && (a.d != Zero[DOUBLE].d)) ||
+		((id == COMPLEX) && (a.z != Zero[COMPLEX].z))) {
+
+	      write_num[id](SP_VAL(A), cnt, &a, 0); 
+	      SP_ROW(A)[cnt++] = mk;
+	      SP_COL(A)[nk+1]++;
+	    } 
+	  }
+	  mk += blk_nrows;
+	}
+	nk++;
+      }
+    }
+  }
+
+  for (i=0; i<n; i++) 
+    SP_COL(A)[i+1] += SP_COL(A)[i];
+
+  return A;
+}
+
+
+static ccs * transpose(ccs *A, int conjugate) {
+
+  ccs *B = alloc_ccs(A->ncols, A->nrows, A->nzmax, A->id);
+  if (!B) return NULL;
+
+  int_t i, j, *buf = calloc(A->nrows,sizeof(int_t));
+  if (!buf) { free_ccs(B); return NULL; }
+  
+  /* Run through matrix and count number of elms in each row */
+  for (i=0; i<A->colptr[A->ncols]; i++) buf[ A->rowind[i] ]++;
+
+  /* generate new colptr */
+  for (i=0; i<B->ncols; i++)
+    B->colptr[i+1] = B->colptr[i] + buf[i];
+
+  /* fill in rowind and values */
+  for (i=0; i<A->nrows; i++) buf[i] = 0;        
+  for (i=0; i<A->ncols; i++) {
+    if (A->id == DOUBLE)
+      for (j=A->colptr[i]; j<A->colptr[i+1]; j++) {
+	B->rowind[ B->colptr[A->rowind[j]] + buf[A->rowind[j]] ] = i;
+	((double *)B->values)[B->colptr[A->rowind[j]] + buf[A->rowind[j]]++] = 
+	  ((double *)A->values)[j];
+      }
+    else 
+      for (j=A->colptr[i]; j<A->colptr[i+1]; j++) {
+	B->rowind[ B->colptr[A->rowind[j]] + buf[A->rowind[j]] ] = i;
+	((complex *)B->values)[B->colptr[A->rowind[j]]+buf[A->rowind[j]]++] = 
+	  (conjugate ? conj(((complex *)A->values)[j]) : 
+	      ((complex *)A->values)[j]);
+      }
+  }
+  free(buf);    
+  return B;
+}
+
+static int sort_ccs(ccs *A) {
+
+  ccs *t = transpose(A, 0);
+  if (!t) return -1;
+
+  ccs *t2 = transpose(t, 0);
+  if (!t2) {
+    free_ccs(t); return -1;
+  }
+
+  free(A->colptr); free(A->rowind); free(A->values);
+  A->colptr = t2->colptr; A->rowind = t2->rowind; A->values = t2->values;
+
+  free(t2);
+  free_ccs(t);
+
+  return 0;
+}
+
+/* 
+   Sparse accumulator (spa) - dense representation of a sparse vector
+*/
+typedef struct {
+  void *val;
+  char *nz;
+  int *idx;
+  int nnz, n, id;
+} spa;
+
+static spa * alloc_spa(int n, int id) {
+  
+  spa *s = malloc(sizeof(spa));
+  
+  if (s) {
+    s->val = malloc( E_SIZE[id]*n );
+    s->nz  = malloc( n*sizeof(char) );
+    s->idx = malloc( n*sizeof(int) );
+    s->nnz = 0;
+    s->n = n;
+    s->id = id;
+  }
+
+  if (!s || !s->val || !s->nz || !s->idx) {
+    free(s->val); free(s->nz); free(s->idx); free(s);
+    return NULL;
+  }
+
+  int i;
+  for (i=0; i<n; i++) s->nz[i] = 0;
+
+  return s;
+}
+
+static void free_spa(spa *s) {
+  if (s) {
+    free(s->val); free(s->nz); free(s->idx); free(s);
+  }
+}
+
+static void init_spa(spa *s, ccs *X, int col) {
+  int i;
+  for (i=0; i<s->nnz; i++) 
+    s->nz[s->idx[i]] = 0;
+  
+  s->nnz = 0;
+
+  if (X && X->id == DOUBLE) {
+    for (i=X->colptr[col]; i<X->colptr[col+1]; i++) {
+      s->nz[X->rowind[i]] = 1;
+      ((double *)s->val)[X->rowind[i]] = ((double *)X->values)[i];
+      s->idx[s->nnz++] = X->rowind[i];
+    }
+  } else if (X && X->id == COMPLEX) {
+    for (i=X->colptr[col]; i<X->colptr[col+1]; i++) {
+      s->nz[X->rowind[i]] = 1;
+      ((complex *)s->val)[X->rowind[i]] = ((complex *)X->values)[i];
+      s->idx[s->nnz++] = X->rowind[i];
+    }
+  }
+}
+
+static inline void 
+spa_daxpy_partial (double a, ccs *X, int col, spa *y) {
+  int i;
+
+  for (i=X->colptr[col]; i<X->colptr[col+1]; i++) {
+    if (y->nz[X->rowind[i]]) {
+      ((double *)y->val)[X->rowind[i]] += a*((double *)X->values)[i];
+    }	
+  }
+}
+
+static inline void 
+spa_zaxpy_partial (complex a, ccs *X, int col, spa *y) {
+  int i;
+
+  for (i=X->colptr[col]; i<X->colptr[col+1]; i++) {
+    if (y->nz[X->rowind[i]]) {
+      ((complex *)y->val)[X->rowind[i]] += a*((complex *)X->values)[i];
+    }	
+  }
+}
+
+static inline void spa_daxpy (double a, ccs *X, int col, spa *y) {
+  int i;
+
+  for (i=X->colptr[col]; i<X->colptr[col+1]; i++) {
+    if (y->nz[X->rowind[i]]) {
+      ((double *)y->val)[X->rowind[i]] += a*((double *)X->values)[i];
+    }
+    else {
+      ((double *)y->val)[X->rowind[i]] = a*((double *)X->values)[i];
+      y->nz[X->rowind[i]] = 1;
+      y->idx[y->nnz++] = X->rowind[i];
+    }
+  }
+} 
+
+static inline void spa_zaxpy (complex a, ccs *X, char conjx, int col, spa *y) 
+{
+  int i;
+
+  for (i=X->colptr[col]; i<X->colptr[col+1]; i++) {
+    if (y->nz[X->rowind[i]]) {
+      ((complex *)y->val)[X->rowind[i]] += 
+	a*CONJ(conjx,((complex *)X->values)[i]);
+    }
+    else {
+      ((complex *)y->val)[X->rowind[i]] = 
+	a*CONJ(conjx,((complex *)X->values)[i]);
+      y->nz[X->rowind[i]] = 1;
+      y->idx[y->nnz++] = X->rowind[i];
+    }
+  }
+} 
+
+static inline void 
+spa_daxpy_uplo (double a, ccs *X, int col, spa *y, int j, char uplo) {
+  int i;
+
+  for (i=X->colptr[col]; i<X->colptr[col+1]; i++) {
+    if ((uplo == 'U' && X->rowind[i] <= j) ||
+	(uplo == 'L' && X->rowind[i] >= j)) {
+      if (y->nz[X->rowind[i]]) {
+	((double *)y->val)[X->rowind[i]] += a*((double *)X->values)[i];
+      }
+      else {
+	((double *)y->val)[X->rowind[i]] = a*((double *)X->values)[i];
+	y->nz[X->rowind[i]] = 1;
+	y->idx[y->nnz++] = X->rowind[i];
+      }
+    }
+  }
+} 
+
+static inline void 
+spa_zaxpy_uplo (complex a, ccs *X, int col, spa *y, int j, char uplo) {
+  int i;
+
+  for (i=X->colptr[col]; i<X->colptr[col+1]; i++) {
+    if ((uplo == 'U' && X->rowind[i] <= j) ||
+	(uplo == 'L' && X->rowind[i] >= j)) {
+      if (y->nz[X->rowind[i]]) {
+	((complex *)y->val)[X->rowind[i]] += a*((complex *)X->values)[i];
+      }
+      else {
+	((complex *)y->val)[X->rowind[i]] = a*((complex *)X->values)[i];
+	y->nz[X->rowind[i]] = 1;
+	y->idx[y->nnz++] = X->rowind[i];
+      }
+    }
+  }
+} 
+
+static inline void spa_symb_axpy (ccs *X, int col, spa *y) {
+  int i;
+  for (i=X->colptr[col]; i<X->colptr[col+1]; i++) 
+    if (!y->nz[X->rowind[i]]) {
+      y->nz[X->rowind[i]] = 1;
+      y->idx[y->nnz++] = X->rowind[i];
+    }
+}
+
+static inline void 
+spa_symb_axpy_uplo (ccs *X, int col, spa *y, int j, char uplo) {
+  int i;
+  for (i=X->colptr[col]; i<X->colptr[col+1]; i++)
+    if ((uplo == 'U' && X->rowind[i] <= j) ||
+	(uplo == 'L' && X->rowind[i] >= j)) {
+         
+      if (!y->nz[X->rowind[i]]) {
+	y->nz[X->rowind[i]] = 1;
+	y->idx[y->nnz++] = X->rowind[i];
+      }
+    }
+}
+
+static inline double spa_ddot (ccs *X, int col, spa *y) {
+  int i;
+  double a = 0;
+  for (i=X->colptr[col]; i<X->colptr[col+1]; i++) 
+    if (y->nz[X->rowind[i]])
+      a += ((double *)X->values)[i]*((double *)y->val)[X->rowind[i]];
+
+  return a;
+}
+
+static inline 
+complex spa_zdot (ccs *X, int col, spa *y, char conjx, char conjy) {
+  int i;
+  complex a = 0;
+  for (i=X->colptr[col]; i<X->colptr[col+1]; i++) 
+    if (y->nz[X->rowind[i]])
+      a += CONJ(conjx, ((complex *)X->values)[i])*
+	CONJ(conjy,((complex *)y->val)[X->rowind[i]]);
+
+  return a;
+}
+
+static void spa2compressed(spa *s, ccs *A, int col) {
+  int i, k=0;
+
+  switch (A->id) {
+  case (DOUBLE):
+    for (i=A->colptr[col]; i<A->colptr[col+1]; i++) {
+      A->rowind[i] = s->idx[k];
+      ((double *)A->values)[i] = ((double *)s->val)[s->idx[k++]];
+    }
+    break;
+  case COMPLEX:
+    for (i=A->colptr[col]; i<A->colptr[col+1]; i++) {
+      A->rowind[i] = s->idx[k];
+      ((complex *)A->values)[i] = ((complex *)s->val)[s->idx[k++]];
+    }
+    break;
+  }   
+}
+
+static int sp_daxpy(number a, void *x, void *y, int sp_x, int sp_y, 
+    int partial, void **z)
+{   
+  int j, k;
+  if (sp_x && !sp_y) {
+
+    ccs *X = x;
+    double *Y = y;
+    
+    for (j=0; j<X->ncols; j++) {
+      for (k=X->colptr[j]; k<X->colptr[j+1]; k++) 	
+	Y[X->rowind[k] + j*X->nrows] += a.d*(((double *)X->values)[k]);	      
+    }
+  }
+  else if (sp_x && sp_y && partial) 
+  {
+    ccs *X = x, *Y = y;    
+    int kX = 0, jX = 0, nnzX = X->colptr[X->ncols], kY, jY;
+    
+    for (jY=0; jY<Y->ncols; jY++) {    
+      for (kY=Y->colptr[jY]; kY<Y->colptr[jY+1]; kY++) {
+	
+	while ((kX < nnzX) && ((jX<jY) || 
+		(jX==jY && X->rowind[kX] < Y->rowind[kY]))) {
+	  while (X->colptr[jX+1] == kX+1) jX++;
+	  kX++;
+	}
+	
+	if ((jX == jY) && (X->rowind[kX] == Y->rowind[kY]) )
+	  ((double *)Y->values)[kY] = a.d*((double *)X->values)[kX] +
+	    ((double *)Y->values)[kY];
+	else 
+	  ((double *)Y->values)[kY] = ((double *)Y->values)[kY];
+      }
+    }
+  } 
+  else if (sp_x && sp_y && !partial) {
+
+    ccs *X = x, *Y = y;    
+    int kX = 0, jX = 0, nnzX = X->colptr[X->ncols];
+    int kY = 0, jY = 0;
+    int nnzZ = 0;
+
+    while (nnzX && !(X->colptr[jX+1])) jX++;
+
+    for (jY=0; jY<Y->ncols; jY++) {    
+      for (kY=Y->colptr[jY]; kY<Y->colptr[jY+1]; kY++) {
+	
+	while ((kX < nnzX) && ((jX<jY) || 
+		(jX==jY && X->rowind[kX] < Y->rowind[kY]))) {
+	  while (X->colptr[jX+1] == kX+1) jX++;
+	  kX++; nnzZ++;
+	}
+
+	if (jX==jY && X->rowind[kX] == Y->rowind[kY]) {
+	  while (X->colptr[jX+1] == kX+1) jX++;
+	  kX++;
+	} 
+	nnzZ++;	
+      }
+    }
+
+    nnzZ += (nnzX - kX);    
+
+    ccs *Z;
+    if (!(Z = alloc_ccs(Y->nrows, Y->ncols, nnzZ, Y->id))) return -1;
+
+    kX = 0; jX = 0; kY = 0; jY = 0, nnzZ = 0;
+    while (nnzX && !(X->colptr[jX+1])) jX++;
+
+    for (jY=0; jY<Y->ncols; jY++) {    
+      for (kY=Y->colptr[jY]; kY<Y->colptr[jY+1]; kY++) {
+	
+	while ((kX < nnzX) && ((jX<jY) || 
+		(jX==jY && X->rowind[kX] < Y->rowind[kY]))) {
+	  Z->colptr[jX+1]++;
+	  Z->rowind[nnzZ] = X->rowind[kX];
+	  ((double *)Z->values)[nnzZ++] = a.d*((double *)X->values)[kX];
+
+	  while (X->colptr[jX+1] == kX+1) jX++;
+	  kX++;
+	}
+	
+	Z->colptr[jY+1]++;
+	Z->rowind[nnzZ] = Y->rowind[kY];
+	if (jX==jY && X->rowind[kX] == Y->rowind[kY]) {
+	  ((double *)Z->values)[nnzZ++] = a.d*((double *)X->values)[kX] +
+	    ((double *)Y->values)[kY];
+	  while (X->colptr[jX+1] == kX+1) jX++;
+	  kX++;
+	} 
+	else ((double *)Z->values)[nnzZ++] = ((double *)Y->values)[kY];		  
+      }
+    }
+    
+    while (kX < nnzX) {
+      Z->colptr[jX+1]++;
+      Z->rowind[nnzZ] = X->rowind[kX];
+      ((double *)Z->values)[nnzZ++] = a.d*((double *)X->values)[kX];
+      
+      while (X->colptr[jX+1] == kX+1) jX++;
+      kX++;      
+    }
+    
+    int i;
+    for (i=0; i<Z->ncols; i++) Z->colptr[i+1] += Z->colptr[i];
+    
+    *z = Z;
+  }    
+  else if (!sp_x && sp_y && partial)
+  { 
+    double *X = x;
+    ccs *Y = y;
+    int kY, jY;
+    
+    for (jY=0; jY<Y->ncols; jY++) {      
+      for (kY=Y->colptr[jY]; kY<Y->colptr[jY+1]; kY++) 
+	((double *)Y->values)[kY] += a.d*X[jY*Y->nrows + Y->rowind[kY]];      
+    }
+  }
+  else { // if (!p_x && !sp_y) {
+
+    double *X = x;
+    ccs *Y = y;
+
+    int mn = Y->nrows*Y->ncols; 
+    ccs *Z = alloc_ccs(Y->nrows, Y->ncols, mn, Y->id);
+    if (!Z) return -1;
+
+    memcpy(Z->values, X, sizeof(double)*mn); 
+    scal[Y->id](&mn, &a, Z->values, (int *)&One[INT]);
+
+    int j, k;
+    for (j=0; j<Y->ncols; j++) {
+
+      Z->colptr[j+1] = Z->colptr[j] + Y->nrows;
+
+      for (k=0; k<Y->nrows; k++) 
+	Z->rowind[j*Y->nrows+k] = k;
+
+      for (k=Y->colptr[j]; k<Y->colptr[j+1]; k++)
+	((double *)Z->values)[j*Y->nrows + Y->rowind[k]] += 
+	  ((double *)Y->values)[k];
+    }    
+    *z = Z;
+  }
+  return 0;
+}
+
+static int sp_zaxpy(number a, void *x, void *y, int sp_x, int sp_y, 
+    int partial, void **z)
+{   
+  int j, k;
+  if (sp_x && !sp_y) {
+
+    ccs *X = x;
+    complex *Y = y;
+    
+    for (j=0; j<X->ncols; j++) {
+      for (k=X->colptr[j]; k<X->colptr[j+1]; k++) 	
+	Y[X->rowind[k] + j*X->nrows] += a.z*(((complex *)X->values)[k]);      
+    }
+  }
+  else if (sp_x && sp_y && partial) 
+  {
+    ccs *X = x, *Y = y;    
+    int kX = 0, jX = 0, nnzX = X->colptr[X->ncols], kY, jY;
+    
+    for (jY=0; jY<Y->ncols; jY++) {    
+      for (kY=Y->colptr[jY]; kY<Y->colptr[jY+1]; kY++) {
+	
+	while ((kX < nnzX) && ((jX<jY) || 
+		(jX==jY && X->rowind[kX] < Y->rowind[kY]))) {
+	  while (X->colptr[jX+1] == kX+1) jX++;
+	  kX++;
+	}
+	
+	if ((jX == jY) && (X->rowind[kX] == Y->rowind[kY]) )
+	  ((complex *)Y->values)[kY] = a.z*((complex *)X->values)[kX] +
+	    ((complex *)Y->values)[kY];
+	else 
+	  ((complex *)Y->values)[kY] = ((complex *)Y->values)[kY];
+      }
+    }
+  } 
+  else if (sp_x && sp_y && !partial) {
+
+    ccs *X = x, *Y = y;    
+    int kX = 0, jX = 0, nnzX = X->colptr[X->ncols];
+    int kY = 0, jY = 0;
+    int nnzZ = 0;
+
+    while (nnzX && !(X->colptr[jX+1])) jX++;
+
+    for (jY=0; jY<Y->ncols; jY++) {    
+      for (kY=Y->colptr[jY]; kY<Y->colptr[jY+1]; kY++) {
+	
+	while ((kX < nnzX) && ((jX<jY) || 
+		(jX==jY && X->rowind[kX] < Y->rowind[kY]))) {
+	  while (X->colptr[jX+1] == kX+1) jX++;
+	  kX++; nnzZ++;
+	}
+
+	if (jX==jY && X->rowind[kX] == Y->rowind[kY]) {
+	  while (X->colptr[jX+1] == kX+1) jX++;
+	  kX++;
+	} 
+	nnzZ++;	
+      }
+    }
+
+    nnzZ += (nnzX - kX);    
+
+    ccs *Z;
+    if (!(Z = alloc_ccs(Y->nrows, Y->ncols, nnzZ, Y->id))) return -1;
+
+    kX = 0; jX = 0; kY = 0; jY = 0, nnzZ = 0;
+    while (nnzX && !(X->colptr[jX+1])) jX++;
+
+    for (jY=0; jY<Y->ncols; jY++) {    
+      for (kY=Y->colptr[jY]; kY<Y->colptr[jY+1]; kY++) {
+	
+	while ((kX < nnzX) && ((jX<jY) || 
+		(jX==jY && X->rowind[kX] < Y->rowind[kY]))) {
+	  Z->colptr[jX+1]++;
+	  Z->rowind[nnzZ] = X->rowind[kX];
+	  ((complex *)Z->values)[nnzZ++] = a.z*((complex *)X->values)[kX];
+
+	  while (X->colptr[jX+1] == kX+1) jX++;
+	  kX++;
+	}
+	
+	Z->colptr[jY+1]++;
+	Z->rowind[nnzZ] = Y->rowind[kY];
+	if (jX==jY && X->rowind[kX] == Y->rowind[kY]) {
+	  ((complex *)Z->values)[nnzZ++] = a.z*((complex *)X->values)[kX] +
+	    ((complex *)Y->values)[kY];
+	  while (X->colptr[jX+1] == kX+1) jX++;
+	  kX++;
+	} 
+	else ((complex *)Z->values)[nnzZ++] = ((complex *)Y->values)[kY];		  
+      }
+    }
+    
+    while (kX < nnzX) {
+      Z->colptr[jX+1]++;
+      Z->rowind[nnzZ] = X->rowind[kX];
+      ((complex *)Z->values)[nnzZ++] = a.z*((complex *)X->values)[kX];
+      
+      while (X->colptr[jX+1] == kX+1) jX++;
+      kX++;      
+    }
+    
+    int i;
+    for (i=0; i<Z->ncols; i++) Z->colptr[i+1] += Z->colptr[i];
+    
+    *z = Z;
+  }    
+  else if (!sp_x && sp_y && partial)
+  { 
+    complex *X = x;
+    ccs *Y = y;
+    int kY, jY;
+    
+    for (jY=0; jY<Y->ncols; jY++) {      
+      for (kY=Y->colptr[jY]; kY<Y->colptr[jY+1]; kY++) 
+	((complex *)Y->values)[kY] += a.z*X[jY*Y->nrows + Y->rowind[kY]];      
+    }
+  }
+  else { // if (!p_x && !sp_y) {
+
+    complex *X = x;
+    ccs *Y = y;
+
+    int mn = Y->nrows*Y->ncols; 
+    ccs *Z = alloc_ccs(Y->nrows, Y->ncols, mn, Y->id);
+    if (!Z) return -1;
+
+    memcpy(Z->values, X, sizeof(complex)*mn); 
+    scal[Y->id](&mn, &a, Z->values, (int *)&One[INT]);
+
+    int j, k;
+    for (j=0; j<Y->ncols; j++) {
+
+      Z->colptr[j+1] = Z->colptr[j] + Y->nrows;
+
+      for (k=0; k<Y->nrows; k++) 
+	Z->rowind[j*Y->nrows+k] = k;
+
+      for (k=Y->colptr[j]; k<Y->colptr[j+1]; k++)
+	((complex *)Z->values)[j*Y->nrows + Y->rowind[k]] += 
+	  ((complex *)Y->values)[k];
+    }    
+    *z = Z;
+  }
+  return 0;
+}
+
+static int sp_dgemv(char tA, int m, int n, number alpha, void *a, int oA, 
+    void *x, int ix, number beta, void *y, int iy)
+{
+  ccs *A = a;
+  double *X = x, *Y = y;
+
+  scal[A->id]((tA == 'N' ? &m : &n), &beta, Y, &iy);
+
+  if (!m) return 0;
+  int i, j, k, oi = oA % A->nrows, oj = oA / A->nrows;
+
+  if (tA == 'N') {
+    for (j=oj; j<n+oj; j++) {  
+      for (k=A->colptr[j]; k<A->colptr[j+1]; k++) 
+	if ((A->rowind[k] >= oi) && (A->rowind[k] < oi+m))
+	  Y[iy*(A->rowind[k]-oi + (iy > 0 ? 0 : 1 - m))] +=
+	    alpha.d*((double *)A->values)[k]*
+	    X[ix*(j-oj + (ix > 0 ? 0 : 1 - n))];      
+      
+    }
+  } else {   
+    for (i=oj; i<oj+n; i++) {
+      for (k=A->colptr[i]; k<A->colptr[i+1]; k++) {
+	if ((A->rowind[k] >= oi) && (A->rowind[k] < oi+m))
+	  Y[iy*(i-oj + (iy > 0 ? 0 : 1 - n))] += alpha.d*
+	    ((double *)A->values)[k]*
+	    X[ix*(A->rowind[k]-oi + (ix > 0 ? 0 : 1 - m))];	  
+      }
+    }    
+  }
+  return 0;
+}
+
+static int sp_zgemv(char tA, int m, int n, number alpha, void *a, int oA, 
+    void *x, int ix, number beta, void *y, int iy)
+{
+  ccs *A = a;
+  complex *X = x, *Y = y;
+
+  scal[A->id]((tA == 'N' ? &m : &n), &beta, Y, &iy);
+
+  if (!m) return 0;
+  int i, j, k, oi = oA % A->nrows, oj = oA / A->nrows;
+
+  if (tA == 'N') {
+    for (j=oj; j<n+oj; j++) {  
+      for (k=A->colptr[j]; k<A->colptr[j+1]; k++) 
+	if ((A->rowind[k] >= oi) && (A->rowind[k] < oi+m))
+	  Y[iy*(A->rowind[k]-oi + (iy > 0 ? 0 : 1 - m))] +=
+	    alpha.z*((complex *)A->values)[k]*
+	    X[ix*(j-oj + (ix > 0 ? 0 : 1 - n))];      
+    }
+  } else {   
+    for (i=oj; i<oj+n; i++) {
+      for (k=A->colptr[i]; k<A->colptr[i+1]; k++) {
+	if ((A->rowind[k] >= oi) && (A->rowind[k] < oi+m))
+	  Y[iy*(i-oj + (iy > 0 ? 0 : 1 - n))] += alpha.z*
+	    CONJ(tA, ((complex *)A->values)[k])*
+	    X[ix*(A->rowind[k]-oi + (ix > 0 ? 0 : 1 - m))];  
+      }
+    }    
+  }
+  return 0;
+}
+
+
+int sp_dsymv(char uplo, int n, number alpha, ccs *A, int oA, void *x, int ix,
+    number beta, void *y, int iy)
+{
+  double *X = x, *Y = y; 
+  scal[A->id](&n, &beta, y, &iy);
+
+  if (!n) return 0;
+  int i, j, k, oi = oA % A->nrows, oj = oA / A->nrows;
+  for (j=0; j<n; j++) {  
+    
+    for (k = A->colptr[j+oj]; k < A->colptr[j+oj+1]; k++) {
+      i = A->rowind[k] - oi; 
+
+      if ((i >= 0) && (i < n)) {
+	if ((uplo == 'U') && (i > j)) 
+	  break;
+	if ((uplo == 'U') && (i <= j)) {
+	  Y[iy*(i + (iy > 0 ? 0 : 1 - n))] += alpha.d*((double *)A->values)[k]*
+	    X[ix*(j + (ix > 0 ? 0 : 1-n))];
+	  if (i != j)
+	    Y[iy*(j + (iy > 0 ? 0 : 1-n))] += alpha.d*((double *)A->values)[k]*
+	      X[ix*(i + (ix > 0 ? 0 : 1-n))];
+	}
+	else if ((uplo == 'L') && (i >= j)) {
+	  Y[iy*(i + (iy > 0 ? 0 : 1-n))] += alpha.d*((double *)A->values)[k]*
+	    X[ix*(j + (ix > 0 ? 0 : 1-n))];
+	  if (i != j)
+	    Y[iy*(j + (iy > 0 ? 0 : 1-n))] += alpha.d*((double *)A->values)[k]*
+	      X[ix*(i + (ix > 0 ? 0 : 1-n))];
+	} 
+      }
+    }
+  }    
+  return 0;
+}
+
+int sp_zsymv(char uplo, int n, number alpha, ccs *A, int oA, void *x, int ix,
+    number beta, void *y, int iy)
+{
+  complex *X = x, *Y = y;
+  scal[A->id](&n, &beta, y, &iy);
+
+  if (!n) return 0;
+  int i, j, k, oi = oA % A->nrows, oj = oA / A->nrows;
+  for (j=0; j<n; j++) {  
+
+    for (k = A->colptr[j+oj]; k < A->colptr[j+oj+1]; k++) {
+      i = A->rowind[k] - oi; 
+
+      if ((i >= 0) && (i < n)) {      
+	if ((uplo == 'U') && (i > j)) 
+	  break;
+	if ((uplo == 'U') && (i <= j)) {
+	  Y[iy*(i + (iy > 0 ? 0 : 1-n))] += alpha.z*((complex *)A->values)[k]*
+	    X[ix*(j + (ix > 0 ? 0 : 1-n))];
+	  if (i != j)
+	    Y[iy*(j+(iy>0 ? 0 : 1-n))] += alpha.z*((complex *)A->values)[k]*
+	      X[ix*(i + (ix > 0 ? 0 : 1-n))];
+	}
+	else if ((uplo == 'L') && (i >= j)) {
+	  Y[iy*(i + (iy > 0 ? 0 : 1-n))] += alpha.z*((complex *)A->values)[k]*
+	    X[ix*(j + (ix > 0 ? 0 : 1-n))];
+	  if (i != j)
+	    Y[iy*(j+(iy > 0 ? 0 : 1-n))] += alpha.z*((complex *)A->values)[k]*
+	      X[ix*(i + (ix > 0 ? 0 : 1-n))];
+	}       
+      }
+    }
+  }    
+  return 0;
+}
+
+static int sp_dgemm(char tA, char tB, number alpha, void *a, void *b, 
+    number beta, void *c, int sp_a, int sp_b, int sp_c, int partial, void **z,
+    int m, int n, int k)
+{
+
+  if (sp_a && sp_b && sp_c && partial) {
+
+    ccs *A = (tA == 'T' ? a : transpose(a, 0));
+    ccs *B = (tB == 'N' ? b : transpose(b, 0));
+    ccs *C = c;
+    int j, l;
+
+    spa *s = alloc_spa(A->nrows, A->id);
+    if (!s) {
+      if (A != a) free_ccs(A);
+      return -1;
+    }
+
+    for (j=0; j<n; j++) {   
+      for (l=C->colptr[j]; l<C->colptr[j+1]; l++) {
+	init_spa(s, A, C->rowind[l]);
+	((double *)C->values)[l] = alpha.d*spa_ddot (B, j, s) +
+	  beta.d*((double *)C->values)[l];	  
+      }
+    }    
+    free_spa(s);
+    if (A != a) free_ccs(A);
+    if (B != b) free_ccs(B);
+  }
+
+  else if (sp_a && sp_b && sp_c && !partial) {
+
+    ccs *A = (tA == 'N' ? a : transpose(a, 0));
+    ccs *B = (tB == 'N' ? b : transpose(b, 0));
+    ccs *C = c;
+    int_t *colptr_new = calloc(C->ncols+1,sizeof(int_t));    
+
+    spa *s = alloc_spa(A->nrows, A->id);
+    if (!s || !colptr_new) {
+      free(colptr_new);
+      if (A != a) free_ccs(A);
+      if (B != b) free_ccs(B);
+      return -1;
+    }
+
+    int j, l;
+    for (j=0; j<n; j++) {
+      init_spa(s, NULL, 0);
+      if (beta.d != 0.0)
+      	spa_symb_axpy (C, j, s);
+      
+      for (l=B->colptr[j]; l<B->colptr[j+1]; l++) 
+	spa_symb_axpy (A, B->rowind[l], s);
+
+      colptr_new[j+1] = colptr_new[j] + s->nnz;
+    }   
+    
+    int nnz = colptr_new[n]; 
+    ccs *Z = alloc_ccs(m, n, MAX(nnz,C->nzmax), C->id);
+    if (!Z) {
+      if (A != a) free_ccs(A); 
+      if (B != b) free_ccs(B); 
+      free(colptr_new); free_spa(s);
+      return -1;
+    }
+    free(Z->colptr); Z->colptr = colptr_new;
+
+    for (j=0; j<n; j++) {
+      init_spa(s, NULL, 0);
+      if (beta.d != 0.0)
+      	spa_daxpy (beta.d, C, j, s);
+      
+      for (l=B->colptr[j]; l<B->colptr[j+1]; l++) 	
+	spa_daxpy (((double *)B->values)[l], A, B->rowind[l], s);
+
+      spa2compressed(s, Z, j);
+    }   
+    
+    free_spa(s);
+
+    if (A != a) free_ccs(A);
+    if (B != b) free_ccs(B);
+    
+    if (sort_ccs(Z)) {
+      free_ccs(Z); return -1;
+    }
+    *z = Z;
+  }
+  else if (sp_a && sp_b && !sp_c) {
+
+    ccs *A = (tA == 'N' ? a : transpose(a, 0));
+    ccs *B = (tB == 'N' ? b : transpose(b, 0));
+    double *C = c;
+
+    spa *s = alloc_spa(A->nrows, A->id);
+    if (!s) {
+      if (A != a) free_ccs(A);
+      if (B != b) free_ccs(B);
+      return -1;
+    }
+
+    int mn = m*n; 
+    scal[A->id](&mn, &beta, C, (int *)&One[DOUBLE]);
+
+    int j, l;    
+    for (j=0; j<n; j++) {
+      init_spa(s, NULL, 0);
+      
+      for (l=B->colptr[j]; l<B->colptr[j+1]; l++) 	
+	spa_daxpy (((double *)B->values)[l], A, B->rowind[l], s);
+
+      for (l=0; l<s->nnz; l++) 
+	C[j*A->nrows + s->idx[l]] += alpha.d*((double *)s->val)[s->idx[l]];
+    }   
+    free_spa(s);
+    
+    if (A != a) free_ccs(A);
+    if (B != b) free_ccs(B);
+  }
+
+  else if (!sp_a && sp_b && !sp_c) {
+   
+    double *A = a, *C = c;    
+    ccs *B = (tB == 'N' ? b : transpose(b, 0));
+
+    int j, l, mn_ = m*n;
+    scal[DOUBLE](&mn_, &beta, C, (int *)&One[DOUBLE]);
+ 
+    for (j=0; j<n; j++) {
+      for (l=B->colptr[j]; l<B->colptr[j+1]; l++) {	
+	double a_ = alpha.d*((double *)B->values)[l];	
+	axpy[DOUBLE](&m, &a_, A + (tA=='N' ? B->rowind[l]*m : B->rowind[l]), 
+	    (tA=='N' ? (int *)&One[INT] : &k), C + j*m, (int *)&One[INT]);
+      }
+    }    
+    if (B != b) free_ccs(B);
+  }
+
+  else if (sp_a && !sp_b && !sp_c) {
+
+    ccs *A = (tA == 'N' ? a : transpose(a, 0));
+    double *B = b, *C = c;    
+
+    int j, l, mn_ = m*n, ib = (tB == 'N' ? k : 1);
+    scal[DOUBLE](&mn_, &beta, C, (int *)&One[INT]);
+    
+    for (j=0; j<A->ncols; j++) {
+      for (l=A->colptr[j]; l<A->colptr[j+1]; l++) {
+
+	double a_ = alpha.d*((double *)A->values)[l];	
+	axpy[DOUBLE](&n, &a_, B + (tB == 'N' ? j : j*n), &ib, 
+	    C + A->rowind[l], &m);
+      }
+    }
+    if (A != a) free_ccs(A);
+  }
+  
+  else if (!sp_a && sp_b && sp_c && partial) {
+
+    double *A = a, val;
+    ccs *B = (tB == 'N' ? b : transpose(b, 0)), *C = c;
+    int j, l, o;
+
+    for (j=0; j<n; j++) {    
+      for (o=C->colptr[j]; o<C->colptr[j+1]; o++) {
+
+	val = 0;
+	for (l=B->colptr[j]; l < B->colptr[j+1]; l++)
+	  val += A[tA == 'N' ? C->rowind[o] + B->rowind[l]*m : 
+		   B->rowind[l] + C->rowind[o]*B->nrows]*
+	    ((double *)B->values)[l];
+	
+	((double *)C->values)[o] = alpha.d*val + 
+	  beta.d*((double *)C->values)[o];
+      }
+    }
+    if (B != b) free_ccs(B);
+  }
+  else if (!sp_a && sp_b && sp_c && !partial) {
+
+    double *A = a;
+    ccs *B = (tB == 'N' ? b : transpose(b,0)), *C = c;
+    int_t *colptr_new = calloc(C->ncols+1,sizeof(int_t));    
+    
+    if (!colptr_new) {
+      if (B != b) free_ccs(B);
+      free(colptr_new);
+      return -1;
+    }
+
+    int j, l;
+    for (j=0; j<n; j++) 
+      colptr_new[j+1] = colptr_new[j] + 
+	MAX(((B->colptr[j+1]-B->colptr[j])>0)*m, C->colptr[j+1]-C->colptr[j]);
+
+    int nnz = colptr_new[n]; 
+    ccs *Z = alloc_ccs(m, n, nnz, C->id);
+    if (!Z) {
+      if (B != b) free_ccs(B); 
+      free(colptr_new);
+      return -1;
+    }
+    free(Z->colptr); Z->colptr = colptr_new;
+    for (l=0; l<nnz; l++) ((double *)Z->values)[l] = 0;
+
+    for (j=0; j<C->ncols; j++) {
+      
+      if (B->colptr[j+1]-B->colptr[j])
+	for (l=0; l<m; l++)
+	  Z->rowind[Z->colptr[j]+l] = l;
+
+      for (k=B->colptr[j]; k<B->colptr[j+1]; k++) {
+	
+	double a_ = alpha.d*((double *)B->values)[k];
+	axpy[DOUBLE](&m, &a_, A + 
+	    (tA=='N' ? B->rowind[k]*m : B->rowind[k]), 
+	    (tA=='N' ? (int *)&One[INT] : &k), 
+	    (double *)Z->values + Z->colptr[j], (int *)&One[INT]);
+      }
+      
+      if (beta.d != 0.0) {
+	if (Z->colptr[j+1]-Z->colptr[j] == m) {
+	  for (l=C->colptr[j]; l<C->colptr[j+1]; l++) {
+	    ((double *)Z->values)[Z->colptr[j]+C->rowind[l]] +=
+	      beta.d*((double *)C->values)[l];
+	  }	
+	}
+	else {
+	  for (l=C->colptr[j]; l<C->colptr[j+1]; l++) {
+	    ((double *)Z->values)[Z->colptr[j]+l-C->colptr[j]] =
+	      beta.d*((double *)C->values)[l];
+	    Z->rowind[Z->colptr[j]+l-C->colptr[j]] = C->rowind[l];
+	  }
+	}
+      }
+    }       
+    if (B != b) free_ccs(B);
+    *z = Z;
+  }
+  else if (sp_a && !sp_b && sp_c && partial) {
+
+    ccs *A = (tA == 'N' ? transpose(a,0) : a), *C = c;
+    double *B = b, val;
+
+    int j, l, o;   
+    for (j=0; j<n; j++) {      
+      for (o=C->colptr[j]; o<C->colptr[j+1]; o++) {
+	
+	val = 0;
+	for (l=A->colptr[C->rowind[o]]; l < A->colptr[C->rowind[o]+1]; l++)
+	  val += ((double *)A->values)[l]*
+	    B[tB == 'N' ? j*A->nrows + A->rowind[l] : 
+		A->rowind[l]*C->ncols + j];
+	
+	((double *)C->values)[o] = alpha.d*val + 
+	  beta.d*((double *)C->values)[o];	
+      }
+    }
+    if (A != a) free_ccs(A);
+  }
+  else if (sp_a && !sp_b && sp_c && !partial) {
+
+    ccs *A = (tA == 'N' ? a : transpose(a,0)), *C = c;
+    double *B = b;
+    
+    spa *s = alloc_spa(A->nrows, A->id);
+    int_t *colptr_new = calloc(n+1,sizeof(int_t));    
+    if (!s || !colptr_new) {
+      free(s); free(colptr_new);
+      if (A != a) free_ccs(A);
+      return -1;
+    }
+        
+    int j, l;    
+    for (j=0; j<n; j++) {
+      init_spa(s, NULL, 0);
+      
+      for (l=0; l<A->ncols; l++) 
+	spa_symb_axpy(A, l, s);
+      
+      if (beta.d != 0.0) spa_symb_axpy(C, j, s);
+      colptr_new[j+1] = colptr_new[j] + s->nnz;
+    } 
+
+    int nnz = colptr_new[n]; 
+    ccs *Z = alloc_ccs(m, n, nnz, C->id);
+    if (!Z) {
+      if (A != a) free_ccs(A); 
+      free_spa(s); free(colptr_new);
+      return -1;
+    }
+    free(Z->colptr); Z->colptr = colptr_new;
+
+    for (j=0; j<n; j++) {
+      init_spa(s, NULL, 0);
+      
+      for (l=0; l<k; l++) {
+	spa_daxpy(alpha.d*B[tB == 'N' ? l + j*k : j + l*n], A, l, s);
+      }
+      
+      if (beta.d != 0.0) spa_daxpy(beta.d, C, j, s);
+      spa2compressed(s, Z, j);
+    }     
+    free_spa(s);
+    if (A != a) free_ccs(A);    
+    if (sort_ccs(Z)) {
+      free_ccs(Z); return -1;
+    }    
+    *z = Z;
+  }
+  else if (!sp_a && !sp_b && sp_c && partial) {
+    ccs *C = c;
+    double *A = a, *B = b, val;
+
+    int j, l, o;   
+    for (j=0; j<C->ncols; j++) {      
+      for (o=C->colptr[j]; o<C->colptr[j+1]; o++) {
+	
+	val = 0;
+	for (l=0; l<k; l++)
+	  val += A[tA == 'N' ? m*l + C->rowind[o] : l + C->rowind[o]*k]*
+	      B[tB == 'N' ? j*k + l : l*n + j];
+		
+	((double *)C->values)[o] = alpha.d*val + 
+	  beta.d*((double *)C->values)[o];	
+      }
+    }
+  }
+  else if (!sp_a && !sp_b && sp_c && !partial) {
+    
+    double *A = a, *B = b;
+    ccs *C = c;
+
+    ccs *Z = alloc_ccs(m, n, m*n, C->id);
+    if (!Z) return -1;
+
+    int j, l;
+    for (j=0; j<m*n; j++) ((double *)Z->values)[j] = 0.0;
+
+    int ldA = MAX(1, (tA == 'N' ? m : k));
+    int ldB = MAX(1, (tB == 'N' ? k : n));
+    int ldC = MAX(1, m);
+
+    gemm[DOUBLE](&tA, &tB, &m, &n, &k, &alpha, A, &ldA, 
+	B, &ldB, &Zero[DOUBLE], Z->values, &ldC);
+
+    for (j=0; j<n; j++) {
+      for (l=0; l<m; l++) 
+	Z->rowind[j*m + l] = l;	
+      
+      Z->colptr[j+1] = Z->colptr[j] + m;
+    }
+    
+    if (beta.d != 0.0) {
+      for (j=0; j<n; j++) {
+	for (l=C->colptr[j]; l<C->colptr[j+1]; l++) {
+	  ((double *)Z->values)[j*m + C->rowind[l]] += 
+	    beta.d*((double *)C->values)[l];
+	}
+      }
+    }
+    *z = Z;
+  }
+  return 0;
+}
+
+static int sp_zgemm(char tA, char tB, number alpha, void *a, void *b, 
+    number beta, void *c, int sp_a, int sp_b, int sp_c, int partial, void **z,
+    int m, int n, int k)
+{
+
+  if (sp_a && sp_b && sp_c && partial) {
+
+    ccs *A = (tA == 'N' ? transpose(a, 0) : a);
+    ccs *B = (tB == 'N' ? b : transpose(b, 0));
+    ccs *C = c;
+    int j, l;
+
+    spa *s = alloc_spa(A->nrows, A->id);
+    if (!s) {
+      if (A != a) free_ccs(A);
+      return -1;
+    }
+
+    for (j=0; j<n; j++) {   
+      for (l=C->colptr[j]; l<C->colptr[j+1]; l++) {
+	init_spa(s, A, C->rowind[l]);
+	((complex *)C->values)[l] = alpha.z*spa_zdot(B, j, s, tB, tA) +
+	  beta.z*((complex *)C->values)[l];	
+      }
+    }    
+    free_spa(s);
+    if (A != a) free_ccs(A);
+    if (B != b) free_ccs(B);
+  }
+
+  else if (sp_a && sp_b && sp_c && !partial) {
+
+    ccs *A = (tA == 'N' ? a : transpose(a, 0));
+    ccs *B = (tB == 'N' ? b : transpose(b, 0));
+    ccs *C = c;
+    int_t *colptr_new = calloc(C->ncols+1,sizeof(int_t));    
+
+    spa *s = alloc_spa(A->nrows, A->id);
+    if (!s || !colptr_new) {
+      free(colptr_new);
+      if (A != a) free_ccs(A);
+      if (B != b) free_ccs(B);
+      return -1;
+    }
+
+    int j, l;
+    for (j=0; j<n; j++) {
+      init_spa(s, NULL, 0);
+      if (beta.z != 0.0)
+      	spa_symb_axpy (C, j, s);
+      
+      for (l=B->colptr[j]; l<B->colptr[j+1]; l++) 
+	spa_symb_axpy (A, B->rowind[l], s);
+
+      colptr_new[j+1] = colptr_new[j] + s->nnz;
+    }   
+    
+    int nnz = colptr_new[n]; 
+    ccs *Z = alloc_ccs(m, n, nnz, A->id);
+    if (!Z) {
+      if (A != a) free_ccs(A); 
+      if (B != b) free_ccs(B); 
+      free(colptr_new); free_spa(s);
+      return -1;
+    }
+    free(Z->colptr); Z->colptr = colptr_new;
+
+    for (j=0; j<n; j++) {
+      init_spa(s, NULL, 0);
+      if (beta.z != 0.0)
+      	spa_zaxpy (beta.z, C, 'N', j, s);
+      
+      for (l=B->colptr[j]; l<B->colptr[j+1]; l++) 	
+	spa_zaxpy(CONJ(tB, ((complex *)B->values)[l]), A, tA, B->rowind[l], s);
+
+      spa2compressed(s, Z, j);
+    }   
+    
+    free_spa(s);
+
+    if (A != a) free_ccs(A);
+    if (B != b) free_ccs(B);
+    
+    if (sort_ccs(Z)) {
+      free_ccs(Z); return -1;
+    }
+    *z = Z;
+  }
+  else if (sp_a && sp_b && !sp_c) {
+
+    ccs *A = (tA == 'N' ? a : transpose(a, 0));
+    ccs *B = (tB == 'N' ? b : transpose(b, 0));
+    complex *C = c;
+
+    spa *s = alloc_spa(A->nrows, A->id);
+    if (!s) {
+      if (A != a) free_ccs(A);
+      if (B != b) free_ccs(B);
+      return -1;
+    }
+
+    int mn = m*n; 
+    scal[A->id](&mn, &beta, C, (int *)&One[COMPLEX]);
+
+    int j, l;    
+    for (j=0; j<n; j++) {
+      init_spa(s, NULL, 0);
+      
+      for (l=B->colptr[j]; l<B->colptr[j+1]; l++) 	
+	spa_zaxpy (CONJ(tB,((complex *)B->values)[l]), A, tA, B->rowind[l], s);
+
+      for (l=0; l<s->nnz; l++) 
+	C[j*A->nrows + s->idx[l]] += alpha.z*((complex *)s->val)[s->idx[l]];
+    }   
+    free_spa(s);
+    
+    if (A != a) free_ccs(A);
+    if (B != b) free_ccs(B);
+  }
+
+  else if (!sp_a && sp_b && !sp_c) {
+
+    complex *A = a, *C = c;    
+    ccs *B = (tB == 'N' ? b : transpose(b, 0));
+
+    int i, j, l, mn_ = m*n;
+    scal[COMPLEX](&mn_, &beta, C, (int *)&One[COMPLEX]);
+    
+    for (j=0; j<n; j++) {
+      for (l=B->colptr[j]; l<B->colptr[j+1]; l++) {
+	
+	for (i=0; i<m; i++)
+	  C[i+j*m] += alpha.z*CONJ(tA,A[tA=='N' ? i+B->rowind[l]*m : 
+		  B->rowind[l]+i*k])*
+	    CONJ(tB,((complex *)B->values)[l]);
+      }
+    }    
+    if (B != b) free_ccs(B);
+  }
+
+  else if (sp_a && !sp_b && !sp_c) {
+
+    ccs *A = (tA == 'N' ? a : transpose(a, 0));
+    complex *B = b, *C = c;    
+
+    int i, j, l, mn_ = m*n;
+    scal[COMPLEX](&mn_, &beta, C, (int *)&One[INT]);
+    
+    for (j=0; j<A->ncols; j++) {
+      for (l=A->colptr[j]; l<A->colptr[j+1]; l++) {
+	
+	for (i=0; i<n; i++)
+	  C[A->rowind[l]+i*m] += alpha.z*CONJ(tA,((complex *)A->values)[l])*
+	    CONJ(tB,B[tB=='N' ? j+i*k : i+j*n]);
+      }
+    }
+    if (A != a) free_ccs(A);
+  }
+  
+  else if (!sp_a && sp_b && sp_c && partial) {
+
+    complex *A = a, val;
+    ccs *B = (tB == 'N' ? b : transpose(b, 0)), *C = c;
+    int j, l, o;
+
+    for (j=0; j<n; j++) {    
+      for (o=C->colptr[j]; o<C->colptr[j+1]; o++) {
+
+	val = 0;
+	for (l=B->colptr[j]; l < B->colptr[j+1]; l++)
+	  val += CONJ(tA,A[tA == 'N' ? C->rowind[o] + B->rowind[l]*m : 
+		  B->rowind[l] + C->rowind[o]*B->nrows])*
+	    CONJ(tB,((complex *)B->values)[l]);
+	
+	((complex *)C->values)[o] = alpha.z*val + 
+	  beta.z*((complex *)C->values)[o];
+      }
+    }
+    if (B != b) free_ccs(B);
+  }
+  else if (!sp_a && sp_b && sp_c && !partial) {
+
+    complex *A = a;
+    ccs *B = (tB == 'N' ? b : transpose(b,0)), *C = c;
+    int_t *colptr_new = calloc(C->ncols+1,sizeof(int_t));    
+    
+    if (!colptr_new) {
+      if (B != b) free_ccs(B);
+      free(colptr_new);
+      return -1;
+    }
+
+    int i, j, l;
+    for (j=0; j<n; j++) 
+      colptr_new[j+1] = colptr_new[j] + 
+	MAX(((B->colptr[j+1]-B->colptr[j])>0)*m, C->colptr[j+1]-C->colptr[j]);
+
+    int nnz = colptr_new[n]; 
+    ccs *Z = alloc_ccs(m, n, nnz, C->id);
+    if (!Z) {
+      if (B != b) free_ccs(B); 
+      free(colptr_new);
+      return -1;
+    }
+    free(Z->colptr); Z->colptr = colptr_new;
+    for (l=0; l<nnz; l++) ((complex *)Z->values)[l] = 0;
+
+    for (j=0; j<C->ncols; j++) {
+      
+      if (B->colptr[j+1]-B->colptr[j])
+	for (l=0; l<m; l++)
+	  Z->rowind[Z->colptr[j]+l] = l;
+
+      for (l=B->colptr[j]; l<B->colptr[j+1]; l++) {
+	
+	for (i=0; i<m; i++) {
+	  ((complex*)Z->values)[Z->colptr[j]+i] += alpha.z*
+	    CONJ(tA,A[tA=='N' ? B->rowind[l]*m+i : B->rowind[l]+i*k])*
+	    CONJ(tB,((complex *)B->values)[l]);
+
+	}
+      }
+      
+      if (beta.z != 0.0) {
+	if (Z->colptr[j+1]-Z->colptr[j] == m) {
+	  for (l=C->colptr[j]; l<C->colptr[j+1]; l++) {
+	    ((complex *)Z->values)[Z->colptr[j]+C->rowind[l]] +=
+	      beta.z*((complex *)C->values)[l];
+	  }	
+	}
+	else {
+	  for (l=C->colptr[j]; l<C->colptr[j+1]; l++) {
+	    ((complex *)Z->values)[Z->colptr[j]+l-C->colptr[j]] =
+	      beta.z*((complex *)C->values)[l];
+	    Z->rowind[Z->colptr[j]+l-C->colptr[j]] = C->rowind[l];
+	  }
+	}
+      }
+    }       
+    if (B != b) free_ccs(B);
+    *z = Z;
+  }
+  else if (sp_a && !sp_b && sp_c && partial) {
+
+    ccs *A = (tA == 'N' ? transpose(a,0) : a), *C = c;
+    complex *B = b, val;
+
+    int j, l, o;   
+    for (j=0; j<n; j++) {      
+      for (o=C->colptr[j]; o<C->colptr[j+1]; o++) {
+	
+	val = 0;
+	for (l=A->colptr[C->rowind[o]]; l < A->colptr[C->rowind[o]+1]; l++)
+	  val += CONJ(tA, ((complex *)A->values)[l])*
+	    CONJ(tB, B[tB == 'N' ? j*A->nrows + A->rowind[l] : 
+		    A->rowind[l]*C->ncols + j]);
+	
+	((complex *)C->values)[o] = alpha.z*val + 
+	  beta.z*((complex *)C->values)[o];	
+      }
+    }
+    if (A != a) free_ccs(A);
+  }
+  else if (sp_a && !sp_b && sp_c && !partial) {
+
+    ccs *A = (tA == 'N' ? a : transpose(a,0)), *C = c;
+    complex *B = b;
+    
+    spa *s = alloc_spa(A->nrows, A->id);
+    int_t *colptr_new = calloc(n+1,sizeof(int_t));    
+    if (!s || !colptr_new) {
+      free(s); free(colptr_new);
+      if (A != a) free_ccs(A);
+      return -1;
+    }
+        
+    int j, l;    
+    for (j=0; j<n; j++) {
+      init_spa(s, NULL, 0);
+      
+      for (l=0; l<A->ncols; l++) 
+	spa_symb_axpy(A, l, s);
+      
+      if (beta.z != 0.0) spa_symb_axpy(C, j, s);
+      colptr_new[j+1] = colptr_new[j] + s->nnz;
+    } 
+
+    int nnz = colptr_new[n]; 
+    ccs *Z = alloc_ccs(m, n, nnz, C->id);
+    if (!Z) {
+      if (A != a) free_ccs(A); 
+      free_spa(s); free(colptr_new);
+      return -1;
+    }
+    free(Z->colptr); Z->colptr = colptr_new;
+
+    for (j=0; j<n; j++) {
+      init_spa(s, NULL, 0);
+      
+      for (l=0; l<k; l++) {
+	spa_zaxpy(alpha.z*CONJ(tB, B[tB == 'N' ? l + j*k : j + l*n]), 
+	    A, tA, l, s);
+      }
+      
+      if (beta.z != 0.0) spa_zaxpy(beta.z, C, 'N', j, s);
+      spa2compressed(s, Z, j);
+    }     
+    free_spa(s);
+    if (A != a) free_ccs(A);    
+    if (sort_ccs(Z)) {
+      free_ccs(Z); return -1;
+    }    
+    *z = Z;
+  }
+  else if (!sp_a && !sp_b && sp_c && partial) {
+    ccs *C = c;
+    complex *A = a, *B = b, val;
+
+    int j, l, o;   
+    for (j=0; j<C->ncols; j++) {      
+      for (o=C->colptr[j]; o<C->colptr[j+1]; o++) {
+	
+	val = 0;
+	for (l=0; l<k; l++)
+	  val += CONJ(tA, A[tA=='N' ? m*l+C->rowind[o] : l+C->rowind[o]*k])*
+	    CONJ(tB, B[tB == 'N' ? j*k + l : l*n + j]);
+		
+	((complex *)C->values)[o] = alpha.z*val + 
+	  beta.z*((complex *)C->values)[o];	
+      }
+    }
+  }
+  else if (!sp_a && !sp_b && sp_c && !partial) {
+    
+    complex *A = a, *B = b;
+    ccs *C = c;
+
+    ccs *Z = alloc_ccs(m, n, m*n, C->id);
+    if (!Z) return -1;
+
+    int j, l;
+    for (j=0; j<m*n; j++) ((complex *)Z->values)[j] = 0.0;
+
+    int ldA = MAX(1, (tA == 'N' ? m : k));
+    int ldB = MAX(1, (tB == 'N' ? k : n));
+    int ldC = MAX(1, m);
+
+    gemm[COMPLEX](&tA, &tB, &m, &n, &k, &alpha, A, &ldA, 
+	B, &ldB, &Zero[COMPLEX], Z->values, &ldC);
+
+    for (j=0; j<n; j++) {
+      for (l=0; l<m; l++) 
+	Z->rowind[j*m + l] = l;	
+      
+      Z->colptr[j+1] = Z->colptr[j] + m;
+    }
+    
+    if (beta.z != 0.0) {
+      for (j=0; j<n; j++) {
+	for (l=C->colptr[j]; l<C->colptr[j+1]; l++) {
+	  ((complex *)Z->values)[j*m + C->rowind[l]] += 
+	    beta.z*((complex *)C->values)[l];
+	}
+      }
+    }
+    *z = Z;
+  }
+  return 0;
+}
+
+static int sp_dsyrk(char uplo, char trans, number alpha, void *a, 
+    number beta, void *c, int sp_a, int sp_c, int partial, int k, void **z)
+{
+  if (sp_a && sp_c && partial) {
+    
+    ccs *A = (trans == 'N' ?  transpose(a, 0) : a), *C = c;
+    spa *s = alloc_spa(A->nrows, C->id);
+    if (!A || !s) {
+      if (A != a) free_ccs(A);
+      free_spa(s);
+      return -1;
+    }
+    int j, k;
+    for (j=0; j<C->ncols; j++) {
+      for (k=C->colptr[j]; k<C->colptr[j+1]; k++) {
+	if ((uplo == 'L' && C->rowind[k] >= j) ||
+	    (uplo == 'U' && C->rowind[k] <= j)) {
+	  init_spa(s, A, C->rowind[k]);
+	  ((double *)C->values)[k] = alpha.d*spa_ddot(A, j, s) +
+	    beta.d*((double *)C->values)[k];
+	}
+      }
+    }
+    free_spa(s);
+    if (A != a) free_ccs(A);
+  }
+  else if (sp_a && sp_c && !partial) {
+
+    ccs *A = (trans == 'N' ? a : transpose(a, 0));
+    ccs *B = (trans == 'N' ? transpose(a, 0) : a);
+    ccs *C = c;
+    spa *s = alloc_spa(C->nrows, C->id);
+    int_t *colptr_new = calloc(C->ncols+1,sizeof(int_t));    
+
+    if (!A || !B || !s || !colptr_new) {
+      if (A != a) free_ccs(A);
+      if (B != a) free_ccs(B);
+      free_spa(s); free(colptr_new);
+      return -1;
+    }
+    
+    int j, k; 
+    for (j=0; j<B->ncols; j++) {
+      init_spa(s, NULL, 0);
+      if (beta.d != 0.0)
+	spa_symb_axpy_uplo(C, j, s, j, uplo);      
+      
+      for (k=B->colptr[j]; k<B->colptr[j+1]; k++) 
+	spa_symb_axpy_uplo(A, B->rowind[k], s, j, uplo);      
+      
+      colptr_new[j+1] = colptr_new[j] + s->nnz;      
+    }
+
+    int nnz = colptr_new[C->ncols];     
+    ccs *Z = alloc_ccs(C->nrows, C->ncols, nnz, C->id);
+    if (!Z) {
+      if (A != a) free_ccs(A);
+      if (B != a) free_ccs(B);
+      free_spa(s); free(colptr_new);
+      return -1;
+    }
+    free(Z->colptr); Z->colptr = colptr_new;
+    
+    for (j=0; j<B->ncols; j++) {
+      init_spa(s, NULL, 0); 
+      if (beta.d != 0.0) 
+	spa_daxpy_uplo(beta.d, C, j, s, j, uplo); 
+      
+      for (k=B->colptr[j]; k<B->colptr[j+1]; k++) {
+	spa_daxpy_uplo(alpha.d*((double *)B->values)[k], A, B->rowind[k], 
+	    s, j, uplo);      
+      }      
+      spa2compressed(s, Z, j);
+    }
+
+    if (A != a) free_ccs(A);
+    if (B != a) free_ccs(B);
+    free_spa(s);
+
+    if (sort_ccs(Z)) {
+      free_ccs(Z); return -1;
+    }
+    *z = Z;     
+  }
+  else if (sp_a && !sp_c) {
+
+    int n  = (trans == 'N' ? ((ccs *)a)->nrows : ((ccs *)a)->ncols);
+    ccs *A = (trans == 'N' ? a : transpose(a, 0));
+    ccs *B = (trans == 'N' ? transpose(a, 0) : a);
+    double *C = c;
+
+    spa *s = alloc_spa(n, A->id);
+    if (!A || !B || !s) {
+      if (A != a) free_ccs(A);
+      if (B != a) free_ccs(B);
+      free_spa(s); 
+      return -1;
+    }
+
+    int j, k; 
+    for (j=0; j<B->ncols; j++) {
+      init_spa(s, NULL, 0); 
+      
+      for (k=B->colptr[j]; k<B->colptr[j+1]; k++) {
+	spa_daxpy_uplo(alpha.d*((double *)B->values)[k], A, B->rowind[k], 
+	    s, j, uplo);      
+      }      
+
+      if (uplo == 'U') {
+	int m = j+1;
+	scal[DOUBLE](&m, &beta, C + j*n, (int *)&One[INT]);
+
+	for (k=0; k<s->nnz; k++) {
+	  if (s->idx[k] <= j) 
+	    C[j*n + s->idx[k]] += alpha.d*((double *)s->val)[s->idx[k]];
+	}
+      } else {
+	int m = n-j;
+	scal[DOUBLE](&m, &beta, C + j*(n+1), (int *)&One[INT]);
+	
+	for (k=0; k<s->nnz; k++) {
+	  if (s->idx[k] >= j) 
+	    C[j*n + s->idx[k]] += alpha.d*((double *)s->val)[s->idx[k]];
+	}
+      }
+    }
+    if (A != a) free_ccs(A);
+    if (B != a) free_ccs(B);
+    free_spa(s);
+  }
+  else if (!sp_a && sp_c && partial) {
+
+    ccs *C = c;
+    double *A = a;
+    
+    int j, i, l, n=C->nrows;
+    for (j=0; j<n; j++) {
+      for (i=C->colptr[j]; i<C->colptr[j+1]; i++) {
+	if ((uplo == 'L' && C->rowind[i] >= j) ||
+	    (uplo == 'U' && C->rowind[i] <= j)) {
+	  
+	  ((double *)C->values)[i] *= beta.d;
+
+	  for (l=0; l<k; l++) 
+	    ((double *)C->values)[i] += 
+	      alpha.d*A[trans == 'N' ? C->rowind[i]+l*n : l+C->rowind[i]*k]*
+	      A[trans == 'N' ? j+l*n : l+j*k];
+	}
+      }
+    }
+  }
+  else if (!sp_a && sp_c) {
+
+    ccs *C = c;
+    double *A = a, *C_ = malloc( C->nrows*C->nrows*sizeof(double) );
+    int_t *colptr_new = calloc(C->ncols+1,sizeof(int_t));    
+    
+    if (!C_ || !colptr_new) {
+      free(C_); free(colptr_new); return -1;
+    }
+    int j, i, n=C->nrows;
+    for (j=0; j<n; j++) 
+      colptr_new[j+1] = colptr_new[j] + (uplo == 'U' ? j+1 : n-j);
+
+    int nnz = colptr_new[n];     
+    ccs *Z = alloc_ccs(n, n, nnz, C->id);
+    if (!Z) {
+      free(C_); free(colptr_new);
+      return -1;
+    }
+    free(Z->colptr); Z->colptr = colptr_new;
+    
+    syrk[DOUBLE](&uplo, &trans, &n, &k, &alpha, A, 
+	(trans == 'N' ? &n : &k), &Zero[DOUBLE], C_, &n);
+
+    for (j=0; j<n; j++) {
+      for (i=Z->colptr[j]; i<Z->colptr[j+1]; i++) {
+	if (uplo == 'U') {
+	  ((double *)Z->values)[i] = C_[j*n + i-Z->colptr[j]];
+	  Z->rowind[i] = i-Z->colptr[j];
+	} else {
+	  ((double *)Z->values)[i] = C_[j*(n+1) + i-Z->colptr[j]];
+	  Z->rowind[i] = j+i-Z->colptr[j];
+	}
+      }
+      
+      for (i=C->colptr[j]; i<C->colptr[j+1]; i++) {
+	if (uplo == 'U' && C->rowind[i] <= j) 
+	  ((double *)Z->values)[Z->colptr[j]+C->rowind[i]] +=
+	    beta.d*((double *)C->values)[i];
+	else if (uplo == 'L' && C->rowind[i] >= j) 
+	  ((double *)Z->values)[Z->colptr[j]+C->rowind[i]-j] +=
+	    beta.d*((double *)C->values)[i];
+      }      
+    }
+    free(C_);
+    *z = Z;    
+  }
+
+  return 0;
+}
+
+/* No error checking: Il and Jl must be valid indexlist, 
+   and Il,Jl,V must be of same length (V can also be NULL) */
+static spmatrix * 
+triplet2dccs(matrix *Il, matrix *Jl, matrix *V,
+    int_t nrows, int_t ncols, int nzmax)     
+{    
+  spmatrix *ret = SpMatrix_New(nrows,ncols, MAX(MAT_LGT(Il),nzmax), DOUBLE);
+  double_list *dlist = malloc(MAT_LGT(Jl)*sizeof(double_list));
+  int_t *colcnt = calloc(ncols,sizeof(int_t));
+
+  if (!ret || !dlist || !colcnt) {
+    Py_XDECREF(ret); free(dlist); free(colcnt);
+    return (spmatrix *)PyErr_NoMemory();
+  }  
+
+  /* build colptr */
+  int_t i,j,k,l;
+  for (j=0; j<ncols+1; j++) SP_COL(ret)[j] = 0;  
+  for (j=0; j<MAT_LGT(Jl); j++) {
+    SP_COL(ret)[1+MAT_BUFI(Jl)[j]]++;
+    dlist[j].key = -1;
+  }
+
+  for (j=0; j<ncols; j++) SP_COL(ret)[j+1] += SP_COL(ret)[j];
+
+  /* build rowind and values */
+  for (k=0; k<MAT_LGT(Il); k++) {
+    i = MAT_BUFI(Il)[k], j = MAT_BUFI(Jl)[k];
+   
+    for (l=SP_COL(ret)[j]; l<SP_COL(ret)[j+1]; l++) 
+      if (dlist[l].key == i) {
+
+	number n;
+	if (V) { 
+	  convert_num[DOUBLE](&n, V, 0, k); 
+	  dlist[l].value += n.d; 
+	}
+
+	goto skip;
+      }
+    
+    if (V) 
+      convert_num[DOUBLE](&dlist[SP_COL(ret)[j]+colcnt[j]].value, V, 0, k);    
+      
+    dlist[SP_COL(ret)[j] + colcnt[j]++].key = i;
+
+  skip:
+    ;
+  }
+
+  for (j=0; j<ncols; j++) 
+    qsort(&dlist[SP_COL(ret)[j]],colcnt[j],sizeof(double_list),&comp_double);
+
+  int_t cnt = 0;
+  for (j=0; j<ncols; j++) {
+    for (i=0; i<colcnt[j]; i++) {
+      
+      SP_ROW(ret)[cnt] = dlist[i + SP_COL(ret)[j]].key;
+      SP_VALD(ret)[cnt++] = dlist[i + SP_COL(ret)[j]].value;
+      
+    }
+  }
+
+  for (j=0; j<ncols; j++) 
+    SP_COL(ret)[j+1] = colcnt[j] + SP_COL(ret)[j];
+  
+  free(dlist); free(colcnt);   
+  return ret;
+}
+
+static spmatrix * 
+triplet2zccs(matrix *Il, matrix *Jl, matrix *V,
+    int_t nrows, int_t ncols, int nzmax)     
+{    
+  spmatrix *ret = SpMatrix_New(nrows,ncols, MAX(MAT_LGT(Il),nzmax), COMPLEX);
+  complex_list *zlist = malloc(MAT_LGT(Jl)*sizeof(complex_list));
+  int_t *colcnt = calloc(ncols,sizeof(int_t));
+
+  if (!ret || !zlist || !colcnt) {
+    Py_XDECREF(ret); free(zlist); free(colcnt);
+    return (spmatrix *)PyErr_NoMemory();
+  }  
+
+  /* build colptr */
+  int_t i,j,k,l;
+  for (j=0; j<ncols+1; j++) SP_COL(ret)[j] = 0;  
+  for (j=0; j<MAT_LGT(Jl); j++) {
+    SP_COL(ret)[1+MAT_BUFI(Jl)[j]]++;
+    zlist[j].key = -1;
+  }
+
+  for (j=0; j<ncols; j++) SP_COL(ret)[j+1] += SP_COL(ret)[j];
+
+  /* build rowind and values */
+  for (k=0; k<MAT_LGT(Il); k++) {
+    i = MAT_BUFI(Il)[k], j = MAT_BUFI(Jl)[k];
+   
+    for (l=SP_COL(ret)[j]; l<SP_COL(ret)[j+1]; l++) 
+      if (zlist[l].key == i) {
+
+	number n;
+	if (V) { 
+	  convert_num[COMPLEX](&n, V, 0, k); 
+	  zlist[l].value += n.z; 
+	}
+
+	goto skip;
+      }
+    
+    if (V) 
+      convert_num[COMPLEX](&zlist[SP_COL(ret)[j]+colcnt[j]].value, V, 0, k);
+
+    zlist[SP_COL(ret)[j] + colcnt[j]++].key = i;
+
+  skip:
+    ;
+  }
+
+  for (j=0; j<ncols; j++) 
+    qsort(&zlist[SP_COL(ret)[j]],colcnt[j],sizeof(complex_list),&comp_complex);
+
+  int_t cnt = 0;
+  for (j=0; j<ncols; j++) {
+    for (i=0; i<colcnt[j]; i++) {
+      
+      SP_ROW(ret)[cnt] = zlist[i + SP_COL(ret)[j]].key;
+      SP_VALZ(ret)[cnt++] = zlist[i + SP_COL(ret)[j]].value;
+      
+    }
+  }
+
+  for (j=0; j<ncols; j++) 
+    SP_COL(ret)[j+1] = colcnt[j] + SP_COL(ret)[j];
+  
+  free(zlist); free(colcnt);   
+  return ret;
+}
+
+/*
+  SpMatrix_New. In API.
+
+  Returns an uninitialized spmatrix object.
+  
+  Arguments:  
+  mrows,nrows  : Dimension of spmatrix. 
+  nzmax        : Number of nonzero elements.
+  id           : DOUBLE/COMPLEX
+*/
+spmatrix *
+SpMatrix_New(int nrows, int ncols, int nzmax, int id) 
+{  
+  spmatrix *ret;  
+  if (!(ret = (spmatrix *)spmatrix_tp.tp_alloc(&spmatrix_tp, 0)))
+    return (spmatrix *)PyErr_NoMemory();
+
+  ret->obj = alloc_ccs(nrows, ncols, nzmax, id);
+  if (!ret->obj) { Py_DECREF(ret); return (spmatrix *)PyErr_NoMemory(); }
+    
+  return ret;  
+ }
+
+static spmatrix * SpMatrix_NewFromCCS(ccs *x) 
+{    
+  spmatrix *ret;  
+  if (!(ret = (spmatrix *)spmatrix_tp.tp_alloc(&spmatrix_tp, 0)))
+    return (spmatrix *)PyErr_NoMemory();
+
+  ret->obj = x;
+  return ret;  
+}
+
+/*
+  SpMatrix_NewFromSpMatrix. In API.
+  
+  Returns a copy of an spmatrix object.
+  
+  Arguments:  
+  A            : spmatrix object 
+  nzmax        : Number of nonzero elements. If nzmax is smaller than
+                 the actual size, it is ignored.
+  id           : DOUBLE/COMPLEX
+*/
+spmatrix * SpMatrix_NewFromSpMatrix(spmatrix *A, int nzmax, int id) 
+{  
+  if ((id == DOUBLE) && (SP_ID(A) == COMPLEX))
+    PY_ERR_TYPE("cannot convert complex to double");
+  
+  spmatrix *ret = SpMatrix_New
+    (SP_NROWS(A), SP_NCOLS(A), MAX(SP_NNZ(A),nzmax), id);
+  
+  if (!ret) return (spmatrix *)PyErr_NoMemory();
+  
+  convert_array(SP_VAL(ret), SP_VAL(A), id, SP_ID(A), SP_NNZ(A)); 
+  memcpy(SP_COL(ret), SP_COL(A), (SP_NCOLS(A)+1)*sizeof(int_t));
+  memcpy(SP_ROW(ret), SP_ROW(A), SP_NNZ(A)*sizeof(int_t));
+  
+  return ret;
+}
+
+/*
+  SpMatrix_NewFromIJV.
+
+  Returns a spmatrix object from a triplet description.
+  
+  Arguments:  
+  Il,Jl,V : (INT,INT,DOUBLE/COMPLEX) triplet description
+  m,n     : Dimension of spmatrix. If either m==0 or n==0, then
+            the dimension is taken as MAX(I) x MAX(Jl).
+  nzmax   : Number of nonzero elements. If nzmax is less than the nnz of 
+            the resulting matrix then nzmax is ignored.
+  id      : DOUBLE, COMPLEX
+*/
+spmatrix * SpMatrix_NewFromIJV(matrix *Il, matrix *Jl, matrix *V, 
+    int_t m, int_t n, int nzmax, int id)
+{   
+
+  if (MAT_ID(Il) != INT || MAT_ID(Jl) != INT)
+    PY_ERR_TYPE("index sets I and J must be integer");
+  
+  if (MAT_LGT(Il) != MAT_LGT(Jl))
+    PY_ERR_TYPE("index sets I and J must be of same length");
+
+  if (V && !Matrix_Check(V)) PY_ERR_TYPE("invalid V argument");
+
+  if (V && Matrix_Check(V) && (MAX(id,MAT_ID(V)) != id)) 
+    PY_ERR_TYPE("matrix V has invalid type");
+  
+  if (V && (MAT_LGT(V) != MAT_LGT(Il)))
+    PY_ERR_TYPE("I, J and V must have same length");
+  
+  if (!Il || !Jl) return SpMatrix_New(0,0,nzmax,id);
+
+  int_t k, Imax=-1, Jmax=-1;
+  for (k=0; k<MAT_LGT(Il); k++) {
+    if (MAT_BUFI(Il)[k]>Imax) Imax = MAT_BUFI(Il)[k];
+    if (MAT_BUFI(Jl)[k]>Jmax) Jmax = MAT_BUFI(Jl)[k];
+  }
+  
+  if ((m<0) || (n<0)) { m = MAX(Imax+1,m); n = MAX(Jmax+1,n);}
+  
+  if (m < Imax+1 || n < Jmax+1) PY_ERR_TYPE("dimension too small");
+
+  for (k=0; k<MAT_LGT(Il); k++) 
+    if ((MAT_BUFI(Il)[k] < 0) || (MAT_BUFI(Il)[k] >= m) || 
+	(MAT_BUFI(Jl)[k] < 0) || (MAT_BUFI(Jl)[k] >= n) ) 
+      PY_ERR_TYPE("index out of range");      
+  
+  return (id == DOUBLE ? triplet2dccs(Il,Jl,V,m,n,nzmax) : 
+      triplet2zccs(Il,Jl,V,m,n,nzmax));  
+}
+
+static void spmatrix_dealloc(spmatrix* self)
+{
+  free(SP_VAL(self));
+  free(SP_ROW(self));
+  free(SP_COL(self));
+  self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+spmatrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+  PyObject *size = NULL;
+  matrix *Il=NULL, *Jl=NULL, *V=NULL;
+  int_t nrows = -1, ncols = -1, nzmax = 0;
+  char tc = 0;
+
+  static char *kwlist[] = { "V", "I", "J", "size","tc","nzmax", NULL};
+  
+  if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO|Ocl:spmatrix", kwlist, 
+	  &V, &Il, &Jl, &size, &tc, &nzmax))
+    return NULL;
+  
+  if (!(PySequence_Check((PyObject *)V) || Matrix_Check(V) || PY_NUMBER(V))) {
+    PY_ERR_TYPE("V must be either a sequence type, a matrix, or a number");
+  }
+
+  if (size && !PyArg_ParseTuple(size, "ll", &nrows, &ncols)) 
+    PY_ERR_TYPE("invalid dimension tuple");
+  
+  if (size && (nrows < 0 || ncols < 0)) 
+    PY_ERR_TYPE("dimensions must be non-negative");
+
+  if (tc && !(VALID_TC_SP(tc))) PY_ERR_TYPE("tc must be 'd' or 'z'");  
+  int id = (tc ? TC2ID(tc) : -1);
+
+  if (nzmax < 0) PY_ERR_TYPE("nzmax must be non-negative");
+
+  int_t ndim = 0;
+  /* convert lists to matrices */
+  if (Matrix_Check(Il)) 
+    Py_INCREF(Il);
+  else if (PyObject_HasAttrString((PyObject *)Il,"__array_struct__")) {
+    if (!(Il = Matrix_NewFromArrayStruct((PyObject *)Il, INT, &ndim)))
+      return NULL;
+  }
+  else if (PySequence_Check((PyObject *)Il))     
+    Il = Matrix_NewFromSequence((PyObject *)Il, INT);
+  
+
+  if (Matrix_Check(Jl)) 
+    Py_INCREF(Jl);
+  else if (PyObject_HasAttrString((PyObject *)Jl,"__array_struct__")) {
+    if (!(Jl = Matrix_NewFromArrayStruct((PyObject *)Jl, INT, &ndim)))
+      return NULL;
+  }
+  else if (PySequence_Check((PyObject *)Jl))     
+    Jl = Matrix_NewFromSequence((PyObject *)Jl, INT);
+
+
+  if (Matrix_Check(V)) 
+    Py_INCREF(V);
+  else if (PyObject_HasAttrString((PyObject *)V,"__array_struct__")) {
+    int_t ndim = 0;
+    if (!(V = Matrix_NewFromArrayStruct((PyObject *)V, id, &ndim)))
+      return NULL;
+  }
+  else if (PySequence_Check((PyObject *)V)) 
+  {  
+    if (!(V = Matrix_NewFromSequence((PyObject *)V, id)))
+      return NULL;
+  }
+  else if (PY_NUMBER(V)) 
+  {
+    if (!(V = Matrix_NewFromNumber(MAT_LGT(Il), 1, get_id(V, 1), V, 1)))
+      return PyErr_NoMemory();
+  }
+
+  id = (id == -1 ? MAX(get_id(V, !Matrix_Check(V)), DOUBLE) : id);
+
+  spmatrix *ret = SpMatrix_NewFromIJV(Il, Jl, V, nrows, ncols, nzmax,
+      id == -1 ? MAX(MAT_ID(V),DOUBLE) : id);
+
+  if (Matrix_Check(Il)) { Py_DECREF(Il); }
+  if (Matrix_Check(Jl)) { Py_DECREF(Jl); }
+  if (Matrix_Check(V))  { Py_DECREF(V); }
+
+  return (PyObject *)ret;
+} 
+
+static PyObject *
+spmatrix_str(spmatrix *self)
+{    
+  char s[50] = "(%li, %li) %- ";
+  
+  /* these PyObject variables will all be borrowed references */
+  PyObject *printopt, *opt;
+  
+  if (!(printopt = PyObject_GetAttrString(base_mod, "print_options")) ||
+      !PyDict_Check(printopt)) {
+    PY_ERR(PyExc_AttributeError, "cannot access 'print_options' dictionary");
+  }
+  
+  if (!(opt = PyDict_GetItemString(printopt, PRINTOPT[SP_ID(self)]))) {
+    Py_DECREF(printopt);
+    PY_ERR(PyExc_KeyError, "missing print format key in 'base_options'");
+  }
+
+  char tmp[50], format_im[20] = "%";
+  if (SP_ID(self)==COMPLEX)
+    strncat(format_im, PyString_AsString(opt), 18);
+
+  strncat(s, PyString_AsString(opt), 37);
+
+  PyObject *ret = PyString_FromFormat("SIZE: (%ld,%ld)\n",
+      (long)SP_NROWS(self),(long)SP_NCOLS(self));
+
+  int_t j, k;
+  for (k=0; k<SP_NCOLS(self); k++)
+    for (j=SP_COL(self)[k]; j<SP_COL(self)[k+1]; j++) {
+
+      char t[100];
+      switch (SP_ID(self)) {
+      case DOUBLE: 
+	if (snprintf(t,100,s,SP_ROW(self)[j],k,SP_VALD(self)[j])<0) 
+	  goto fail;
+	break;
+      case COMPLEX:
+
+	if (snprintf(t,100,s,SP_ROW(self)[j],k,creal(SP_VALZ(self)[j]))<0)
+	  goto fail;
+	
+	if (strncat(t,(cimag(SP_VALZ(self)[j])>0 ? "+j" : "-j"),100)<0)
+	  goto fail;
+
+	if (snprintf(tmp,100,format_im,fabs(cimag(SP_VALZ(self)[j])))<0)
+	  goto fail;
+
+	if (strncat(t,tmp,100)<0)
+	  goto fail;
+	
+	break;
+      }   
+      
+      PyString_ConcatAndDel(&ret, PyString_FromFormat("%s\n",t));
+    }  
+    
+  Py_DECREF(printopt);
+  return ret;
+   
+ fail:
+  Py_DECREF(printopt); 
+  Py_DECREF(ret); return PyErr_NoMemory();
+
+} 
+
+static PyObject *
+spmatrix_repr(spmatrix *self) {
+  
+  PyObject *s = PyString_FromFormat("<%ldx%ld spmatrix, tc='%s', nnz=%ld>",
+      (long)SP_NROWS(self), (long)SP_NCOLS(self),
+      TC_CHAR[SP_ID(self)], (long)SP_NNZ(self));
+
+  return s;
+}
+
+
+static PyObject * spmatrix_get_size(spmatrix *self, void *closure)
+{
+  PyObject *t = PyTuple_New(2);
+  
+  PyTuple_SET_ITEM(t, 0, PyInt_FromLong(SP_NROWS(self)));
+  PyTuple_SET_ITEM(t, 1, PyInt_FromLong(SP_NCOLS(self)));
+  
+  return t;
+}
+
+static int spmatrix_set_size(spmatrix *self, PyObject *value, void *closure)
+{
+  if (!value) PY_ERR_INT(PyExc_TypeError,"size attribute cannot be deleted");
+
+  PY_ERR_INT(PyExc_TypeError, "sparse reshape not implemented");
+  return -1;
+}
+
+static PyObject * spmatrix_get_typecode(matrix *self, void *closure)
+{
+  return PyString_FromStringAndSize(TC_CHAR[SP_ID(self)], 1);
+}
+
+static PyObject *
+spmatrix_get_V(spmatrix *self, void *closure)
+{
+  matrix *ret = Matrix_New(SP_NNZ(self), 1, SP_ID(self));
+  if (!ret) return PyErr_NoMemory();
+
+  memcpy(MAT_BUF(ret), SP_VAL(self), SP_NNZ(self)*E_SIZE[SP_ID(self)]);
+  return (PyObject *)ret;
+}
+
+static int 
+spmatrix_set_V(spmatrix *self, PyObject *value, void *closure)
+{
+  if (!value) PY_ERR_INT(PyExc_AttributeError, "attribute cannot be deleted");
+  
+  if (PY_NUMBER(value)) {
+    number val;
+    if (convert_num[SP_ID(self)](&val, value, 1, 0))
+      PY_ERR_INT(PyExc_TypeError, "invalid type in assignment");
+    
+    int i;
+    for (i=0; i<SP_NNZ(self); i++) 
+      write_num[SP_ID(self)](SP_VAL(self),i,&val,0);
+
+    return 0;
+  }  
+  else if (Matrix_Check(value) && MAT_ID(value) == SP_ID(self) && 
+      MAT_LGT(value) == SP_NNZ(self) && MAT_NCOLS(value) == 1) {
+    
+    memcpy(SP_VAL(self), MAT_BUF(value), MAT_LGT(value)*E_SIZE[SP_ID(self)]);
+    return 0;
+  } else PY_ERR_INT(PyExc_TypeError, "invalid assignment for V attribute");
+}
+
+static PyObject *spmatrix_get_I(spmatrix *self, void *closure)
+{
+  matrix *A = Matrix_New( SP_NNZ(self), 1, INT);
+  if (!A) return PyErr_NoMemory();
+  
+  memcpy(MAT_BUF(A), SP_ROW(self), SP_NNZ(self)*sizeof(int_t));
+  return (PyObject *)A;
+}
+
+static PyObject * spmatrix_get_J(spmatrix *self, void *closure)
+{
+  matrix *A = Matrix_New( SP_NNZ(self), 1, INT);
+  if (!A) return PyErr_NoMemory();
+  
+  int_t k, j;
+  for (k=0; k<SP_NCOLS(self); k++)
+    for (j=SP_COL(self)[k]; j<SP_COL(self)[k+1]; j++)
+      MAT_BUFI(A)[j] = k;
+  
+  return (PyObject *)A;
+}
+
+static spmatrix * spmatrix_get_T(spmatrix *self, void *closure)
+{
+  return SpMatrix_NewFromCCS(transpose(((spmatrix *)self)->obj,0));
+}
+
+static spmatrix * spmatrix_get_H(spmatrix *self, void *closure)
+{
+  return SpMatrix_NewFromCCS(transpose(((spmatrix *)self)->obj,1));
+}
+
+
+static PyGetSetDef spmatrix_getsets[] = {
+  {"size", (getter) spmatrix_get_size, (setter) spmatrix_set_size, 
+   "matrix dimensions"}, 
+  {"typecode", (getter) spmatrix_get_typecode, NULL, "type character"},
+  {"V", (getter) spmatrix_get_V, (setter) spmatrix_set_V, 
+   "the value list of the matrix in triplet form"},
+  {"I", (getter) spmatrix_get_I, NULL, 
+   "the I (row) list of the matrix in triplet form"},
+  {"J", (getter) spmatrix_get_J, NULL, 
+   "the J (column) list of the matrix in triplet form"},
+  {"T", (getter) spmatrix_get_T, NULL, "transpose"},
+  {"H", (getter) spmatrix_get_H, NULL, "conjugate transpose"},
+  {NULL}  /* Sentinel */
+};
+
+static PyObject *
+spmatrix_getstate(spmatrix *self)
+{
+  PyObject *Il = spmatrix_get_I(self, NULL);
+  PyObject *Jl = spmatrix_get_J(self, NULL);
+  PyObject *V  = spmatrix_get_V(self, NULL);
+  PyObject *size = PyTuple_New(2);
+  if (!Il || !Jl || !V || !size) {
+    Py_XDECREF(Il); Py_XDECREF(Jl); Py_XDECREF(V); Py_XDECREF(size);
+    return NULL;
+  }
+  
+  PyTuple_SET_ITEM(size, 0, PyInt_FromLong(SP_NROWS(self)));
+  PyTuple_SET_ITEM(size, 1, PyInt_FromLong(SP_NCOLS(self)));
+
+  return Py_BuildValue("NNNNs", V, Il, Jl, size, TC_CHAR[SP_ID(self)]);
+
+  return NULL;
+}
+
+static PyObject * spmatrix_trans(spmatrix *self) {
+  
+  return (PyObject *)SpMatrix_NewFromCCS(transpose(((spmatrix *)self)->obj,0));
+
+}
+
+static PyObject * spmatrix_ctrans(spmatrix *self) {
+  
+  return (PyObject *)SpMatrix_NewFromCCS(transpose(((spmatrix *)self)->obj,1));
+
+}
+
+static PyObject * spmatrix_real(spmatrix *self) {
+
+  if (SP_ID(self) != COMPLEX) 
+    return (PyObject *)SpMatrix_NewFromSpMatrix(self, 0, SP_ID(self));
+  
+  spmatrix *ret = SpMatrix_New(SP_NROWS(self), SP_NCOLS(self), 
+      SP_NNZ(self), DOUBLE);
+  if (!ret) return PyErr_NoMemory();
+
+  int i;
+  for (i=0; i < SP_NNZ(self); i++) 
+    SP_VALD(ret)[i] = creal(SP_VALZ(self)[i]);
+  
+  memcpy(SP_COL(ret), SP_COL(self), (SP_NCOLS(self)+1)*sizeof(int_t));
+  memcpy(SP_ROW(ret), SP_ROW(self), SP_NNZ(self)*sizeof(int_t));
+  return (PyObject *)ret;
+}
+
+static PyObject * spmatrix_imag(spmatrix *self) {
+
+  if (SP_ID(self) != COMPLEX) 
+    return (PyObject *)SpMatrix_NewFromSpMatrix(self, 0, SP_ID(self));
+  
+  spmatrix *ret = SpMatrix_New(SP_NROWS(self), SP_NCOLS(self), 
+      SP_NNZ(self), DOUBLE);
+  if (!ret) return PyErr_NoMemory();
+
+  int i;
+  for (i=0; i < SP_NNZ(self); i++) 
+    SP_VALD(ret)[i] = cimag(SP_VALZ(self)[i]);
+  
+  memcpy(SP_COL(ret), SP_COL(self), (SP_NCOLS(self)+1)*sizeof(int_t));
+  memcpy(SP_ROW(ret), SP_ROW(self), SP_NNZ(self)*sizeof(int_t));
+  return (PyObject *)ret;
+}
+
+static PyObject *
+spmatrix_reduce(spmatrix* self)
+{
+  return Py_BuildValue("ON", self->ob_type, spmatrix_getstate(self));
+}
+
+static PyMethodDef spmatrix_methods[] = {
+  {"real", (PyCFunction)spmatrix_real, METH_NOARGS, 
+   "Returns real part of sparse matrix"},
+  {"imag", (PyCFunction)spmatrix_imag, METH_NOARGS, 
+   "Returns imaginary part of sparse matrix"},
+  {"trans", (PyCFunction)spmatrix_trans, METH_NOARGS, 
+   "Returns the matrix transpose"},
+  {"ctrans", (PyCFunction)spmatrix_ctrans, METH_NOARGS, 
+   "Returns the matrix conjugate transpose"},
+  {"__reduce__", (PyCFunction)spmatrix_reduce, METH_NOARGS,
+   "__reduce__() -> (cls, state)"},
+  {NULL}  /* Sentinel */
+};
+
+
+static int 
+bsearch_int(int_t *lower, int_t *upper, int_t key, int_t *k) {  
+
+  if (lower>upper) { *k = 0; return 0; }
+
+  int_t *mid, *start = lower;
+
+  while (upper - lower > 1) {
+    mid = lower+((upper-lower)>>1);
+    if (*mid > key) 
+      upper = mid;
+    else if (*mid < key)
+      lower = mid;
+    else {
+      *k = mid - start;
+      return 1;
+    }
+  }
+  
+  if (*upper == key) {
+    *k = upper - start; return 1;
+  }
+  else if (*lower == key) {
+    *k = lower - start; return 1;
+  } 
+  else {
+    if (*lower > key) 
+      *k = lower - start;
+    else if (*upper < key)
+      *k = upper - start + 1;
+    else 
+      *k = upper - start;
+    return 0;
+  }
+}
+
+int spmatrix_getitem_ij(spmatrix *A, int_t i, int_t j, number *value)
+{
+  int_t k;  
+  
+  if (SP_NNZ(A) && bsearch_int(&(SP_ROW(A)[SP_COL(A)[j]]),&
+	  (SP_ROW(A)[SP_COL(A)[j+1]-1]), i, &k)) {
+
+    write_num[SP_ID(A)](value, 0, SP_VAL(A), SP_COL(A)[j]+k);
+    return 1;
+
+  } else {
+
+    write_num[SP_ID(A)](value, 0, &Zero, 0);
+    return 0;
+  }
+}
+
+static void
+spmatrix_setitem_ij(spmatrix *A, int_t i, int_t j, number *value) {
+
+  int_t k,l;  
+  
+  if (bsearch_int(&(SP_ROW(A)[SP_COL(A)[j]]),
+	  &(SP_ROW(A)[SP_COL(A)[j+1]-1]),i, &k)) {
+
+    write_num[SP_ID(A)](SP_VAL(A), SP_COL(A)[j] + k, value, 0);
+    return;
+  }
+  k += SP_COL(A)[j];
+
+  for (l=j+1; l<SP_NCOLS(A)+1; l++) SP_COL(A)[l]++;
+    
+  /* split rowind and value lists at position 'k' and insert element */
+  for (l=SP_NNZ(A)-1; l>k; l--) {
+    SP_ROW(A)[l] = SP_ROW(A)[l-1]; 
+      write_num[SP_ID(A)](SP_VAL(A),l,SP_VAL(A),l-1);
+  }
+  
+  SP_ROW(A)[k] = i;   
+  write_num[SP_ID(A)](SP_VAL(A), k, value, 0);
+}
+
+static int
+spmatrix_length(spmatrix *self)
+{
+  return SP_NNZ(self);
+}
+
+static PyObject*
+spmatrix_subscr(spmatrix* self, PyObject* args)
+{
+  int_t i = 0, j = 0;
+  number val;
+  matrix *Il = NULL, *Jl = NULL;
+  
+  /* single integer */
+  if (PyInt_Check(args)) {
+    i = PyInt_AS_LONG(args);
+    if ( i<-SP_LGT(self) || i >= SP_LGT(self) ) 
+      PY_ERR(PyExc_IndexError, "index out of range");
+    
+    spmatrix_getitem_i(self, CWRAP(i,SP_LGT(self)), &val);
+    
+    return num2PyObject[SP_ID(self)](&val, 0);
+  }
+
+  else if (PyList_Check(args) || Matrix_Check(args) || PySlice_Check(args)) {
+    
+    if (!(Il = create_indexlist(SP_LGT(self), args))) return NULL;
+
+    int_t i, idx, lgt = MAT_LGT(Il), nnz = 0, k = 0;        
+    /* count # elements in index list */
+    for (i=0; i<lgt; i++) {
+      idx = MAT_BUFI(Il)[i];
+      if (idx < -SP_LGT(self) || idx >= SP_LGT(self)) {
+	Py_DECREF(Il);
+	PY_ERR(PyExc_IndexError, "index out of range");
+      }
+      nnz += spmatrix_getitem_i(self, CWRAP(idx,SP_LGT(self)), &val);
+    }
+
+    spmatrix *B = SpMatrix_New(lgt,1,nnz,SP_ID(self));
+    if (!B) { Py_DECREF(Il); return PyErr_NoMemory(); }
+    
+    SP_COL(B)[1] = nnz;
+    /* fill up rowind and values */
+    for (i=0; i<lgt; i++) {
+      idx = MAT_BUFI(Il)[i];
+      if (spmatrix_getitem_i(self, CWRAP(idx,SP_LGT(self)), &val)) {
+	SP_ROW(B)[k] = i; 
+	write_num[SP_ID(B)](SP_VAL(B), k++, &val, 0);
+      }	
+    }    
+    free_lists_exit(args,(PyObject *)NULL,Il,(PyObject *)NULL,(PyObject *)B);
+  }
+  
+  /* remainding cases are different two argument indexing */
+  PyObject *argI = NULL, *argJ = NULL;
+  if (!PyArg_ParseTuple(args, "OO", &argI, &argJ)) 
+    PY_ERR(PyExc_TypeError, "invalid index sets I or J");
+  
+  /* two integers, subscript form, handle separately */
+  if (PyInt_Check(argI) && PyInt_Check(argJ)) {
+    i = PyInt_AS_LONG(argI); j = PyInt_AS_LONG(argJ);
+    if ( OUT_RNG(i, SP_NROWS(self)) || OUT_RNG(j, SP_NCOLS(self)) )
+      PY_ERR(PyExc_IndexError, "index out of range");
+
+    spmatrix_getitem_ij(self,CWRAP(i,SP_NROWS(self)),
+	CWRAP(j,SP_NCOLS(self)), &val);
+
+    return num2PyObject[SP_ID(self)](&val,0);
+  }
+
+  if (!(Il = create_indexlist(SP_NROWS(self), argI)) ||
+      !(Jl = create_indexlist(SP_NCOLS(self), argJ))) {
+    PyErr_SetNone(PyExc_MemoryError);
+    free_lists_exit(argI, argJ, Il, Jl, NULL);
+  }
+
+  int lgt_row = MAT_LGT(Il), lgt_col = MAT_LGT(Jl), k, nnz = 0;
+  ccs *A = self->obj;
+  spa *s = alloc_spa(A->nrows, A->id);
+  if (!s) {
+    PyErr_SetString(PyExc_MemoryError, "insufficient memory");
+    free_lists_exit(argI, argJ, Il, Jl, NULL);
+  }
+
+  for (j=0; j<lgt_col; j++) {    
+    init_spa(s, A, CWRAP(MAT_BUFI(Jl)[j], SP_NCOLS(self)));
+
+    for (k=0; k<lgt_row; k++) 
+      nnz += s->nz[CWRAP(MAT_BUFI(Il)[k], SP_NROWS(self))];
+  }
+  spmatrix *B = SpMatrix_New(lgt_row, lgt_col,nnz,A->id);
+  if (!B) {
+    free_spa(s);
+    PyErr_SetNone(PyExc_MemoryError);
+    free_lists_exit(argI, argJ, Il, Jl, NULL);
+  }
+  
+  nnz = 0;
+  for (j=0; j<lgt_col; j++) {    
+    init_spa(s, A, CWRAP(MAT_BUFI(Jl)[j],SP_NCOLS(self)));
+
+    for (k=0; k<lgt_row; k++) {
+      if (s->nz[ CWRAP(MAT_BUFI(Il)[k], SP_NROWS(self))]) {
+	if (A->id == DOUBLE) 
+	  SP_VALD(B)[nnz]   = ((double *)s->val)
+	    [CWRAP(MAT_BUFI(Il)[k],SP_NROWS(self))];
+	else
+	  SP_VALZ(B)[nnz]   = ((complex *)s->val)
+	    [CWRAP(MAT_BUFI(Il)[k],SP_NROWS(self))];
+	SP_ROW(B) [nnz++] = k;
+	SP_COL(B)[j+1]++;
+      }
+    }
+    SP_COL(B)[j+1] += SP_COL(B)[j];
+  }
+  free_spa(s);  
+  free_lists_exit(argI, argJ, Il, Jl, (PyObject *)B);
+}
+
+
+static int
+spmatrix_ass_subscr(spmatrix* self, PyObject* args, PyObject* value)
+{
+  int_t i = 0, j = 0, id = SP_ID(self), decref_val = 0, arraystruct_nd = 0;
+  char itype;
+  number val, tempval;
+  matrix *Il = NULL, *Jl = NULL;
+
+  if (!value) PY_ERR_INT(PyExc_NotImplementedError, 
+      "cannot delete matrix entries");
+
+  if (!(PY_NUMBER(value) || Matrix_Check(value) || SpMatrix_Check(value))) {
+    if (PyObject_HasAttrString(value,"__array_struct__")) 
+      value = (PyObject *)Matrix_NewFromArrayStruct(value, -1, 
+	  &arraystruct_nd);
+    else 
+      value = (PyObject *)Matrix_NewFromSequence(value, SP_ID(self));
+
+    if (!value)
+      PY_ERR_INT(PyExc_NotImplementedError, "invalid type in assignment");    
+
+    decref_val = 1;
+  }
+  
+  int val_id = get_id(value, (PY_NUMBER(value) ? 1 : 0));
+  if (val_id > id) 
+    PY_ERR_INT(PyExc_TypeError, "invalid type in assignment");
+
+  /* assigment value is matrix or number ? */
+  if (PY_NUMBER(value)) {
+    if (convert_num[id](&val, value, 1, 0))
+      PY_ERR_INT(PyExc_TypeError, "invalid argument type");
+    itype = 'n';
+  } 
+  else if (Matrix_Check(value) && MAT_LGT(value)==1) { 
+    convert_num[id](&val, value, 0, 0);
+    itype = 'n';
+  }
+  else if (Matrix_Check(value)) 
+    itype = 'd';
+  else 
+    itype = 's';
+
+  /* single integer */
+  if (PyInt_Check(args)) {
+    if (itype != 'n') 
+      PY_ERR_INT(PyExc_IndexError, "incompatible sizes in assigment");
+
+    i = PyInt_AsLong(args);
+    if ( i<-SP_LGT(self) || i >= SP_LGT(self) ) 
+      PY_ERR_INT(PyExc_IndexError, "index out of range");
+
+    i = CWRAP(i,SP_LGT(self));
+
+    if (spmatrix_getitem_i(self, i, &tempval)) 
+      spmatrix_setitem_i(self, i, &val);
+    else {
+      if (SP_NNZ(self) == SP_NZMAX(self)) 
+	if (!realloc_ccs(self->obj, SP_NZMAX(self)+1)) 
+	  PY_ERR_INT(PyExc_MemoryError, "Cannot reallocate sparse matrix");
+      spmatrix_setitem_i(self, i, &val); 
+    }
+    return 0;
+  }
+
+  /* integer matrix list */
+  if (PyList_Check(args) || Matrix_Check(args) || PySlice_Check(args)) {    
+    
+    if (!(Il = create_indexlist(SP_LGT(self), args))) {
+      if (decref_val) { Py_DECREF(value); }
+      return -1;
+    }
+
+    int_t i, lgtI = MAT_LGT(Il);
+    int_t nnz = MAX(SP_NNZ(self)+MAT_LGT(Il),SP_NZMAX(self));    
+    
+    if (((itype == 'd') && 
+	    ((lgtI != MAT_LGT(value) || MAT_NCOLS(value) != 1))) ||
+	(((itype == 's') && 
+	    ((lgtI != SP_LGT(value)) || SP_NROWS(value) != 1)))) {
+      if (!Matrix_Check(args)) { Py_DECREF(Il); }
+      if (decref_val) { Py_DECREF(value); }
+      PY_ERR_INT(PyExc_TypeError, "incompatible sizes in assigment");
+    }
+    
+    /* ass. argument is dense matrix or number */
+    if  (itype == 'd' || itype == 'n') {
+
+      int_t *col_merge = calloc(SP_NCOLS(self)+1,sizeof(int_t));
+      int_t *row_merge = malloc(nnz*sizeof(int_t));
+      void *val_merge = malloc(nnz*E_SIZE[id]);
+      int_list *ilist = malloc(lgtI*sizeof(int_list));
+      if (!col_merge || !row_merge || !val_merge || !ilist) {
+	if (!Matrix_Check(args)) { Py_DECREF(Il); }
+	free(col_merge); free(row_merge); free(val_merge); free(ilist);
+	if (decref_val) { Py_DECREF(value); }
+	PY_ERR_INT(PyExc_MemoryError, "insufficient memory");
+      }
+      
+      for (i=0; i<lgtI; i++) {
+	ilist[i].key = CWRAP(MAT_BUFI(Il)[i],SP_NROWS(self)*SP_NCOLS(self));
+	ilist[i].value = i;
+      }
+      qsort(ilist, lgtI, sizeof(int_list), comp_int);      
+
+      /* merge lists */
+      int_t rhs_cnt = 0, tot_cnt = 0;
+      int_t rhs_j = ilist[rhs_cnt].key / SP_NROWS(self);
+      int_t rhs_i = ilist[rhs_cnt].key % SP_NROWS(self);
+      for (j=0; j<SP_NCOLS(self); j++) {
+	for (i=SP_COL(self)[j]; i<SP_COL(self)[j+1]; i++) {
+	  while (rhs_cnt<lgtI && rhs_j == j && rhs_i < SP_ROW(self)[i]) {
+	    if (rhs_cnt == 0 || (rhs_cnt>0 && 
+		    ilist[rhs_cnt].key != ilist[rhs_cnt-1].key)) {
+	      row_merge[tot_cnt] = rhs_i;
+	      if (itype == 'n')
+		write_num[id](val_merge, tot_cnt++, &val, 0);
+	      else
+		convert_num[id](val_merge + E_SIZE[id]*tot_cnt++, 
+		    value, 0, ilist[rhs_cnt].value);
+
+	      col_merge[j+1]++;
+	    }	    
+	    if (rhs_cnt++ < lgtI-1) {
+	      rhs_j = ilist[rhs_cnt].key / SP_NROWS(self); 
+	      rhs_i = ilist[rhs_cnt].key % SP_NROWS(self);
+	    }
+	  }
+	  if (rhs_cnt<lgtI && rhs_i == SP_ROW(self)[i] && rhs_j == j) {
+	    if (rhs_cnt == 0 || 
+		(rhs_cnt>0 && ilist[rhs_cnt].key != ilist[rhs_cnt-1].key)) {
+	      row_merge[tot_cnt] = rhs_i;
+	      if (itype == 'n')
+		write_num[id](val_merge, tot_cnt++, &val, 0);
+	      else
+		convert_num[id](val_merge + E_SIZE[id]*tot_cnt++, 
+		    value, 0, ilist[rhs_cnt].value);
+	      col_merge[j+1]++;
+	    }	    
+	    if (rhs_cnt++ < lgtI-1) {
+	      rhs_j = ilist[rhs_cnt].key / SP_NROWS(self); 
+	      rhs_i = ilist[rhs_cnt].key % SP_NROWS(self);
+	    }
+	  }
+	  else {
+	    row_merge[tot_cnt] = SP_ROW(self)[i];
+	    write_num[id](val_merge, tot_cnt++, SP_VAL(self), i);
+	    col_merge[j+1]++;
+	  }
+	}
+	while (rhs_cnt<lgtI && rhs_j == j) {	  
+	  if (rhs_cnt == 0 || 
+	      (rhs_cnt>0 && ilist[rhs_cnt].key != ilist[rhs_cnt-1].key)) {
+	    row_merge[tot_cnt] = rhs_i;
+	    if (itype == 'n')
+	      write_num[id](val_merge, tot_cnt++, &val, 0);
+	    else
+	      convert_num[id](val_merge + E_SIZE[id]*tot_cnt++, 
+		  value, 0, ilist[rhs_cnt].value);
+	    col_merge[j+1]++;
+	  }	    
+	  if (rhs_cnt++ < lgtI-1) {
+	    rhs_j = ilist[rhs_cnt].key / SP_NROWS(self); 
+	    rhs_i = ilist[rhs_cnt].key % SP_NROWS(self);
+	  }
+	}
+      }
+
+      for (i=0; i<SP_NCOLS(self); i++) 
+	col_merge[i+1] += col_merge[i];      
+
+      free(SP_COL(self)); SP_COL(self) = col_merge;
+      free(SP_ROW(self)); SP_ROW(self) = row_merge;
+      free(SP_VAL(self)); SP_VAL(self) = val_merge;      
+      free(ilist); 
+
+      int_t nzmax = MAX(SP_NNZ(self),SP_NZMAX(self));
+      if (nnz > nzmax) realloc_ccs(self->obj, nzmax);
+    }
+    /* ass. argument is a sparse matrix */
+    else 
+    {    
+      int_list *ilist = malloc(lgtI*sizeof(int_list));
+      int_t *col_merge = calloc(SP_NCOLS(self)+1,sizeof(int_t));
+      int_t *row_merge = malloc(nnz*sizeof(int_t));
+      void *val_merge = malloc(nnz*E_SIZE[id]);
+      if (!ilist || !col_merge || !row_merge || !val_merge) {
+	free(ilist); free(col_merge); free(row_merge); free(val_merge);
+	if (!Matrix_Check(args)) { Py_DECREF(Il); }
+	if (decref_val) { Py_DECREF(value); }
+	PY_ERR_INT(PyExc_MemoryError, "insufficient memory");
+      }      
+     
+      for (i=0; i<lgtI; i++) {
+	ilist[i].key = CWRAP(MAT_BUFI(Il)[i],SP_NROWS(self)*SP_NCOLS(self));
+	ilist[i].value = -1;
+      }
+
+      for (i=0; i<SP_NNZ(value); i++) 
+	ilist[SP_ROW(value)[i]].value = i;
+
+      qsort(ilist, lgtI, sizeof(int_list), comp_int);
+              
+      /* merge lists */
+      int_t rhs_cnt = 0, tot_cnt = 0;
+      int_t rhs_j = ilist[rhs_cnt].key / SP_NROWS(self);
+      int_t rhs_i = ilist[rhs_cnt].key % SP_NROWS(self);
+      for (j=0; j<SP_NCOLS(self); j++) {
+	for (i=SP_COL(self)[j]; i<SP_COL(self)[j+1]; i++) {
+
+	  while (rhs_cnt<lgtI && rhs_j == j && rhs_i < SP_ROW(self)[i]) {
+	    if (ilist[rhs_cnt].value >= 0 && 
+		(rhs_cnt==0 || (rhs_cnt>0 && ilist[rhs_cnt].key != 
+		    ilist[rhs_cnt-1].key))) {
+	      row_merge[tot_cnt] = rhs_i;
+	      convert_array(val_merge + E_SIZE[id]*tot_cnt++,  
+		  SP_VAL(value) + E_SIZE[val_id]*ilist[rhs_cnt].value, 
+		  id, val_id, 1);
+	      col_merge[j+1]++;
+	    }	    
+	    if (rhs_cnt++ < lgtI-1) {
+	      rhs_j = ilist[rhs_cnt].key / SP_NROWS(self); 
+	      rhs_i = ilist[rhs_cnt].key % SP_NROWS(self);
+	    }
+	  }
+
+	  if (rhs_cnt<lgtI && rhs_i == SP_ROW(self)[i] && rhs_j == j) {
+	    if (ilist[rhs_cnt].value >= 0 && (rhs_cnt==0 || 
+		    (rhs_cnt>0 && ilist[rhs_cnt].key != 
+			ilist[rhs_cnt-1].key))) {
+	      row_merge[tot_cnt] = rhs_i;
+	      convert_array(val_merge + E_SIZE[id]*tot_cnt++,  
+		  SP_VAL(value) + E_SIZE[val_id]*ilist[rhs_cnt].value, 
+		  id, val_id, 1);
+	      col_merge[j+1]++;
+	    }	    
+	    if (rhs_cnt++ < lgtI-1) {
+	      rhs_j = ilist[rhs_cnt].key / SP_NROWS(self); 
+	      rhs_i = ilist[rhs_cnt].key % SP_NROWS(self);
+	    }
+	  }
+	  else {
+	    row_merge[tot_cnt] = SP_ROW(self)[i];
+	    convert_array(val_merge + E_SIZE[id]*tot_cnt++,  
+		SP_VAL(self) + E_SIZE[id]*i, id, id, 1);
+	    col_merge[j+1]++;
+	  }
+	}
+	while (rhs_cnt<lgtI && rhs_j == j) {	  
+	  if (ilist[rhs_cnt].value >= 0 && (rhs_cnt==0 || (rhs_cnt>0 && 
+		      ilist[rhs_cnt].key != ilist[rhs_cnt-1].key))) {
+	    row_merge[tot_cnt] = rhs_i;
+	    convert_array(val_merge + E_SIZE[id]*tot_cnt++,  
+		SP_VAL(value) + E_SIZE[val_id]*ilist[rhs_cnt].value, 
+		id, val_id, 1);
+	    col_merge[j+1]++;
+	  }	    
+	  if (rhs_cnt++ < lgtI-1) {
+	    rhs_j = ilist[rhs_cnt].key / SP_NROWS(self); 
+	    rhs_i = ilist[rhs_cnt].key % SP_NROWS(self);
+	  }
+	}
+      }
+      
+      for (i=0; i<SP_NCOLS(self); i++) 
+	col_merge[i+1] += col_merge[i];      
+
+      free(SP_COL(self)); SP_COL(self) = col_merge;
+      free(SP_ROW(self)); SP_ROW(self) = row_merge;
+      free(SP_VAL(self)); SP_VAL(self) = val_merge;      
+      free(ilist); 
+
+      int_t nzmax = MAX(SP_NNZ(self),SP_NZMAX(self));
+      if (nnz > nzmax) realloc_ccs(self->obj, nzmax);
+    }
+    
+    if (!Matrix_Check(args)) { Py_DECREF(Il); }
+    if (decref_val) { Py_DECREF(value); }
+
+    SP_NZMAX(self) = MAX(SP_NNZ(self),SP_NZMAX(self));
+    return 0;
+  }
+
+  /* remainding cases are different two argument indexing */
+  PyObject *argI = NULL, *argJ = NULL;
+  if (!PyArg_ParseTuple(args, "OO", &argI, &argJ)) 
+    PY_ERR_INT(PyExc_TypeError, "invalid index arguments");
+
+  /* two integers, subscript form, handle separately */
+  if (PyInt_Check(argI) && PyInt_Check(argJ)) {
+
+    if (itype != 'n')
+      PY_ERR_INT(PyExc_TypeError, "argument has wrong size");
+    
+    i = PyInt_AS_LONG(argI); j = PyInt_AS_LONG(argJ);
+    if ( OUT_RNG(i, SP_NROWS(self)) || OUT_RNG(j, SP_NCOLS(self)) )
+      PY_ERR_INT(PyExc_IndexError, "index out of range");
+
+    i = CWRAP(i,SP_NROWS(self)); j = CWRAP(j,SP_NCOLS(self)); 
+    if (spmatrix_getitem_ij(self, i, j, &tempval))
+      spmatrix_setitem_ij(self, i, j, &val);
+    else {
+      if (SP_NNZ(self) == SP_NZMAX(self)) 
+	if (!realloc_ccs(self->obj, SP_NZMAX(self)+1)) 
+	  PY_ERR_INT(PyExc_MemoryError, "insufficient memory");
+      
+      spmatrix_setitem_ij(self, i, j, &val);
+    }
+    return 0;
+  }
+  
+  if (!(Il = create_indexlist(SP_NROWS(self), argI)) ||
+      !(Jl = create_indexlist(SP_NCOLS(self), argJ))) {
+    PyErr_SetNone(PyExc_MemoryError); 
+    free_lists_exit(argI,argJ,Il,Jl,-1);
+  }
+
+  if (decref_val && arraystruct_nd < 2 && 
+      MAT_LGT(value) == MAT_LGT(Il)*MAT_LGT(Jl)) {
+    MAT_NROWS(value) = MAT_LGT(Il); MAT_NCOLS(value) = MAT_LGT(Jl);
+  }
+
+  int_t lgtI = MAT_LGT(Il), lgtJ = MAT_LGT(Jl);
+  
+  if ((itype == 'd' && (lgtI != MAT_NROWS(value) ||
+	      lgtJ != MAT_NCOLS(value))) ||
+      (itype == 's' && (lgtI != SP_NROWS(value) ||
+	  lgtJ != SP_NCOLS(value)))) {
+    if (!Matrix_Check(argI)) { Py_DECREF(Il); }
+    if (!Matrix_Check(argJ)) { Py_DECREF(Jl); }
+    if (decref_val) { Py_DECREF(value); }
+    PY_ERR_INT(PyExc_TypeError, "incompatible size of assigment");
+  }
+
+  /* ass. argument is dense matrix or number */
+  if  ((itype == 'd' || itype == 'n') && lgtI*lgtJ> 0) {
+
+    int_t nnz = MAX(SP_NNZ(self)+lgtI*lgtJ,SP_NZMAX(self));    
+      
+    int_t *col_merge = calloc(SP_NCOLS(self)+1,sizeof(int_t));
+    int_t *row_merge = malloc(nnz*sizeof(int_t));
+    void *val_merge  = malloc(nnz*E_SIZE[id]);     
+    int_list *Is = malloc(lgtI*sizeof(int_list));
+    int_list *Js = malloc(lgtJ*sizeof(int_list));
+    if (!Is || !Js || !col_merge || !row_merge || !val_merge) {
+      if (!Matrix_Check(argI)) { Py_DECREF(Il); }
+      if (!Matrix_Check(argJ)) { Py_DECREF(Jl); }
+      free(Is); free(Js); 
+      free(col_merge); free(row_merge); free(val_merge);
+      if (decref_val) { Py_DECREF(value); }
+      PY_ERR_INT(PyExc_MemoryError, "insufficient memory");
+    }
+     
+    for (i=0; i<lgtI; i++) {
+      Is[i].key = CWRAP(MAT_BUFI(Il)[i],SP_NROWS(self));
+      Is[i].value = i;
+    }
+    qsort(Is, lgtI, sizeof(int_list), comp_int);
+
+    for (i=0; i<lgtJ; i++) {
+      Js[i].key = CWRAP(MAT_BUFI(Jl)[i],SP_NCOLS(self));
+      Js[i].value = i;
+    }
+    qsort(Js, lgtJ, sizeof(int_list), comp_int);
+
+    int_t rhs_cnti, rhs_cntj = 0, tot_cnt = 0;
+    int_t rhs_i, rhs_j = Js[0].key; 
+    for (j=0; j<SP_NCOLS(self); j++) {
+
+      if (rhs_j < j && rhs_cntj++ < lgtJ-1) {
+	rhs_j = Js[rhs_cntj].key;	
+      }
+
+      rhs_cnti = 0; rhs_i = Is[0].key;
+      for (i=SP_COL(self)[j]; i<SP_COL(self)[j+1]; i++) {
+	
+	while (rhs_cnti<lgtI && rhs_j == j && rhs_i < SP_ROW(self)[i]) {
+	  if (rhs_cnti == 0 || (rhs_cnti>0 && 
+		  Is[rhs_cnti].key != Is[rhs_cnti-1].key)) {
+	    row_merge[tot_cnt] = rhs_i;
+
+	    if (itype == 'n')
+	      write_num[id](val_merge, tot_cnt++, &val, 0);
+	    else
+	      convert_num[id](val_merge + E_SIZE[id]*tot_cnt++, 
+		  value, 0, Is[rhs_cnti].value + lgtI*Js[rhs_cntj].value);
+	    col_merge[j+1]++;
+	  }	    
+	  if (rhs_cnti++ < lgtI-1) 
+	    rhs_i = Is[rhs_cnti].key;	  
+	}
+	
+	if (rhs_cnti<lgtI && rhs_i == SP_ROW(self)[i] && rhs_j == j) {
+	  if (rhs_cnti == 0 || (rhs_cnti>0 && 
+		  Is[rhs_cnti].key != Is[rhs_cnti-1].key)) {
+	    row_merge[tot_cnt] = rhs_i;
+
+	    if (itype == 'n')
+	      write_num[id](val_merge, tot_cnt++, &val, 0);
+	    else
+	      convert_num[id](val_merge + E_SIZE[id]*tot_cnt++, 
+		  value, 0, Is[rhs_cnti].value + lgtI*Js[rhs_cntj].value);
+
+	    col_merge[j+1]++;
+	  }	    
+	  if (rhs_cnti++ < lgtI-1) 
+	    rhs_i = Is[rhs_cnti].key;	  
+	}
+	else {
+	  row_merge[tot_cnt] = SP_ROW(self)[i];
+	  convert_array(val_merge + E_SIZE[id]*tot_cnt++,  
+	      SP_VAL(self) + E_SIZE[id]*i, id, id, 1);
+	  col_merge[j+1]++;
+	}
+      }
+      while (rhs_cnti<lgtI && rhs_j == j) {	  
+	if (rhs_cnti == 0 || (rhs_cnti>0 && 
+		Is[rhs_cnti].key != Is[rhs_cnti-1].key)) {
+	  
+	  row_merge[tot_cnt] = rhs_i;
+
+	  if (itype == 'n')
+	    write_num[id](val_merge, tot_cnt++, &val, 0);
+	  else
+	    convert_num[id](val_merge + E_SIZE[id]*tot_cnt++, 
+		value, 0, Is[rhs_cnti].value + lgtI*Js[rhs_cntj].value);
+	  
+	  col_merge[j+1]++;
+	}	    
+	if (rhs_cnti++ < lgtI-1) 
+	  rhs_i = Is[rhs_cnti].key;	  
+      }
+    }
+    
+    for (i=0; i<SP_NCOLS(self); i++) 
+      col_merge[i+1] += col_merge[i];      
+
+    free(SP_COL(self)); SP_COL(self) = col_merge;
+    free(SP_ROW(self)); SP_ROW(self) = row_merge;
+    free(SP_VAL(self)); SP_VAL(self) = val_merge;      
+    free(Is); free(Js); 
+
+    int nzmax = MAX(SP_NNZ(self),SP_NZMAX(self));
+    if (nnz > nzmax) realloc_ccs(self->obj, nzmax);    
+
+  }
+  /* ass. argument is a sparse matrix */
+  else if (itype == 's' && lgtI*lgtJ > 0) {
+
+    int_t nnz = MAX(SP_NNZ(self)+SP_NNZ(value),SP_NZMAX(self));    
+    
+    int_t *col_merge = calloc((SP_NCOLS(self)+1),sizeof(int_t));
+    int_t *row_merge = malloc(nnz*sizeof(int_t));
+    void *val_merge  = malloc(nnz*E_SIZE[id]);
+    int_list *Is = malloc(lgtI*sizeof(int_list));
+    int_list *Js = malloc(lgtJ*sizeof(int_list));
+    if (!Is || !Js || !col_merge || !row_merge || !val_merge) {
+      if (!Matrix_Check(argI)) { Py_DECREF(Il); }
+      if (!Matrix_Check(argJ)) { Py_DECREF(Jl); }
+      free(Is); free(Js); 
+      free(col_merge); free(row_merge); free(val_merge);
+      if (decref_val) { Py_DECREF(value); }
+      PY_ERR_INT(PyExc_MemoryError,"insufficient memory");
+    }
+     
+    for (i=0; i<lgtJ; i++) {
+      Js[i].key = CWRAP(MAT_BUFI(Jl)[i],SP_NCOLS(self));
+      Js[i].value = i;
+    }
+    qsort(Js, lgtJ, sizeof(int_list), comp_int);
+
+    int_t rhs_cnti, rhs_cntj = -1, tot_cnt = 0, rhs_offs_rptr = 0;
+    int_t rhs_i, rhs_j = -1;     
+    for (j=0; j<SP_NCOLS(self); j++) {
+      if (rhs_j < j && rhs_cntj++ < lgtJ-1) {	
+	rhs_j = Js[rhs_cntj].key;
+	rhs_offs_rptr = SP_COL(value)[Js[rhs_cntj].value];
+
+	for (i=0; i<lgtI; i++) {
+	  Is[i].key = CWRAP(MAT_BUFI(Il)[i],SP_NROWS(self));
+	  Is[i].value = -1;
+	}
+
+	for (i=rhs_offs_rptr; i<SP_COL(value)[Js[rhs_cntj].value+1]; i++) 
+	  Is[SP_ROW(value)[i]].value = i-rhs_offs_rptr;
+	
+	qsort(Is, lgtI, sizeof(int_list), comp_int);
+
+      }
+      
+      rhs_cnti = 0; rhs_i = Is[0].key;
+      for (i=SP_COL(self)[j]; i<SP_COL(self)[j+1]; i++) {
+	
+	while (rhs_cnti<lgtI && rhs_j == j && rhs_i < SP_ROW(self)[i]) {
+	  if (Is[rhs_cnti].value >= 0 && (rhs_cnti==0 || 
+		  (rhs_cnti>0 && Is[rhs_cnti].key != Is[rhs_cnti-1].key))) {
+	    row_merge[tot_cnt] = rhs_i;
+
+	    convert_array(val_merge + E_SIZE[id]*tot_cnt++,  
+		SP_VAL(value) + E_SIZE[val_id]*
+		(Is[rhs_cnti].value+rhs_offs_rptr), id, val_id, 1);
+
+	    col_merge[j+1]++;
+	  }	    
+	  if (rhs_cnti++ < lgtI-1) 
+	    rhs_i = Is[rhs_cnti].key;	  
+	}
+	if (rhs_cnti<lgtI && rhs_i == SP_ROW(self)[i] && rhs_j == j) {
+	  if (Is[rhs_cnti].value >= 0 && (rhs_cnti==0 || 
+		  (rhs_cnti>0 && Is[rhs_cnti].key != Is[rhs_cnti-1].key))) {
+	    row_merge[tot_cnt] = rhs_i;
+
+	    convert_array(val_merge + E_SIZE[id]*tot_cnt++,  
+		SP_VAL(value) + E_SIZE[val_id]*
+		(Is[rhs_cnti].value+rhs_offs_rptr), id, val_id, 1);
+
+	    col_merge[j+1]++;
+	  }	    
+	  if (rhs_cnti++ < lgtI-1) 
+	    rhs_i = Is[rhs_cnti].key;	  
+	}
+	else {
+	  row_merge[tot_cnt] = SP_ROW(self)[i];
+	  convert_array(val_merge + E_SIZE[id]*tot_cnt++,  
+	      SP_VAL(self) + E_SIZE[id]*i, id, id, 1);
+	  col_merge[j+1]++;
+	}
+      }
+      while (rhs_cnti<lgtI && rhs_j == j) {	  
+	if (Is[rhs_cnti].value >= 0 && (rhs_cnti == 0 || (rhs_cnti>0 && 
+		    Is[rhs_cnti].key != Is[rhs_cnti-1].key))) {
+	  
+	  row_merge[tot_cnt] = rhs_i;
+
+	  convert_array(val_merge + E_SIZE[id]*tot_cnt++,  
+	      SP_VAL(value) + E_SIZE[val_id]*
+	      (Is[rhs_cnti].value+rhs_offs_rptr), id, val_id, 1);
+
+	  col_merge[j+1]++;
+	}	    
+	if (rhs_cnti++ < lgtI-1) 
+	  rhs_i = Is[rhs_cnti].key;	  
+      }    
+    }
+    
+    for (i=0; i<SP_NCOLS(self); i++) 
+      col_merge[i+1] += col_merge[i];      
+
+    free(SP_COL(self)); SP_COL(self) = col_merge;
+    free(SP_ROW(self)); SP_ROW(self) = row_merge;
+    free(SP_VAL(self)); SP_VAL(self) = val_merge;      
+    free(Is); free(Js); 
+
+    int_t nzmax = MAX(SP_NNZ(self),SP_NZMAX(self));
+    if (nnz > nzmax) realloc_ccs(self->obj, nzmax);    
+    
+  }
+  if (!Matrix_Check(argI)) { Py_DECREF(Il); }
+  if (!Matrix_Check(argJ)) { Py_DECREF(Jl); }
+  if (decref_val) { Py_DECREF(value); }
+  
+  SP_NZMAX(self) = MAX(SP_NNZ(self),SP_NZMAX(self));
+  return 0;
+  
+}
+
+static PyMappingMethods spmatrix_as_mapping = {
+  (lenfunc)spmatrix_length,
+  (binaryfunc)spmatrix_subscr,
+  (objobjargproc)spmatrix_ass_subscr
+};
+
+
+static PyObject * spmatrix_neg(spmatrix *self)
+{  
+  spmatrix *x = SpMatrix_NewFromSpMatrix(self,0,SP_ID(self));
+  if (!x) return PyErr_NoMemory();
+
+  int n=SP_NNZ(x);
+  scal[SP_ID(self)](&n, &MinusOne[SP_ID(self)], SP_VAL(x), (int *)&One[INT]);
+  
+  return (PyObject *)x;
+}
+
+static PyObject * spmatrix_pos(spmatrix *self)
+{  
+  spmatrix *x = SpMatrix_NewFromSpMatrix(self,0,SP_ID(self));
+  if (!x) return PyErr_NoMemory();
+  
+  return (PyObject *)x;
+}
+
+static PyObject * spmatrix_abs(spmatrix *self)
+{
+  spmatrix *x = SpMatrix_New(SP_NROWS(self), SP_NCOLS(self), 
+      SP_NNZ(self), DOUBLE);
+  if (!x) return PyErr_NoMemory();
+
+  int_t i;
+  
+  if (SP_ID(self) == DOUBLE)
+    for (i=0; i<SP_NNZ(self); i++) SP_VALD(x)[i] = fabs(SP_VALD(self)[i]);
+  else
+    for (i=0; i<SP_NNZ(self); i++) SP_VALD(x)[i] = cabs(SP_VALZ(self)[i]);
+
+  memcpy(SP_ROW(x), SP_ROW(self), SP_NNZ(self)*sizeof(int_t));
+  memcpy(SP_COL(x), SP_COL(self), (SP_NCOLS(self)+1)*sizeof(int_t));
+
+  return (PyObject *)x;
+}
+
+static PyObject * 
+spmatrix_add_helper(PyObject *self, PyObject *other, int add)
+{  
+  if (!SpMatrix_Check(self)  || 
+      !(Matrix_Check(other) || SpMatrix_Check(other)))
+  {
+    Py_INCREF(Py_NotImplemented);
+    return Py_NotImplemented;
+  }
+
+  if ((X_NROWS(self) != X_NROWS(other)) || (X_NCOLS(self) != X_NCOLS(other)))
+    PY_ERR_TYPE("incompatible dimensions");
+
+  int id = MAX(SP_ID(self),X_ID(other));    
+
+  ccs *x, *z = NULL;
+  void *y;
+
+  if (!(x = convert_ccs(((spmatrix *)self)->obj, id))) 
+    return NULL;
+
+  if (!(y = (Matrix_Check(other) ?
+	      (void *)Matrix_NewFromMatrix((matrix *)other, id) : 
+	      (void *)convert_ccs(((spmatrix *)other)->obj, id)))) {
+    if (x->id != id) free_ccs(x);
+    return NULL;
+  }
+      
+  if (sp_axpy[id]((add ? One[id] : MinusOne[id]), x,  
+	  (Matrix_Check(other) ? MAT_BUF(y) : y),  
+	  1, SpMatrix_Check(other), 0, (void *)&z)) 
+  {
+    if (x->id != id) free_ccs(x);
+    if (Matrix_Check(other)) 
+      Py_DECREF((PyObject *)y);
+    else
+      if (((ccs *)y)->id != id) free_ccs(y);
+    
+    return PyErr_NoMemory(); 
+  }
+  
+  if (x->id != id) free_ccs(x);
+  if (SpMatrix_Check(other)) {
+    if (((ccs *)y)->id != id) free_ccs(y);
+    spmatrix *ret = SpMatrix_New(SP_NROWS(other), SP_NCOLS(other), 0, id);
+    if (!ret) return PyErr_NoMemory();
+    ret->obj = z;
+    return (PyObject *)ret;
+  } 
+  else return (PyObject *)y;
+}
+
+static PyObject * 
+spmatrix_add(PyObject *self, PyObject *other) 
+{
+  if (!SpMatrix_Check(self) && SpMatrix_Check(other)) {
+    void *ptr = other; other = self; self = ptr;
+  }
+  
+  PyObject *ret, *tmp;
+  if (PY_NUMBER(other) || (Matrix_Check(other) && MAT_LGT(other)==1)) 
+    if ((tmp = (PyObject *)dense((spmatrix *)self))) {
+      ret = matrix_add(tmp, other);
+      Py_DECREF(tmp);
+      return ret;
+    } 
+    else return NULL;
+  
+  else return spmatrix_add_helper(self, other, 1);
+}
+
+
+static PyObject * 
+spmatrix_iadd(PyObject *self, PyObject *other)
+{  
+  if (!SpMatrix_Check(other))
+    PY_ERR_TYPE("invalid inplace operation");
+  
+  int id = SP_ID(self);
+  if (SP_ID(other) > id)
+    PY_ERR_TYPE("incompatible types for inplace operation");
+
+  if ((SP_NROWS(self) != SP_NROWS(other)) ||
+      (SP_NCOLS(self) != SP_NCOLS(other))) 
+    PY_ERR_TYPE("incompatible dimensions");
+
+  ccs *x = ((spmatrix *)self)->obj, *y;
+  void *z;
+  
+  if (!(y = convert_ccs(((spmatrix *)other)->obj, id))) 
+    return NULL;
+  
+  if (sp_axpy[id](One[id], x, y, 1, 1, 0, &z))
+  {
+    if (y->id != id) free_ccs(y);      
+    return PyErr_NoMemory(); 
+  }
+  
+  free_ccs(x); ((spmatrix *)self)->obj = z;
+  if (y->id != id) free_ccs(y);      
+
+  Py_INCREF(self);
+  return self;
+}
+
+
+static PyObject * 
+spmatrix_sub(PyObject *self, PyObject *other) 
+{
+  PyObject *ret, *tmp;
+  if (PY_NUMBER(self) || (Matrix_Check(self) && MAT_LGT(self)==1)) {
+    if ((tmp = (PyObject *)dense((spmatrix *)other))) {
+      ret = matrix_sub(self, tmp);
+      Py_DECREF(tmp);
+      return ret;
+    } 
+    else return NULL;
+  }     
+  else if (PY_NUMBER(other) || (Matrix_Check(other) && MAT_LGT(other)==1)) {
+    if ((tmp = (PyObject *)dense((spmatrix *)self))) {
+      ret = matrix_sub(tmp, other);
+      Py_DECREF(tmp);
+      return ret;
+    } 
+    else return NULL;
+  }
+  else if (!SpMatrix_Check(self) && SpMatrix_Check(other))
+  {
+    return spmatrix_add_helper(other, self, 0);
+  }
+  else if (SpMatrix_Check(self) && !SpMatrix_Check(other)) {
+    if ((ret = spmatrix_add_helper(self, other, 0))) {
+      int n = MAT_LGT(other), id = MAT_ID(ret); 
+      scal[id](&n, &MinusOne[id], MAT_BUF(ret), (int *)&One[INT]);
+      return ret;
+    }
+    else return NULL;    
+  }
+  else return spmatrix_add_helper(other, self, 0);
+}
+
+static PyObject * 
+spmatrix_isub(PyObject *self, PyObject *other)
+{  
+  if (!SpMatrix_Check(other))
+    PY_ERR_TYPE("invalid inplace operation");
+  
+  int id = SP_ID(self);
+  
+  if (SP_ID(other) > id)
+    PY_ERR_TYPE("incompatible types for inplace operation");
+
+  if ((SP_NROWS(self) != SP_NROWS(other)) ||
+      (SP_NCOLS(self) != SP_NCOLS(other)))
+    PY_ERR_TYPE("incompatible dimensions");
+  
+  ccs *x = ((spmatrix *)self)->obj, *y;
+  void *z;
+  
+  if (!(y = convert_ccs(((spmatrix *)other)->obj, id))) 
+    return NULL;
+  
+  if (sp_axpy[id](MinusOne[id], y, x, 1, 1, 0, &z))
+  {
+    if (y->id != id) free_ccs(y);      
+    return PyErr_NoMemory(); 
+  }
+  
+  free_ccs(x); ((spmatrix *)self)->obj = z;
+  if (y->id != id) free_ccs(y);      
+
+  Py_INCREF(self);
+  return self;
+}
+
+static PyObject * 
+spmatrix_mul(PyObject *self, PyObject *other) 
+{
+  if (!(SpMatrix_Check(self) || Matrix_Check(self) || PY_NUMBER(self)) || 
+      !(SpMatrix_Check(other) || Matrix_Check(other) || PY_NUMBER(other)))
+  {
+    Py_INCREF(Py_NotImplemented);
+    return Py_NotImplemented;
+  }
+  
+  int id = MAX(get_id(self, PY_NUMBER(self)),get_id(other, PY_NUMBER(other)));
+  if (PY_NUMBER(self) || (Matrix_Check(self) && MAT_LGT(self) == 1) || 
+      PY_NUMBER(other) || (Matrix_Check(other) && MAT_LGT(other) == 1)) {
+    
+    spmatrix *ret = SpMatrix_NewFromSpMatrix((spmatrix *)
+	(SpMatrix_Check(self) ? self : other), 0, id);
+
+    number val;
+    convert_num[id](&val, !SpMatrix_Check(self) ? self : other, 
+	PY_NUMBER(other) || PY_NUMBER(self), 0);
+
+    scal[id]((int *)&SP_NNZ(ret), &val, SP_VAL(ret), (void *)&One[INT]);
+    return (PyObject *)ret;
+  }
+
+  else {
+    if (X_NCOLS(self) != X_NROWS(other))
+      PY_ERR_TYPE("incompatible dimensions");
+    
+    void *x, *y, *z = NULL;
+    int sp_c = SpMatrix_Check(self) && SpMatrix_Check(other);
+    PyObject *C = (sp_c ? 
+	(PyObject *)SpMatrix_New(SP_NROWS(self), SP_NCOLS(other), 0, id) :
+	(PyObject *)Matrix_New(X_NROWS(self), X_NCOLS(other), id));
+
+    if (SpMatrix_Check(self)) 
+      x = convert_ccs(((spmatrix *)self)->obj, id);
+    else
+      x = convert_mtx_alloc((matrix *)self, id);
+    
+    if (SpMatrix_Check(other)) 
+      y = convert_ccs(((spmatrix *)other)->obj, id);
+    else
+      y = convert_mtx_alloc((matrix *)other, id);
+      
+    if (!C || !x || !y) {
+      PyErr_SetNone(PyExc_MemoryError);
+      Py_XDECREF(C);
+      C = NULL;
+      goto cleanup;
+    }
+    if (sp_gemm[id]('N', 'N', One[id], x, y, Zero[id], 
+	    sp_c ? ((spmatrix *)C)->obj : MAT_BUF(C), 
+	    SpMatrix_Check(self), SpMatrix_Check(other), sp_c, 0, &z,
+	    X_NROWS(self), X_NCOLS(other), X_NROWS(other)))
+    {
+      Py_DECREF(C); C = NULL;
+    }
+
+    if (z) { 
+      free_ccs( ((spmatrix *)C)->obj );
+      ((spmatrix *)C)->obj = z;
+    }    
+
+  cleanup:
+    if (SpMatrix_Check(self)) {
+      if (((ccs *)x)->id != id) free_ccs(x);
+    } 
+    else if (MAT_ID(self) != id) free(x);
+    
+    if (SpMatrix_Check(other)) {
+      if (((ccs *)y)->id != id) free_ccs(y);
+    } 
+    else if (MAT_ID(other) != id) free(y);	
+    
+    return (PyObject *)C;
+  }
+}
+
+static PyObject *
+spmatrix_imul(PyObject *self, PyObject *other)
+{
+  if (!(PY_NUMBER(other) || (Matrix_Check(other) && MAT_LGT(other) == 1))) 
+    PY_ERR_TYPE("invalid operands for sparse multiplication");
+
+  if (SP_ID(self) < get_id(other, PY_NUMBER(other))) 
+    PY_ERR_TYPE("invalid operands for inplace sparse multiplication");
+
+  number val;
+  convert_num[SP_ID(self)](&val, other, !Matrix_Check(other), 0);
+  scal[SP_ID(self)]((int *)&SP_NNZ(self), &val, SP_VAL(self), 
+      (void *)&One[INT]);
+
+  Py_INCREF(self);
+  return self;
+}
+
+static PyObject * 
+spmatrix_div_generic(spmatrix *A, PyObject *B, int inplace)
+{
+  if (!SpMatrix_Check(A) || !(PY_NUMBER(B) || 
+	  (Matrix_Check(B) && MAT_LGT(B)) == 1))  
+    PY_ERR_TYPE("invalid operands for sparse division");
+
+  int idA = get_id(A, 0);
+  int idB = get_id(B, (Matrix_Check(B) ? 0 : 1));
+  int id  = MAX(idA,idB);    
+
+  number n;
+  convert_num[id](&n, B, (Matrix_Check(B) ? 0 : 1), 0);
+
+  if (!inplace) {      
+    PyObject *ret = (PyObject *)SpMatrix_NewFromSpMatrix((spmatrix *)A, 0, id);
+    if (!ret) return NULL;
+
+    if (div_array[id](SP_VAL(ret), n, SP_NNZ(ret))) { 
+      Py_DECREF(ret); return NULL; 
+    }
+    return ret;
+  } else {
+    if (id != idA) PY_ERR_TYPE("invalid inplace operation");
+
+    if (div_array[id](SP_VAL(A), n, SP_NNZ(A)))  
+      return NULL; 
+
+    Py_INCREF(A);
+    return (PyObject *)A;
+  }
+} 
+
+static PyObject * spmatrix_div(PyObject *self,PyObject *other) {
+  return spmatrix_div_generic((spmatrix *)self, other, 0);
+}
+
+static PyObject * spmatrix_idiv(PyObject *self,PyObject *other) {
+  return spmatrix_div_generic((spmatrix *)self, other, 1);
+}
+
+
+static PyNumberMethods spmatrix_as_number = {
+        (binaryfunc)spmatrix_add, /*nb_add*/
+	(binaryfunc)spmatrix_sub, /*nb_subtract*/
+	(binaryfunc)spmatrix_mul, /*nb_multiply*/
+	(binaryfunc)spmatrix_div, /*nb_divide*/
+	0,                      /*nb_remainder*/
+	0,	                /*nb_divmod*/
+	0,	                /*nb_power*/
+	(unaryfunc)spmatrix_neg,/*nb_negative*/
+	(unaryfunc)spmatrix_pos,/*nb_positive*/
+	(unaryfunc)spmatrix_abs,/*nb_absolute*/
+	0,	                /*nb_nonzero*/
+	0,	                /*nb_invert*/
+	0,	                /*nb_lshift*/
+	0,	                /*nb_rshift*/
+	0,	                /*nb_and*/
+	0,	                /*nb_xor*/
+	0,	                /*nb_or*/
+	0,		        /*nb_coerce*/
+	0,	                /*nb_int*/
+	0,	                /*nb_long*/
+	0,	                /*nb_float*/
+	0,	                /*nb_oct*/
+	0, 	                /*nb_hex*/
+	(binaryfunc)spmatrix_iadd,/*nb_inplace_add*/
+	(binaryfunc)spmatrix_isub,/*nb_inplace_subtract*/
+	(binaryfunc)spmatrix_imul,/*nb_inplace_multiply*/
+	(binaryfunc)spmatrix_idiv,/*nb_inplace_divide*/
+	0,                      /*nb_inplace_remainder*/
+	0,			/*nb_inplace_power*/
+	0,			/*nb_inplace_lshift*/
+	0,			/*nb_inplace_rshift*/
+	0,			/*nb_inplace_and*/
+	0,			/*nb_inplace_xor*/
+	0,			/*nb_inplace_or*/
+	0,	                /* nb_floor_divide */
+	0,	                /* nb_true_divide */
+	0,			/* nb_inplace_floor_divide */
+	0,			/* nb_inplace_true_divide */
+};
+
+
+/*********************** Iterator **************************/
+
+typedef struct {
+  PyObject_HEAD
+  long index;
+  spmatrix *mObj;   /* Set to NULL when iterator is exhausted */
+} spmatrixiter;
+
+static PyTypeObject spmatrixiter_tp;
+
+#define SpMatrixIter_Check(O) PyObject_TypeCheck(O, &spmatrixiter_tp)
+
+static PyObject *
+spmatrix_iter(spmatrix *obj)
+{
+  spmatrixiter *it;
+  
+  if (!SpMatrix_Check(obj)) {
+    PyErr_BadInternalCall();
+    return NULL;
+  }
+
+  spmatrixiter_tp.tp_iter = PyObject_SelfIter;
+  spmatrixiter_tp.tp_getattro = PyObject_GenericGetAttr;
+
+  it = PyObject_GC_New(spmatrixiter, &spmatrixiter_tp);
+  if (it == NULL)
+    return NULL;
+ 
+  Py_INCREF(obj);
+  it->index = 0;
+  it->mObj = obj;
+  PyObject_GC_Track(it);
+
+  return (PyObject *)it;
+}
+
+static void
+spmatrixiter_dealloc(spmatrixiter *it)
+{
+  PyObject_GC_UnTrack(it);
+  Py_XDECREF(it->mObj);
+  PyObject_GC_Del(it);
+}
+
+static int
+spmatrixiter_traverse(spmatrixiter *it, visitproc visit, void *arg)
+{
+  if (it->mObj == NULL)
+    return 0;
+
+  return visit((PyObject *)(it->mObj), arg);
+}
+
+static PyObject *
+spmatrixiter_next(spmatrixiter *it)
+{
+  assert(SpMatrixIter_Check(it));
+  if (it->index >= SP_NNZ(it->mObj))
+    return NULL;
+  
+  return num2PyObject[SP_ID(it->mObj)](SP_VAL(it->mObj), it->index++);
+}
+
+static PyTypeObject spmatrixiter_tp = {
+        PyObject_HEAD_INIT(NULL)
+	0,					/* ob_size */
+	"spmatrixiter", 			/* tp_name */
+	sizeof(spmatrixiter),           	/* tp_basicsize */
+	0,					/* tp_itemsize */
+	(destructor)spmatrixiter_dealloc,	/* tp_dealloc */
+	0,					/* tp_print */
+	0,					/* tp_getattr */
+	0,					/* tp_setattr */
+	0,					/* tp_compare */
+	0,					/* tp_repr */
+	0,					/* tp_as_number */
+	0,					/* tp_as_sequence */
+	0,					/* tp_as_mapping */
+	0,					/* tp_hash */
+	0,					/* tp_call */
+	0,					/* tp_str */
+	0,       		                /* tp_getattro */
+	0, 		                        /* tp_setattro */
+	0,					/* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
+	0,					/* tp_doc */
+	(traverseproc)spmatrixiter_traverse,	/* tp_traverse */
+	0,					/* tp_clear */
+	0,					/* tp_richcompare */
+	0,					/* tp_weaklistoffset */
+	0,              			/* tp_iter */
+	(iternextfunc)spmatrixiter_next,	/* tp_iternext */
+	0,					/* tp_methods */
+};
+
+
+PyTypeObject spmatrix_tp = {
+	PyObject_HEAD_INIT(NULL)
+	0,
+	"cvxopt.base.spmatrix",
+	sizeof(spmatrix),
+	0,
+	(destructor)spmatrix_dealloc,	        /* tp_dealloc */
+	0,	               	                /* tp_print */
+	0,					/* tp_getattr */
+	0,					/* tp_setattr */
+	0,					/* tp_compare */
+	(reprfunc)spmatrix_repr,                /* tp_repr */
+	&spmatrix_as_number,			/* tp_as_number */
+	0,	                                /* tp_as_sequence */
+	&spmatrix_as_mapping,                   /* tp_as_mapping */
+	0,					/* tp_hash */
+	0,					/* tp_call */
+	(reprfunc)spmatrix_str,			/* tp_str */
+	0,					/* tp_getattro */
+	0,			                /* tp_setattro */
+	0,			                /* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | 
+	Py_TPFLAGS_CHECKTYPES,                  /* tp_flags */
+	0,					/* tp_doc */
+	0,					/* tp_traverse */
+	0,					/* tp_clear */
+	0,	      		                /* tp_richcompare */
+	0,					/* tp_weaklistoffset */
+	(getiterfunc)spmatrix_iter,		/* tp_iter */
+	0,	       	                        /* tp_iternext */
+	spmatrix_methods,                       /* tp_methods */
+	0,				        /* tp_members */
+	spmatrix_getsets,      		        /* tp_getset */
+	0,		                        /* tp_base */
+	0,					/* tp_dict */
+	0,	       			        /* tp_descr_get */
+	0,					/* tp_descr_set */
+	0,					/* tp_dictoffset */
+	0,                                      /* tp_init */
+	0,               			/* tp_alloc */
+	spmatrix_new,				/* tp_new */
+};
diff --git a/src/C/umfpack.c b/src/C/umfpack.c
new file mode 100644
index 0000000..e79468c
--- /dev/null
+++ b/src/C/umfpack.c
@@ -0,0 +1,448 @@
+/*
+ * This file is part of CVXOPT version 0.8.2.
+ * Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+ */
+
+#include "cvxopt.h"
+#include "umfpack.h"
+#include "misc.h"
+
+#if (SIZEOF_INT < SIZEOF_LONG)
+#define UMFD(name) umfpack_dl_ ## name
+#define UMFZ(name) umfpack_zl_ ## name
+#else
+#define UMFD(name) umfpack_di_ ## name
+#define UMFZ(name) umfpack_zi_ ## name
+#endif
+
+const int E_SIZE[] = {sizeof(int_t), sizeof(double), sizeof(complex)};
+
+static char umfpack_error[20];
+
+PyDoc_STRVAR(umfpack__doc__,"Interface to the UMFPACK library.\n\n"
+    "Routines for symbolic and numeric LU factorization of sparse\n"
+    "matrices and for solving sparse sets of linear equations.\n"
+    "The default control settings of UMPFACK are used.\n\n"
+    "See also http://www.cise.ufl.edu/research/sparse/umfpack.");
+
+static void free_umfpack_d_symbolic(void *F, void *descr)
+{
+    UMFD(free_symbolic)(&F);
+}
+
+static void free_umfpack_z_symbolic(void *F, void *descr)
+{
+    UMFZ(free_symbolic)(&F);
+}
+
+static void free_umfpack_d_numeric(void *F, void *descr)
+{
+    UMFD(free_numeric)(&F);
+}
+
+static void free_umfpack_z_numeric(void *F, void *descr)
+{
+    UMFZ(free_numeric)(&F);
+}
+
+static char doc_linsolve[] =
+    "Solves a sparse set of linear equations.\n\n"
+    "linsolve(A, B, trans='N', nrhs=B.size[1], ldB=max(1,B.size[0]),\n"
+    "         offsetB=0)\n\n" 
+    "PURPOSE\n"
+    "If trans is 'N', solves A*X = B.\n"
+    "If trans is 'T', solves A^T*X = B.\n"
+    "If trans is 'C', solves A^H*X = B.\n"
+    "A is a sparse n by n matrix, and B is n by nrhs.\n"
+    "On exit B is replaced by the solution.  A is not modified.\n\n" 
+    "ARGUMENTS\n"
+    "A         square sparse matrix\n\n"
+    "B         dense matrix of the same type as A, stored following \n"
+    "          the BLAS conventions\n\n"
+    "trans     'N', 'T' or 'C'\n\n"
+    "nrhs      integer.  If negative, the default value is used.\n\n"
+    "ldB       nonnegative integer.  ldB >= max(1,n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* linsolve(PyObject *self, PyObject *args, 
+    PyObject *kwrds)
+{
+    spmatrix *A; 
+    matrix *B;
+    char trans='N';
+    double info[UMFPACK_INFO];
+    int oB=0, n, nrhs=-1, ldB=0, k;
+    void *symbolic, *numeric, *x;
+    char *kwlist[] = {"A", "B", "trans", "nrhs", "ldB", "offsetB", 
+        NULL};
+  
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciii", kwlist, 
+        &A, &B, &trans, &nrhs, &ldB, &oB)) return NULL;
+  
+    if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A))
+        PY_ERR_TYPE("A must be a square sparse matrix");
+    n = SP_NROWS(A);
+    if (!Matrix_Check(B) || MAT_ID(B) != SP_ID(A)) 
+        PY_ERR_TYPE("B must a dense matrix of the same numeric type "
+            "as A");
+  
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("i", 0);
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1,n)) err_ld("ldB");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (nrhs-1)*ldB + n > MAT_LGT(B)) err_buf_len("B");
+
+    if (trans != 'N' && trans != 'T' && trans != 'C')
+        err_char("trans", "'N', 'T', 'C'");
+  
+    if (SP_ID(A) == DOUBLE)
+        UMFD(symbolic)(n, n, SP_COL(A), SP_ROW(A), SP_VAL(A), &symbolic,
+            NULL, info);    
+    else
+        UMFZ(symbolic)(n, n, SP_COL(A), SP_ROW(A), SP_VAL(A), NULL,
+            &symbolic, NULL, info);    
+  
+    if (info[UMFPACK_STATUS] != UMFPACK_OK){
+        if (SP_ID(A) == DOUBLE)
+            UMFD(free_symbolic)(&symbolic);
+        else 
+            UMFZ(free_symbolic)(&symbolic);
+        if (info[UMFPACK_STATUS] == UMFPACK_ERROR_out_of_memory)
+            return PyErr_NoMemory();
+        else {
+            snprintf(umfpack_error,20,"%s %i","UMFPACK ERROR",
+                (int) info[UMFPACK_STATUS]);
+            PyErr_SetString(PyExc_ValueError, umfpack_error);
+            return NULL;
+        }
+    }
+
+    if (SP_ID(A) == DOUBLE) {
+        UMFD(numeric)(SP_COL(A), SP_ROW(A), SP_VAL(A), symbolic, 
+            &numeric, NULL, info);
+        UMFD(free_symbolic)(&symbolic);
+    } else {
+        UMFZ(numeric)(SP_COL(A), SP_ROW(A), SP_VAL(A), NULL, symbolic, 
+            &numeric, NULL, info);
+        UMFZ(free_symbolic)(&symbolic);
+    }
+    if (info[UMFPACK_STATUS] != UMFPACK_OK){
+        if (SP_ID(A) == DOUBLE)
+            UMFD(free_numeric)(&numeric);
+        else
+            UMFZ(free_numeric)(&numeric);
+        if (info[UMFPACK_STATUS] == UMFPACK_ERROR_out_of_memory)
+            return PyErr_NoMemory();
+        else { 
+            if (info[UMFPACK_STATUS] == UMFPACK_WARNING_singular_matrix)
+                PyErr_SetString(PyExc_ArithmeticError, "singular "
+                    "matrix");
+            else {
+                snprintf(umfpack_error,20,"%s %i","UMFPACK ERROR",
+                    (int) info[UMFPACK_STATUS]);
+                PyErr_SetString(PyExc_ValueError, umfpack_error);
+            }
+            return NULL;
+        }
+    }
+  
+    if (!(x = malloc(n*E_SIZE[SP_ID(A)]))) {
+        if (SP_ID(A) == DOUBLE)
+            UMFD(free_numeric)(&numeric);
+        else
+            UMFZ(free_numeric)(&numeric);
+        return PyErr_NoMemory();
+    }
+    for (k=0; k<nrhs; k++){
+        if (SP_ID(A) == DOUBLE)
+            UMFD(solve)(trans == 'N' ? UMFPACK_A: UMFPACK_Aat, 
+                SP_COL(A), SP_ROW(A), SP_VAL(A), x, 
+                MAT_BUFD(B) + k*ldB + oB, numeric, NULL, info);
+        else
+            UMFZ(solve)(trans == 'N' ? UMFPACK_A: trans == 'C' ? 
+                UMFPACK_At : UMFPACK_Aat, SP_COL(A), SP_ROW(A), 
+                SP_VAL(A), NULL, x, NULL, 
+                (double *)(MAT_BUFZ(B) + k*ldB + oB), NULL, numeric, 
+                NULL, info);
+        if (info[UMFPACK_STATUS] == UMFPACK_OK) 
+            memcpy(B->buffer + (k*ldB + oB)*E_SIZE[SP_ID(A)], x, 
+                n*E_SIZE[SP_ID(A)]);
+        else
+	    break;
+    }
+    free(x);
+    if (SP_ID(A) == DOUBLE)
+        UMFD(free_numeric)(&numeric);
+    else
+        UMFZ(free_numeric)(&numeric);
+  
+    if (info[UMFPACK_STATUS] != UMFPACK_OK){
+        if (info[UMFPACK_STATUS] == UMFPACK_ERROR_out_of_memory)
+            return PyErr_NoMemory();
+        else { 
+            if (info[UMFPACK_STATUS] == UMFPACK_WARNING_singular_matrix)
+                PyErr_SetString(PyExc_ArithmeticError, "singular "
+                    "matrix");
+            else {
+                snprintf(umfpack_error,20,"%s %i","UMFPACK ERROR",
+                    (int) info[UMFPACK_STATUS]);
+                PyErr_SetString(PyExc_ValueError, umfpack_error);
+            }
+        return NULL;
+        }
+    }
+    return Py_BuildValue("");
+}
+
+
+static char doc_symbolic[] =
+    "Symbolic LU factorization of a sparse matrix.\n\n"
+    "F = symbolic(A)\n\n" 
+    "ARGUMENTS\n"
+    "A         sparse matrix with at least one row and at least one\n"
+    "          column.  A may be rectangular.\n\n"
+    "F         the symbolic factorization as an opaque C object";
+
+static PyObject* symbolic(PyObject *self, PyObject *args)
+{
+    spmatrix *A; 
+    double info[UMFPACK_INFO];
+    void *symbolic; 
+    
+    if (!PyArg_ParseTuple(args, "O", &A)) return NULL;
+  
+    if (!SpMatrix_Check(A)) PY_ERR_TYPE("A must be a sparse matrix");
+    if (SP_NCOLS(A) == 0 || SP_NROWS(A) == 0) { 
+        PyErr_SetString(PyExc_ValueError, "A must have at least one "
+            "row and column");
+        return NULL;
+    } 
+
+    switch (SP_ID(A)){
+        case DOUBLE:  
+            UMFD(symbolic)(SP_NROWS(A), SP_NCOLS(A), SP_COL(A), 
+                SP_ROW(A), SP_VAL(A), &symbolic, NULL, info);
+            if (info[UMFPACK_STATUS] == UMFPACK_OK) 
+                return (PyObject *) PyCObject_FromVoidPtrAndDesc(
+                    (void *) symbolic, "UMFPACK SYM D FACTOR",   
+                    free_umfpack_d_symbolic); 
+            else 
+                UMFD(free_symbolic)(&symbolic);
+            break;
+
+        case COMPLEX:
+            UMFZ(symbolic)(SP_NROWS(A), SP_NCOLS(A), SP_COL(A), 
+                SP_ROW(A), SP_VAL(A), NULL, &symbolic, NULL, info);
+            if (info[UMFPACK_STATUS] == UMFPACK_OK) 
+                return (PyObject *) PyCObject_FromVoidPtrAndDesc(
+                    (void *) symbolic, "UMFPACK SYM Z FACTOR",  
+                free_umfpack_z_symbolic); 
+            else 
+                UMFZ(free_symbolic)(&symbolic);
+            break;
+    }
+
+    if (info[UMFPACK_STATUS] == UMFPACK_ERROR_out_of_memory)
+        return PyErr_NoMemory();
+    else {
+        snprintf(umfpack_error,20,"%s %i","UMFPACK ERROR",
+            (int) info[UMFPACK_STATUS]);
+        PyErr_SetString(PyExc_ValueError, umfpack_error);
+        return NULL;
+    }
+}
+
+
+static char doc_numeric[] =
+    "Numeric LU factorization of a sparse matrix, given a symbolic\n"
+    "factorization computed by umfpack.symbolic.  Raises an\n"
+    "ArithmeticError if A is singular.\n\n"
+    "Fn = numeric(A, Fs)\n\n" 
+    "ARGUMENTS\n"
+    "A         sparse matrix; may be rectangular\n\n"
+    "Fs        symbolic factorization of A, or a matrix with the same\n"
+    "          sparsity pattern, dimensions, and typecode as A, \n"
+    "          created by umfpack.symbolic\n\n"
+    "Fn        the numeric factorization, as an opaque C object";
+
+static PyObject* numeric(PyObject *self, PyObject *args)
+{
+    spmatrix *A;
+    PyObject *Fs; 
+    double info[UMFPACK_INFO];
+    void *numeric; 
+  
+    if (!PyArg_ParseTuple(args, "OO", &A, &Fs)) return NULL;
+  
+    if (!SpMatrix_Check(A)) PY_ERR_TYPE("A must be a sparse matrix");
+    if (!PyCObject_Check(Fs)) err_CO("Fs");
+
+    switch (SP_ID(A)) { 
+	case DOUBLE:
+            TypeCheck_CObject(Fs, "UMFPACK SYM D FACTOR", "Fs is not "
+                "the UMFPACK symbolic factor of a 'd' matrix");
+            UMFD(numeric)(SP_COL(A), SP_ROW(A), SP_VAL(A), 
+	        (void *) PyCObject_AsVoidPtr(Fs), &numeric, NULL, info);
+            if (info[UMFPACK_STATUS] == UMFPACK_OK) 
+                return (PyObject *) PyCObject_FromVoidPtrAndDesc(
+                    (void *) numeric, "UMFPACK NUM D FACTOR", 
+                    free_umfpack_d_numeric);
+            else 
+                UMFD(free_numeric)(&numeric);
+	    break;
+
+        case COMPLEX: 
+            TypeCheck_CObject(Fs, "UMFPACK SYM Z FACTOR", "Fs is not "
+                "the UMFPACK symbolic factor of a 'z' matrix");
+            UMFZ(numeric)(SP_COL(A), SP_ROW(A), SP_VAL(A), NULL,
+	         (void *) PyCObject_AsVoidPtr(Fs), &numeric, NULL, 
+		 info);
+            if (info[UMFPACK_STATUS] == UMFPACK_OK) 
+                return (PyObject *) PyCObject_FromVoidPtrAndDesc(
+                    (void *) numeric, "UMFPACK NUM Z FACTOR", 
+                    free_umfpack_z_numeric);
+	    else 
+                 UMFZ(free_numeric)(&numeric);
+	    break;
+    }
+
+    if (info[UMFPACK_STATUS] == UMFPACK_ERROR_out_of_memory)
+        return PyErr_NoMemory();
+    else { 
+        if (info[UMFPACK_STATUS] == UMFPACK_WARNING_singular_matrix)
+	    PyErr_SetString(PyExc_ArithmeticError, "singular matrix");
+        else {
+	    snprintf(umfpack_error,20,"%s %i","UMFPACK ERROR",
+	        (int) info[UMFPACK_STATUS]);
+	    PyErr_SetString(PyExc_ValueError, umfpack_error);
+        }
+        return NULL;
+    }
+}
+
+
+static char doc_solve[] =
+    "Solves a factored set of linear equations.\n\n"
+    "solve(A, F, B, trans='N', nrhs=B.size[1], ldB=max(1,B.size[0]),\n"
+    "      offsetB=0)\n\n" 
+    "PURPOSE\n"
+    "If trans is 'N', solves A*X = B.\n"
+    "If trans is 'T', solves A^T*X = B.\n"
+    "If trans is 'C', solves A^H*X = B.\n"
+    "A is a sparse n by n matrix, and B is n by nrhs.  F is the\n"
+    "numeric factorization of A, computed by umfpack.numeric.\n"
+    "On exit B is replaced by the solution.  A is not modified.\n\n"
+    "ARGUMENTS\n"
+    "A         square sparse matrix\n\n"
+    "F         numeric factorization, as returned by umfpack.numeric\n"
+    "\n"
+    "B         dense matrix of the same type as A, stored following \n"
+    "          the BLAS conventions\n\n"
+    "trans     'N', 'T' or 'C'\n\n"
+    "nrhs      integer.  If negative, the default value is used.\n\n"
+    "ldB       nonnegative integer.  ldB >= max(1,n).  If zero, the\n"
+    "          default value is used.\n\n"
+    "offsetB   nonnegative integer";
+
+static PyObject* solve(PyObject *self, PyObject *args, PyObject *kwrds)
+{
+    spmatrix *A;
+    PyObject *F; 
+    matrix *B;
+    char trans='N';
+    double *x, info[UMFPACK_INFO];
+    int oB=0, n, ldB=0, nrhs=-1, k;
+    char *kwlist[] = {"A", "F", "B", "trans", "nrhs", "ldB", "offsetB", 
+        NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ciii", kwlist,
+        &A, &F, &B, &trans, &nrhs, &ldB, &oB)) return NULL;
+
+    if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A))
+        PY_ERR_TYPE("A must a square sparse matrix");
+    n = SP_NROWS(A);
+
+    if (!PyCObject_Check(F)) err_CO("F");
+    if (SP_ID(A) == DOUBLE) {
+        TypeCheck_CObject(F, "UMFPACK NUM D FACTOR", "F is not the "
+            "UMFPACK numeric factor of a 'd' matrix");
+    }
+    else {
+        TypeCheck_CObject(F, "UMFPACK NUM Z FACTOR", "F is not the "
+            "UMFPACK numeric factor of a 'z' matrix");
+    }
+
+    if (!Matrix_Check(B) || MAT_ID(B) != SP_ID(A)) 
+        PY_ERR_TYPE("B must a dense matrix of the same numeric type "
+            "as A");
+    if (nrhs < 0) nrhs = B->ncols;
+    if (n == 0 || nrhs == 0) return Py_BuildValue("");
+    if (ldB == 0) ldB = MAX(1,B->nrows);
+    if (ldB < MAX(1,n)) err_ld("ldB");
+    if (oB < 0) err_nn_int("offsetB");
+    if (oB + (nrhs-1)*ldB + n > MAT_LGT(B)) err_buf_len("B");
+
+    if (trans != 'N' && trans != 'T' && trans != 'C')
+        err_char("trans", "'N', 'T', 'C'");
+  
+    if (!(x = malloc(n*E_SIZE[SP_ID(A)]))) return PyErr_NoMemory();
+
+    for (k=0; k<nrhs; k++) {
+        if (SP_ID(A) == DOUBLE)
+            UMFD(solve)(trans == 'N' ? UMFPACK_A : UMFPACK_Aat, 
+                SP_COL(A), SP_ROW(A), SP_VAL(A), x, 
+                MAT_BUFD(B) + k*ldB + oB, 
+                (void *) PyCObject_AsVoidPtr(F), NULL, info);
+        else
+            UMFZ(solve)(trans == 'N' ? UMFPACK_A : trans == 'C' ? 
+                UMFPACK_At : UMFPACK_Aat, SP_COL(A), SP_ROW(A), 
+                SP_VAL(A), NULL, x, NULL, 
+                (double *)(MAT_BUFZ(B) + k*ldB + oB), NULL,  
+                (void *) PyCObject_AsVoidPtr(F), NULL, info);
+        if (info[UMFPACK_STATUS] == UMFPACK_OK)
+            memcpy(B->buffer + (k*ldB + oB)*E_SIZE[SP_ID(A)], x, 
+                n*E_SIZE[SP_ID(A)]);
+        else
+	    break;
+    }
+    free(x);
+
+    if (info[UMFPACK_STATUS] != UMFPACK_OK){
+        if (info[UMFPACK_STATUS] == UMFPACK_ERROR_out_of_memory)
+            return PyErr_NoMemory();
+        else { 
+            if (info[UMFPACK_STATUS] == UMFPACK_WARNING_singular_matrix)
+                PyErr_SetString(PyExc_ArithmeticError, 
+                    "singular matrix");
+            else {
+                snprintf(umfpack_error,20,"%s %i","UMFPACK ERROR",
+                    (int) info[UMFPACK_STATUS]);
+                PyErr_SetString(PyExc_ValueError, umfpack_error);
+            }
+            return NULL;
+        }
+    }
+  
+    return Py_BuildValue("");
+}
+
+static PyMethodDef umfpack_functions[] = {
+{"linsolve", (PyCFunction) linsolve, METH_VARARGS|METH_KEYWORDS, 
+    doc_linsolve},
+{"symbolic", (PyCFunction) symbolic, METH_VARARGS, doc_symbolic},
+{"numeric", (PyCFunction) numeric, METH_VARARGS, doc_numeric},
+{"solve", (PyCFunction) solve, METH_VARARGS|METH_KEYWORDS, doc_solve},
+{NULL}  /* Sentinel */
+};
+
+PyMODINIT_FUNC initumfpack(void)
+{
+  PyObject *m;
+
+  m = Py_InitModule3("cvxopt.umfpack", umfpack_functions, 
+      umfpack__doc__);
+
+  if (import_cvxopt() < 0) return;
+}
diff --git a/src/python/__init__.py b/src/python/__init__.py
new file mode 100644
index 0000000..896a33c
--- /dev/null
+++ b/src/python/__init__.py
@@ -0,0 +1,2 @@
+__all__ = ['base', 'random', 'blas', 'lapack', 'amd', 'umfpack', 
+    'cholmod', 'solvers', 'modeling', 'info']
diff --git a/src/python/coneprog.py b/src/python/coneprog.py
new file mode 100644
index 0000000..50b0ce2
--- /dev/null
+++ b/src/python/coneprog.py
@@ -0,0 +1,2151 @@
+"""
+Linear and semidefinite programming solver.
+"""
+
+# This file is part of CVXOPT version 0.8.2.
+# Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+
+import math
+from cvxopt import base, blas, lapack, cholmod, misc
+from cvxopt.base import matrix, spmatrix
+cholmod.options['supernodal'] = 2
+
+__all__ = []
+options = {}
+
+def conelp(c, kktsolver, Gl=None, hl=None, Gs=None, hs=None, A=None, 
+    b=None, primalstart=None, dualstart=None, xnewcopy=matrix, 
+    xdot=blas.dot, xaxpy=blas.axpy, xscal=blas.scal, ynewcopy=matrix, 
+    ydot=blas.dot, yaxpy=blas.axpy, yscal=blas.scal):
+    """
+
+    Solves a pair of primal and dual cone programs
+
+        minimize    <c,x>             
+        subject to  Gl(x) + sl = hl      
+                    Gs(x) + ss = hs
+                    A(x) = b                      
+                    sl >= 0,  ss >= 0
+
+        maximize    -<hl,zl> - <hs,zs> - <b,y>
+        subject to  Gl'(zl) + Gs'(zs) + A'(y) + c = 0
+                    zl >= 0,  zs >= 0
+
+    Gl: V -> reals^ml, Gs: V -> S^m1 x ... x S^mN, and A: V -> W are 
+    linear mappings, where V and W are real vector spaces.
+
+    Input arguments:
+
+        c is a matrix, list of matrices, dictionary of matrices, ...
+        representing a vector in the vector space V.
+
+        Gl is a function Gl(x, y, alpha=1.0, beta=0.0, trans='N'):
+
+            y := alpha*Gl(x) + beta*y if trans is 'N' 
+            y := alpha*Gl'(x) + beta*y if trans is 'T'.
+
+        If trans is 'N', x is in V and y is in R^ml.
+        If trans is 'T', x is in R^ml and y is in V.
+
+        hl is a dense 'd' matrix of size (ml,1).
+
+        Gs is a function Gs(x, y, alpha=1.0, beta=0.0, trans='N'):
+
+            y := alpha*Gs(x) + beta*y if trans is 'N'
+            y := alpha*Gs'(x) + beta*y if trans is 'T'.
+
+        If trans is 'N', x is in V and y is in S^m1 x ... x S^mN.
+        If trans is 'T', x is in S^m1 x ... x S^mN and y is in V.
+
+        hs is a list of N square dense 'd' matrices, representing a 
+        symmetric block diagonal matrix in 'L' storage.
+
+        A is a function A(x, y, alpha, beta, trans='N'):
+
+            y := alpha*A(x) + beta*y if trans is 'N'
+            y := alpha*A'(x) + beta*y if trans is 'T'.
+
+        If trans is 'N', x is in V and y is in W
+        If trans is 'T', x is in S^m1 x ... x S^mN and y is in V.
+
+        b is a matrix, list of matrices, dictionary of matrices, ...
+        representing a vector in the vector space W.
+        
+        kktsolver is a function that returns a function for solving
+        KKT systems 
+        
+            [ 0   A'  Gl'          Gs'           ] [ x  ]   [ bx  ]
+            [ A   0   0            0             ] [ y  ] = [ by  ].
+            [ Gl  0   -diag(d)^2   0             ] [ zl ]   [ bzl ]
+            [ Gs  0   0            -r*r'*()*r*r' ] [ zs ]   [ bzs ]
+        
+        Called as f = kktsolver(di, rti) with di = 1.0./d (a dense 'd' 
+        matrix of size (ml,1)) and rti = (r')^{-1} (a list of square 
+        dense 'd' matrices of size (mk,mk)).  
+        The KKT system is solved by f(x,y,zl,zs).  On entry, x, y, zl, 
+        zs contain the righthand side.  On exit, they contain the 
+        solution, with zl, zs scaled: d.*zl and r'*zs*r are returned 
+        instead of zl and zs.
+
+        xnewcopy, xdot, xscal, xaxpy, ynewcopy, ydot, yscal, yaxpy are 
+        Python functions.
+        xnewcopy(x), ynewcopy(x) create new copies of vectors in V and 
+        W, respectively. 
+        xdot(x,y), ydot(x,y) return the inner product of vectors in V 
+        and W, respectively.
+        xscal(alpha, x), yscal(alpha,x) compute x := alpha*x for x in V
+        and W, respectively.
+        xaxpy(x, y, alpha=1, beta=0), yaxpy(x, y, alpha=1, beta=0) 
+        compute y := alpha*x + y for vectors in V and W, respectively.
+
+    conelp() returns a dictionary with keys 'status', 'x', 'sl', 
+    'ss', 'y', 'zl', 'zs'.
+
+    The control parameters can be modified by adding an entry to the 
+    dictionary options.  
+
+        options['show_progress'] True/False (default: True)
+        options['maxiters'] positive integer (default: 100)
+        options['abstol'] scalar (default: 1e-7)
+        options['reltol'] scalar (default: 1e-7)
+        options['feastol'] scalar (default: 1e-7)
+        options['refinement'] True/False (default: True)
+    """
+
+    EXPON = 3
+    STEP = 0.99
+
+    try: DEBUG = options['debug']
+    except KeyError: DEBUG = False
+
+    try: MAXITERS = options['maxiters']
+    except KeyError: MAXITERS = 100
+    else:
+        if type(MAXITERS) is not int or MAXITERS < 1:
+           raise ValueError, "options['maxiters'] must be a positive "\
+               "integer"
+
+    try: ABSTOL = options['abstol']
+    except KeyError: ABSTOL = 1e-7
+    else:
+        if type(ABSTOL) is not float and type(ABSTOL) is not int:
+            raise ValueError, "options['abstol'] must be a scalar"
+
+    try: RELTOL = options['reltol']
+    except KeyError: RELTOL = 1e-7
+    else:
+        if type(RELTOL) is not float and type(RELTOL) is not int:
+            raise ValueError, "options['reltol'] must be a scalar"
+
+    try: FEASTOL = options['feastol']
+    except KeyError: FEASTOL = 1e-7
+    else:
+        if type(FEASTOL) is not float and type(FEASTOL) is not int:
+            raise ValueError, "options['feastol'] must be a scalar"
+
+    try: show_progress = options['show_progress']
+    except KeyError: show_progress = True
+
+    try: refinement = options['refinement']
+    except KeyError: refinement = True
+
+    def f0(x, y, alpha=1.0, beta=0.0, trans='N'):  
+        # y := alpha*F(x)  + beta*y  (trans = 'N') 
+        # y := alpha*F'(x) + beta*y  (trans = 'T')
+        # when F : R^n -> a 0-dimensional space
+        if trans == 'N':  pass
+        else: xscal(beta, y)
+    if Gl is None: Gl = f0
+    if Gs is None: Gs = f0
+    if A is None: A = f0
+    if hl is None: hl = matrix(0.0, (0,1))
+    if hs is None: hs = []
+    if b is None: b = matrix(0.0, (0,1))
+    ml, ms, p = hl.size[0], [ h_k.size[0] for h_k in hs ], b.size[0]
+    maxm = max( [0] + ms )
+    m = ml + sum(ms) 
+
+    def xcopy(x, y): xscal(0, y); xaxpy(x, y)
+    def ycopy(x, y): yscal(0, y); yaxpy(x, y)
+
+    x = xnewcopy(c);  xscal(0,x)
+    sl = matrix(1.0, (ml,1))
+    ss = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+    for sk in ss:  sk[::sk.size[0]+1] = 1.0
+    y = ynewcopy(b);  yscal(0,y)
+    zl = matrix(1.0, (ml,1))
+    zs = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+    for zk in zs:  zk[::zk.size[0]+1] = 1.0
+
+    resx, hresx = xnewcopy(c), xnewcopy(c)
+    reszl, hreszl = matrix(0.0, (ml,1)), matrix(0.0, (ml,1))
+    reszs = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+    hreszs = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+    resy, hresy = ynewcopy(b), ynewcopy(b)
+    dx = xnewcopy(c)
+    dsl = matrix(0.0, (ml,1))
+    dss = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+    dy = ynewcopy(b)
+    dzl = matrix(0.0, (ml,1))
+    dzs = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+    dkappa, dtau = matrix(0.0, (1,1)), matrix(0.0, (1,1))
+    dx1 = xnewcopy(c)
+    dy1 = ynewcopy(b)
+    dsl1 = matrix(0.0, (ml,1))
+    dss1 = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+    dzl1 = matrix(0.0, (ml,1))
+    dzs1 = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+    if refinement:
+        dx2 = xnewcopy(c)
+        dy2 = ynewcopy(b)
+        dsl2 = matrix(0.0, (ml,1))
+        dss2 = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+        dzl2 = matrix(0.0, (ml,1))
+        dzs2 = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+        dkappa2, dtau2 = matrix(0.0, (1,1)), matrix(0.0, (1,1))
+    r = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+    rti = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+    lmbda = matrix(0.0, (m+1,1))
+    gamma = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+    thl = matrix(0.0, (ml,1))
+    ths = [ matrix(0.0, (m_k, m_k)) for m_k in ms ]
+    sigs, sigz = matrix(0.0, (m+1,1)), matrix(0.0, (m+1,1))
+    ones = matrix(1.0, (max(maxm,ml),1))
+    work, work2 = matrix(0.0, (maxm,maxm)), matrix(0.0, (maxm,maxm))
+
+
+    # Initial points more or less as in Mehrotra's paper.
+
+    if primalstart is None or dualstart is None:
+
+        # Factor
+        #
+        #     [ 0   A'  Gl' Gs' ] 
+        #     [ A   0   0   0   ]
+        #     [ Gl  0  -I   0   ]
+        #     [ Gs  0   0  -I   ]
+        
+        dli = matrix(1.0, (ml,1)) 
+        for e in rti:
+            blas.scal(0.0, e)
+            e[::e.size[0]+1] = 1.0
+        try: 
+            f = kktsolver(dli, rti)
+        except ArithmeticError:  
+            raise ValueError, "Rank(A) < p or Rank([Gl; Gs; A]) < n"
+
+    if primalstart is None:
+
+        # minimize    || Gl(x) - hl ||^2
+        # subject to  A(x) = b
+        #
+        # by solving
+        #
+        # [ 0   A'  Gl' Gs' ] [x  ]   [0 ]
+        # [ A   0   0   0   ] [dy ] = [b ]
+        # [ Gl  0  -I   0   ] [dzl]   [hl]
+        # [ Gs  0   0  -I   ] [dzs]   [hs]
+        #
+        # (sl, ss) = (hl-Gl*x, hs-Gs(x)) and add a multiple of the
+        # identity to make (sl,ss) >= 0. 
+
+        xscal(0.0, x)
+        ycopy(b, dy)  
+        blas.copy(hl, dzl)
+        misc.scopy(hs, dzs)
+        f(x, dy, dzl, dzs) 
+        blas.scal(0.0, sl);  blas.axpy(dzl, sl, alpha=-1)
+        misc.sscal(0.0, ss);  misc.saxpy(dzs, ss, alpha=-1)
+        blas.copy(sl, lmbda)
+        if sl: ap = min(sl)
+        else: ap = 0.0
+        for e in ss:
+            if e.size[0]:
+                lapack.syevr(+e, lmbda, range='I', il=1, iu=1)
+                ap = min(ap, lmbda[0])
+        if ap < 0.0:  
+            sl += -1.5*ap 
+            for e in ss: e[::e.size[0]+1] -= 1.5*ap 
+
+    else:
+        xcopy(primalstart['x'], x)
+        if ml: blas.copy(primalstart['sl'], sl)
+        if ms: misc.scopy(primalstart['ss'], ss)
+
+
+    if dualstart is None:
+
+        # minimize   || zl ||^2
+        # subject to Gl'(zl) + A'(y) + c = 0
+        #
+        # by solving
+        #
+        # [ 0   A'  Gl'  Gs' ] [dx]   [-c]
+        # [ A   0   0    0   ] [y ] = [ 0]
+        # [ Gl  0  -I    0   ] [zl]   [ 0]
+        # [ Gs  0   0   -I   ] [zs]   [ 0]
+
+        xcopy(c, dx); xscal(-1.0, dx)
+        yscal(0.0, y)
+        blas.scal(0.0, zl)
+        misc.sscal(0.0, zs)
+        f(dx, y, zl, zs)
+        blas.copy(zl, lmbda)
+        if zl: ad = min(zl) 
+        else: ad = 0.0 
+        for e in zs:
+            if e.size[0]:
+                lapack.syevr(+e, lmbda, range='I', il=1, iu=1)
+                ad = min(ad, lmbda[0]) 
+        if ad <= 0.0:  
+            zl += -1.5*ad 
+            for e in zs: e[::e.size[0]+1] -= 1.5*ad 
+
+    else:
+        if p: ycopy(dualstart['y'], y)
+        if ml: blas.copy(dualstart['zl'], zl)
+        if ms: misc.scopy(dualstart['zs'], zs) 
+
+    gap = blas.dot(sl,zl) + misc.sdot(ss, zs)
+
+    if primalstart is None and dualstart is None and gap < 1e-10:
+        # If gap is zero, z, s must have zero components, and this means
+        # that ad and ap were zero.  Therefore the initial point 
+        # happens to be feasible and optimal.  So it does not matter 
+        # if (sl,ss) or (zl,zs) are not strictly positive and we can 
+        # skip to the computation of the residuals.
+        pass
+
+    else: 
+        if primalstart is None:  
+            # (sl, ss) >= could be non-strictly positive so we need to
+            # make it positive definite.  Note that sum(zl) + tr(zs)
+            # cannot be zero, because (zl,zs)=0 means dualstart is None
+            # and gap = 0, and that was handled above.
+            trz = blas.asum(zl) + sum([ blas.asum(e, inc=e.size[0]+1) 
+                for e in zs ])                
+            a = max(gap, 1e-8) / trz
+            sl += a 
+            for e in ss: e[::e.size[0]+1] += a
+
+        if dualstart is None:
+            # Idem for (zl, zs).
+            trs = blas.asum(sl) + sum([ blas.asum(e, inc=e.size[0]+1) 
+                for e in ss ])
+            a = max(gap, 1e-8) / trs
+            zl += a
+            for e in zs: e[::e.size[0]+1] += a
+
+    tau, kappa = 1.0, 1.0
+    gap = blas.dot(sl, zl) + misc.sdot(ss, zs) 
+
+    for iters in xrange(MAXITERS):
+
+        # hresx = -A'(y) - Gl'(zl) - Gs'(zs)  
+        A(y, hresx, alpha=-1.0, trans='T') 
+        Gl(zl, hresx, alpha=-1.0, beta=1.0, trans='T') 
+        Gs(zs, hresx, alpha=-1.0, beta=1.0, trans='T') 
+
+        # resx = hresx - c*tau = -A'(y) - Gl'(zl) - Gs'(zs) - c*tau
+        xcopy(hresx, resx)
+        xaxpy(c, resx, alpha=-tau)
+
+        # hresy = A(x)  
+        A(x, hresy)
+
+        # resy = hresy - b*tau = A(x) - b*tau
+        ycopy(hresy, resy)
+        yaxpy(b, resy, alpha=-tau)
+
+        # hreszl = sl + Gl(x)  
+        Gl(x, hreszl)
+        blas.axpy(sl, hreszl)
+
+        # reszl = hreszl - hl*tau = sl + Gl(x) - hl*tau
+        blas.scal(0, reszl)
+        blas.axpy(hreszl, reszl)
+        blas.axpy(hl, reszl, alpha=-tau)
+
+        # hreszs = ss + Gs(x) 
+        Gs(x, hreszs)
+        misc.saxpy(ss, hreszs)
+
+        # reszs = hreszs - hs*tau = ss + Gs(x) - hs*tau 
+        misc.sscal(0, reszs)
+        misc.saxpy(hreszs, reszs)
+        misc.saxpy(hs, reszs, alpha=-tau)
+
+        # rest = kappa + <c,x> + <b,y> + <hl,zl> + <hs,zs>
+        cx, by = xdot(c,x), ydot(b,y) 
+        hlzl, hszs = blas.dot(hl,zl), misc.sdot(hs,zs)
+        rest = kappa + cx + by + hlzl + hszs
+
+        # stopping criteria
+        pcost, dcost = cx/tau, -(by + hlzl + hszs) / tau        
+        nrmhresx = math.sqrt(xdot(hresx, hresx)) 
+        nrmresx = math.sqrt(xdot(resx, resx)) / tau
+        nrmhresy = math.sqrt(ydot(hresy, hresy))
+        nrmresy = math.sqrt(ydot(resy, resy)) / tau
+        nrmhreszl = blas.nrm2(hreszl) 
+        nrmreszl = blas.nrm2(reszl) / tau 
+        nrmhreszs = misc.snrm2(hreszs) 
+        nrmreszs = misc.snrm2(reszs) / tau
+        if pcost < 0.0:
+            relgap = gap / -pcost
+        elif dcost > 0.0:
+            relgap = gap / dcost
+        else: 
+            relgap = None
+
+        if iters == 0: 
+            nrmresx0 = max(1.0, math.sqrt(xdot(c,c)))
+            nrmresy0 = max(1.0, math.sqrt(ydot(b,b)))
+            nrmreszl0 = max(1.0, blas.nrm2(hl))
+            nrmreszs0 = max(1.0, misc.snrm2(hs))
+
+        if show_progress:
+            if iters==0:
+                print "% 10s% 12s% 10s% 8s% 7s % 5s" %("pcost", "dcost",
+                    "gap", "pres", "dres", "k/t")
+            print "%2d: % 8.4e % 8.4e % 4.0e% 7.0e% 7.0e% 7.0e" \
+                %(iters, pcost, dcost, gap, max(nrmreszl/nrmreszl0,
+                nrmreszs/nrmreszs0, nrmresy/nrmresy0), nrmresx/nrmresx0,
+                kappa/tau)
+
+        if max(nrmreszl/nrmreszl0, nrmreszs/nrmreszs0, 
+            nrmresy/nrmresy0) <= FEASTOL and \
+            nrmresx/nrmresx0 <= FEASTOL and (gap <= ABSTOL or 
+            (relgap is not None and relgap <= RELTOL)):
+            xscal(1.0/tau, x)
+            yscal(1.0/tau, y)
+            blas.scal(1.0/tau, sl)
+            misc.sscal(1.0/tau, ss)
+            blas.scal(1.0/tau, zl)
+            misc.sscal(1.0/tau, zs)
+            return {'status': 'optimal', 'x': x, 'y': y, 'sl': sl, 
+                'ss': ss, 'zl': zl, 'zs': zs}
+
+        elif hlzl + hszs + by < 0.0 and nrmhresx / (-hlzl - hszs - by) \
+            <= FEASTOL:
+            yscal(1.0/(-hlzl - hszs - by), y)
+            blas.scal(1.0/(-hlzl - hszs - by), zl)
+            misc.sscal(1.0/(-hlzl - hszs - by), zs)
+            return {'status': 'primal infeasible', 'x': None, 
+                'sl': None, 'ss': None, 'y': y, 'zl': zl, 'zs': zs}
+
+        elif cx < 0.0 and max(nrmhresy, nrmhreszl, nrmhreszs) / (-cx) \
+            <= FEASTOL:
+            xscal(1.0/(-cx), x)
+            blas.scal(1.0/(-cx), sl)
+            misc.sscal(1.0/(-cx), ss)
+            return {'status': 'dual infeasible', 'x': x, 'sl': sl, 
+                'ss': ss, 'y': None, 'zl': None, 'zs': None}
+
+
+        if iters == 0:
+
+            # Compute initial scaling.
+            #
+            # For the linear inequalities: 
+            #
+            #     dl = sqrt(sl./zl), dli = sqrt(zl./sl)
+            #     lmbdl = sqrt(sl.*zl).
+            #
+            # Store lmbdl in lmbda[:ml].
+            #
+            # Matrix inequalities: lists of square matrices r, rti with
+            #
+            #     r[k]'*ss[k]^{-1}*r[k] = diag(lmbds[k])^{-1}
+            #     r[k]'*zs[k]*r[k] = diag(lmbds[k])
+            #
+            # rti[k] is the inverse of r[k]', so that
+            #
+            #     rti[k]'*ss[k]*rti[k] = diag(lmbds[k])^{-1}
+            #     rti[k]'*zs[k]^{-1}*rti[k] = diag(lmbds[k]).
+            #
+            # Store (lmbds[0], ..., lmbds[N-1]) in lmbda[ml:ml+sum(ms)].
+            #
+            # Also compute gamma: gamma[k] has entries 
+            #
+            #     gamma[k][i,j] = 0.5*(lmbds[k][i]+lmbds[k][j])
+            #
+            # For kappa, tau:  
+            #
+            #     dg = sqrt(kappa/tau), dgi = sqrt(tau/kappa)
+            #     lmbdg = sqrt(tau*kappa)  
+            # 
+            # Store lmbdg in lmbda[-1].
+	
+            dli = base.sqrt(misc.ihad(zl, sl)) 
+            lmbda[:ml] = base.sqrt(misc.had(sl,zl)) 
+
+            dgi = math.sqrt(tau/kappa)
+            lmbda[-1] = math.sqrt(tau*kappa)
+
+            ind = ml
+            for k in xrange(len(ms)):
+
+                # Factor ss = L1*L1', zs = L2*L2'.  Store L1 and L2 in 
+                # dss and dzs.
+                blas.copy(ss[k], dss[k]);  lapack.potrf(dss[k])
+                blas.copy(zs[k], dzs[k]);  lapack.potrf(dzs[k])
+	 
+                # SVD of L2'*L1 = U*diag(lambda)*V'.  Keep U in work. 
+                for i in xrange(ms[k]): dss[k][i,i+1:] = 0
+                blas.copy(dss[k], work)
+                blas.trmm(dzs[k], work, transA='T', ldB=ms[k], n=ms[k],
+                    m=ms[k])
+                lapack.gesvd(work, lmbda, jobu='O', ldA=ms[k], m=ms[k], 
+                    n=ms[k], offsetS=ind)
+	       
+                # r = L2^{-T}*U*diag(sqrt(lambda)) 
+                #   = L1*V*diag(1./sqrt(lambda))
+                # rti = L2*U*diag(1./sqrt(lambda)) 
+                #     = L1^{-T}*V*diag(sqrt(lambda))
+                blas.copy(work, r[k], n=ms[k]*ms[k])
+                blas.trsm(dzs[k], r[k], transA='T')
+                blas.copy(work, rti[k], n=ms[k]*ms[k])
+                blas.trmm(dzs[k], rti[k])
+                for i in xrange(ms[k]):
+                    a = math.sqrt(lmbda[ind+i])
+                    blas.scal(a, r[k], offset=ms[k]*i, n=ms[k])
+                    blas.scal(1/a, rti[k], offset=ms[k]*i, n=ms[k])
+
+                # gamma[k][i,j] = .5 * (lambda_i + lambda_j)
+                # Use blas.ger to make sure there are no zeros or nan's
+                # in upper triangular part.
+                blas.scal(0.0, gamma[k])
+                blas.ger(lmbda, ones, gamma[k], alpha=.5, offsetx=ind)
+                blas.ger(ones, lmbda, gamma[k], alpha=.5, offsety=ind)
+
+                ind += ms[k]
+
+        
+        # Define a function 
+        #
+        #    solve_newton(dx, dy, dzl, dzs, dtau, dsl, dss, dkappa)
+        #
+        # for solving 
+        #
+        #     [0     ]   [ 0    A'  Gl'  Gs' 0 ] [dx  ]    [rhsx  ]
+        #     [0     ]   [-A    0   0    0   b ] [dy  ]    [rhsy  ]
+        #     [dsl   ] - [-Gl   0   0    0   hl] [dzl ] = -[rhszl ]
+        #     [dsk   ]   [-Gs   0   0    0   hs] [dzs ]    [rhszs ]
+        #     [dkappa]   [-c'  -b' -hl' -hs' 0 ] [dtau]    [rhstau]
+        #    
+        #     sl.*dzl + zl.*dsl = -rhssl
+        #     Hc(dzs*ss + zs*dss) = -rhsss
+        #     kappa*dtau + tau*dkappa = -rhskappa.
+        #
+        # where Hc(x) = 0.5 * (r'*x*(r')^{-1} + r^{-1}*x'*r).
+    
+        try: f = kktsolver(dli, rti)
+        except ArithmeticError:
+            if iters == 0 and primalstart and dualstart: 
+                raise ValueError, "Rank(A) < p or Rank([Gl; Gs; A]) < n"
+            else:
+                raise ArithmeticError, "singular KKT matrix"
+
+        # thl := dli .* hl;  ths := rti'*hs*rti
+        blas.copy(hl, thl)
+        misc.had2(thl, dli)
+        misc.cngrnc(rti, hs, ths, trans='T')
+
+        # Solve
+        #
+        #     [ 0   A'  Gl'         Gs'         ] [dx1 ]          [c ]
+        #     [-A   0   0           0           ] [dy1 ] = -dgi * [b ]
+        #     [-Gl  0   diag(dl)^2  0           ] [dzl1]          [hl]
+        #     [-Gs  0   0           r*r'*()*r*r'] [dzs1]          [hs] 
+         
+        xcopy(c, dx1);  xscal(-1, dx1)
+        ycopy(b, dy1)
+        blas.copy(hl, dzl1)
+        misc.scopy(hs, dzs1)
+        f(dx1, dy1, dzl1, dzs1)
+        xscal(dgi, dx1)
+        yscal(dgi, dy1)
+        blas.scal(dgi, dzl1)
+        misc.sscal(dgi, dzs1)
+        
+        if DEBUG: 
+            print "first 4x4 system"
+
+            # unscaled variables
+            duzl1 = misc.had(dzl1, dli)
+            duzs1 = [ +z_k for z_k in dzs1 ]
+            misc.cngrnc(rti, duzs1, duzs1)
+
+            rxdb = xnewcopy(c)
+            A(dy1, rxdb, alpha=1, beta=dgi, trans='T')
+            Gl(duzl1, rxdb, alpha=1, beta=1, trans='T')
+            Gs(duzs1, rxdb, alpha=1, beta=1, trans='T')
+            print "    norm(rxdb) = %e" %math.sqrt(xdot(rxdb,rxdb))
+
+            rydb = ynewcopy(b)
+            A(dx1, rydb, alpha=-1.0, beta=dgi)
+            print "    norm(rydb) = %e" %math.sqrt(ydot(rydb,rydb))
+
+            rzldb = +hl
+            Gl(dx1, rzldb, alpha=-1.0, beta=dgi)
+            rzldb += misc.ihad(duzl1, misc.had(dli,dli))
+            print "    norm(rzldb) = %e" %blas.nrm2(rzldb)
+
+            rzsdb = [ +hs_k for hs_k in hs ]
+            Gs(dx1, rzsdb, alpha=-1.0, beta=dgi)
+            misc.cngrnc(r, duzs1, duzs1, trans='T')
+            misc.cngrnc(r, duzs1, rzsdb, alpha=1.0, beta=1.0)
+            print "    norm(rzsdb) = %e\n" %misc.snrm2(rzsdb)
+
+
+        def solve_newton1(dx, dy, dzl, dzs, dtau, dsl, dss, dkappa):
+
+            # Solve without refinement
+            #
+            #     [0     ]   [ 0    A'  Gl'  Gs' 0 ] [dx  ]    [rhsx  ]
+            #     [0     ]   [-A    0   0    0   b ] [dy  ]    [rhsy  ]
+            #     [dsl   ] - [-Gl   0   0    0   hl] [dzl ] = -[rhszl ]
+            #     [dsk   ]   [-Gs   0   0    0   hs] [dzs ]    [rhszs ]
+            #     [dkappa]   [-c'  -b' -hl' -hs' 0 ] [dtau]    [rhstau]
+            #    
+            #     sl.*dzl + zl.*dsl = -rhssl
+            #     Hc(dzs*ss + zs*dss) = -rhsss
+            #     kappa*dtau + tau*dkappa = -rhskappa
+            #
+            # Last three equations in scaled variables: 
+            #
+            #     lmbdl .* (dzl + dsl) = -rhssl
+            #     gamma .* (dzs + dss) = -rhsss
+            #     lmbdg * (dtau + dkappa) = -rhskappa.
+            #
+            # On entry, the righthand sides are stored in dx, dy, dzl, 
+            # dzs, dtau, dssl, dsss, dkappa.  
+            # On exit, scaled quantities are returned for dsl, dzl,
+            # dss, dzs.
+
+            if DEBUG:  
+                rxdb = xnewcopy(dx)    
+                rydb = ynewcopy(dy)
+                rzldb = +dzl
+                rzsdb = [ +dzs_k for dzs_k in dzs ]
+                rtdb = dtau[0]
+                rsldb = +dsl
+                rssdb = [ +dss_k for dss_k in dss ]
+                rkdb = dkappa[0]
+
+            # dy := -dy = -rhsy
+            yscal(-1.0, dy) 
+
+            # dsl := -dsl ./ lmbdl   (replace with btmv)
+            misc.ihad2(dsl, lmbda, n=ml);  blas.scal(-1,dsl)
+            
+            # dzl := -(dzl + dsl ./ dli) = -(rhszl - rhssl./zl)  
+            blas.axpy(misc.ihad(dsl,dli), dzl);  blas.scal(-1, dzl)  
+
+            # dss := -dss ./ gamma
+            for num, den in zip(dss, gamma): misc.ihad2(num, den)
+            misc.sscal(-1.0, dss) 
+
+            # dzs := -(dzs + r*dss*r') = -(rhszs - r*(rhss./gamma)*r')
+            misc.cngrnc(r, dss, dzs, alpha=-1.0, beta=-1.0)
+  
+            # dkappa[0] := -dkappa[0]/lmbd[-1] 
+            #            = -rhskappa / sqrt(kappa*tau)
+            dkappa[0] = -dkappa[0] / lmbda[-1]
+
+            # dtau[0] = dtau[0] + dkappa[0] / dgi
+            #         = rhstau[0] - rhskappa / tau
+            dtau[0] += dkappa[0] / dgi
+ 
+
+            # Solve 
+            #
+            #  [ 0   A'  Gl'  Gs'  0  ][dx  ]   [rhsx                  ]
+            #  [-A   0   0    0    b  ][dy  ]   [rhsy                  ]
+            #  [-Gl  0   Dl   0    hl ][dzl ] = [rhszl-rhssl./zl       ]
+            #  [-Gs  0   0    Ds   hs ][dzs ]   [rhszs-r*(rhszs./ga)*r']
+            #  [-c'  -b' -hl' -hs' k/t][dtau]   [rhst-rhsk/tau         ]
+            #
+            # Dl = diag(dl)^2,  Ds = r*r'*()*r*r'.
+
+            if DEBUG:  
+                rxdb2 = xnewcopy(dx)    
+                rydb2 = ynewcopy(dy);  xscal(-1, rydb2)
+                rzldb2 = -dzl
+                rzsdb2 = [-dzs_k for dzs_k in dzs]
+
+                rxdb3 = xnewcopy(dx)    
+                rydb3 = ynewcopy(dy);  xscal(-1, rydb3)
+                rzldb3 = -dzl
+                rzsdb3 = [-dzs_k for dzs_k in dzs]
+
+            f(dx, dy, dzl, dzs)
+
+            if DEBUG: 
+                print "second 4x4 system"
+
+                # unscaled variables
+                duzl = misc.had(dzl, dli)
+                duzs = [ +z_k for z_k in dzs ]
+                misc.cngrnc(rti, duzs, duzs)
+
+                A(dy, rxdb2, alpha=-1.0, beta=1.0, trans='T')
+                Gl(duzl, rxdb2, alpha=-1.0, beta=1.0, trans='T')
+                Gs(duzs, rxdb2, alpha=-1.0, beta=1.0, trans='T')
+                print "    norm(rxdb2) = %e" \
+                    %math.sqrt(xdot(rxdb2,rxdb2))
+
+                A(dx, rydb2, alpha=1.0, beta=1.0)
+                print "    norm(rydb2) = %e" \
+                    %math.sqrt(ydot(rydb2,rydb2))
+
+                Gl(dx, rzldb2, alpha=1.0, beta=1.0)
+                rzldb2 -= misc.ihad(duzl, misc.had(dli,dli))
+                print "    norm(rzldb2) = %e" %blas.nrm2(rzldb2)
+
+                Gs(dx, rzsdb2, alpha=1.0, beta=1.0)
+                misc.cngrnc(r, duzs, duzs, trans='T')
+                misc.cngrnc(r, duzs, rzsdb2, alpha=-1.0, beta=1.0)
+                print "    norm(rzsdb2) = %e\n" %misc.snrm2(rzsdb2)
+
+            dtau[0] = dgi * ( dtau[0] + xdot(c,dx) + ydot(b,dy) + 
+                blas.dot(thl, dzl) + misc.sdot(ths, dzs) ) / \
+                ( 1.0 + blas.dot(dzl1, dzl1) + misc.sdot(dzs1, dzs1) )
+            xaxpy(dx1, dx, alpha=dtau[0])
+            yaxpy(dy1, dy, alpha=dtau[0])
+            blas.axpy(dzl1, dzl, alpha=dtau[0])
+            misc.saxpy(dzs1, dzs, alpha=dtau[0])
+ 
+            # dsl := dsl - dzl = -rhsl ./ lmbdl - dtzl
+            blas.axpy(dzl, dsl, alpha=-1)
+
+            # dss := dss - dzs = -rhss ./ Gamma - dzs
+            misc.saxpy(dzs, dss, alpha=-1)
+
+            dkappa[0] -= dtau[0]
+
+            if DEBUG: 
+                print "solvenewton errors"
+
+                # unscaled variables
+                duzl = misc.had(dzl, dli)
+                dusl = misc.ihad(dsl, dli)
+                duzs = [ +z_k for z_k in dzs ]
+                misc.cngrnc(rti, duzs, duzs)
+                duss = [ +s_k for s_k in dss ]
+                misc.cngrnc(r, duss, duss)
+                dutau = dtau[0] * dgi
+                dukappa = dkappa[0] / dgi
+
+                print "    norm(rsldb) = %e" %blas.nrm2(rsldb + 
+                    misc.had(lmbda[:ml], dzl+dsl))
+
+                for k in xrange(len(ms)):
+                    for j in xrange(ms[k]):
+                        rssdb[k][j,j+1:] = rssdb[k][j+1:,j].trans() 
+                    rssdb[k] += misc.had(dzs[k] + dss[k], gamma[k])
+                print "    norm(rssdb) = %e" %misc.snrm2(rssdb)
+
+                print "    abs(rtdb) = %e" %abs(rtdb + dukappa + 
+                    xdot(c,dx) + ydot(b,dy) + blas.dot(hl,duzl) + 
+                    misc.sdot(hs,duzs))
+
+                A(dy, rxdb, alpha=-1.0, beta=1.0, trans='T')
+                Gl(duzl, rxdb, alpha=-1.0, beta=1.0, trans='T')
+                Gs(duzs, rxdb, alpha=-1.0, beta=1.0, trans='T')
+                xaxpy(c, rxdb, alpha=-dutau)
+                print "    norm(rxdb) = %e" %math.sqrt(xdot(rxdb,rxdb))
+
+                A(dx, rydb, alpha=1.0, beta=1.0)
+                yaxpy(b, rydb, alpha=-dutau) 
+                print "    norm(rydb) = %e" %math.sqrt(ydot(rydb,rydb))
+
+                rzldb += dusl - hl*dutau
+                Gl(dx, rzldb, alpha=1.0, beta=1.0)
+                print "    norm(rzldb) = %e" %blas.nrm2(rzldb)
+
+                misc.saxpy(duss, rzsdb)
+                misc.saxpy(hs, rzsdb, alpha=-dutau)
+                Gs(dx, rzsdb, alpha=1.0, beta=1.0)
+                print "    norm(rzsdb) = %e\n" %misc.snrm2(rzsdb)
+
+        if refinement:
+            def solve_newton(dx, dy, dzl, dzs, dtau, dsl, dss, dkappa):
+            
+                if DEBUG:  
+                    rxdb2 = xnewcopy(dx)    
+                    rydb2 = ynewcopy(dy)
+                    rzldb2 = +dzl
+                    rzsdb2 = [+dzs_k for dzs_k in dzs]
+                    rtdb2 = dtau[0]
+                    rsldb2 = +dsl
+                    rssdb2 = [+dss_k for dss_k in dss]
+                    rkdb2 = dkappa[0]
+
+                # copy righthand sides to dx2 etc
+                xcopy(dx, dx2)
+                ycopy(dy, dy2)
+                blas.copy(dzl, dzl2)
+                misc.scopy(dzs, dzs2)
+                dtau2[0] = dtau[0]
+                blas.copy(dsl, dsl2)
+                misc.scopy(dss, dss2)
+                dkappa2[0] = dkappa[0]
+ 
+                solve_newton1(dx, dy, dzl, dzs, dtau, dsl, dss, dkappa)
+
+                # store residuals in dx2, dy2, etc
+                #
+                #    [0     ]   [ 0  A'  Gl'  Gs'  c ] [dx  ]   [rhsx  ]
+                #    [0     ]   [-A  0   0    0    b ] [dy  ]   [rhsy  ]
+                #    [dsl   ] - [-Gl 0   0    0    hl] [dzl ] + [rhszl ]
+                #    [dss   ]   [-Gs 0   0    0    hs] [dzs ]   [rhszs ]
+                #    [dkappa]   [-c' -b' -hl' -hs' 0 ] [dtau]   [rhstau]
+                # 
+                #    sl.*dzl + zl.*dsl + rhssl
+                #    Hc(dzs*ss + zs*dss) + rhsss
+                #    kappa*dtau + tau*dkappa + rhskappa
+                #
+                # Last 3 equations with scaled variables:
+                # 
+                #    lmbdl .* (dzl + dsl) + rhssl
+                #    0.5 * (diag(lmbds)*dzs + dzs*diag(lmbds) + 
+                #        diag(lmbds)*dss + dss*diag(lmbds)) + rhsss
+                #    lmbdg * (dtau + dkappa) + rhskappa.
+ 
+                # Store unscaled steps in sl, zl, ss, zs.
+                blas.copy(dzl, zl)
+                misc.had2(zl, dli)
+                blas.copy(dsl, sl)
+                misc.ihad2(sl, dli)
+                misc.scopy(dzs, zs)
+                misc.cngrnc(rti, zs, zs)
+                misc.scopy(dss, ss)
+                misc.cngrnc(r, ss, ss)
+                dutau = dtau[0] * dgi
+                dukappa = dkappa[0] / dgi
+
+                A(dy, dx2, alpha=-1.0, beta=1.0, trans='T')
+                Gl(zl, dx2, alpha=-1.0, beta=1.0, trans='T')
+                Gs(zs, dx2, alpha=-1.0, beta=1.0, trans='T')
+                xaxpy(c, dx2, alpha=-dutau)
+
+                A(dx, dy2, alpha=1.0, beta=1.0)
+                yaxpy(b, dy2, alpha=-dutau)
+
+                Gl(dx, dzl2, alpha=1.0, beta=1.0)
+                blas.axpy(hl, dzl2, alpha=-dutau)
+                blas.axpy(sl, dzl2)
+
+                Gs(dx, dzs2, alpha=1.0, beta=1.0) 
+                misc.saxpy(hs, dzs2, alpha=-dutau)
+                misc.saxpy(ss, dzs2)
+
+                dtau2[0] += dukappa + xdot(c,dx) + ydot(b,dy) + \
+                    blas.dot(hl, zl) + misc.sdot(hs, zs)
+
+                dsl2[:] += misc.had(dzl+dsl, lmbda[:ml]) 
+
+                for k in xrange(len(ms)):
+                    dss2[k] += misc.had(dzs[k]+dss[k], gamma[k])
+
+                dkappa2[0] += lmbda[-1] * (dtau[0] + dkappa[0])
+
+                solve_newton1(dx2, dy2, dzl2, dzs2, dtau2, dsl2, dss2, 
+                    dkappa2)
+
+                xaxpy(dx2, dx)
+                yaxpy(dy2, dy)
+                blas.axpy(dzl2, dzl)
+                misc.saxpy(dzs2, dzs)
+                dtau[0] += dtau2[0]
+                blas.axpy(dsl2, dsl)
+                misc.saxpy(dss2, dss)
+                dkappa[0] += dkappa2[0]
+
+                if DEBUG: 
+                    print "solvenewton2 errors"
+
+                    # unscaled variables
+                    duzl = misc.had(dzl, dli)
+                    dusl = misc.ihad(dsl, dli)
+                    duzs = [ +z_k for z_k in dzs ]
+                    misc.cngrnc(rti, duzs, duzs)
+                    duss = [ +s_k for s_k in dss ]
+                    misc.cngrnc(r, duss, duss)
+                    dutau = dtau[0]*dgi
+                    dukappa = dkappa[0]/dgi
+
+                    print "    norm(rsldb2) = %e" %blas.nrm2(rsldb2 + 
+                        misc.had(lmbda[:ml],dzl+dsl))
+
+                    for k in xrange(len(ms)):
+                        for j in xrange(ms[k]): rssdb2[k][j,j+1:] = \
+                            rssdb2[k][j+1:,j].trans()
+                        rssdb2[k] += misc.had(dzs[k] + dss[k], gamma[k])
+                    print "    norm(rssdb2) = %e" %misc.snrm2(rssdb2)
+
+                    print "    abs(rtdb2) = %e" %abs(rtdb2 + dukappa 
+                        + xdot(c,dx) + ydot(b,dy) + blas.dot(hl,duzl) 
+                        + misc.sdot(hs,duzs))
+
+                    A(dy, rxdb2, alpha=-1.0, beta=1.0, trans='T')
+                    Gl(duzl, rxdb2, alpha=-1.0, beta=1.0, trans='T')
+                    Gs(duzs, rxdb2, alpha=-1.0, beta=1.0, trans='T')
+                    xaxpy(c, rxdb2, alpha=-dutau)
+                    print "    norm(rxdb2) = %e" \
+                        %math.sqrt(xdot(rxdb2,rxdb2))
+
+                    A(dx, rydb2, alpha=1.0, beta=1.0)
+                    yaxpy(b, rydb2, alpha=-dutau) 
+                    print "    norm(rydb2) = %e" \
+                        %math.sqrt(ydot(rydb2,rydb2))
+                    rzldb2 += dusl - hl*dutau
+                    Gl(dx, rzldb2, alpha=1.0, beta=1.0)
+                    print "    norm(rzldb2) = %e" %blas.nrm2(rzldb2)
+
+                    misc.saxpy(duss, rzsdb2)
+                    misc.saxpy(hs, rzsdb2, alpha=-dutau)
+                    Gs(dx, rzsdb2, alpha=1.0, beta=1.0)
+                    print "    norm(rzsdb2) = %e\n" %misc.snrm2(rzsdb2)
+
+        else:
+            solve_newton = solve_newton1
+
+        mu = blas.dot(lmbda,lmbda) / (m+1)
+
+        # Affine scaling step 
+        blas.copy(lmbda, dsl, n=ml)        
+        misc.had2(dsl,lmbda, n=ml)        
+        misc.sscal(0.0, dss) 
+        ind = ml
+        for e, mk in zip(dss, ms):
+             blas.copy(lmbda, e, n=mk, offsetx=ind, incy=mk+1)
+             blas.tbmv(lmbda, e, n=mk, k=0, ldA=1, offsetA=ind, 
+                 incx=mk+1)
+             ind += mk
+        dkappa[0] = kappa*tau
+        xcopy(resx, dx)
+        ycopy(resy, dy)
+        blas.copy(reszl, dzl)
+        misc.scopy(reszs, dzs)
+        dtau[0] = rest
+        solve_newton(dx, dy, dzl, dzs, dtau, dsl, dss, dkappa)
+
+        # Maximum step to boundary
+        blas.copy(dzl, sigz)
+        misc.ihad2(sigz, lmbda, n=ml) 
+        blas.copy(dsl, sigs)
+        misc.ihad2(sigs, lmbda, n=ml) 
+        misc.scopy(dss, ss)
+        misc.scopy(dzs, zs)
+        ind = ml
+        for k in xrange(len(ms)):
+            for i in xrange(ms[k]):
+                a = 1.0 / math.sqrt(lmbda[ind+i])
+                blas.scal(a, ss[k], offset=i, n=i+1, inc=ms[k])
+                blas.scal(a, ss[k], offset=i*ms[k]+i, n=ms[k]-i)
+                blas.scal(a, zs[k], offset=i, n=i+1, inc=ms[k])
+                blas.scal(a, zs[k], offset=i*ms[k]+i, n=ms[k]-i)
+            lapack.syevd(ss[k], sigs, offsetW=ind, jobz='V')  
+            lapack.syevd(zs[k], sigz, offsetW=ind, jobz='V')  
+            ind += ms[k]
+        sigz[-1], sigs[-1] = dtau[0]/lmbda[-1], dkappa[0]/lmbda[-1]
+        step = min(1.0, STEP / max(-min(sigz), -min(sigs))) 
+
+        newmu = ( (1-step) * blas.dot(lmbda,lmbda) + step**2 * 
+            (blas.dot(dsl, dzl) + misc.sdot(dss, dzs) + 
+            dkappa[0]*dtau[0]) ) / ( m+1)
+        sigma = min(1.0, (newmu/mu)**EXPON)
+
+        # Centering-corrector step
+        misc.had2(dsl, dzl)
+        blas.axpy(misc.had(lmbda[:ml], lmbda[:ml]), dsl)
+        blas.axpy(ones, dsl, alpha=-sigma*mu, n=ml)
+        ind = ml
+	for k in xrange(len(ms)):
+            # work := dss[k] with upper triangular part
+            for i in xrange(ms[k]-1):
+                dss[k][i,i+1:] = dss[k][i+1:,i].trans()
+                dzs[k][i,i+1:] = dzs[k][i+1:,i].trans()
+            blas.copy(dss[k], work)
+
+            # dss[k] := 0.5 * (work*dzs[k] + dzs[k]*work)
+            #     = 0.5 * (dss[k]*dzs[k] + dzs[k]*dss[k])
+            blas.syr2k(work, dzs[k], dss[k], n=ms[k], k=ms[k], 
+                ldA=ms[k], alpha=0.5)
+
+            # dss[k] := dss[k] + diag(lambda)^2 - sigma*mu*I
+            blas.copy(lmbda, work, n=ms[k], offsetx=ind)
+            blas.tbmv(lmbda, work, n=ms[k], k=0, ldA=1, offsetA=ind)
+            blas.axpy(work, dss[k], incy=ms[k]+1, n=ms[k])
+            blas.axpy(ones, dss[k], alpha=-sigma*mu, incy=ms[k]+1, 
+                n=ms[k])
+
+            ind += ms[k]
+
+        dkappa[0] = lmbda[-1]**2 + dkappa[0]*dtau[0] - sigma*mu
+        xcopy(resx, dx);  xscal(1.0-sigma, dx)
+        ycopy(resy,dy);  yscal(1.0-sigma, dy)
+        blas.copy(reszl, dzl);  blas.scal(1.0-sigma, dzl)
+        misc.scopy(reszs, dzs); misc.sscal(1.0-sigma, dzs)
+        dtau[0] = (1.0-sigma)*rest 
+        solve_newton(dx, dy, dzl, dzs, dtau, dsl, dss, dkappa)
+
+        # Maximum step to boundary
+        blas.copy(dzl, sigz)
+        misc.ihad2(sigz, lmbda, n=ml) 
+        blas.copy(dsl, sigs)
+        misc.ihad2(sigs, lmbda, n=ml) 
+        ind = ml
+        for k in xrange(len(ms)):
+            for i in xrange(ms[k]):
+                a = 1.0 / math.sqrt(lmbda[ind+i])
+                blas.scal(a, dss[k], offset=i, n=i+1, inc=ms[k])
+                blas.scal(a, dss[k], offset=i*(ms[k]+1), n=ms[k]-i)
+                blas.scal(a, dzs[k], offset=i, n=i+1, inc=ms[k])
+                blas.scal(a, dzs[k], offset=i*(ms[k]+1), n=ms[k]-i)
+            lapack.syevd(dss[k], sigs, offsetW=ind, jobz='V')  
+            lapack.syevd(dzs[k], sigz, offsetW=ind, jobz='V')  
+            ind += ms[k]
+        sigz[-1], sigs[-1] = dtau[0]/lmbda[-1], dkappa[0]/lmbda[-1]
+        step = min(1.0, STEP / max(-min(sigz), -min(sigs))) 
+
+        # Update lmbdl, dli
+        dli = misc.ihad(dli, base.sqrt(misc.ihad(lmbda[:ml] + step*dsl, 
+            lmbda[:ml] + step*dzl)))
+        lmbda[:ml] = base.sqrt(misc.had(lmbda[:ml]+step*dsl, 
+            lmbda[:ml]+step*dzl))
+
+        dgi = dgi * math.sqrt( (lmbda[-1] + step*dtau[0]) / 
+            (lmbda[-1] + step*dkappa[0]) )
+        lmbda[-1] =  math.sqrt( (lmbda[-1] + step*dtau[0]) *  
+            (lmbda[-1] + step*dkappa[0]) )  
+
+        # Update scaling matrices, lmbdas, gamma.
+        ind = ml
+        for k in xrange(len(ms)):
+            for i in xrange(ms[k]):
+                # dss[k] := L1 
+                #     = lmbdas[k]^{1/2} * dss[k] * (1+step*sigs)^{1/2}
+                # dzs[k] := L2 
+                #     = lmbdas[k]^{1/2} * dzs[k] * (1+step*sigz)^{1/2}
+                a = math.sqrt(lmbda[ind+i]) 
+                blas.scal(a, dss[k], offset=i, inc=ms[k], n=ms[k])
+                blas.scal(a, dzs[k], offset=i, inc=ms[k], n=ms[k])
+                blas.scal(math.sqrt(1+step*sigs[ind+i]), dss[k], 
+                    offset=ms[k]*i, n=ms[k])
+                blas.scal(math.sqrt(1+step*sigz[ind+i]), dzs[k], 
+                    offset=ms[k]*i, n=ms[k])
+
+            # r[k] := r[k]*dss[k] = r[k]*L1[k]
+            # rti[k] := rti[k]*dzs[k] = rti[k]*L2[k]
+            blas.gemm(r[k], dss[k], work, ldC=ms[k])
+            blas.copy(work, r[k], n=ms[k]**2)
+            blas.gemm(rti[k], dzs[k], work, ldC=ms[k])
+            blas.copy(work, rti[k], n=ms[k]**2)
+
+            # SVD of L2'*L1 = U*lmbds^+*V', store U in dss[k] and V' in
+            # dzs[k]
+            blas.gemm(dzs[k], dss[k], work, transA='T', ldC=ms[k])
+            lapack.gesvd(work, lmbda, jobu='A', jobvt='A', m=ms[k],
+                n=ms[k], ldA=ms[k], U=dss[k], Vt=dzs[k], offsetS=ind)
+
+            # r[k] := r[k]*V,  rti[k] := rti[k]*U
+            blas.gemm(r[k], dzs[k], work, transB='T', ldC=ms[k])
+            blas.copy(work, r[k], n=ms[k]**2)
+            blas.gemm(rti[k], dss[k], work, ldC=ms[k])
+            blas.copy(work, rti[k], n=ms[k]**2)
+
+            # r[k] := r[k]*lambda^{-1/2}; rti[k] := rti[k]*lambda^{-1/2}
+            for i in xrange(ms[k]):    
+                a = 1.0 / math.sqrt(lmbda[ind+i])
+                blas.scal(a, r[k], offset=ms[k]*i, n=ms[k])
+                blas.scal(a, rti[k], offset=ms[k]*i, n=ms[k])
+
+            # gamma[k][i,j] = .5 * (lambda_i + lambda_j)
+            # Use blas.ger to make sure there are no zeros or nan's in 
+            # upper triangular part.
+
+            blas.scal(0.0, gamma[k])
+            blas.ger(lmbda, ones, gamma[k], alpha=.5, offsetx=ind)
+            blas.ger(ones, lmbda, gamma[k], alpha=.5, offsety=ind)
+
+            ind += ms[k]
+
+
+        # Compute new sl, zl, ss, zs, tau, kappa (used to evaluate the
+        # residuals).
+
+        # sl := lmbdl ./ dli  
+        blas.copy(lmbda, sl, n=ml)
+        misc.ihad2(sl, dli) 
+
+        # zl = lmbdl .* dli
+        blas.copy(lmbda, zl, n=ml)
+        misc.had2(zl, dli)
+
+        kappa, tau = lmbda[-1]/dgi, lmbda[-1]*dgi
+
+        # ss = r*lambda*r',  zs = rti*lambda*rti'
+        ind = ml
+        for k in xrange(len(ms)):
+            blas.copy(r[k], work)
+            blas.copy(rti[k], work2)
+            for i in xrange(ms[k]):
+                a = math.sqrt(lmbda[ind+i])
+                blas.scal(a, work, offset=ms[k]*i, n=ms[k])
+                blas.scal(a, work2, offset=ms[k]*i, n=ms[k])
+            blas.syrk(work, ss[k], ldA=ms[k], n=ms[k], k=ms[k])
+            blas.syrk(work2, zs[k], ldA=ms[k], n=ms[k], k=ms[k])
+            ind += ms[k]
+
+        xaxpy(dx, x, alpha=step)
+        yaxpy(dy, y, alpha=step)
+
+        gap = blas.dot(lmbda, lmbda, n=m-1) / tau**2
+
+
+    return {'status': 'unknown', 'x': None, 'y': None, 'sl': None, 
+        'ss': None, 'zl': None, 'zs': None}
+
+
+
+def lp(c, G, h, A=None, b=None, solver=None, primalstart=None,
+    dualstart=None):
+    """
+
+    Solves a pair of primal and dual LPs
+
+        minimize    c'*x             maximize    -h'*z - b'*y 
+        subject to  G*x + s = h      subject to  G'*z + A'*y + c = 0
+                    A*x = b                      z >= 0
+                    s >= 0
+
+    Input arguments:
+
+        G is mxn, h is mx1, A is pxn, b is px1.  G and A must be dense
+        or sparse 'd' matrices.   h and b are dense 'd' matrices with 
+        one column.  The default values for A and b are empty matrices 
+        with zero rows.
+
+        solver is None, 'glpk' or 'mosek'.  The default solver (None)
+        uses an LP solver implemented in Python.  The 'glpk' solver is 
+        the simplex LP solver from GLPK.  The 'mosek' solver is the LP 
+        solver from MOSEK.
+
+        The arguments primalstart and dualstart are ignored when solver
+        is 'glpk' or 'mosek' and are optional when solver is None.  
+        The argument primalstart is a dictionary with keys 'x' and 's'
+        and specifies a primal starting point.  primalstart['x'] must 
+        be a dense 'd' matrix of length n;  primalstart['s'] must be a 
+        positive dense 'd' matrix of length m.
+        The argument dualstart is a dictionary with keys 'z' and 'y' 
+        and specifies a dual starting point.   dualstart['y'] must 
+        be a dense 'd' matrix of length p;  dualstart['z'] must be a 
+        positive dense 'd' matrix of length m.
+
+        When solver is None, we require n >= 1, Rank(A) = p and 
+        Rank([G; A]) = n
+
+
+    Returns a dictionary with keys 'status', 'x', 's', 'y', 'z'.
+
+        If solver is None or 'mosek':
+        
+            If status is 'optimal', x, s, y, z are the primal and dual 
+            optimal solutions.
+
+            If status is 'primal infeasible', x = s = None, and z, y 
+            are a proof of infeasibility: 
+
+                h'*z + b'*y = -1,  G'*z + A'*y = 0,  z >= 0.
+
+            If status is 'dual infeasible', z = y = None, and x, s are 
+            a proof of dual infeasibility: 
+
+                c'*x = -1,  G*x + s = 0,  A*x = 0,  s >= 0.
+
+            If status is 'unknown', x, y, s, z are None.
+
+
+        If solver is 'glpk':
+        
+            If status is 'optimal', x, s, y, z are the primal and dual 
+            optimal solutions.
+
+            If status is 'primal infeasible', 'dual infeasible',
+            or 'unknown', then x = s = z = y = None.
+
+
+    The control parameters for the different solvers can be modified by 
+    adding an entry to the dictionary cvxopt.solvers.options.  The 
+    following parameters control the execution of the default solver.
+
+        options['show_progress'] True/False (default: True)
+        options['maxiters'] positive integer (default: 100)
+        options['abstol'] scalar (default: 1e-7)
+        options['reltol'] scalar (default: 1e-7)
+        options['feastol'] scalar (default: 1e-7)
+        options['refinement'] True/False (default: True)
+
+    The control parameter names for GLPK and MOSEK can be found in the
+    GLPK and MOSEK documentation.  Options that are not recognized are 
+    replaced by their default values.
+    """
+
+    if type(c) is not matrix or c.typecode != 'd' or c.size[1] != 1: 
+        raise TypeError, "'c' must be a dense column matrix"
+    n = c.size[0]
+    if n < 1: raise ValueError, "number of variables must be at least 1"
+
+    if (type(G) is not matrix and type(G) is not spmatrix) or \
+        G.typecode != 'd' or G.size[1] != n:
+        raise TypeError, "'G' must be a dense or sparse 'd' matrix "\
+            "with %d columns" %n 
+    m = G.size[0]
+    if type(h) is not matrix or h.typecode != 'd' or h.size != (m,1):
+        raise TypeError, "'h' must be a 'd' matrix of size (%d,1)" %m
+
+    if A is None:  A = spmatrix([], [], [], (0,n), 'd')
+    if (type(A) is not matrix and type(A) is not spmatrix) or \
+        A.typecode != 'd' or A.size[1] != n:
+        raise TypeError, "'A' must be a dense or sparse 'd' matrix "\
+            "with %d columns" %n
+    p = A.size[0]
+    if b is None: b = matrix(0.0, (0,1))
+    if type(b) is not matrix or b.typecode != 'd' or b.size != (p,1): 
+        raise TypeError, "'b' must be a dense matrix of size (%d,1)" %p
+
+    if solver == 'glpk':
+        try: from cvxopt import glpk
+        except ImportError: raise ValueError, "invalid option "\
+            "(solver='glpk'): cvxopt.glpk is not installed" 
+        glpk.options = options
+        status, x, z, y = glpk.solvelp(c,G,h,A,b)
+        if status == 'optimal':
+            s = matrix(h)
+            base.gemv(G, x, s, alpha=-1.0, beta=1.0)
+        else:
+            s = None
+        return {'status': status, 'x': x, 's': s, 'y': y, 'z': z}
+
+    if solver == 'mosek':
+        try: from cvxopt import mosek
+        except ImportError: raise ValueError, "invalid option "\
+            "(solver='mosek'): cvxopt.mosek is not installed" 
+        mosek.options = options
+        prosta, solsta, x, z, y  = mosek.solvelp(c,G,h,A,b)
+        if solsta == 'OPTIMAL':
+            s = matrix(h)
+            base.gemv(G, x, s, alpha=-1.0, beta=1.0)
+            status = 'optimal'
+        elif solsta == 'PRIMAL_INFEASIBLE_CER':
+            status = 'primal infeasible'
+            ducost = -blas.dot(h,z) - blas.dot(b,y)
+            blas.scal(1.0/ducost, y)
+            blas.scal(1.0/ducost, z)
+            x, s = None, None
+        elif solsta == 'DUAL_INFEASIBLE_CER':
+            status = 'dual infeasible'
+            pcost = blas.dot(c,x)
+            blas.scal(-1.0/pcost, x)
+            s = matrix(0.0, (m,1))
+            base.gemv(G, x, s, alpha=-1.0)
+            z, y = None, None
+        else: 
+            status = 'unknown'
+            x, s, y, z = None, None, None, None
+        return {'status': status, 'x': x, 's': s, 'y': y, 'z': z}
+
+    if p > n or n-p > m:
+        raise ValueError, "Rank(A) < p or Rank([G; A]) < n"
+
+    def Fi(x, y, alpha=1.0, beta=0.0, trans='N'):
+        base.gemv(G, x, y, alpha=alpha, beta=beta, trans=trans)
+
+    def Fe(x, y, alpha=1.0, beta=0.0, trans='N'):
+        base.gemv(A, x, y, alpha=alpha, beta=beta, trans=trans)
+
+    def Fs(x, y, alpha=1.0, beta=0.0, trans='N'): 
+        pass
+    
+
+    # kktsolver(di, rti) returns a function for solving 
+    #
+    #    [ 0  A'  G'             ] [x]   [bx]
+    #    [ A  0   0              ] [y] = [by].
+    #    [ G  0   -diag(di)^{-2} ] [z]   [bz]
+    #
+    # di is a positive mx1 'd' matrix;  the argument rti is ignored. 
+    #
+    # We return the scaled z: z./di instead of z.
+
+    global kktmethod
+    try: kktmethod = options['kktmethod']
+    except KeyError: kktmethod = 3
+    else: 
+        if type(kktmethod) is not int or kktmethod not in [1,2,3]:
+            raise ValueError, "options['kktmethod'] must be 1, 2, or 3"
+
+    if kktmethod == 1:
+
+        # The entire matrix is factored using a dense LDL factorization.
+
+        K = matrix(0.0, (n+p+m,n+p+m))
+        ipiv = matrix(0, (n+p+m,1))
+        u = matrix(0.0, (n+p+m,1))
+        def kktsolver(di, rti):
+            blas.scal(0, K)
+            K[n:n+p,:n],  K[n+p:,:n] = A, G  
+            K[(m+p+n+1)*(p+n)::n+m+p+1] = -misc.ihad(1.0, 
+                misc.had(di, di))
+            lapack.sytrf(K, ipiv)
+            def solve_kkt(x, y, z, zs):
+		blas.copy(x, u)
+		blas.copy(y, u, offsety=n)
+		blas.copy(z, u, offsety=n+p)
+		lapack.sytrs(K, ipiv, u)
+		blas.copy(u, x, n=n)
+		blas.copy(u, y, offsetx=n, n=p)
+		blas.copy(u, z, offsetx=n+p, n=m)
+                misc.ihad2(z, di)
+            return solve_kkt
+
+    else:
+        if type(G) is matrix: 
+            Gsc = matrix(0.0, (m,n)) 
+        else:
+            Gsc = spmatrix(0.0, G.I, G.J, (m,n)) 
+
+        def GDG(Gsc, S, di, pattern_S_is_correct=True):  
+
+            # Compute 
+            #
+            #    Gsc := diag(di)*G and 
+            #    S[:n,:n] := G' * diag(di)^2 * G.
+            #
+            # If G is dense, Gsc and S must be dense.  If G is sparse, 
+            # Gsc is sparse and S may be dense or sparse.
+
+            base.gemm(spmatrix(di, range(m), range(m), tc='d'), G, 
+                Gsc, partial=True)
+            base.syrk(Gsc, S, trans='T', partial=pattern_S_is_correct)
+
+        if kktmethod == 2:
+
+            # We compute x, y, z by solving
+            #
+            #    [G'*diag(di)^2*G  A'] [x]   [bx + G'*(di.^2).*bz)]
+            #    [                   ]*[ ] = [                    ]
+            #    [A                0 ] [y]   [by                  ]
+            #
+            #    z = (di.^2) .* (G*x - bz).
+            #    
+            # We return the scaled z:  z = di .* (G*x - bz).
+            #
+            # The coefficient matrix is factored using a dense LDL 
+            # (if p>0) or dense Cholesky factorization (if p=0).  
+
+            K = matrix(0.0, (n+p,n+p))
+            if p: ipiv = matrix(0, (n+p,1))
+            u = matrix(0.0, (n+p,1))
+            def kktsolver(di, rti):
+                blas.scal(0.0, K)
+                K[n:,:n] = A
+                GDG(Gsc, K, di)
+                if p: lapack.sytrf(K, ipiv)
+                else: lapack.potrf(K)
+                def solve_kkt(x, y, z, zs):
+                    blas.copy(x, u)
+                    blas.copy(y, u, offsety=n)
+                    misc.had2(z, di)
+                    base.gemv(Gsc, z, u, trans='T', beta=1.0)
+                    if p: lapack.sytrs(K, ipiv, u)
+                    else: lapack.potrs(K, u)
+                    blas.copy(u, x, n=n)
+                    blas.copy(u, y, n=p, offsetx=n)
+                    base.gemv(Gsc, x, z, beta=-1.0)
+                return solve_kkt
+
+        else:
+
+            # Solve 
+            #
+            #    K*y = A * S^{-1} * (bx + G'*((di.^2).*bz)) - by
+            #    S*x = bx + G'*((di.^2).*bz) - A'*y
+            #    z = (di.^2) .* (G*x - bz).
+            #
+            # where K = A*S^{-1}*A', S = G'*diag(di)^2*G.
+            #
+            # If in the first call to kktsolver, S is singular, switch
+            # to kktmethod 4, i.e., solve
+            #
+            #    K*y = A * S^{-1} * (bx + G'*((di.^2).*bz) + A'*by) - by
+            #    S*x = bx + G'*((di.^2).*bz) + A'*by - A'*y
+            #    z = (di.^2) .* (G*x - bz).
+            #
+            # where K = A'*S^{-1}*A, S = G'*diag(di)^2*G + A'*A
+            # 
+            # The matrices K and S are factored using dense or sparse 
+            # Cholesky factorizations.
+            #
+            # We return the scaled z:  z = di .* (G*x - bz).
+
+            global S, Sf, firstcall
+            firstcall = True
+
+            if type(G) is matrix:
+                S = matrix(0.0, (n,n))
+                K = matrix(0.0, (p,p))
+            else:
+                S = spmatrix([], [], [], (n,n), 'd')
+                if type(A) is matrix: K = matrix(0.0, (p,p))
+                else: K = spmatrix([], [], [], (p,p), tc='d')
+
+            def factorS(di,S):
+
+                # Factor S = G'*diag(di)^2*G if kktmethod = 3.
+                # Factor S = G'*diag(di)^2*G + A'*A if kktmethod = 4.
+                # If S is sparse, store factorization in Sf.
+
+                global Sf
+                GDG(Gsc, S, di, not firstcall)
+                if kktmethod == 4:
+                    base.syrk(A, S, trans='T', beta=1.0, partial=not
+                        firstcall) 
+                if type(S) is matrix:
+                    lapack.potrf(S) 
+                else:
+                    if firstcall: Sf = cholmod.symbolic(S)
+                    cholmod.numeric(S, Sf)
+
+            def kktsolver(di, rti):
+                global firstcall, kktmethod, S
+                if kktmethod == 3:
+                    try: factorS(di,S)
+                    except ArithmeticError:
+                        if firstcall:
+                            kktmethod = 4
+                            if type(S) is spmatrix and type(A) is \
+                                matrix: S = matrix(0.0, (n,n))
+                            factorS(di,S)
+                        else: raise ArithmeticError
+                else: 
+                    factorS(di,S)
+                firstcall = False
+
+                if type(S) is matrix:
+                    # Asct := L^{-1}*A',  factor K = Asct'*Asct
+                    if type(A) is matrix:
+                        Asct = A.trans()
+                    else:
+                        Asct = matrix(A.trans())
+                    blas.trsm(S, Asct)
+                    blas.syrk(Asct, K, trans='T')
+                    lapack.potrf(K)
+
+                else:
+                    # Asct := L^{-1}*P*A' and factor K = Asct'*Asct.
+                    if type(A) is matrix:
+                        Asct = A.trans()
+                        cholmod.solve(Sf, Asct, sys=7)
+                        cholmod.solve(Sf, Asct, sys=4)
+                        blas.syrk(Asct, K, trans='T')
+                        lapack.potrf(K) 
+                    else:
+                        Asct = cholmod.spsolve(Sf, A.trans(), sys=7)
+                        Asct = cholmod.spsolve(Sf, Asct, sys=4)
+                        base.syrk(Asct, K, trans='T')
+                        Kf = cholmod.symbolic(K)
+                        cholmod.numeric(K, Kf)
+
+                def solve_kkt(x, y, z, zs):
+
+                    # If kktmethod is 3:
+                    # x := L^{-1}*P * (x + G'*((di.^2).*z)) 
+                    #    = L^{-1}*P * (bx + G'*((di.^2).*bz))
+                    #
+                    # If kktmethod is 4:
+                    # x := L^{-1}*P * (x + G'*((di.^2).*z) + A'*y)
+                    #    = L^{-1}*P * (bx + G'*((di.^2).*bz) + A'*by)
+                    misc.had2(z, di)
+                    base.gemv(Gsc, z, x, trans='T', beta=1.0)
+                    if kktmethod == 4:
+                        base.gemv(A, y, x, trans='T', beta=1.0)
+                    if type(S) is matrix:
+                        blas.trsv(S, x)
+                    else:
+                        cholmod.solve(Sf, x, sys=7)
+                        cholmod.solve(Sf, x, sys=4)
+
+		    # y := K^{-1} * (Asc*x - y)
+                    #    = K^{-1} * (A*S^{-1}* (bx + G'*((di.^2).*bz)) 
+                    #      - by)  (kktmethod = 3)
+                    #    = K^{-1} * (A*S^{-1}* (bx + G'*((di.^2).*bz))
+                    #      + A'*by) - by) (kktmethod = 4)
+		    base.gemv(Asct, x, y, trans='T', beta=-1.0)
+		    if type(K) is matrix:
+                        lapack.potrs(K, y)
+                    else:
+                        cholmod.solve(Kf, y)
+
+                    # x := P' * L^{-T} * (x - Asc'*y)
+                    #    = S^{-1}* (bx + G'*((di.^2).*bz) - A'*y)
+                    #      (kktmethod = 3)  
+                    #    = S^{-1}*(bx + G'*((di.^2).*bz) + A'*by - 
+                    #      A'*y) (kktmethod = 4)
+		    base.gemv(Asct, y, x, alpha=-1.0, beta=1.0)
+                    if type(S) is matrix:
+                        blas.trsv(S, x, trans='T')
+                    else:
+                        cholmod.solve(Sf, x, sys=5)
+                        cholmod.solve(Sf, x, sys=8)
+
+		    # z := Gsc*x - z = di .* (G*x - bz)
+                    base.gemv(Gsc, x, z, beta=-1.0)
+
+                return solve_kkt 
+
+    if primalstart:
+        pst = {'x': primalstart['x'], 'sl': primalstart['s'], 'ss': []}
+    else: 
+        pst = None
+    if dualstart:
+        dst = {'y': dualstart['y'], 'zl': dualstart['z'], 'zs': []}
+    else: 
+        dst = None
+    sol = conelp(c, kktsolver, Gl=Fi, hl=h, A=Fe, b=b, primalstart=pst,
+        dualstart=dst)
+    return {'status': sol['status'], 'x': sol['x'], 'y': sol['y'],
+         'z': sol['zl'], 's': sol['sl']}
+
+
+
+def sdp(c, Gl=None, hl=None, Gs=None, hs=None, A=None, b=None, 
+    solver=None, primalstart=None, dualstart=None):
+    """
+
+    Solves a pair of primal and dual SDPs
+
+        minimize    c'*x             
+        subject to  Gl*x + sl = hl      
+                    Gs(x) + ss = hs
+                    A*x = b                      
+                    sl >= 0,  ss >= 0
+
+        maximize    -hl'*z - tr(hs,zs) - b'*y
+        subject to  Gl'*zl + Gs'(zs) + A'*y + c = 0
+                    zl >= 0,  zs >= 0
+
+    Input arguments:
+
+        Gl is an mlxn dense or sparse 'd' matrix.  
+        hl is an mlx1 dense 'd' matrix.  The default values of Gl and 
+        hl are matrices with zero rows.
+
+        The argument Gs is a list of N dense or sparse 'd' matrices of 
+        size (ms[k]**2, n), k=1,...,N. 
+        The matrix-vector products Gs[k]*x, k=1,...,N, represent a 
+        block-diagonal symmetric matrix with N diagonal blocks of size 
+        (ms[k],ms[k]), stored columnwise as vectors.   
+        hs is a list of dense 'd' matrices of size (ms[k],ms[k]).  
+        Only the lower-triangular part of hs[k] is accessed.
+
+        A is a pxn dense or sparse 'd' matrix.
+        b is a px1 dense 'd' matrix.  The default values of A and b are 
+        matrices with zero rows.
+
+        solver is None or 'dsdp'.  The default solver (None) uses an 
+        SDP solver implemented in Python.  The 'dsdp' solver uses an
+        interface to DSDP5.  It does not accept problems with equality
+        constraints (A and b must have zero rows, or be absent).
+
+        The argument primalstart is a dictionary with keys 'x', 'sl',
+        'ss', and specifies a primal starting point.  primalstart['x'] 
+        must be a dense 'd' matrix of length n;  primalstart['sl'] must
+        be a positive dense 'd' matrix of length ml;  primalstart['ss']
+        must be a list of positive definite matrices of size 
+        ms[k]xms[k].
+        The argument dualstart is a dictionary with keys 'zl', 'zs', 
+        'y' and specifies a dual starting point.   primalstart['y'] 
+        must be a dense 'd' matrix of length p;  primalstart['zl'] 
+        must be a positive dense 'd' matrix of length ml;  
+        primalstart['zs'] must be a list of positive definite matrices 
+        of size (ms[k],ms[k]).
+        The arguments primalstart and dualstart are ignored when solver
+        is 'dsdp'.
+
+    Returns a dictionary with keys 'status', 'x', 'sl', 'ss', 'y', 'zl',
+        'zs'.
+
+        If status is 'optimal', x, sl, ss, y, zl, zs are the primal and
+        dual optimal solutions.
+
+        If status is 'primal infeasible', x = sl = ss = None, and zl, 
+        zs, y are a proof of infeasibility: 
+
+            hl'*zl + tr(hs,zs) + b'*y = -1,  
+            Gl'*zl + Gs'(zs) + A'*y = 0,  
+            zl >= 0, zs >= 0.
+
+        If status is 'dual infeasible', zl = zs = y = None, and x, sl, 
+        ss are a proof of dual infeasibility: 
+
+            c'*x = -1,  Gl*x + sl = 0,  Gs(x) + ss = 0,  A*x = 0,  
+            sl >= 0, ss >= 0.
+
+        If status is 'unknown', x, y, sl, ss, zl, zs are None.
+
+    The following parameters control the execution of the default 
+    solver.
+
+        options['show_progress'] True/False (default: True)
+        options['maxiters'] positive integer (default: 100)
+        options['abstol'] scalar (default: 1e-7)
+        options['reltol'] scalar (default: 1e-7)
+        options['feastol'] scalar (default: 1e-7)
+        options['refinement'] True/False (default: True).
+
+    The execution of the 'dsdp' solver is controlled by: 
+
+        options['show_progress'] integer (default: 0)
+        options['maxiters'] positive integer 
+        options['rgaptol'] scalar (default: 1e-5).
+    """
+
+    if type(c) is not matrix or c.typecode != 'd' or c.size[1] != 1: 
+        raise TypeError, "'c' must be a dense column matrix"
+    n = c.size[0]
+    if n < 1: raise ValueError, "number of variables must be at least 1"
+
+    if Gl is None: Gl = spmatrix([], [], [], (0,n), tc='d')
+    if (type(Gl) is not matrix and type(Gl) is not spmatrix) or \
+        Gl.typecode != 'd' or Gl.size[1] != n:
+        raise TypeError, "'Gl' must be a dense or sparse 'd' matrix "\
+            "with %d columns" %n 
+    ml = Gl.size[0]
+    if hl is None: hl = matrix(0.0, (0,1))
+    if type(hl) is not matrix or hl.typecode != 'd' or \
+        hl.size != (ml,1):
+        raise TypeError, "'hl' must be a 'd' matrix of size (%d,1)" %ml
+
+    if Gs is None: Gs = []
+    if type(Gs) is not list or [ Gs_k for Gs_k in Gs if (type(Gs_k) is 
+        not matrix and type(Gs_k) is not spmatrix) or 
+        Gs_k.typecode != 'd' or Gs_k.size[1] != n ]:
+        raise TypeError, "'Gs' must be a list of sparse or dense 'd' "\
+            "matrices with %d columns" %n 
+    ms = [ int(math.sqrt(Gs_k.size[0])) for Gs_k in Gs ]
+    maxm, N = max([0] + ms), len(ms)
+    a = [ k for k in xrange(len(Gs)) if ms[k]**2 != Gs[k].size[0] ]
+    if a: raise TypeError, "the squareroot of the number of rows in "\
+        "'Gs[%d]' is not an integer" %k
+    if hs is None: hs = []
+    if type(hs) is not list or len(hs) != N or [ k for k in xrange(N) 
+        if type(hs[k]) not in (matrix, spmatrix) or 
+        hs[k].typecode != 'd' or hs[k].size != (ms[k],ms[k]) ]:
+        raise TypeError, "'hs' must be a list of %d dense or sparse "\
+            "'d' matrices of size (%d,%d)" %(N,ms[k],ms[k])
+
+    if A is None: A = spmatrix([], [], [], (0,n), 'd')
+    if (type(A) is not matrix and type(A) is not spmatrix) or \
+        A.typecode != 'd' or A.size[1] != n:
+        raise TypeError, "'A' must be a dense or sparse 'd' matrix "\
+            "with %d columns" %n
+    p = A.size[0]
+    if b is None: b = matrix(0.0, (0,1))
+    if type(b) is not matrix or b.typecode != 'd' or b.size != (p,1): 
+        raise TypeError, "'b' must be a dense matrix of size (%d,1)" %p
+
+    if p > n or n-p > ml+ sum([mk*(mk+1)/2 for mk in ms]):
+        raise ValueError, "Rank(A) < p or Rank([Gl; Gs; A]) < n"
+
+    if not sum(ms):   # call lp() 
+        if primalstart is not None:
+            ps = primalstart.copy()
+            if ps.has_key('sl'): ps['s'] = ps['sl']
+        else: 
+            ps = None
+        if dualstart is not None:
+            ds = dualstart.copy()
+            if ds.has_key('zl'): ds['z'] = ds['zl']
+        else:
+            ds = None
+        sol = lp(c, Gl, hl, A, b, solver=solver, primalstart=ps, 
+            dualstart=ds)
+        sol['sl'] = sol['s'];  del sol['s']  
+        sol['ss'] = [ matrix(0.0, (0,0)) for k in xrange(N)] 
+        sol['zl'] = sol['z'];  del sol['z']  
+        sol['zs'] = [ matrix(0.0, (0,0)) for k in xrange(N)];  
+        return sol
+
+    if solver == 'dsdp':
+        try: from cvxopt import dsdp
+        except ImportError: raise ValueError, "invalid option "\
+            "(solver = 'dsdp'): cvxopt.dsdp is not installed"
+        dsdp.options = options
+        if p: raise ValueError, "sdp() with the 'solver=dsdp' option "\
+            "does not handle problems with equality constraints"
+        dsdpstatus, x, r, zl, zs = dsdp.sdp(c, Gl, hl, Gs, hs)
+        sl = hl - Gl*x
+        ss = [ hs[k] - matrix(Gs[k]*x, hs[k].size) for k in 
+            xrange(len(hs)) ]
+        if dsdpstatus == 'DSDP_PDFEASIBLE':
+            y = matrix(0.0, (0,1))
+            status = 'optimal'
+        elif dsdpstatus == 'DSDP_UNBOUNDED':
+            pcost = blas.dot(c,x)
+            x /= -pcost
+            sl /= -pcost
+            ss = [sk / -pcost for sk in ss]
+            zl, zs = None, None
+            status = 'dual infeasible'
+        elif dsdpstatus == 'DSDP_INFEASIBLE':
+            dcost = -blas.dot(hl,zl) - misc.sdot(hs, zs)
+            zl /= -dcost 
+            zs = [zs / -docst for zk in zs]
+            y = matrix(0.0, (0,1))
+            x, sl, ss = None, None, None
+            status = 'primal infeasible'
+        else:
+            status = 'unknown'
+            x, sl, ss, y, zl, zs, = None, None, None, None, None, None
+
+        return {'status': status, 'x': x, 'y': y, 'sl': sl, 'ss': ss, 
+            'zl': zl, 'zs': zs}
+         
+
+    def Fi(x, y, alpha=1.0, beta=0.0, trans='N'):
+        base.gemv(Gl, x, y, alpha=alpha, beta=beta, trans=trans)
+
+    def Fs(x, y, alpha=1.0, beta=0.0, trans='N'): 
+        if trans == 'N':
+            for k in xrange(N):
+                # y[k] := alpha*mat(Gs[k]*x) + beta*y[k]
+                base.gemv(Gs[k], x, y[k], alpha=alpha, beta=beta) 
+
+        else:
+            # y[i] := alpha*sum_k tr(mat(Gs[k][:,i])*x[k]) + beta*y[i] 
+            # for i=0,...,n-1.
+
+            for k in xrange(N):
+                # Scale diagonal of x[k] by 1/2 and set the upper 
+                # triangular part to zero, so that the matrix product 
+                # of Gs[k]' and vec(x[k]) is equal to the inner 
+                # product of mat(Gs[k][:j]) with x[k].  Then make the 
+                # matrix-vector product.
+                blas.scal(0.5, x[k], inc=ms[k]+1)
+                for j in xrange(ms[k]):
+                    blas.scal(0.0, x[k], offset=j+ms[k]*(j+1), 
+                        inc=ms[k])
+                if k == 0:
+                    base.gemv(Gs[k], x[k], y, alpha=2*alpha, beta=beta,
+                        trans='T')
+                else:
+                    base.gemv(Gs[k], x[k], y, alpha=2*alpha, beta=1.0,
+                        trans='T')
+                blas.scal(2.0, x[k], inc=ms[k]+1)
+        
+    def Fe(x, y, alpha=1.0, beta=0.0, trans='N'):
+        base.gemv(A, x, y, alpha=alpha, beta=beta, trans=trans)
+
+    
+    # kktsolver(di, rti) returns a function for solving 
+    #
+    #    [ 0   A'  Gl'          Gs()'         ] [x ]   [bx ]
+    #    [ A   0   0            0             ] [y ] = [by ].
+    #    [ Gl  0   -diag(d)^2   0             ] [zl]   [bzl]
+    #    [ Gs  0   0            -r*r'*()*r*r' ] [zs]   [bzs]
+    #
+    # di = 1./d is a positive mx1 'd' matrix;  
+    # rti = inv(r') is a list of square matrices.
+    #
+    # The scaled zl and zs are returned: d.*zl instead of zl, r'*zs*r  
+    # instead of zs.
+
+    global kktmethod
+    try: kktmethod = options['kktmethod']
+    except KeyError: kktmethod = 5
+    else: 
+        if type(kktmethod) is not int or kktmethod not in [1,4,5]:
+            raise ValueError, "options['kktmethod'] must be 1, 4, or 5"
+
+    if kktmethod == 1:
+
+        # The matrix 
+        # 
+        #    [ 0     A'   Glsc'  Gssc()' ] 
+        #    [ A     0    0      0       ] 
+        #    [ Glsc  0   -I      0       ] 
+        #    [ Gssc  0    0     -(1/2)*I ]
+        #
+        # is factored as LDL, with:
+        #
+        #     Glsc = diag(d)^{-1}*G = diag(di)*G 
+        #     Gssc() = rti'*Gs()*rti in packed storage with diagonal 
+        #              elements scaled by 1/sqrt(2). 
+        
+        pms = [ mk*(mk+1)/2 for mk in ms ] 
+        K = matrix(0.0, (n+p+ml+sum(pms), n+p+ml+sum(pms)))
+        ipiv = matrix(0, (K.size[0],1))
+        Gssc = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+        u = matrix(0.0, (K.size[0],1))
+
+        def kktsolver(di, rti):
+            blas.scal(0.0, K)
+
+            # 3,3-block of K is -I.
+            K[ (K.size[0]+1)*(p+n) : (K.size[0]+1)*(p+n+ml): 
+                K.size[0]+1 ] = -1.0
+
+            # 4,4-block of K is -I/2.
+            K[ (K.size[0]+1)*(p+n+ml) :: K.size[0]+1 ] = -0.5
+
+            # 2,1-block of K is A.
+            K[n:n+p,:n] = A  
+
+            # 3,1-block of K is diag(di)*Gl.
+            K[n+p:n+p+ml, :n] = Gl
+            for k in xrange(ml):
+                blas.scal(di[k], K, n=n, offset=n+p+k, inc=K.size[0])
+
+            # 4,1-block of K is rti'*G()*rti in packed storage with 
+            # diagonal elements scaled by 1/sqrt(2).
+            for j in xrange(n):
+                # Gssc = rti' * mat(Gs[:,j]) * rti.
+                for k in xrange(N): Gssc[k][:] = Gs[k][:,j]
+                misc.cngrnc(rti, Gssc, Gssc, trans='T')
+
+                # copy Gssc in packed storage to column j of K
+                ind = n+p+ml + j*K.size[0]
+                for k in xrange(N):
+                    blas.scal(1.0/math.sqrt(2), Gssc[k], inc=ms[k]+1)
+                    for i in xrange(ms[k]):
+                        blas.copy(Gssc[k], K, n=ms[k]-i, 
+                            offsetx=(ms[k]+1)*i, offsety=ind)
+                        ind += ms[k]-i
+
+            lapack.sytrf(K, ipiv)
+
+            def solve_kkt(x, y, zl, zs):
+
+                # Solve
+                #
+                #   [0    A'  Glsc' Gssc()'] [x        ]   [bx         ]
+                #   [A    0   0     0      ] [y        ] = [by         ]
+                #   [Glsc 0  -I     0      ] [d.*zl    ]   [di.*zl     ]
+                #   [Gssc 0   0    -(1/2)*I] [2*r'*zs*r]   [rti'*zs*rti]
+                #
+                # and return x, y, d.*zl, r'*zs*r.
+
+		blas.copy(x, u)
+		blas.copy(y, u, offsety=n)
+                misc.had2(zl, di)
+                blas.copy(zl, u, offsety=n+p)
+                misc.cngrnc(rti, zs, zs, trans='T')
+                ind = n+p+ml
+                for k in xrange(N):
+                    blas.scal(1.0/math.sqrt(2), zs[k], inc=ms[k]+1)
+                    for i in xrange(ms[k]):
+                        blas.copy(zs[k], u, n=ms[k]-i, 
+                            offsetx=(ms[k]+1)*i, offsety=ind)
+                        ind += ms[k]-i    
+                lapack.sytrs(K, ipiv, u)
+                blas.copy(u, x, n=n)
+                blas.copy(u, y, offsetx=n, n=p)
+                blas.copy(u, zl, offsetx=n+p, n=ml)
+                ind = n+p+ml
+                for k in xrange(N):
+                    for i in xrange(ms[k]):
+                        blas.copy(u, zs[k], offsetx=ind, 
+                            offsety=i*(ms[k]+1), n=ms[k]-i)
+                        zs[k][i,i] *= math.sqrt(2)
+                        ind += ms[k]-i    
+                misc.sscal(0.5, zs)
+
+            return solve_kkt
+
+    elif kktmethod == 2: 
+
+        pass   # not implemented
+
+    elif kktmethod == 3: 
+
+        pass   # not implemented
+
+    elif kktmethod == 4: 
+
+        # Factor the matrices
+        #
+        #     S = Gl'*diag(di)^2*Gl + Gs'(rti*rti'*Gs(x)*rti*rti') 
+        #         + A'*A
+        #     K = A*S^{-1}*A'. 
+        #
+        # Solve for y, x:
+        #
+        #     K*y = A * S^{-1} * (bx + Gl'*diag(di)^2*bzl  
+        #           + Gs'(rti*rti'*bzs*rti*rti') + A'*by) - by
+        #     S*x = bx + Gl'*diag(di)^2*bzl + Gs'(rti*rti'*bzs*rti*rti')
+        #           + A'*by - A'*y.
+        #
+        # Compute scaled zl, zs:
+        #
+        #    zl = di .* (Gl*x - bzl) 
+        #    zs = rti' * (Gs(x) - bzs) * rti.
+
+        S, K = matrix(0.0, (n,n)), matrix(0.0, (p,p))
+        if type(Gl) is matrix: 
+            Glsc = matrix(0.0, (ml,n)) 
+        else:
+            Glsc = spmatrix(0.0, Gl.I, Gl.J, (ml,n)) 
+        T = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+        Gssc = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+        zsc = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+
+        def kktsolver(di, rti):
+
+            # S = Gl'*diag(di)^2*Gl
+            base.gemm(spmatrix(di, range(ml), range(ml), tc='d'), Gl, 
+                Glsc, partial=True)
+            base.syrk(Glsc, S, trans='T')
+
+            # T = rti*rti' as a nonsymmetric matrix
+            for k in xrange(N):
+                blas.gemm(rti[k], rti[k], T[k], transB='T')
+
+            for j in xrange(n):
+                # Gssc[k] = T[k] * mat(Gs[k][:,j]) * T[k]
+                for k in xrange(N): Gssc[k][:] = Gs[k][:,j]
+                misc.cngrnc(T, Gssc, Gssc, trans='T')
+
+                # N matrix vector products to get lower triangular part 
+                # of column j of S.
+                for k in xrange(N):
+                    blas.scal(0.5, Gssc[k], inc=ms[k]+1)
+                    for i in xrange(ms[k]):
+                        blas.scal(0.0, Gssc[k], offset=i+ms[k]*(i+1), 
+                            inc=ms[k])
+                    base.gemv(Gs[k], Gssc[k], S, trans='T', n=n-j, 
+                        alpha=2.0, beta=1.0, offsetA=j*(ms[k]**2), 
+                        offsety=j*(n+1))
+                    
+            # S += A'*A    
+            base.syrk(A, S, trans='T', beta=1.0)
+
+            # factor S = L*L'
+            lapack.potrf(S) 
+
+            # Asct := L^{-1}*A',  factor K = Asct'*Asct
+            if type(A) is matrix:
+                Asct = A.trans()
+            else:
+                Asct = matrix(A.trans())
+            blas.trsm(S, Asct)
+            blas.syrk(Asct, K, trans='T')
+            lapack.potrf(K)
+
+            def solve_kkt(x, y, zl, zs):
+
+                # zl := di.*zl = di.*bzl 
+                # zsc := T*zs*T = T*bzs*T
+                misc.had2(zl, di)
+                misc.cngrnc(T, zs, zsc, trans='T')
+
+                # x := x + Glsc'*zl + Gs'(zsc) + A'*y
+                #    = bx + Gl'*diag(di)^2*bzl) + Gs'(T*bzs*T) + A'*by
+                base.gemv(Glsc, zl, x, trans='T', beta=1.0)
+                Fs(zsc, x, alpha=1.0, beta=1.0, trans='T') 
+                base.gemv(A, y, x, trans='T', beta=1.0)
+
+                # x := L^{-1}*x 
+                #    = L^{-1} * (bx + Gl'*diag(di)^2*bzl + Gs'(T*bzs*T)
+                #      + A'*by)
+                blas.trsv(S, x)
+
+                # y := Asc*x - y
+                #    = A*S^{-1}* (bx + Gl'*diag(di)^2.*bzl + 
+                #      Gs'(T*mat(bzs)*T) + A'*by) - by 
+                base.gemv(Asct, x, y, trans='T', beta=-1.0)
+
+                # y := K^{-1} * y
+                #    = K^{-1} * (A*S^{-1}* (bx + Gl'*diag(di)^2*bzl + 
+                #      Gs'(T*mat(bzs)*T) + A'*by) - by) 
+                lapack.potrs(K, y)
+
+                # x := x - Asc'*y
+                base.gemv(Asct, y, x, alpha=-1.0, beta=1.0)
+
+                # x := L^{-T} * x
+                #    = S^{-1} * (bx + Gl'*diag(di)^2*bzl + 
+                #      Gs'*(T*bzs*T) + A'*by - A'*y) 
+                blas.trsv(S, x, trans='T')
+
+                # zl := Glsc*x - zl 
+                #     = di .* (Gl*x - bzl)
+                base.gemv(Glsc, x, zl, beta=-1.0)
+
+                # zs = rti' * (Gs(x) - bzs) * rti
+                Fs(x, zs, alpha=1.0, beta=-1.0)
+                misc.cngrnc(rti, zs, zs, trans='T')
+
+            return solve_kkt 
+
+    elif kktmethod == 5:  
+
+        # Solve by eliminating the equality constraints and using 
+        # QR factorizations
+        #
+        #     A' = Q1*R1,   G*Q1 = Q3*R3
+        # 
+        # where G = [Glsc; Gssc], Glsc = diag(di)*G, and 
+        # Gssc = rti'*Gs()*rti (in packed storage with off-diagonal 
+        # elements scaled by sqrt(2)).
+
+        # A' = [Q1, Q2] * [R1; 0]
+        if type(A) is matrix:
+            QA = +A.trans()
+        else:
+            QA = matrix(A.trans())
+        tauA, tauG = matrix(0.0, (p,1)), matrix(0.0, (n-p,1))
+        lapack.geqrf(QA, tauA)
+
+        pms = [ mk*(mk+1)/2 for mk in ms ] 
+        Gssc = [ matrix(0.0, (m_k,m_k)) for m_k in ms ]
+        G = matrix(0.0, (ml+sum(pms), n))
+        z = matrix(0.0, (ml+sum(pms),1)) 
+        w = matrix(0.0, (ml+sum(pms),1))
+        v = matrix(0.0, (n,1))
+        def kktsolver(di, rti):
+
+            # G = [Glsc; Gssc] where , Glsc = diag(di)*G, and 
+            # Gssc = rti'*Gs()*rti (in packed storage with off-diagonal 
+            # elements scaled by sqrt(2)).
+
+            G[:ml,:] = Gl
+            for k in xrange(ml):
+                blas.scal(di[k], G, n=n, offset=k, inc=G.size[0])
+
+            for j in xrange(n):
+                # Gssc = sqrt(2) * rti' * mat(Gs[:,j]) * rti.
+                for k in xrange(N): Gssc[k][:] = Gs[k][:,j]
+                misc.cngrnc(rti, Gssc, Gssc, trans='T', 
+                    alpha=math.sqrt(2))
+                # copy Gssc in packed storage to column j of G and 
+                # scale diagonal elements by 1/sqrt(2).
+                ind = ml + j*G.size[0]
+                for k in xrange(N):
+                    blas.scal(1.0/math.sqrt(2), Gssc[k], inc=ms[k]+1)
+                    for i in xrange(ms[k]):
+                        blas.copy(Gssc[k], G, n=ms[k]-i, 
+                            offsetx=(ms[k]+1)*i, offsety=ind)
+                        ind += ms[k]-i
+
+            # G = [G1, G2] := G * [Q1, Q2]
+            lapack.ormqr(QA, tauA, G, side='R')
+
+            # QR factorization G2 := [Q3, Q4] * [R3; 0]. 
+            lapack.geqrf(G, tauG, n=n-p, offsetA=G.size[0]*p)
+
+            def solve_kkt(x, y, zl, zs):
+
+                # Solve
+                #
+                #     [0  A'  G'] [x ]   [bx]
+                #     [A  0   0 ] [y ] = [by]
+                #     [G  0  -I ] [z ]   [bz]
+                #
+                # where
+                #    z = [d.*zl; r'*zs*r] (with r'*zs*r in packed 
+                #        storage with off-diagonal elements scaled by 
+                #        sqrt(2))
+                #    bz = [di.*bzl; rti'*bzs*rti] (with rti'*bzs*rti in
+                #        packed storage with off-diagonal elements 
+                #        scaled by sqrt(2))
+                #
+                # If we eliminate x = [Q1 Q2] * [ R1^{-T}*by; v ] the 
+                # equations reduce to
+                # 
+                #        G2'*z = Q2'*bx
+                #     G2*v - z = bz - G1*R1^{-T}*by
+                #        R1*y  = Q1'*bx - G1'*z.
+                #
+                # This can be solved in 5 steps:
+                #
+                #     w := bz - G1*R1^{-T}*by 
+                #     u := Q3'*w + R3^{-T}*Q2'*bx 
+                #     z := Q3*u - w
+                #     x := [Q1, Q2] * [ R1^{-T}*by;  R3^{-1}*u]
+                #     y := R1^{-1} * (Q1'*bx - G1'*z).
+
+                # w := bz = [bzlc; bzsc]
+                misc.had2(zl, di)
+                blas.copy(zl, w)
+                misc.cngrnc(rti, zs, zs, trans='T', alpha=math.sqrt(2))
+                ind = ml
+                for k in xrange(N):
+                    blas.scal(1.0/math.sqrt(2), zs[k], inc=ms[k]+1)
+                    for i in xrange(ms[k]):
+                        blas.copy(zs[k], w, n=ms[k]-i, 
+                            offsetx=(ms[k]+1)*i, offsety=ind)
+                        ind += ms[k]-i    
+
+                # v := [Q1'*bx;  R3^{-T}*Q2'*bx]
+                blas.copy(x, v)
+                lapack.ormqr(QA, tauA, v, trans='T') 
+                lapack.trtrs(G, v, uplo='U', trans='T', n=n-p,
+                    offsetA=G.size[0]*p, offsetB=p)
+
+                # x[:p] := R1^{-T}*by 
+                blas.copy(y, x)
+                lapack.trtrs(QA, x, uplo='U', trans='T', n=p)
+
+                # w := w - G1*x[:p] 
+                #    = bz - G1*R1^{-T}*by 
+                blas.gemv(G, x, w, alpha=-1.0, beta=1.0, n=p)
+
+                # z := [Q3'*w + v[p:]; 0]
+                #    = [Q3'*w + R3^{-T}*Q2'*bx; 0]
+                blas.copy(w, z)
+                lapack.ormqr(G, tauG, z, trans='T', k=n-p, 
+                    offsetA=G.size[0]*p)
+                blas.axpy(v, z, offsetx=p, n=n-p)
+                blas.scal(0.0, z, offset=n-p)
+
+                # x[p:] := R3^{-1}*z[:n-p]  
+                blas.copy(z, x, offsety=p, n=n-p)
+                lapack.trtrs(G, x, uplo='U', n=n-p, offsetA=G.size[0]*p,
+                    offsetB=p)
+
+                # x is now [ R1^{-T}*by;  Q3'*w + R3^{-T}*Q2'*bx ]
+                # x := [Q1 Q2]*x
+                lapack.ormqr(QA, tauA, x) 
+ 
+                # z := [Q3, Q4] * z - w
+                lapack.ormqr(G, tauG, z, k=n-p, offsetA=G.size[0]*p)
+                blas.axpy(w, z, alpha=-1.0)
+
+                # y := R1^{-1} * ( v[:p] - G1'*z )
+                #    = R1^{-1} * ( Q1'*bx - G1'*z )
+                blas.copy(v, y, n=p)
+                blas.gemv(G, z, y, n=p, trans='T', alpha=-1.0, beta=1.0)
+                lapack.trtrs(QA, y, uplo='U', n=p) 
+
+                # zl = z[:ml]
+                blas.copy(z, zl, n=ml)
+
+                # zs = z[ml:] unpacked and with offdiagonal elts 
+                # scaled by 1/sqrt(2)
+                ind = ml
+                for k in xrange(N):
+                     for i in xrange(ms[k]):
+                         blas.copy(z, zs[k], offsetx=ind, 
+                             offsety=i*(ms[k]+1), n=ms[k]-i)
+                         ind += ms[k]-i    
+                     blas.scal(math.sqrt(2.0), zs[k], inc=ms[k]+1)
+                misc.sscal(1.0/math.sqrt(2.0), zs)
+
+            return solve_kkt
+
+    return conelp(c, kktsolver, Gl=Fi, hl=hl, Gs=Fs, hs=hs, A=Fe, b=b, 
+        primalstart=primalstart, dualstart=dualstart)
diff --git a/src/python/cvxprog.py b/src/python/cvxprog.py
new file mode 100644
index 0000000..59658d3
--- /dev/null
+++ b/src/python/cvxprog.py
@@ -0,0 +1,1074 @@
+"""
+Convex programming solver.
+
+A primal-dual interior-point solver written in Python and interfaces
+for quadratic and geometric programming.  Also includes an interface
+to the quadratic programming solver from MOSEK.
+"""
+
+# This file is part of CVXOPT version 0.8.2.
+# Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+
+import math 
+from cvxopt import base, blas, lapack, misc
+from cvxopt.base import matrix, spmatrix, sqrt, exp, mul, div
+
+__all__ = []
+options = {}
+
+def nlclp(c, kktsolver, F=None, G=None, h=None, A=None, b=None, 
+    xnewcopy=matrix, xdot=blas.dot, xaxpy=blas.axpy, xscal=blas.scal,
+    ynewcopy=matrix, ydot=blas.dot, yaxpy=blas.axpy, yscal=blas.scal):
+
+    """
+    Solves a nonlinearly constrained convex optimization problem with a
+    linear objective
+
+        minimize    c'*x 
+        subject to  f(x) <= 0
+                    G(x) <= h
+                    A(x) = b.                      
+
+    f: V -> R^mnl is convex and twice differentiable,  G: V -> R^ml and
+    A: V -> W are linear mappings, where V and W are real vector spaces.
+    The default choices for V and W are Euclidean vector spaces V=R^n 
+    and W=R^p, with elements represented as 'd' matrices of size (n,1) 
+    and (p,1).
+
+
+    Input arguments 
+
+        c is an element in V (stored as a matrix, list, dictionary,...).
+
+        kktsolver is a function for the factorization of a KKT system
+
+            [ H   *   *    *  ] [ ux   ]   [ bx   ]
+            [ A   0   *    *  ] [ uy   ] = [ by   ]
+            [ Df  0  -Dnl  *  ] [ uznl ]   [ bznl ]
+            [ G   0   0   -Dl ] [ uzl  ]   [ bzl  ] 
+ 
+        where H = sum_k z[k]*Hk, Hk is the Hessian of fk, Df is the 
+        derivative matrix of f, and Dnl and Dl are positive diagonal 
+        matrices.
+        Called as g = kktsolver(x, z, dnl, dl), it returns a function g 
+        that can be used to solve the system with Df and H evaluated 
+        at x and z, Dnl = diag(dnl)^-2, and Dl = diag(dl)^-2.  It can 
+        be assumed that x is in the domain of f and that z is positive.
+        The function call g(bx, by, bznl, bzl) replaces its arguments 
+        with the solution ux, uy, uznl, uzl.
+
+
+        F is a function that handles the following arguments.
+
+            F() returns a tuple (mnl, x0).  mnl is the number of 
+            nonlinear inequality constraints.  x0 is a point in the
+            domain of f.
+
+            F(x), with x an element in V, returns a tuple (f, Df).
+
+                f is  a dense 'd' matrix of size (mnl,1) with the 
+                function values f(x). 
+
+                Df is a function or a dense or sparse 'd' matrix.   
+                When Df is a function, Df(u, v) where u is a 'd' matrix 
+                of size (mnl,1) and v an element in V, updates v as 
+
+                    v := sum_k u[k] * grad fk(x) + v.
+
+                When V=R^n, Df can also be passed as 'd' matrix of 
+                size (mnl,n) that contains the derivative matrix of f 
+                at x, i.e., Df[k,:] is the transpose of the gradient of 
+                fk at x.  
+
+                If x is not in dom f, F(x) should return (None, None) 
+                or None.
+
+            If F is None, it is assumed that mnl = 0.
+
+
+        G is None, a function, or a sparse or dense 'd' matrix. 
+
+            If G is None, it is assumed that ml = 0.  
+
+            If G is a function, then
+
+                G(u, v, alpha=1.0, beta=0.0, trans='N')
+
+            evaluates
+
+                v := alpha*G(u) + beta*v if trans is 'N'
+                v := alpha*G'(u) + beta*v if trans is 'T'.
+
+            
+        h is None, or a dense 'd' matrix with one column.  If h is None,
+        it is interpreted as a 0x1 matrix.
+
+
+        A is None, a function, or a dense or sparse 'd' matrix.  
+
+            If A is None, it is assumed that dim W  = 0.  
+
+            If A is a function then
+
+                A(u, v, alpha=1.0, beta=0.0, trans='N')
+
+            evaluates
+
+                v := alpha*A(u) + beta*v if trans is 'N'
+                v := alpha*A'(u) + beta*v if trans is 'T'.
+
+
+        b is None, or an element in W.  If b is None, it is assumed 
+        that dim W = 0.
+
+
+    Returns a dictionary with keys 'status', 'x', 'snl', 'sl', 'y', 
+    'znl', 'zl'.  
+
+        status is 'optimal' or 'unknown'.
+
+        x, s, snl, sl, y, znl, zl are None if status is 'unknown'.  
+        Otherwise x is the optimal solution;  snl, sl are the optimal 
+        slacks for the nonlinear and linear inequalities;  y is the 
+        optimal dual variable associated with the equality constraints; 
+        znl, zl are the optimal dual variables associated with the 
+        nonlinear and linear inequalities.
+    """
+
+    STEP = 0.99
+    BETA = 0.5
+    ALPHA = 0.01
+    GAMMA1 = 1e5
+    GAMMA2 = 1e-5
+    GAMMA3 = 0.5
+    GAMMA4 = 1.0
+
+    try: MAXITERS = options['maxiters']
+    except KeyError: MAXITERS = 100
+    else: 
+        if type(MAXITERS) is not int or MAXITERS < 1: 
+            raise ValueError, "options['maxiters'] must be a positive "\
+                "integer"
+
+    try: ABSTOL = options['abstol']
+    except KeyError: ABSTOL = 1e-7
+    else: 
+        if type(ABSTOL) is not float and type(ABSTOL) is not int: 
+            raise ValueError, "options['abstol'] must be a scalar"
+
+    try: RELTOL = options['reltol']
+    except KeyError: RELTOL = 1e-7
+    else: 
+        if type(RELTOL) is not float and type(RELTOL) is not int: 
+            raise ValueError, "options['reltol'] must be a scalar"
+
+    try: FEASTOL = options['feastol']
+    except KeyError: FEASTOL = 1e-7
+    else: 
+        if type(FEASTOL) is not float and type(FEASTOL) is not int: 
+            raise ValueError, "options['feastol'] must be a scalar"
+
+    try: show_progress = options['show_progress']
+    except KeyError: show_progress = True
+
+    if F is None:  # There are no nonlinear inequality constraints.
+        def F(x=None, z=None):
+            if x is None: 
+                x0 = xnewcopy(c)
+                xscal(0.0, x0)
+                return 0, x0
+            def Df(u, v): pass
+            return matrix(0.0, (0,1)), Df
+
+    mnl, x0 = F()
+
+    def fzero(x, y, alpha=1.0, beta=0.0, trans='N'):
+        if trans == 'T':  xscal(beta, y)
+
+    if G is None: G = fzero
+    if h is None: h = matrix(0.0, (0,1))
+    ml = h.size[0]
+    if type(G) in (matrix, spmatrix):
+        if G.typecode != 'd' or G.size[0] != ml:
+            raise TypeError, "'G' must be a 'd' matrix with %d rows" %ml
+        def fG(u, v, alpha=1.0, beta=0.0, trans='N'):
+            base.gemv(G, u, v, alpha=alpha, beta=beta, trans=trans)
+    else:    
+        fG = G 
+
+    if (mnl+ml == 0):
+        raise ValueError, "problem must have at least one inequality "\
+            "constraint"
+
+    if A is None: A = fzero 
+    if b is None: b = matrix(0.0, (0,1))
+    if type(A) in (matrix,spmatrix):
+        if A.typecode != 'd' or A.size[0] != b.size[0]:
+            raise TypeError, "'A' must be a 'd' matrix with %d rows" \
+            %b.size[0]
+        def fA(u, v, alpha=1.0, beta=0.0, trans='N'):
+            base.gemv(A, u, v, alpha=alpha, beta=beta, trans=trans)
+    else:
+        fA = A
+
+    def xcopy(x, y):  xscal(0.0, y);  xaxpy(x, y)
+    def ycopy(x, y):  yscal(0.0, y);  yaxpy(x, y)
+
+    x = xnewcopy(x0)
+    y = ynewcopy(b);  yscal(0.0, y)
+    znl, zl = matrix(1.0, (mnl,1)), matrix(1.0, (ml,1)) 
+    snl, sl = matrix(1.0, (mnl,1)), matrix(1.0, (ml,1))
+    rx, rx2 = xnewcopy(x0), xnewcopy(x0)
+    ry = ynewcopy(b)
+    rznl, rznl2 = matrix(0.0, (mnl,1)), matrix(0.0, (mnl,1))
+    rzl = matrix(0.0, (ml,1))
+    dx, dy = xnewcopy(x), ynewcopy(y)   
+    newx, newy = xnewcopy(x),  ynewcopy(y)
+
+    if show_progress: 
+        print "% 10s% 12s% 10s% 8s% 7s" %("pcost", "dcost", "gap", 
+            "pres", "dres")
+
+    for iters in xrange(MAXITERS):  
+
+        f, Df = F(x)
+        f = matrix(f, tc='d')
+        if f.typecode != 'd' or f.size != (mnl,1):
+            raise TypeError, "first output argument of F() must be a "\
+                "'d' matrix of size (%d,%d)" %(mnl,1)
+        if type(Df) in (matrix, spmatrix):
+            if Df.typecode != 'd' or Df.size[0] != mnl:
+                raise TypeError, "second output argument of F() must "\
+                    "be a 'd' matrix with %d rows" %mnl
+            def fDf(u, v): 
+                base.gemv(Df, u, v, beta=1.0, trans='T')
+        else: 
+            fDf = Df
+
+        gap = blas.dot(snl, znl) + blas.dot(sl, zl) 
+        mu = gap / (mnl + ml)
+
+        # rx = c + A'*y + Df'*znl + G'*zl
+        xcopy(c, rx) 
+        fA(y, rx, beta=1.0, trans='T')
+        fDf(znl, rx)
+        fG(zl, rx, beta=1.0, trans='T')
+        resx = math.sqrt(xdot(rx, rx))
+           
+        # ry = A*x - b
+        ycopy(b, ry)
+        fA(x, ry, alpha=1.0, beta=-1.0)
+        resy = math.sqrt(ydot(ry, ry))
+
+        # rznl = snl + f 
+        blas.copy(snl, rznl)
+        blas.axpy(f, rznl)
+        resznl = blas.nrm2(rznl)
+
+        # rzl = sl + G*x - h
+        blas.copy(sl, rzl)
+        blas.axpy(h, rzl, alpha=-1.0)
+        fG(x, rzl, beta=1.0)
+        reszl = blas.nrm2(rzl)
+
+        # pcost = c'*x
+        # dcost = c'*x + y'*(Ax-b) + znl'*f(x) + zl'*(G*x-h)
+        #       = c'*x + y'*(Ax-b) + znl'*(f(x)+snl) + zl'*(G*x-h+sl) 
+        #         - znl'*snl - zl'*sl
+        pcost = xdot(c,x)
+        dcost = pcost + ydot(y, ry) + blas.dot(znl, rznl) + \
+            blas.dot(zl, rzl) - gap
+
+        pres = math.sqrt( resy**2 + resznl**2 + reszl**2 )
+        dres = resx
+        if iters == 0: 
+            pres0 = max(1.0, pres)
+            pres0_nl = max(1.0, resznl)
+            dres0 = max(1.0, dres)
+
+        if show_progress:
+            print "%2d: % 8.4e % 8.4e % 4.0e% 7.0e% 7.0e" \
+                %(iters, pcost, dcost, gap, pres/pres0, dres/dres0) 
+
+        # Stopping criteria.    
+        if pres/pres0 <= FEASTOL and dres/dres0 <= FEASTOL and \
+            (gap <= ABSTOL or (dcost > 0 and gap/dcost <= RELTOL) or
+            (pcost < 0 and gap/(-pcost) <= RELTOL)):
+            return {'status': 'optimal', 'x': x,  'y': y, 'znl': znl,  
+                'zl': zl, 'snl': snl, 'sl': sl}
+
+        dnl, dl = sqrt(div(znl, snl)), sqrt(div(zl, sl)), 
+        g = kktsolver(x, znl, dnl, dl)
+
+        sigma = 0.0    
+        for i in [0,1]:
+
+            # Solve
+            #
+            # [0 ]   [ hessian  A^T  [Df;G]' ]   [dx]
+            # [0 ] + [ A        0    0       ] * [dy] = -r  
+            # [ds]   [ [Df;G]   0    0       ]   [dz]
+            #
+            # s.*dz + z.*ds = -s.*z + sigma*mu  
+            #
+            # by solving
+            #
+            # [ hessian   A^T   [Df;G]^T    ]   [dx]      
+            # [ A         0     0           ] * [dy] = rhs 
+            # [ [Df;G]    0     -diag(s./z) ]   [dz]     
+            #         
+            # with rhs = -r + (0,0,0, (s*z - sigma*mu)./z).
+            # Take  ds = -(s.*z - sigma*mu + s.*dz) ./ z.
+       
+            rcpnl = mul(snl, znl) - sigma*mu
+            rcpl = mul(sl, zl) - sigma*mu
+            xscal(0.0, dx);  xaxpy(rx, dx, alpha=-1.0)
+            yscal(0.0, dy);  yaxpy(ry, dy, alpha=-1.0)
+            dznl = -rznl + div(rcpnl, znl)
+            dzl = -rzl + div(rcpl, zl)
+            g(dx, dy, dznl, dzl)
+            dsnl = -div( rcpnl + mul(snl,dznl), znl ) 
+            dsl = -div( rcpl + mul(sl,dzl), zl ) 
+
+            # line search 
+            step = min( 1.0, STEP / max( list(-div(dsnl,snl)) + 
+                list(-div(dsl, sl)) + list(-div(dznl,znl)) 
+                + list(-div(dzl,zl))) )
+            rescpnl, rescpl = blas.nrm2(rcpnl), blas.nrm2(rcpl) 
+            aa, bb = max(rescpnl, rescpl), min(rescpnl, rescpl)
+            if aa: rescp = aa * math.sqrt( 1.0 + (bb/aa)**2 )
+            else: rescp = 0.0
+            phi = resx  + resznl + rescp
+
+            for lsiters in xrange(50):
+                
+                xcopy(x, newx);  xaxpy(dx, newx, alpha=step)
+                ycopy(y, newy);  yaxpy(dy, newy, alpha=step)
+                newznl, newzl = znl + step*dznl, zl+step*dzl
+                newsnl, newsl = snl + step*dsnl, sl+step*dsl
+                newgap = blas.dot(newsnl, newznl) + \
+                    blas.dot(newsl, newzl)
+                t = F(newx)
+                if t is None: newf = None
+                else: newf, newDf = t[0], t[1]
+
+                if newf is not None:
+                    newf = matrix(newf, tc='d')
+                    if type(newDf) in (matrix, spmatrix):
+                        def fDf(u, v):
+                            base.gemv(newDf, u, v, beta=1.0, trans='T')
+                    else: 
+                        fDf = newDf
+
+                    # rx2 = c + A'*newy + newDf'*newznl + G'*newzl
+                    xcopy(c, rx2) 
+                    fA(newy, rx2, beta=1.0, trans='T')
+                    fDf(newznl, rx2)
+                    fG(newzl, rx2, beta=1.0, trans='T')
+                    resx2 = math.sqrt(xdot(rx2, rx2))
+
+                    # rznl2 = newsnl + newf
+                    blas.copy(newsnl, rznl2)
+                    blas.axpy(newf, rznl2)
+                    resznl2 = blas.nrm2(rznl2)
+
+                    # rcpnl = newsnl .* newznl
+                    # rcpl = newsl .* newzl
+                    rcpnl = mul(newsnl, newznl)
+                    rcpl = mul(newsl, newzl)
+                    rescpnl = blas.nrm2(rcpnl - sigma*mu)
+                    rescpl = blas.nrm2(rcpl - sigma*mu)
+                    aa, bb = max(rescpnl, rescpl), min(rescpnl, rescpl)
+                    if aa: rescp = aa * math.sqrt( 1.0 + (bb/aa)**2 )
+                    else: rescp = 0.0
+
+                    newphi = resx2  + resznl2 + rescp
+                    newmu = newgap / (mnl+ml)
+
+                    if resx2 <= GAMMA1 * dres0 * newgap and \
+                        resznl2 <= GAMMA1 * pres0_nl * newgap and \
+                        (not rcpnl or min(rcpnl) >= GAMMA2*newmu) \
+                        and (not rcpl or min(rcpl) >= GAMMA2*newmu) \
+                        and newphi <= (1.0 - ALPHA*step) * phi: 
+                        break
+                
+                step *= BETA
+
+            else: raise StandardError, "line search did not terminate"
+
+            if i == 0:  sigma = min(GAMMA3*newmu/mu, (newmu/mu)**GAMMA4)
+
+        xaxpy(dx, x, alpha=step)
+        yaxpy(dy, y, alpha=step)
+        blas.axpy(dznl, znl, alpha=step)
+        blas.axpy(dzl, zl, alpha=step)
+        blas.axpy(dsnl, snl, alpha=step)
+        blas.axpy(dsl, sl, alpha=step)
+
+    return {'status': 'unknown', 'x': None,  'y': None, 'znl': None, 
+        'zl': None, 'snl': None, 'sl': None}
+
+
+
+def nlcp(kktsolver, F, G=None, h=None, A=None, b=None,
+    xnewcopy=matrix, xdot=blas.dot, xaxpy=blas.axpy, xscal=blas.scal,
+    ynewcopy=matrix, ydot=blas.dot, yaxpy=blas.axpy, yscal=blas.scal):
+
+    """
+    Solves a convex optimization problem
+    
+        minimize    f0(x)
+        subject to  fk(x) <= 0, k=1,...,mnl
+                    G(x) <= h
+                    A(x) = b.                      
+
+    fk: V -> R is convex and twice differentiable.  
+    G: V -> R^ml and A: V -> W are linear mappings, where V and W are 
+    real vector spaces.  The default choices for V and W are Euclidean 
+    vector spaces V=R^n and W=R^p, with elements stored as 'd' matrices 
+    of size (n,1) and (p,1).
+
+    Input arguments
+
+        kktsolver is a function for the factorization of a KKT system
+
+            [ H       *   *    *  ] [ ux   ]    [ bx   ]
+            [ A       0   *    *  ] [ uy   ] =  [ by   ]
+            [ Df[1:]  0  -Dnl  *  ] [ uznl ]    [ bznl ]
+            [ G       0   0   -Dl ] [ uzl  ]    [ bzl  ] 
+ 
+        where H = sum_{k=0}^mnl z[k]*Hk and H[k] is the Hessian 
+        of fk,  Df is the derivative of f and Dnl and Dl are positive 
+        diagonal matrices.
+        g = kktsolver(x, z, dnl, dl) returns a function g that can be 
+        used to solve the system with H and Df evaluated at x and z, 
+        Dnl = diag(dnl)^-2, Dl = diag(dl)^-2.
+        It can be assumed that x is in the domain of f0 and f.
+        The function calll g(bx, by, bznl, bzl) replaces the
+        arguments with the solution ux, uy, uznl, uzl.
+
+        F: a function that handles the following arguments.
+
+            F() returns a tuple (mnl, x0).  
+
+                mnl is the number of nonlinear inequality constraints.
+                x0 is a point in dom f.
+
+            F(x), with x a point in V, returns (f, Df).
+
+                f is  a dense 'd' matrix of size (mnl+1,1) with the 
+                function values f0(x), ...., fmnl(x). 
+                Df is a function or a sparse or dense 'd' matrix.  
+                If Df is a function, Df(u, v) evaluates 
+ 
+                    v := sum_k=0^mnl u[k]*gradfk + v.
+
+                If V = Rn, Df can also be a 'd' matrix or sparse matrix
+                of size (mnl, n).  In this case Df[k,:] contains the 
+                transpose of gradfk.  
+ 
+                If x is not in dom f, F(x) returns None or (None, None).
+ 
+
+        G is None, a function, or a sparse or dense 'd' matrix. 
+
+            If G is a function then
+
+                G(u, v, alpha=1.0, beta=0.0, trans='N')
+
+            evaluates
+
+                v := alpha * G(u)  + beta * v if trans is 'N'
+                v := alpha * G'(u) + beta * v if trans is 'T'.
+
+            If G is None, it is assumed that ml = 0.
+
+            
+        h is None, or a dense 'd' matrix with one column.  If h is None,
+        it is interpreted as a 0x1 matrix.
+
+
+        A is None, a function, or a dense or sparse 'd' matrix. 
+
+            If A is a function then
+
+                A(u, v, alpha=1.0, beta=0.0, trans='N')
+
+            evaluates
+
+                v := alpha * A(u)  + beta * v if trans is 'N'
+                v := alpha * A'(u) + beta * v if trans is 'T'.
+
+            If A is None, it is assumed that dim W  = 0.
+
+
+        b is None, or an element in W.  If b is None, it is assumed 
+        that dim W = 0.
+
+
+    Returns a dictionary with keys 'status', 'x', 'snl', 'sl', 'y', 
+    'znl', 'zl'.  
+
+        status is 'optimal' or 'unknown'.
+
+        x, s, snl, sl, y, znl, zl are None if status is 'unknown'.  
+        Otherwise x is the optimal solution;  snl, sl are the optimal 
+        slacks for the nonlinear and linear inequalities;  y is the 
+        optimal dual variable associated with the equality constraints; 
+        znl, zl are the optimal dual variables associated with the 
+        nonlinear and linear inequalities.
+    """
+
+    mnl, x0 = F()
+    if type(mnl) is not int or mnl < 0:
+        raise TypeError, "invalid return value for 'mnl, x = F()'"
+
+    def fzero(x, y, alpha=1.0, beta=0.0, trans='N'):
+        if trans == 'T':  xscal(beta, y)
+
+    if G is None: G = fzero
+    if h is None: h = matrix(0.0, (0,1))
+    ml = h.size[0]
+    if type(G) in (matrix, spmatrix):
+        if G.typecode != 'd' or G.size[0] != ml:
+            raise TypeError, "'G' must be a 'd' matrix with %d rows" %ml
+        def fG(u, v, alpha=1.0, beta=0.0, trans='N'):
+            base.gemv(G, u, v, alpha=alpha, beta=beta, trans=trans)
+    else:    
+        fG = G 
+
+    if A is None: A = fzero
+    if b is None: b = matrix(0.0, (0,1))
+    if type(A) in (matrix,spmatrix):
+        if A.typecode != 'd' or A.size[0] != b.size[0]:
+            raise TypeError, "'A' must be a 'd' matrix with %d rows" \
+            %b.size[0]
+        def fA(u, v, alpha=1.0, beta=0.0, trans='N'):
+            base.gemv(A, u, v, alpha=alpha, beta=beta, trans=trans)
+    else:
+        fA = A
+
+    def xcopy(x, y):  xscal(0.0, y);  xaxpy(x, y)
+    def ycopy(x, y):  yscal(0.0, y);  yaxpy(x, y)
+
+
+    # Apply nlclp() to problem in epigraph form:
+    #    
+    #     minimize    t
+    #     subject to  f0(x) - t <= 0
+    #                 fk(x) <= 0,  k=1,...,mnl
+    #                 G(x) <= h
+    #                 A(x) = b.
+    #
+    # Store the variable as a list [ x, t ].
+
+    # c = [0, 1.0]
+    c = [ xnewcopy(x0), 1.0 ]
+    xscal(0.0, c[0])
+
+    ux, uznl = xnewcopy(x0), matrix(0.0, (mnl,1))
+
+    def kktsolver_epi(x, z, dnl, dl):
+             
+        # g(x, y, znl, zl) is a solver for the smaller KKT system
+        #
+        #     [ H         *   *     *  ] [ x   ]   [ bx   ]
+        #     [ A         0   *     *  ] [ y   ] = [ by   ]
+        #     [ Df[1:,:]  0  -Dnl   *  ] [ znl ]   [ bznl ]
+        #     [ G         0   0    -Dl ] [ zl  ]   [ bzl  ]
+        #
+        # where H = sum_k=0^mnl zk*Hk, Df is the derivative matrix of
+        # (f0, ..., fmnl), Dnl = diag(dnl[1:])^-2, and Dl = diag(dl)^-2.
+        # The variables are x (in V), y (in W), znl (in R^mnl), 
+        # zl (in R^ml).
+
+        g = kktsolver(x[0], z, dnl[1:], dl)
+ 
+        f, Df = F(x[0])
+        if type(Df) in (matrix, spmatrix):
+            gradf0 = Df[0,:].T
+        else: 
+            gradf0 = xnewcopy(x[0])
+            xscal(0.0, gradf0)
+            e0 = matrix(0.0, (mnl+1,1))
+            e0[0] = 1.0
+            Df(e0, gradf0)
+ 
+        def g_epi(x, y, znl, zl):
+
+            # g_epi(x, y, znl, zl) solves the augmented KKT system
+            #
+            #    [ [H,    0;               ] [ x   ]    [ bx   ]
+            #    [  0,    0]  *   *    *   ] [     ]    [      ]
+            #    [ [A,    0]  0   *    *   ] [ y   ] =  [ by   ]
+            #    [ [Df, -e0]  0  -Dnl  *   ] [ znl ]    [ bznl ]
+            #    [ [G,    0]  0   0    -Dl ] [ zl  ]    [ bzl  ]
+            #
+            # The variables are x (a tuple (x[0], x[1]) with x[0] in
+            # V and x[1] in R), y (in W), znl (in R^(mnl+1)) and
+            # zl (in R^ml).
+            #
+            # The system is solved as follows:
+            #
+            # x[0], y, znl[1:], zl solve the smaller KKT system
+            # with rhs (bx[0] + bx[1]*Df[0,:]', by, bnl[1:], bl).
+            #
+            # Take znl[0] = -bx[1] and 
+            # x[1] = Df[0,:]*x[0] + bx[1]/dnl[0]**2 - bnl[0].
+
+            a = znl[0]
+            xcopy(x[0], ux)
+            xaxpy(gradf0, ux, alpha=x[1])
+            uznl[:] = znl[1:] 
+            g(ux, y, uznl, zl)
+            znl[1:] = uznl
+            znl[0] = -x[1]
+            xcopy(ux , x[0])
+            x[1] = xdot(gradf0, x[0]) - znl[0] / dnl[0]**2 - a
+
+        return g_epi
+
+    
+    # fA_epi evaluates [A, 0] * [x[0]; x[1]] and its adjoint.
+    #
+    #      v := alpha * A(u[0]) + beta*v if trans is 'N'
+    #      v := alpha * ( A'(u), 0 ) + beta*v if trans is 'N'
+ 
+    def fA_epi(u, v, alpha=1.0, beta=0.0, trans='N'):
+        if trans == 'N':
+            fA(u[0], v, alpha=alpha, beta=beta) 
+        else:
+            fA(u, v[0], alpha=alpha, beta=beta, trans='T') 
+            v[1] *= beta
+
+
+    # fG_epi evaluates  [G, 0] * [x[0]; x[1]] and its adjoint
+    #
+    #     v := alpha * G(u[0]) + beta*v  if trans is 'N' 
+    #     v := alpha * ( G'(u), 0 )  + beta*v  if trans is 'T'.
+
+    def fG_epi(u, v, alpha=1.0, beta=0.0, trans='N'):
+        if trans == 'N':
+            fG(u[0], v, alpha=alpha, beta=beta) 
+        else:
+            fG(u, v[0], alpha=alpha, beta=beta, trans='T') 
+            v[1] *= beta
+
+
+    # F_epi evaluates nonlinear constraint functions and derivatives.
+    
+    def F_epi(x=None, z=None):
+        if x is None: 
+            x0_epi = (x0, 0.0)
+            return mnl+1, x0_epi 
+        else:
+            t = F(x[0])
+            if t is None or t[0] is None:  return None, None
+            f_epi, Df = matrix(t[0]), t[1]
+            f_epi[0] -= x[1]
+            def Df_epi(u, v):  
+                # Evaluates v := [Df, -e0]' * u + v
+                if type(Df) in (matrix, spmatrix):
+                    base.gemv(Df, u, v[0], beta=1.0, trans='T')
+                else:
+                    Df(u, v[0])
+                v[1] -= u[0]
+            return f_epi, Df_epi
+
+    def xnewcopy_epi(x):
+        return [ xnewcopy(x[0]), 0.0 ]
+
+    def xdot_epi(x, y):
+        return xdot(x[0], y[0]) + x[1]*y[1]
+
+    def xaxpy_epi(x, y, alpha=1.0):
+        xaxpy(x[0], y[0], alpha=alpha)
+        y[1] += alpha*x[1]
+
+    def xscal_epi(alpha, x):
+        xscal(alpha, x[0])
+        x[1] *= alpha
+
+    sol = nlclp(c, kktsolver_epi, F_epi, fG_epi, h, fA_epi, b, 
+        xnewcopy_epi, xdot_epi, xaxpy_epi, xscal_epi, ynewcopy, ydot, 
+        yaxpy, yscal) 
+    if sol['status'] == 'optimal':
+        sol['x'] = sol['x'][0]
+        sol['znl'], sol['snl'] = sol['znl'][1:], sol['snl'][1:]
+    else:
+        sol['x'] = None
+        sol['znl'], sol['snl'] = None, None 
+    return sol
+
+
+def cp(F, G=None, h=None, A=None, b=None):
+
+    """
+    Solves a convex optimization problem
+    
+        minimize    f0(x)
+        subject to  fk(x) <= 0, k=1,...,m
+                    G*x <= h
+                    A*x = b.                      
+
+    f: R^n -> R^(m+1) is convex and twice differentiable.  
+
+    Input arguments
+
+        F is a function that handles the following arguments.
+
+            F() returns a tuple (m, x0).  
+
+                m is the number of nonlinear inequality constraints.
+                x0 is an nx1 dense 'd' matrix specifying a point in 
+                dom f.
+
+            F(x), with x a 'd' matrix of size (n,1), returns (f, Df).
+
+                f is  a dense 'd' matrix of size (m+1,1) with the 
+                function values f(x). 
+
+                Df is a dense or sparse 'd' matrix of size (m+1,n). 
+                Its kth row contains the transpose of the gradient
+                of fk at x.
+
+                If x is not in dom f, F(x) returns None or (None, None).
+ 
+            F(x, z), with x a 'd' matrix of size (n,1) and z a positive 
+            'd' matrix of size (m+1,1), returns (f, Df, H).
+            
+                f and Df are defined as above.
+                
+                H is a dense or sparse 'd' matrix of size (n,n).  The 
+                lower triangular part of H contains the lower triangular
+                part of sum_{k=0}^m z[k]*Hk where Hk is the Hessian of 
+                fk at x.  
+
+                If F is called with two arguments, it can be assumed
+                that x is dom f. 
+
+        G is None or a sparse or dense 'd' matrix.  If G is None, it 
+        is interpreted as a 0xn matrix.  
+
+        h is None or a dense 'd' matrix with one column.  If h is None, 
+        it is interpreted as a 0x1 matrix.
+
+        A is None, or a dense or sparse 'd' matrix.  If A is None, it 
+        is interpreted as a 0xn matrix.  
+
+        b is a dense 'd' matrix with one column or None.  If b is None,
+        it is interpreted as a 0x1 matrix.
+
+    Returns a dictionary with keys 'status', 'x', 'snl', 'sl', 'y', 
+    'znl', 'zl'.  
+
+        status is 'optimal' or 'unknown'.
+
+        x, s, snl, sl, y, znl, zl are None if status is 'unknown'.  
+        Otherwise x is the optimal solution;  snl, sl are the optimal 
+        slacks for the nonlinear and linear inequalities;  y is the 
+        optimal dual variable associated with the equality constraints; 
+        znl, zl are the optimal dual variables associated with the 
+        nonlinear and linear inequalities.
+    """
+
+    try: kktmethod = options['kktmethod']
+    except KeyError: kktmethod = 3
+    else: 
+        if type(kktmethod) is not int or kktmethod not in [1,2,3]:
+            raise ValueError, "options['kktmethod'] must be 1, 2 or 3"
+
+    mnl, x0 = F()
+    if type(mnl) is not int or mnl < 0 or type(x0) is not matrix or \
+        x0.typecode != 'd' or x0.size[1] != 1:
+        raise TypeError, "invalid return values for '(m, x) = F()'"
+    n = x0.size[0]
+
+    if G is None: G = spmatrix([], [], [], (0,n))
+    if h is None: h = matrix(0.0, (0,1))
+    if type(G) not in (matrix, spmatrix) or G.typecode != 'd' or \
+        G.size[1] != n:
+        raise TypeError, "'G' must be a dense or sparse 'd' matrix "\
+            "with %d columns" %n 
+    ml = G.size[0]
+    if type(h) is not matrix or h.typecode != 'd' or h.size != (ml,1):
+        raise TypeError, "'h' must be a dense 'd' matrix of size "\
+            "(%d,1)" %ml
+
+    if A is None: A = spmatrix([], [], [], (0,n))
+    if b is None: b = matrix(0.0, (0,1))
+    if type(A) not in (matrix,  spmatrix) or A.typecode != 'd' or \
+        A.size[1] != n: 
+        raise TypeError, "'A' must be a dense or sparse 'd' matrix "\
+            "with %d columns" %n
+    p = A.size[0]
+    if type(b) is not matrix or b.typecode != 'd' or b.size != (p,1): 
+        raise TypeError, "'b' must be a dense 'd' matrix of "\
+            "size (%d,1)" %p
+
+    status = {'kkt_num': None}  # 'pointer' to numeric factorization
+    def kkt(x, z, dnl, dl):
+        f, Df, H = F(x, z)
+        if mnl==0:  
+            Df2 = spmatrix([],[],[],(0,n))
+        else:  
+            Df2 = Df[1:,:]
+        if status['kkt_num'] is None:
+            status['kkt_num'] = misc.kkt(H, A, Df2, G, kktmethod)
+        return status['kkt_num'](H, Df2, dnl, dl)
+    
+    return nlcp(kkt, F, G, h, A, b) 
+
+
+def qp(P, q, G=None, h=None, A=None, b=None, solver=None):
+
+    """
+    Solves a quadratic program
+
+        minimize    (1/2)*x'*P*x + q'*x 
+        subject to  G*x <= h      
+                    A*x = b.
+
+
+    Input arguments 
+
+        P is a nxn dense or sparse 'd' matrix with the lower triangular 
+        part of P stored in the lower triangle.  Must be positive 
+        semidefinite.
+
+        q is an nx1 dense 'd' matrix.
+
+        G is an mxn dense or sparse 'd' matrix.
+
+        h is an mx1 dense 'd' matrix.
+
+        A is a pxn dense or sparse 'd' matrix.
+
+        b is a px1 dense 'd' matrix or None.
+
+        solver is None or 'mosek'.
+
+        The default values for G, h, A and b are empty matrices with 
+        zero rows.
+
+
+    Returns a dictionary with keys 'status', 'x', 's', 'y', 'z'.
+
+        The default solver returns with status 'optimal' or 'unknown'.
+        The MOSEK solver can also return with status 'primal infeasible'
+        or 'dual infeasible'.
+
+        If status is 'optimal', x, s, y, z are the primal and dual 
+        optimal solutions.
+
+        If status is 'primal infeasible', x = s = None and z, y are 
+        a proof of primal infeasibility:
+
+            G'*z + A'*y = 0,  h'*z + b'*y = -1,  z >= 0.
+
+        If status is 'dual infeasible', z = y = None, and x, s are 
+        a proof of dual infeasibility:
+
+            P*x = 0,  q'*x = -1,  G*x + s = 0,  A*x = 0,  s >=0
+
+        If status is 'unknown', x, y, s, z are None.  
+    """
+
+    if solver == 'mosek':
+        try: from cvxopt import mosek
+        except ImportError: raise ValueError, "invalid option "\
+            "(solver='mosek'): cvxopt.mosek is not installed" 
+        mosek.options = options
+        prosta, solsta, x, z, y = mosek.solveqp(P, q, G, h, A, b)
+        m = G.size[0]
+        if solsta == 'OPTIMAL':
+            s = matrix(0.0, (m,1))
+            blas.copy(h, s)    
+            base.gemv(G, x, s, alpha=-1.0, beta=1.0)
+            status = 'optimal'
+        elif solsta == 'PRIMAL_INFEASIBLE_CER':
+            status = 'primal infeasible'
+            ducost = -blas.dot(h,z) - blas.dot(b,y)
+            blas.scal(1.0/ducost, y);
+            blas.scal(1.0/ducost, z);
+            x, s = None, None
+        elif solsta == 'DUAL_INFEASIBLE_CER':
+            status = 'dual infeasible'
+            qx = blas.dot(q,x)
+            if qx:  x /= (-qx)
+            s = matrix(0.0, (m,1))
+            base.gemv(G, x, s, alpha=-1.0)
+            z, y = None, None
+        else: 
+            status = 'unknown'
+            x, s, y, z = None, None, None, None
+        return {'status': status, 'x': x, 's': s, 'y': y, 'z': z}
+
+    if type(P) not in (matrix, spmatrix) or P.typecode != 'd' or \
+        P.size[0] != P.size[1]:
+        raise TypeError, "'P' must be a square dense or sparse 'd' "\
+            "matrix"
+    n = P.size[0]
+    if type(q) is not matrix or q.typecode != 'd' or q.size != (n,1): 
+        raise TypeError, "'q' must be a dense 'd' matrix of "\
+            "size (%d,1)" %n
+
+    def F(x=None, z=None):
+        if x is None: return 0, matrix(0.0, (n,1))
+        grad = matrix(0.0, (1,n))
+        base.symv(P, x, grad) 
+        f = .5 * blas.dot(grad, x) + blas.dot(q, x) 
+        blas.axpy(q, grad)
+        if z is None: return f, grad
+        else: return f, grad, z[0]*P
+
+    sol =  cp(F, G, h, A, b)
+    return {'status': sol['status'], 'x': sol['x'], 's': sol['sl'],
+        'y': sol['y'], 'z': sol['zl']}
+
+
+
+def gp(K, F, g, G=None, h=None, A=None, b=None):
+
+    """
+    Solves a geometric program
+
+        minimize    log sum exp (F0*x+g0)
+        subject to  log sum exp (Fi*x+gi) <= 0,  i=1,...,m
+                    G*x <= h      
+                    A*x = b
+
+    Input arguments
+
+        K is a list of positive integers [K0, K1, K2, ..., Km].
+
+        F is a sum(K)xn dense or sparse 'd' matrix with block rows F0, 
+        F1, ..., Fm.  Each Fi is Kixn.
+
+        g is a sum(K)x1 dense or sparse 'd' matrix with blocks g0, g1, 
+        g2, ..., gm.  Each gi is Kix1.
+
+        G is an mxn dense or sparse 'd' matrix.
+
+        h is an mx1 dense 'd' matrix.
+
+        A is a pxn dense or sparse 'd' matrix.
+
+        b is a px1 dense 'd' matrix.
+
+        The default values for G, h, A and b are empty matrices with 
+        zero rows.
+
+
+    Returns a dictionary with keys 'status', 'x', 'snl', 'sl, 'y', 
+        'znl', 'zl'.
+
+        If status is 'optimal', x is the optimal solution, snl and sl
+        are the optimal slacks for the nonlinear and linear 
+        inequalities, znl and zl are the optimal dual veriables 
+        associated with the nonlinear and linear inequalities, and 
+        y are the optimal variables associated with the equality 
+        constraints.
+
+        If status is 'unknown', x, snl, sl, y, znl and zl are None.
+    """
+
+    if type(K) is not list or [ k for k in K if type(k) is not int 
+        or k <= 0 ]:
+        raise TypeError, "'K' must be a list of positive integers" 
+    mnl = len(K)-1
+    l = sum(K)
+
+    if type(F) not in (matrix, spmatrix) or F.typecode != 'd' or \
+        F.size[0] != l:
+        raise TypeError, "'F' must be a dense or sparse 'd' matrix "\
+            "with %d rows" %l
+    if type(g) is not matrix or g.typecode != 'd' or g.size != (l,1): 
+        raise TypeError, "'g' must be a dene 'd' matrix of "\
+            "size (%d,1)" %l
+    n = F.size[1]
+
+    if G is None: G = spmatrix([], [], [], (0,n))
+    if h is None: h = matrix(0.0, (0,1))
+    if type(G) not in (matrix, spmatrix) or G.typecode != 'd' or \
+        G.size[1] != n:
+        raise TypeError, "'G' must be a dense or sparse 'd' matrix "\
+            "with %d columns" %n 
+    ml = G.size[0]
+    if type(h) is not matrix or h.typecode != 'd' or h.size != (ml,1):
+        raise TypeError, "'h' must be a dense 'd' matrix of "\
+            "size (%d,1)" %ml
+
+    if A is None: A = spmatrix([], [], [], (0,n))
+    if b is None: b = matrix(0.0, (0,1))
+    if type(A) not in (matrix, spmatrix) or A.typecode != 'd' or \
+        A.size[1] != n:
+        raise TypeError, "'A' must be a dense or sparse 'd' matrix "\
+            "with %d columns" %n
+    p = A.size[0]
+    if type(b) is not matrix or b.typecode != 'd' or b.size != (p,1): 
+        raise TypeError, "'b' must be a dense 'd' matrix of "\
+            "size (%d,1)" %p
+
+    y = matrix(0.0, (l,1))
+    u = matrix(0.0, (max(K),1))
+    Fsc = matrix(0.0, (max(K),n))
+
+    cs1 = [ sum(K[:i]) for i in xrange(mnl+1) ] 
+    cs2 = [ cs1[i] + K[i] for i in xrange(mnl+1) ]
+    ind = zip(range(mnl+1), cs1, cs2)
+
+    def Fgp(x=None, z=None):
+
+        if x is None: return mnl, matrix(0.0, (n,1))
+	
+        f = matrix(0.0, (mnl+1,1))
+        Df = matrix(0.0, (mnl+1,n))
+
+        # y = F*x+g
+        blas.copy(g, y)
+        base.gemv(F, x, y, beta=1.0)
+
+        if z is not None: H = matrix(0.0, (n,n))
+
+        for i, start, stop in ind:
+
+            # yi := exp(yi) = exp(Fi*x+gi) 
+            ymax = max(y[start:stop])
+            y[start:stop] = exp(y[start:stop] - ymax)
+
+            # fi = log sum yi = log sum exp(Fi*x+gi)
+            ysum = blas.asum(y, n=stop-start, offset=start)
+            f[i] = ymax + math.log(ysum)
+
+            # yi := yi / sum(yi) = exp(Fi*x+gi) / sum(exp(Fi*x+gi))
+            blas.scal(1.0/ysum, y, n=stop-start, offset=start)
+
+            # gradfi := Fi' * yi 
+            #        = Fi' * exp(Fi*x+gi) / sum(exp(Fi*x+gi))
+            base.gemv(F, y, Df, trans='T', m=stop-start, incy=mnl+1,
+                offsetA=start, offsetx=start, offsety=i)
+
+            if z is not None:
+
+                # Hi = Fi' * (diag(yi) - yi*yi') * Fi 
+                #    = Fisc' * Fisc
+                # where 
+                # Fisc = diag(yi)^1/2 * (I - 1*yi') * Fi
+                #      = diag(yi)^1/2 * (Fi - 1*gradfi')
+
+                Fsc[:K[i], :] = F[start:stop, :] 
+                for k in xrange(start,stop):
+                   blas.axpy(Df, Fsc, n=n, alpha=-1.0, incx=mnl+1,
+                       incy=Fsc.size[0], offsetx=i, offsety=k-start)
+                   blas.scal(math.sqrt(y[k]), Fsc, inc=Fsc.size[0],
+                       offset=k-start)
+
+                # H += z[i]*Hi = z[i] * Fisc' * Fisc
+                blas.syrk(Fsc, H, trans='T', k=stop-start, alpha=z[i],
+                    beta=1.0)
+
+        if z is None: return f, Df
+        else: return f, Df, H
+
+    return cp(Fgp, G, h, A, b)
diff --git a/src/python/info.py b/src/python/info.py
new file mode 100644
index 0000000..43dd9db
--- /dev/null
+++ b/src/python/info.py
@@ -0,0 +1,41 @@
+version = '0.8.2'
+
+def license(): print(
+"""CVXOPT version 0.8.2.  Copyright (c) 2004-2007 J. Dahl and L. Vandenberghe.
+
+This program is free software; you can redistribute it and/or modify it under 
+the terms of the GNU General Public License as published by the Free Software 
+Foundation; either version 2 of the License, or (at your option) any later 
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT 
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
+FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+The full text of the GNU General Public License can be found at
+www.gnu.org/copyleft/gpl.html or in the LICENSE file distributed with CVXOPT.  
+
+The CVXOPT distribution includes source code for the following software 
+libraries.  The copyright of these libraries is owned by their authors.
+
+1. Part of the SuiteSparse suite of sparse matrix algorithms, including:
+   - AMD Version 2.0.  Copyright (c) 2006 by Timothy A. Davis, 
+     Patrick R. Amestoy, and Iain S. Duff.
+   - CHOLMOD Version 1.4.  Copyright (c) 2005-2006 by University of Florida, 
+     Timothy A. Davis and W. Hager.  
+   - COLAMD version 2.6.  Copyright (c) 1998-2006 by Timothy A. Davis.
+   - UMFPACK Version 5.0.2.  Copyright (c) 1995-2006 by Timothy A. Davis.
+
+   These packages are licensed under the terms of the GNU Lesser General Public 
+   License (UMFPACK, parts of CHOLMOD, AMD, COLAMD) and the GNU General Public 
+   License (parts of CHOLMOD).  For details, consult the README files in the 
+   source directories or the website listed below.
+
+   Availability: www.cise.ufl.edu/research/sparse. 
+
+2. RNGS Random Number Generation -- Multiple Streams (Sep. 22, 1998) by Steve 
+   Park and Dave Geyer.
+
+   Availability: www.cs.wm.edu/~va/software/park/park.html.
+"""
+)
diff --git a/src/python/misc.py b/src/python/misc.py
new file mode 100644
index 0000000..df2f8f2
--- /dev/null
+++ b/src/python/misc.py
@@ -0,0 +1,515 @@
+"""
+Miscellaneous functions used by the CVXOPT solvers.
+"""
+
+# This file is part of CVXOPT version 0.8.2.
+# Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+
+import math
+from cvxopt import base, blas, lapack, cholmod
+from cvxopt.base import matrix, spmatrix
+cholmod.options['supernodal'] = 2
+
+__all__ = []
+
+def had(x,y):  
+    """
+    Returns Hadamard product x.*y of dense 'd' matrices x and y.
+
+    x and y are 'd' matrices of equal size.
+
+    Returns x .* y as a new matrix.
+    """ 
+
+    if x.size != y.size:
+        raise ValueError, "x and y must have the same size"
+    z = +x 
+    blas.tbmv(y, z, n=len(y), k=0, ldA=1) 
+    return z
+
+
+def had2(x, y, n=None):  
+    """
+    In-place Hadamard product x.*y of dense 'd' matrices x and y.
+
+    x and y are 'd' matrices of equal size.
+    
+    n is a nonnegative integer, with default value len(x).  If the
+    default value is used, len(x) must be equal to len(y).
+
+    On exit x[:n] is replaced with  x[:n].*y[:n].
+    """ 
+
+    if n is None: 
+        if x.size != y.size:
+            raise ValueError, "x and y must have the same size"
+        else:
+            n = len(x)
+    if len(x) < n or len(y) < n:
+        raise ValueError, "x and y must have length at least n"
+    blas.tbmv(y, x, n=n, k=0, ldA=1) 
+
+
+def ihad(x,y):  
+    """
+    Returns componentwise division x./y of dense 'd' matrices x and y.
+
+    y is a 'd' matrix.   x is a scalar or a 'd' matrix of the same
+    size as y.
+
+    Returns x ./ y as a new matrix.
+    """ 
+
+    if type(x) is float or type(x) is int:
+        z = matrix(x, y.size, tc='d')
+    else:
+        z = +x 
+    if z.size != y.size:
+        raise ValueError, "x and y must have the same size"
+    blas.tbsv(y, z, n=len(y), k=0, ldA=1) 
+    return z
+
+
+def ihad2(x, y, n=None):  
+    """
+    In-place Hadamard division x./y of dense matrices x and y.
+
+    x and y are dense 'd' matrices of equal size.
+    
+    n is a nonnegative integer, with default value len(x).  If the
+    default value is used, len(x) must be equal to len(y).
+
+    On exit x[:n] is replaced with  x[:n]./y[:n].
+    """ 
+
+    if n is None: 
+        if x.size != y.size:
+            raise ValueError, "x and y must have the same size"
+        else:
+            n = len(x)
+    if len(x) < n or len(y) < n:
+        raise ValueError, "x and y must have length at least n"
+    blas.tbsv(y, x, n=n, k=0, ldA=1) 
+
+
+def scopy(x, y):
+    """
+    y := x for symmetric or block-diagonal symmetric dense matrices.
+    """
+
+    if type(x) is matrix: 
+	blas.copy(x, y)
+    else:
+	for k in xrange(len(x)): blas.copy(x[k], y[k])
+
+	
+def sdot(x, y):
+    """
+    Inner product of two block-diagonal symmetric dense 'd' matrices.
+
+    x and y are square dense 'd' matrices, or lists of N square dense
+    'd' matrices.
+    """
+
+    a = 0.0
+    if type(x) is matrix:
+	n = x.size[0]
+	a += blas.dot(x, y, incx=n+1, incy=n+1, n=n)
+	for j in xrange(1,n):
+	    a += 2.0 * blas.dot(x, y, incx=n+1, incy=n+1, offsetx=j,
+		offsety=j, n=n-j)
+
+    else:
+	for k in xrange(len(x)):
+	    n = x[k].size[0]
+	    a += blas.dot(x[k], y[k], incx=n+1, incy=n+1, n=n)
+	    for j in xrange(1,n):
+		a += 2.0 * blas.dot(x[k], y[k], incx=n+1, incy=n+1, 
+		    offsetx=j, offsety=j, n=n-j)
+    return a
+
+
+def sscal(alpha, x):
+    """
+    x := alpha*x for symmetric or block-diagonal symmetric dense 'd'
+    matrices.
+    """
+
+    if type(x) is matrix: 
+	blas.scal(alpha, x)
+    else:
+	for xk in x: blas.scal(alpha, xk)
+
+
+def saxpy(x, y, alpha=1.0):
+    """
+    y := alpha*x + y for symmetric or block-diagonal symmetric dense 
+    'd' matrices.
+    """
+
+    if type(x) is matrix: 
+	blas.axpy(x, y, alpha=alpha)
+    else:
+	for k in xrange(len(x)): blas.axpy(x[k], y[k], alpha=alpha)
+
+
+def snrm2(x):
+    """
+    Frobenius norm of symmetric matrix or block-diagonal symmetric 
+    dense 'd' matrix.
+    """
+
+    return math.sqrt(sdot(x,x))
+
+
+def cngrnc(R, X, Y, trans='N', alpha=1.0, beta=0.0):
+    """
+    Congruence transformation
+
+	Y := alpha * R*X*R^T + beta*Y  if trans is 'N' 
+	Y := alpha * R^T*X*R + beta*Y  if trans is 'T'
+
+    R, X and Y are lists of square dense 'd' matrices.  
+    X may be equal to Y.
+    Note that trans='T' is slightly faster than trans='N'.
+    """
+
+    maxn = max([0] + [R_k.size[0] for R_k in R])
+    W = matrix(0.0, (maxn,maxn))
+    for k in xrange(len(R)):
+        n = R[k].size[0]
+
+        # scale diagonal of X by 1/2
+        blas.scal(0.5, X[k], inc=n+1)
+    
+        # W := R*tril(X) (trans is 'N') or W := tril(X)*R (trans is 'T')
+        blas.copy(R[k], W)
+        if trans == 'N': 
+	    blas.trmm(X[k], W, side='R', m=n, n=n, ldB=n)
+        else: 
+	    blas.trmm(X[k], W, side='L', m=n, n=n, ldB=n)
+
+        # scale diagonal of X by 2
+        blas.scal(2.0, X[k], inc=n+1)
+
+        # Y := alpha*(W*R' + R*W') + beta*Y 
+        blas.syr2k(R[k], W, Y[k], trans=trans, n=n, k=n, ldB=n, 
+            alpha=alpha, beta=beta)
+
+
+def kkt(H, A, Df, G, method=3):
+    """
+    Generates a solver for the KKT system
+
+        [ H   *   *     *  ] [ x   ]   [ bx   ]
+        [ A   0   *     *  ] [ y   ] = [ by   ].
+        [ Df  0  -Dnl   *  ] [ znl ]   [ bznl ] 
+        [ G   0   0    -Dl ] [ zl  ]   [ bzl  ]
+
+    kkt() does a symbolic factorization and returns a function for the 
+    numeric factorization.
+
+    If f = kkt(H, A, Df, G, method) then f(H, Df, dnl, dl) does the 
+    numeric factorization of the KKT matrix, with  
+    
+        Dnl = diag(dnl)^-2,  Dl = diag(dl)^-2, 
+
+    and returns a function for solving the system.   The arguments H 
+    and Df in f() can be different from the arguments in the call to 
+    kkt() but they must have the same sparsity pattern.
+
+    If g = f(H, Df, dnl, dl) then g(x, y, znl, zl) solves the system. 
+    On entry x, y, znl, zl are the righthand side.  On exit they are 
+    overwritten with the solution.
+    """
+
+    n, p, mnl, ml = H.size[0], A.size[0], Df.size[0], G.size[0]
+
+    if method == 1:
+
+        # Factor entire matrix via dense LDL.
+
+        ldK = n + p + mnl + ml
+        K = matrix(0.0, (ldK,ldK))
+        ipiv = matrix(0, (ldK,1))
+        u = matrix(0.0, (ldK,1))
+        def f(H, Df, dnl, dl):
+            blas.scal(0.0, K)
+            K[:n, :n] = H
+            K[n:n+p, :n] = A
+            K[n+p:n+p+mnl, :n] = Df
+            K[n+p+mnl:, :n] = G
+            K[(ldK+1)*(n+p) : (ldK+1)*(n+p+mnl) : ldK+1] = -dnl**-2
+            K[(ldK+1)*(n+p+mnl) :: ldK+1] = -dl**-2
+            lapack.sytrf(K, ipiv)
+            def g(x, y, znl, zl):
+                u[:n] = x
+                u[n:n+p] = y
+                u[n+p:n+p+mnl] = znl 
+                u[n+p+mnl:] = zl 
+                lapack.sytrs(K, ipiv, u)
+                x[:] = u[:n]
+                y[:] = u[n:n+p]
+                znl[:] = u[n+p:n+p+mnl]
+                zl[:] = u[n+p+mnl:]
+            return g 
+        return f
+
+    elif method == 2:
+ 
+        # Factor 
+        #
+        #        [ H + Df'*Dnl^-2*Df + G'*Dl^-2*G    * ]
+        #    S = [                                     ]
+        #        [ A                                 0 ] 
+        #
+        # via dense LDL (if p > 0) or Cholesky (if p = 0).
+        # To solve the KKT system, first solve 
+        #        
+        #        [ x ]   [ bx + Df'*Dnl^-2*bznl + G'*Dl^-2*bzl ]
+        #    S * [   ] = [                                     ]
+        #        [ y ]   [ by                                  ]
+        #
+        #    Dnl^2 * znl = Df*x - bznl
+        #    Dl^2 * zl = Dl.^-2 * (G*x - bzl).
+
+        ldK = n + p
+        K = matrix(0.0, (ldK,ldK))
+        if p: 
+            ipiv = matrix(0, (ldK,1))
+        if type(G) is matrix: 
+            Gsc = matrix(0.0, G.size) 
+        else:
+            Gsc = spmatrix(0.0, G.I, G.J, G.size) 
+        if type(Df) is matrix: 
+            Dfsc = matrix(0.0, Df.size) 
+        else:
+            Dfsc = spmatrix(0.0, Df.I, Df.J, Df.size) 
+        u = matrix(0.0, (ldK,1))
+        def f(H, Df, dnl, dl):
+            blas.scal(0.0, K)
+            K[:n, :n] = H
+            base.gemm(spmatrix(dnl, range(mnl), range(mnl), tc='d'), 
+                Df, Dfsc, partial=True)
+            base.syrk(Dfsc, K, trans='T', beta=1.0)
+            base.gemm(spmatrix(dl, range(ml), range(ml), tc='d'), G, 
+                Gsc, partial=True)
+            base.syrk(Gsc, K, trans='T', beta=1.0)
+            K[n:,:n] = A
+            if p: 
+                lapack.sytrf(K, ipiv)
+            else: 
+                lapack.potrf(K)
+            def g(x, y, znl, zl):
+                u[:n] = x
+                had2(znl, dnl)
+                base.gemv(Dfsc, znl, u, trans='T', beta=1.0)
+                had2(zl, dl)
+                base.gemv(Gsc, zl, u, trans='T', beta=1.0)
+                u[n:n+p] = y
+                if p: 
+                    lapack.sytrs(K, ipiv, u)
+                else: 
+                    lapack.potrs(K, u)
+                x[:] = u[:n]
+                y[:] = u[n:n+p]
+                base.gemv(Dfsc, x, znl, beta=-1.0)
+                had2(znl, dnl)
+                base.gemv(Gsc, x, zl, beta=-1.0)
+                had2(zl, dl)
+            return g 
+        return f
+
+    else: 
+
+        # Factor 
+        #
+        #     S = H + Df'*Dnl^-2*Df + G'*Dl^-2*G  
+        #     K = A*S^-1*A'
+        #
+        # using dense (L*L') or sparse (P'*L*L'*P) Cholesky 
+        # factorizations.  To solve the system, solve
+        #
+        #     K*y = A * S^{-1} * (bx + Df'*Dnl^-2*bznl + G'*Dl^-2*bzl) 
+        #          - by
+        #     S*x = bx + Df'*Dnl.^-2* bznl + G'*Dl^-2*bzl - A'*y
+        #     Dnl^2 * znl = Df*x - bznl
+        #     Dl^2 * zl  = G*x - bzl
+        #    
+        # If S turns out to be singular in the first factorization,
+        # then switch to the following method.
+        #
+        # Factor 
+        #
+        #     S = H + Df'*Dnl^-2*Df + G'*Dl^-2*G  + A'*A
+        #     K = A*S^-1*A'
+        #
+        # using dense (L*L') or sparse (P'*L*L'*P) Cholesky 
+        # factorizations.  To solve the system, solve
+        #
+        #    K*y = A*S^{-1} * (bx + Df'*Dnl^-2*bznl + G'*Dl^-2*bzl + 
+        #          A'*by) - by
+        #    S*x = bx + Df'*Dnl.^-2*bznl + G'*Dl^-2*bzl + A'*by - A'*y
+        #    Dnl^2*znl = Df*x - bznl
+        #    Dl^2*zl = G*x - bzl.
+
+        if type(G) is matrix: 
+            Gsc = matrix(0.0, G.size) 
+        else:
+            Gsc = spmatrix(0.0, G.I, G.J, G.size) 
+        if type(Df) is matrix: 
+            Dfsc = matrix(0.0, Df.size) 
+        else:
+            Dfsc = spmatrix(0.0, Df.I, Df.J, Df.size) 
+        F = {'firstcall': True, 'singular': False}
+        if matrix in (type(H), type(G), type(Df)):
+            F['S'] = matrix(0.0, (n,n))
+            F['K'] = matrix(0.0, (p,p))
+        else: 
+            F['S'] = spmatrix([], [], [], (n,n), 'd')
+            F['Sf'] = None
+            if type(A) is matrix:
+                F['K'] = matrix(0.0, (p,p))
+            else:
+                F['K'] = spmatrix([], [], [], (p,p), 'd')
+
+        def f(H, Df, dnl, dl):
+            base.gemm(spmatrix(dnl, range(mnl), range(mnl), tc='d'), Df,
+                Dfsc, partial=True)
+            base.gemm(spmatrix(dl, range(ml), range(ml), tc='d'), G, 
+                Gsc, partial=True)
+            if F['firstcall']:
+                F['firstcall'] = False
+                F['S'][:,:] = H
+                base.syrk(Dfsc, F['S'], trans='T', beta=1.0) 
+                base.syrk(Gsc, F['S'], trans='T', beta=1.0) 
+                try:
+                    if type(F['S']) is matrix: 
+                        lapack.potrf(F['S']) 
+                    else:
+                        F['Sf'] = cholmod.symbolic(F['S'])
+                        cholmod.numeric(F['S'], F['Sf'])
+                except ArithmeticError:
+                    F['singular'] = True 
+                    if type(A) is matrix and type(F['S']) is spmatrix:
+                        F['S'] = matrix(0.0, (n,n))
+                    F['S'][:,:] = H 
+                    base.syrk(Dfsc, F['S'], trans='T', beta=1.0) 
+                    base.syrk(Gsc, F['S'], trans='T', beta=1.0) 
+                    base.syrk(A, F['S'], trans='T', beta=1.0) 
+                    if type(F['S']) is matrix: 
+                        lapack.potrf(F['S']) 
+                    else:
+                        F['Sf'] = cholmod.symbolic(F['S'])
+                        cholmod.numeric(F['S'], F['Sf'])
+
+            else:
+                # S := H, but do not remove nonzeros from the zero 
+                # pattern of S if S is sparse.
+                if type(F['S']) is spmatrix and type(H) is spmatrix:
+                    F['S'] *= 0.0
+                    F['S'] += H
+                else:
+                    F['S'][:,:] = H 
+
+                base.syrk(Dfsc, F['S'], trans='T', beta=1.0, 
+                    partial=True)
+                base.syrk(Gsc, F['S'], trans='T', beta=1.0, 
+                    partial=True)
+                if F['singular']:
+                    base.syrk(A, F['S'], trans='T', beta=1.0, 
+                        partial=True) 
+                if type(F['S']) is matrix: 
+                    lapack.potrf(F['S']) 
+                else:
+                    cholmod.numeric(F['S'], F['Sf'])
+
+            if type(F['S']) is matrix: 
+                # Asct := L^-1*A', factor K = Asct'*Asct.
+                if type(A) is matrix: 
+                    Asct = A.T
+                else: 
+                    Asct = matrix(A.T)
+                blas.trsm(F['S'], Asct)
+                blas.syrk(Asct, F['K'], trans='T')
+                lapack.potrf(F['K'])
+
+            else:
+                # Asct := L^{-1}*P*A' and factor K = Asct'*Asct.
+                if type(A) is matrix:
+                    Asct = A.T
+                    cholmod.solve(F['Sf'], Asct, sys=7)
+                    cholmod.solve(F['Sf'], Asct, sys=4)
+                    blas.syrk(Asct, F['K'], trans='T')
+                    lapack.potrf(F['K']) 
+                else:
+                    Asct = cholmod.spsolve(F['Sf'], A.T, sys=7)
+                    Asct = cholmod.spsolve(F['Sf'], Asct, sys=4)
+                    base.syrk(Asct, F['K'], trans='T')
+                    Kf = cholmod.symbolic(F['K'])
+                    cholmod.numeric(F['K'], Kf)
+
+            def g(x, y, znl, zl):
+
+                # If not F['singular']:
+                # x := L^{-1} * P * (x + Df'*(dnl.^2.*znl) + 
+                #      G'*dl.^2.*zl)
+                #    = L^{-1} * P * (bx + Df'*Dnl^-2*bznl + 
+                #      G'*Dl^-2*bzl)
+                #
+                # If F['singular']:
+                # x := L^{-1} * P * (x + Df'*(dnl.^2.*znl) + 
+                #      G'*(dl.^2.*zl) + A'*y)
+                #    = L^{-1} * P * (bx + Df'*Dnl^-2*bznl + 
+                #      G'*Dl^-2*bzl + A'*by)
+
+                had2(znl, dnl)
+                base.gemv(Dfsc, znl, x, trans='T', beta=1.0)
+                had2(zl, dl)
+                base.gemv(Gsc, zl, x, trans='T', beta=1.0)
+                if F['singular']:
+                    base.gemv(A, y, x, trans='T', beta=1.0)
+                if type(F['S']) is matrix:
+                    blas.trsv(F['S'], x)
+                else:
+                    cholmod.solve(F['Sf'], x, sys=7)
+                    cholmod.solve(F['Sf'], x, sys=4)
+
+                # y := K^{-1} * (Asc*x - y)
+                #    = K^{-1} * (A * S^{-1} * (bx + Df'*Dnl^-2*bznl +
+                #      G'*Dl^-2*bzl) - by)  (if not F['singular'])
+                #    = K^{-1} * (A * S^{-1} * (bx + Df'*Dnl^-2*bznl +
+                #      G'*Dl^-2*bzl + A'*by) - by)  (if F['singular'])
+
+                base.gemv(Asct, x, y, trans='T', beta=-1.0)
+                if type(F['K']) is matrix:
+                    lapack.potrs(F['K'], y)
+                else:
+                    cholmod.solve(Kf, y)
+
+                # x := P' * L^{-T} * (x - Asc'*y)
+                #    = S^{-1} * (bx + Df'*Dnl^-2*bznl + G'*Dl^-2*bzl 
+                #      - A'*y) (if not F['singular'])  
+                #    = S^{-1} * (bx + Df'*Dnl^-2*bznl + G'*Dl^-2*bzl
+                #      + A'*by - A'*y) (if F['singular'])
+
+                base.gemv(Asct, y, x, alpha=-1.0, beta=1.0)
+                if type(F['S']) is matrix:
+                    blas.trsv(F['S'], x, trans='T')
+                else:
+                    cholmod.solve(F['Sf'], x, sys=5)
+                    cholmod.solve(F['Sf'], x, sys=8)
+
+                # znl := dnl .* (Dfsc*x - znl) 
+                #      = Dnl^-2 * (Df*x - bznl)
+                base.gemv(Dfsc, x, znl, beta=-1.0)
+                had2(znl, dnl)
+
+                # zl := dl .* (Gsc*x - zl) 
+                #     = Dl^-2 * (G*x - bzl)
+                base.gemv(Gsc, x, zl, beta=-1.0)
+                had2(zl, dl)
+
+            return g
+
+        return f
diff --git a/src/python/modeling.py b/src/python/modeling.py
new file mode 100644
index 0000000..8b8cb70
--- /dev/null
+++ b/src/python/modeling.py
@@ -0,0 +1,3214 @@
+"""
+Modeling tools for PWL convex optimization.
+
+Routines for specifying and solving convex optimization problems with
+piecewise-linear objective and constraint functions.
+"""
+
+# This file is part of CVXOPT version 0.8.2.
+# Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+
+from string import strip
+from cvxopt.base import matrix, spmatrix
+from cvxopt import blas, solvers 
+import __builtin__
+
+__all__ = ["variable", "constraint", "op", "min", "max", "sum", "dot"]
+ 
+class variable(object):
+
+    """
+    Vector valued optimization variable.
+
+    variable(size=1, name='') creates a variable of length size.
+
+
+    Arguments:
+
+    size      length of the variable (positive integer)
+    name      name of the variable (string)
+
+
+    Attributes:
+
+    name      the name of the variable
+    value     None or a 'd' matrix of size (len(self),1)
+    _size     the length of the variable  
+    """
+
+    def __init__(self, size=1, name=''):
+
+        self.name = name   
+        self.value = None
+        if type(size) is int and size > 0: 
+            self._size = size
+        else: 
+            raise TypeError, "size must be a positive integer"
+
+
+    def __len__(self):
+         
+        return self._size
+
+
+    def __repr__(self):
+
+        return "variable(%d,'%s')" %(len(self),self.name)  
+
+
+    def __str__(self):
+
+        s = self.name
+        if self.name:  s += ': '
+        s += 'variable of length %d\nvalue: ' %len(self)
+        if self.value is None: 
+            s += 'None'
+        else: 
+            s += '\n' + str(self.value)
+        return s
+
+
+    def __setattr__(self,name,value):
+
+        if name == 'value':
+            if value is None or (_isdmatrix(value) and 
+                value.size == (len(self),1)):
+                object.__setattr__(self, name, value)
+
+            elif type(value) is int or type(value) is float:
+                object.__setattr__(self, name, 
+                    matrix(value, (len(self),1), tc='d'))
+
+            else:
+                raise AttributeError, "invalid type or size for "\
+                    "attribute 'value'"
+
+        elif name == 'name':
+            if type(value) is str:
+                object.__setattr__(self,name,value)
+
+            else:
+                raise AttributeError, "invalid type for attribute "\
+                    "'name'"
+
+        elif name == '_size':
+            object.__setattr__(self,name,value)
+
+        else:
+            raise AttributeError, "'variable' object has no attribute "\
+                "'%s'" %name
+
+
+    def __pos__(self):
+
+        f = _function()
+        f._linear._coeff[self] = matrix(1.0)
+        return f
+
+
+    def __neg__(self):
+
+        f = _function()
+        f._linear._coeff[self] = matrix(-1.0)
+        return f
+
+
+    def __abs__(self):
+
+        return max(self,-self)
+        
+
+    def __add__(self,other):
+
+        return (+self).__add__(other)
+
+
+    def __radd__(self,other):
+
+        return (+self).__radd__(other)
+
+
+    def __iadd__(self,other):
+
+        raise NotImplementedError, "in-place addition not implemented"\
+            " for 'variable' objects"
+
+
+    def __sub__(self,other):
+
+        return (+self).__sub__(other)
+
+
+    def __rsub__(self,other):
+
+        return (+self).__rsub__(other)
+
+
+    def __isub__(self,other):
+
+        raise NotImplementedError, "in-place subtraction not "\
+            "implemented for 'variable' objects"
+
+
+    def __mul__(self,other):
+
+        return (+self).__mul__(other)
+
+
+    def __rmul__(self,other):
+
+        return (+self).__rmul__(other)
+
+
+    def __imul__(self,other):
+
+        raise NotImplementedError, "in-place multiplication not "\
+            "implemented for 'variable' objects"
+
+
+    def __div__(self,other):
+
+        return (+self).__div__(other)
+
+
+    def __idiv__(self,other):
+
+        raise NotImplementedError, "in-place division not implemented "\
+            "for 'variable' objects"
+
+
+    def __eq__(self,other):
+
+        return constraint(self-other, '=')
+
+
+    def __le__(self,other):
+
+        return constraint(self-other, '<')
+
+
+    def __ge__(self,other):
+
+        return constraint(other-self, '<')
+
+
+    def __lt__(self,other):
+
+        raise NotImplementedError
+
+
+    def __gt__(self,other):
+
+        raise NotImplementedError
+
+
+    def __getitem__(self,key):
+
+        return (+self).__getitem__(key)
+
+
+
+class _function(object):
+
+    """
+    Vector valued function.
+
+    General form: 
+
+        f = constant + linear + sum of nonlinear convex terms + 
+            sum of nonlinear concave terms 
+
+    The length of f is the maximum of the lengths of the terms in the 
+    sum.  Each term must have length 1 or length equal to len(f).
+
+    _function() creates the constant function f=0 with length 1.
+
+
+    Attributes:
+
+    _constant      constant term as a 1-column dense 'd' matrix of 
+                   length 1 or length len(self)
+    _linear        linear term as a _lin  object of length 1 or length
+                   len(self)
+    _cvxterms      nonlinear convex terms as a list [f1,f2,...] with 
+                   each fi of type _minmax or _sum_minmax.  Each fi has
+                   length 1 or length equal to len(self).
+    _ccvterms      nonlinear concave terms as a list [f1,f2,...] with 
+                   each fi of type _minmax or _sum_minmax.  Each fi has
+                   length 1 or length equal to len(self).
+
+
+    Methods:
+
+    value()        returns the value of the function: None if one of the
+                   variables has value None;  a dense 'd' matrix of size
+                   (len(self),1) if all the variables have values
+    variables()    returns a (copy of) the list of variables
+    _iszero()      True if self is identically zero
+    _isconstant()  True if there are no linear/convex/concave terms
+    _islinear()    True if there are no constant/convex/concave terms
+    _isaffine()    True if there are no nonlinear convex/concave terms 
+    _isconvex()    True if there are no nonlinear concave terms
+    _isconcave()   True if there are no nonlinear convex terms
+    """
+
+    def __init__(self): 
+
+        self._constant = matrix(0.0)
+        self._linear = _lin()
+        self._cvxterms = []
+        self._ccvterms = []
+
+
+    def __len__(self):
+
+        if len(self._constant) > 1: return len(self._constant)
+
+        lg = len(self._linear)
+        if lg > 1: return lg
+
+        for f in self._cvxterms:
+            lg = len(f)
+            if lg > 1: return lg
+
+        for f in self._ccvterms:
+            lg = len(f)
+            if lg > 1: return lg
+
+        return 1
+
+
+    def __repr__(self):
+
+        if self._iszero():
+            return '<zero function of length %d>' %len(self)
+
+        elif self._isconstant():
+            return '<constant function of length %d>' %len(self)
+
+        elif self._islinear():
+            return '<linear function of length %d>' %len(self)
+
+        elif self._isaffine():
+            return '<affine function of length %d>' %len(self)
+
+        elif self._isconvex():
+            return '<convex function of length %d>' %len(self)
+
+        elif self._isconcave():
+            return '<concave function of length %d>' %len(self)
+
+        else:
+            return '<function of length %d>' %len(self)
+
+
+    def __str__(self):
+
+        s = repr(self)[1:-1] 
+
+        # print constant term if nonzero
+        if not self._iszero() and (len(self._constant) != 1 or 
+            self._constant[0]):
+            s += '\nconstant term:\n' + str(self._constant)
+
+        else:
+            s += '\n'
+
+        # print linear term if nonzero
+        if self._linear._coeff:
+            s += 'linear term: ' + str(self._linear)
+
+        # print nonlinear convex term if nonzero
+        if self._cvxterms: 
+            s += '%d nonlinear convex term(s):' %len(self._cvxterms)
+            for f in self._cvxterms: s += '\n' + str(f) 
+
+        # print nonlinear concave term if nonzero
+        if self._ccvterms: 
+            s += '%d nonlinear concave term(s):' %len(self._ccvterms)
+            for f in self._ccvterms: s += '\n' + str(f) 
+
+        return s
+
+    
+    def value(self):
+
+        val = self._constant
+
+        if self._linear._coeff:
+            nval = self._linear.value()     
+            if nval is None: return None
+            else: val = val + nval 
+
+        for f in self._cvxterms:
+            nval = f.value()
+            if nval is None: return None
+            else: val = val + nval
+
+        for f in self._ccvterms:
+            nval = f.value()
+            if nval is None: return None
+            else: val = val + nval
+
+        return val
+
+
+    def variables(self):
+
+        l = self._linear.variables()
+        for f in self._cvxterms:
+            l += [v for v in f.variables() if v not in l]
+        for f in self._ccvterms:
+            l += [v for v in f.variables() if v not in l]
+        return l
+
+
+    def _iszero(self):
+
+        if not self._linear._coeff and not self._cvxterms and \
+            not self._ccvterms and not blas.nrm2(self._constant): 
+            return True
+        else: return False
+
+
+    def _isconstant(self):
+
+        if not self._linear._coeff and not self._cvxterms and \
+            not self._ccvterms: return True
+        else: return False
+
+
+    def _islinear(self):
+
+        if len(self._constant) == 1 and not self._constant[0] and \
+            not self._cvxterms and not self._ccvterms: return True
+        else: return False
+
+
+    def _isaffine(self):
+
+        if not self._cvxterms and not self._ccvterms: return True
+        else: return False
+
+
+    def _isconvex(self):
+
+        if not self._ccvterms: return True
+        else: return False
+
+
+    def _isconcave(self):
+
+        if not self._cvxterms: return True
+        else: return False
+
+
+    def __pos__(self):
+
+        f = _function()
+        f._constant = +self._constant
+        f._linear = +self._linear
+        f._cvxterms = [+g for g in self._cvxterms]
+        f._ccvterms = [+g for g in self._ccvterms]
+        return f
+
+
+    def __neg__(self):
+
+        f = _function()
+        f._constant = -self._constant
+        f._linear = -self._linear
+        f._ccvterms = [-g for g in self._cvxterms]
+        f._cvxterms = [-g for g in self._ccvterms]
+        return f
+
+
+    def __add__(self,other):
+
+        # convert other to matrix (dense 'd' or sparse) or _function
+        if type(other) is int or type(other) is float:
+            other = matrix(other, tc='d')
+        elif _ismatrix(other):  # ie, dense 'd' or sparse
+            if other.size[1] != 1:
+                raise ValueError, 'incompatible dimensions'
+        elif type(other) is variable:
+            other = +other
+        elif type(other) is not _function:
+            return NotImplemented
+
+        if 1 != len(self) != len(other) != 1: 
+            raise ValueError, 'incompatible lengths'
+
+        f = _function()
+
+        if _ismatrix(other):
+            # this converts sparse other to dense 'd' 
+            f._constant = self._constant + other
+            f._linear = +self._linear 
+            f._cvxterms = [+fk for fk in self._cvxterms] 
+            f._ccvterms = [+fk for fk in self._ccvterms] 
+
+        else:  #type(other) is _function:
+            if not (self._isconvex() and other._isconvex()) and \
+                not (self._isconcave() and other._isconcave()):
+                raise ValueError, 'operands must be both convex or '\
+                    'both concave'
+
+            f._constant = self._constant + other._constant
+            f._linear = self._linear + other._linear
+            f._cvxterms = [+fk for fk in self._cvxterms] + \
+                [+fk for fk in other._cvxterms]
+            f._ccvterms = [+fk for fk in self._ccvterms] + \
+                [+fk for fk in other._ccvterms]
+
+        return f
+
+
+    def __radd__(self,other):
+
+        return self.__add__(other)
+
+
+    def __iadd__(self,other):
+
+        # convert other to matrix (dense 'd' or sparse) or _function
+        if type(other) is int or type(other) is float:
+            other = matrix(other, tc='d')
+        elif _ismatrix(other):
+            if other.size[1] != 1: 
+                raise ValueError, 'incompatible dimensions'
+        elif type(other) is variable:
+            other = +other
+        elif type(other) is not _function:
+            return NotImplemented
+
+        if len(self) != len(other) != 1: 
+            raise ValueError, 'incompatible lengths'
+
+        if _ismatrix(other):
+            if 1 == len(self._constant) != len(other): 
+                self._constant = self._constant + other
+            else:
+                self._constant += other
+
+        else:   #type(other) is _function:
+            if not (self._isconvex() and other._isconvex()) and \
+                not (self._isconcave() and other._isconcave()):
+                raise ValueError, 'operands must be both convex or '\
+                    'both concave'
+
+            if 1 == len(self._constant) != len(other._constant): 
+                self._constant = self._constant + other._constant
+            else:
+                self._constant += other._constant
+
+            if 1 == len(self._linear) != len(other._linear): 
+                self._linear = self._linear + other._linear
+            else:
+                self._linear += other._linear
+
+            self._cvxterms += [+fk for fk in other._cvxterms] 
+            self._ccvterms += [+fk for fk in other._ccvterms] 
+
+        return self
+
+
+    def __sub__(self,other):
+
+        # convert other to matrix (dense 'd' or sparse) or _function
+        if type(other) is int or type(other) is float:
+            other = matrix(other, tc='d')
+        elif _ismatrix(other):
+            if other.size[1] != 1: 
+                raise ValueError, 'incompatible dimensions'
+        elif type(other) is variable:
+            other = +other
+        elif type(other) is not _function:
+            return NotImplemented
+
+        if 1 != len(self) != len(other) != 1: 
+            raise ValueError, 'incompatible lengths'
+
+        f = _function()
+
+        if _ismatrix(other):
+            f._constant = self._constant - other
+            f._linear = +self._linear 
+            f._cvxterms = [+fk for fk in self._cvxterms]  
+            f._ccvterms = [+fk for fk in self._ccvterms] 
+
+        else:   #type(other) is _function:
+            if not (self._isconvex() and other._isconcave()) and \
+                not (self._isconcave() and other._isconvex()):
+                raise ValueError, 'operands must be convex and '\
+                    'concave or concave and convex'
+
+            f._constant = self._constant - other._constant
+            f._linear = self._linear - other._linear
+            f._cvxterms = [+fk for fk in self._cvxterms] + \
+                [-fk for fk in other._ccvterms]
+            f._ccvterms = [+fk for fk in self._ccvterms] + \
+                [-fk for fk in other._cvxterms]
+
+        return f
+
+
+    def __rsub__(self,other):
+
+        # convert other to matrix (dense 'd' or sparse) or _function
+        if type(other) is int or type(other) is float:
+            other = matrix(other, tc='d')
+        elif _isdmatrix(other):
+            if other.size[1] != 1: 
+                raise ValueError, 'incompatible dimensions'
+        elif type(other) is variable:
+            other = +other
+        elif type(other) is not _function:
+            return NotImplemented
+
+        if 1 != len(self) != len(other) != 1: 
+            raise ValueError, 'incompatible lengths'
+
+        f = _function()
+
+        if _ismatrix(other):
+            f._constant = other - self._constant 
+            f._linear = -self._linear 
+            f._cvxterms = [-fk for fk in self._ccvterms] 
+            f._ccvterms = [-fk for fk in self._cvxterms] 
+
+        else:   # type(other) is _function:
+            if not (self._isconvex() and other._isconcave()) and \
+                not (self._isconcave() and other._isconvex()):
+                raise ValueError, 'operands must be convex and '\
+                    'concave or concave and convex'
+
+            f._constant = other._constant - self._constant 
+            f._linear = other._linear - self._linear 
+            f._cvxterms = [-fk for fk in self._ccvterms] + \
+                [fk for fk in other._cvxterms]
+            f._ccvterms = [-fk for fk in self._cvxterms] + \
+                [fk for fk in other._ccvterms]
+
+        return f
+
+
+    def __isub__(self,other):
+
+        # convert other to matrix (dense or sparse 'd') or _function
+        if type(other) is int or type(other) is float:
+            other = matrix(other, tc='d')
+        elif _ismatrix(other):
+            if other.size[1] != 1: 
+                raise ValueError, 'incompatible dimensions'
+        elif type(other) is variable:
+            other = +other
+        elif type(other) is not _function:
+            return NotImplemented
+
+        if len(self) != len(other) != 1: 
+            raise ValueError, 'incompatible lengths'
+
+        if _ismatrix(other):
+            if 1 == len(self._constant) != len(other): 
+                self._constant = self._constant - other
+            else:
+                self._constant -= other
+
+        else:   #type(other) is _function:
+            if not (self._isconvex() and other._isconcave()) and \
+                not (self._isconcave() and other._isconvex()):
+                raise ValueError, 'operands must be convex and '\
+                    'concave or concave and convex'
+
+            if 1 == len(self._constant) != len(other._constant): 
+                self._constant = self._constant - other._constant
+            else:
+                self._constant -= other._constant
+
+            if 1 == len(self._linear) != len(other._linear): 
+                self._linear = self._linear - other._linear
+            else:
+                self._linear -= other._linear
+
+            self._cvxterms += [-fk for fk in other._ccvterms] 
+            self._ccvterms += [-fk for fk in other._cvxterms] 
+
+        return self
+
+
+    def __mul__(self,other):
+
+        if type(other) is int or type(other) is float: 
+            other = matrix(other, tc='d')
+
+        if (_ismatrix(other) and other.size == (1,1)) or \
+            (_isdmatrix(other) and other.size[1] == 1 == len(self)):
+
+            f = _function()
+
+            if other.size == (1,1) and other[0] == 0.0:
+                # if other is zero, return constant zero function
+                # of length len(self)
+                f._constant = matrix(0.0, (len(self),1))
+                return f
+
+            if len(self._constant) != 1 or self._constant[0]:
+                # skip if self._constant is zero
+                f._constant = self._constant*other
+
+            if self._linear._coeff: 
+                # skip if self._linear is zero
+                f._linear = self._linear*other
+
+            if not self._isaffine():  
+                # allow only multiplication with scalar
+                if other.size == (1,1):
+                    if other[0] > 0.0:
+                        f._cvxterms = \
+                            [fk*other[0] for fk in self._cvxterms]
+                        f._ccvterms = \
+                            [fk*other[0] for fk in self._ccvterms]
+
+                    elif other[0] < 0.0: 
+                        f._cvxterms = \
+                            [fk*other[0] for fk in self._ccvterms]
+                        f._ccvterms = \
+                            [fk*other[0] for fk in self._cvxterms]
+
+                    else: # already dealt with above
+                        pass
+
+                else: 
+                    raise ValueError, 'can only multiply with scalar'
+
+        else: 
+            raise TypeError, 'incompatible dimensions or types'
+
+        return f
+
+
+    def __rmul__(self,other):
+
+        if type(other) is int or type(other) is float: 
+            other = matrix(other, tc='d')
+
+        lg = len(self)
+
+        if (_ismatrix(other) and other.size[1] == lg) or \
+            (_isdmatrix(other) and other.size == (1,1)):
+
+            f = _function()
+
+            if other.size == (1,1) and other[0] == 0.0:
+                # if other is zero, return constant zero function
+                # of length len(self)
+                f._constant = matrix(0.0, (len(self),1))
+                return f
+
+            if len(self._constant) != 1 or self._constant[0]:
+                if 1 == len(self._constant) != lg and \
+                    not _isscalar(other):
+                    f._constant = other * self._constant[lg*[0]]
+                else:
+                    f._constant = other * self._constant
+            
+            if self._linear._coeff:
+                if 1 == len(self._linear) != lg and \
+                    not _isscalar(other):
+                    f._linear = other * self._linear[lg*[0]]
+                else:
+                    f._linear = other * self._linear
+
+            if not self._isaffine():
+                # allow only scalar multiplication
+                if other.size == (1,1):
+                    if other[0] > 0.0:
+                        f._cvxterms = [other[0] * fk for 
+                            fk in self._cvxterms]  
+                        f._ccvterms = [other[0] * fk for 
+                            fk in self._ccvterms]  
+
+                    elif other[0] < 0.0:
+                        f._cvxterms = [other[0] * fk for 
+                            fk in self._ccvterms]  
+                        f._ccvterms = [other[0] * fk for 
+                            fk in self._cvxterms]  
+
+                    else: pass
+
+                else: 
+                    raise ValueError, 'can only multiply with scalar'
+
+        else: 
+            raise TypeError, 'incompatible dimensions or types'
+
+        return f
+                
+
+    def __imul__(self,other):
+
+        if type(other) is int or type(other) is float: 
+            other = matrix(other, tc='d')
+
+        if _isdmatrix(other) and other.size == (1,1):
+
+            if other[0] == 0.0: 
+                self._constant = matrix(0.0, (len(self),1))
+                return self
+
+            if len(self._constant) != 1 or self._constant[0]:
+                self._constant *= other[0]
+
+            if self._linear._coeff:  self._linear *= other[0]
+
+            if not self._isaffine():
+                if other[0] > 0.0:
+                    for f in self._cvxterms: f *= other[0]
+                    for f in self._ccvterms: f *= other[0]
+
+                elif other[0] < 0.0:
+                    cvxterms = [f*other[0] for f in self._ccvterms]
+                    self._ccvterms = [f*other[0] for f in 
+                        self._cvxterms]
+                    self._cvxterms = cvxterms
+
+                else:
+                    pass
+
+            return self
+
+        else: 
+            raise TypeError, 'incompatible dimensions or types'
+
+
+    def __div__(self,other):
+
+        if type(other) is int or type(other) is float:
+            return self.__mul__(1.0/other)
+
+        elif _isdmatrix(other) and other.size == (1,1):
+            return self.__mul__(1.0/other[0])
+
+        else:
+            return NotImplemented
+
+
+    def __rdiv__(self,other):
+
+        return NotImplemented
+
+
+    def __idiv__(self,other):
+
+        if type(other) is int or type(other) is float:
+            return self.__imul__(1.0/other)
+
+        elif _isdmatrix(other) and other.size == (1,1):
+            return self.__imul__(1.0/other[0])
+
+        else:
+            return NotImplemented
+        
+
+    def __abs__(self):
+
+        return max(self,-self)
+
+
+    def __eq__(self,other):
+
+        return constraint(self-other, '=')
+
+
+    def __le__(self,other):
+
+        return constraint(self-other, '<')
+
+
+    def __ge__(self,other):
+
+        return constraint(other-self, '<')
+
+
+    def __lt__(self,other):
+
+        raise NotImplementedError
+
+
+    def __gt__(self,other):
+
+        raise NotImplementedError
+
+
+    def __getitem__(self,key):
+
+        lg = len(self)
+        l = _keytolist(key,lg)
+        if not l: raise ValueError, 'empty index set'
+
+        f = _function()
+
+        if len(self._constant) != 1 or self._constant[0]:
+            if 1 == len(self._constant) != lg: 
+                f._constant = +self._constant
+            else: 
+                f._constant = self._constant[l]
+
+        if self._linear:
+            if 1 == len(self._linear) != lg: 
+                f._linear = +self._linear
+            else: 
+                f._linear = self._linear[l]
+
+        for fk in self._cvxterms:
+            if 1 == len(fk) != lg: 
+                f._cvxterms += [+fk]
+
+            elif type(fk) is _minmax: 
+                f._cvxterms += [fk[l]]
+
+            else:  # type(fk) is _sum_minmax 
+                # fk is defined as fk = sum(fmax)
+                fmax = _minmax('max', *fk._flist)
+                # take f += sum_j fk[j][l] = sum_{gk in fmax} gk[l] 
+                f._cvxterms += [gk[l] for gk in fmax]
+
+        for fk in self._ccvterms:
+            if 1 == len(fk) != lg: 
+                f._ccvterms += [+fk]
+
+            elif type(fk) is _minmax:
+                f._ccvterms += [fk[l]]
+
+            else:  # type(fk) is _sum_minmax
+                # fk is defined as fk = sum(fmin)
+                fmin = _minmax('min',*fk._flist)
+                # take f += sum_j fk[j][l] = sum_{gk in fmin} gk[l] 
+                f._ccvterms += [gk[l] for gk in fmin]
+
+        return f
+
+
+
+def sum(s):
+
+    """
+    Built-in sum redefined to improve efficiency when s is a vector
+    function.  
+    
+    If type(s) is not _function object, this is the built-in sum 
+    without start argument.
+    """
+
+    if type(s) is _function:
+        lg = len(s)
+        f = _function()
+
+        if 1 == len(s._constant) != lg:
+            f._constant = lg * s._constant
+        else:
+            f._constant = matrix(sum(s._constant), tc='d')
+
+        if 1 == len(s._linear) != lg:
+            f._linear = lg * s._linear
+        else:
+            f._linear = sum(s._linear)
+
+        for c in s._cvxterms:
+            if len(c) == 1:
+                f._cvxterms += [lg*c]
+            else:  #type(c) must be _minmax if len(c) > 1
+                f._cvxterms += [_sum_minmax('max', *c._flist)]
+
+        for c in s._ccvterms:
+            if len(c) == 1:
+                f._ccvterms += [lg*c]
+            else:  #type(c) must be _minmax if len(c) > 1
+                f._ccvterms += [_sum_minmax('min', *c._flist)]
+
+        return f
+
+    else:
+        return __builtin__.sum(s)
+
+
+
+class _lin(object):
+
+    """
+    Vector valued linear function.
+
+
+    Attributes:
+
+    _coeff       dictionary {variable: coefficient}.  The coefficients
+                 are dense or sparse matrices.  Scalar coefficients are
+                 stored as 1x1 'd' matrices.
+
+
+    Methods:
+
+    value()        returns the value of the function: None if one of the
+                   variables has value None;  a dense 'd' matrix of size
+                   (len(self),1) if all the variables have values
+    variables()    returns a (copy of) the list of variables
+    _addterm()     adds a linear term  a*v
+    _mul()         in-place multiplication
+    _rmul()        in-place right multiplication
+    """
+
+
+    def __init__(self):
+     
+        self._coeff = {}
+
+
+    def __len__(self):
+    
+        for v,c in self._coeff.iteritems():
+            if c.size[0] > 1: 
+                return c.size[0]
+            elif _isscalar(c) and len(v) > 1: 
+                return len(v)
+        return 1
+
+
+    def __repr__(self):
+
+        return '<linear function of length %d>' %len(self)
+
+
+    def __str__(self):
+
+        s = repr(self)[1:-1] + '\n'
+        for v,c in self._coeff.iteritems(): 
+            s += 'coefficient of ' + repr(v) + ':\n'  + str(c) 
+        return s
+
+
+    def value(self):
+
+        value = matrix(0.0, (len(self),1))
+        for v,c in self._coeff.iteritems():
+            if v.value is None: 
+                return None
+            else: 
+                value += c*v.value   
+        return value
+
+
+    def variables(self):
+
+        return varlist(self._coeff.keys())
+   
+
+    def _addterm(self,a,v):   
+
+        """ 
+        self += a*v  with v variable and a int, float, 1x1 dense 'd' 
+        matrix, or sparse or dense 'd' matrix with len(v) columns.
+        """
+
+        lg = len(self)
+
+        if self._coeff.has_key(v):
+
+            # self := self + a*v with v a variable of self
+            #
+            # Valid types/sizes:
+            #
+            # 1. a is a matrix (sparse or dense) with a.size[0]>1,
+            #    a.size[1]=len(v), and either lg=1 or lg=a.size[0].
+            #
+            # 2. a is a matrix (sparse or dense), a.size = (1,len(v)),
+            #    lg arbitrary.
+            #
+            # 3. a is int or float or 1x1 dense matrix, and len(v)>1
+            #    and either lg=1 or lg=len(v)
+            #
+            # 4. a is int or float or 1x1 dense matrix, and len(v)=1
+
+            c = self._coeff[v]
+            if _ismatrix(a) and a.size[0] > 1 and a.size[1] == len(v)\
+                and (lg == 1 or lg == a.size[0]):
+                newlg = a.size[0]
+                if c.size == a.size:
+                    self._coeff[v] = c + a 
+                elif c.size == (1,len(v)):
+                    self._coeff[v] = c[newlg*[0],:] + a
+                elif _isdmatrix(c) and c.size == (1,1):
+                    m = +a
+                    m[::newlg+1] += c[0]
+                    self._coeff[v] = m
+                else:
+                    raise TypeError, 'incompatible dimensions'
+                    
+            elif _ismatrix(a) and a.size == (1,len(v)):
+                if c.size == (lg,len(v)):
+                    self._coeff[v] = c + a[lg*[0],:]
+                elif c.size == (1,len(v)):
+                    self._coeff[v] = c + a
+                elif _isdmatrix(c) and c.size == (1,1):
+                    m = a[lg*[0],:]
+                    m[::lg+1] += c[0]
+                    self._coeff[v] = m
+                else:
+                    raise TypeError, 'incompatible dimensions'
+
+            elif _isscalar(a) and len(v) > 1 and (lg == 1 or 
+                lg == len(v)):
+                newlg = len(v)
+                if c.size == (newlg,len(v)):
+                    self._coeff[v][::newlg+1] = c[::newlg+1] + a
+                elif c.size == (1,len(v)):
+                    self._coeff[v] = c[newlg*[0],:]
+                    self._coeff[v][::newlg+1] = c[::newlg+1] + a 
+                elif _isscalar(c):
+                    self._coeff[v] = c + a
+                else:
+                    raise TypeError, 'incompatible dimensions'
+
+            elif _isscalar(a) and len(v) == 1:
+                self._coeff[v] = c + a    # add a to every elt of c
+
+            else:
+                raise TypeError, 'coefficient has invalid type or '\
+                    'incompatible dimensions '
+
+        elif type(v) is variable:
+
+            # self := self + a*v with v not a variable of self
+            #
+            # 1. if a is a scalar and len(v)=lg or lg=1 or len(v)=1:
+            #    convert a to dense 1x1 matrix and add v:a pair to 
+            #    dictionary
+            #
+            # 2. If a is a matrix (dense or sparse) and a.size[1]=len(v)
+            #    and a.size[0]=lg or lg=1 or a.size[0]=1: 
+            #    make a copy of a and add v:a pair to dictionary
+
+            if _isscalar(a) and (lg == 1 or len(v) == 1 or 
+                len(v) == lg):
+                self._coeff[v] = matrix(a, tc='d')
+
+            elif _ismatrix(a) and a.size[1] == len(v) and \
+                (lg == 1 or a.size[0] == 1 or a.size[0] == lg):
+                self._coeff[v] = +a
+
+            else:
+                raise TypeError, 'coefficient has invalid type or '\
+                    'incompatible dimensions '
+        
+        else: 
+            raise TypeError, 'second argument must be a variable'
+
+
+    def _mul(self,a):
+
+        ''' 
+        self := self*a where a is scalar or matrix 
+        '''
+
+        if type(a) is int or type(a) is float:
+            for v in self._coeff.iterkeys(): self._coeff[v] *= a
+
+        elif _ismatrix(a) and a.size == (1,1):
+            for v in self._coeff.iterkeys(): self._coeff[v] *= a[0]
+        
+        elif len(self) == 1 and _isdmatrix(a) and a.size[1] == 1:
+            for v,c in self._coeff.iteritems(): self._coeff[v] = a*c
+
+        else: 
+            raise TypeError, 'incompatible dimensions'
+
+
+    def _rmul(self,a):
+
+        ''' 
+        self := a*self where a is scalar or matrix 
+        '''
+
+        lg = len(self)
+        if _isscalar(a):
+            for v in self._coeff.iterkeys(): self._coeff[v] *= a
+        
+        elif lg == 1 and _ismatrix(a) and a.size[1] == 1:
+            for v,c in self._coeff.iteritems(): self._coeff[v] = a*c
+
+        elif _ismatrix(a) and a.size[1] == lg: 
+            for v,c in self._coeff.iteritems():
+                if c.size == (1,len(v)):
+                    self._coeff[v] = a*c[lg*[0],:]
+                else: 
+                    self._coeff[v] = a*c
+             
+        else: 
+            raise TypeError, 'incompatible dimensions'
+
+
+    def __pos__(self):
+
+        f = _lin()
+        for v,c in self._coeff.iteritems(): f._coeff[v] = +c
+        return f
+
+
+    def __neg__(self):
+
+        f = _lin()
+        for v,c in self._coeff.iteritems(): f._coeff[v] = -c
+        return f
+
+
+    def __add__(self,other):
+
+        # self + other with other variable or _lin
+
+        f = +self
+
+        if type(other) is int or type(other) is float and not other:
+            # Needed to make sum(f) work, because it defaults to
+            # 0 + f[0] + ... + f[len(f)-1].
+            return f
+
+        if type(other) is variable: 
+            f._addterm(1.0, other)
+
+        elif type(other) is _lin:
+            for v,c in other._coeff.iteritems(): f._addterm(c,v)
+
+        else: return NotImplemented
+
+        return f
+
+
+    def __radd__(self,other):
+
+        return self.__add__(other)
+
+    
+    def __iadd__(self,other):
+
+        '''
+        self += other  
+        
+        Only allowed if it does not change the length of self.
+        '''
+
+        lg = len(self)
+
+        if type(other) is variable and (len(other) == 1 or 
+            len(other) == lg):
+            self._addterm(1.0,other)
+
+        elif type(other) is _lin and (len(other) == 1 or 
+            len(other) == lg): 
+            for v,c in other._coeff.iteritems(): self._addterm(c,v)
+
+        else: 
+            raise NotImplementedError, 'in-place addition must result '\
+                'in a function of the same length'
+        
+        return self
+
+
+    def __sub__(self,other):
+
+        f = +self
+
+        if type(other) is variable:
+            f._addterm(-1.0, other)
+        elif type(other) is _lin:
+            for v,c in other._coeff.iteritems(): f._addterm(-c,v)
+        else: 
+            return NotImplemented
+        
+        return f
+
+
+    def __rsub__(self,other):
+
+        f = -self
+
+        if type(other) is variable:
+            f._addterm(1.0, other)
+        elif type(other) is _lin:
+            for v,c in other._coeff.iteritems(): f._addterm(c,v)
+        else: 
+            return NotImplemented
+        
+        return f
+
+
+    def __isub__(self,other):
+
+        '''
+        self -= other  
+        
+        Only allowed if it does not change the length of self.
+        '''
+
+        lg = len(self)
+
+        if type(other) is variable and (len(other) == 1 or 
+            len(other) == lg):
+            self._addterm(-1.0, other)
+
+        elif type(other) is _lin and (len(other) == 1 or 
+            len(other) == lg):
+            for v,c in other._coeff.iteritems(): self._addterm(-c,v)
+
+        else: 
+            raise NotImplementedError, 'in-place subtraction must '\
+                'result in a function of the same length'
+        
+        return self
+
+
+    def __mul__(self,other):
+
+        if _isscalar(other) or _ismatrix(other):
+            f = +self
+            f._mul(other)
+
+        else: 
+            return NotImplemented
+
+        return f
+
+
+    def __rmul__(self,other):
+
+        if _isscalar(other) or _ismatrix(other):
+            f = +self
+            f._rmul(other)
+
+        else:
+            return NotImplemented
+
+        return f
+        
+
+    def __imul__(self,other):    
+
+        '''
+        self *= other  
+        
+        Only allowed for scalar multiplication with a constant (int, 
+        float, 1x1 'd' matrix).
+        '''
+
+        if _isscalar(other): 
+            self._mul(other)
+        else: 
+            raise NotImplementedError, 'in-place multiplication '  \
+                'only defined for scalar multiplication'
+        return self
+
+
+    def __getitem__(self,key):
+
+        l = _keytolist(key,len(self))
+        if not l: raise ValueError, 'empty index set'
+
+        f = _lin()
+        for v,c in self._coeff.iteritems():
+            if c.size == (len(self), len(v)):  
+                f._coeff[v] = c[l,:]
+
+            elif _isscalar(c) and len(v) == 1:  
+                f._coeff[v] = matrix(c, tc='d')
+
+            elif c.size == (1,1) and len(v) > 1:
+                # create a sparse matrix with 1.0 element in 
+                # position (k,l[k]) for k in xrange(len(l)) 
+                f._coeff[v] = spmatrix([], [], [], (len(l),len(v)), 'd')
+                f._coeff[v][[l[k]*len(l)+k for k in xrange(len(l))]] \
+                    = c[0]
+
+            else:  # c is 1 by len(v)
+                f._coeff[v] = c[len(l)*[0],:]
+
+        return f
+
+
+
+class _minmax(object):
+
+    """
+    Componentwise maximum or minimum of functions.  
+
+    A function of the form f = max(f1,f2,...,fm) or f = max(f1) or
+    f = min(f1,f2,...,fm) or f = min(f1) with each fi an object of 
+    type _function.  
+
+    If m>1, then len(f) = max(len(fi)) and f is the componentwise 
+    maximum/minimum of f1,f2,...,fm.  Each fi has length 1 or length 
+    equal to len(f).
+
+    If m=1, then len(f) = 1 and f is the maximum/minimum of the 
+    components of f1: f = max(f1[0],f1[1],...) or 
+    f = min(f1[0],f1[1],...).
+   
+
+    Attributes:
+
+    _flist       [f1,f2,...,fm]
+    _ismax       True for 'max', False for 'min'
+
+
+    Methods:
+
+    value()      returns the value of the function
+    variables()  returns a copy of the list of variables
+    """
+
+    def __init__(self,op,*s):  
+
+        self._flist = []
+
+        if op == 'max':
+            self._ismax = True
+        else: 
+            self._ismax = False
+
+        if len(s) == 1: 
+
+            if type(s[0]) is variable or (type(s[0]) is _function and 
+                (s[0]._isconvex() and self._ismax) or 
+                (s[0]._isconcave() and not self._ismax)):
+                self._flist += [+s[0]]
+            else:
+                raise TypeError, 'unsupported argument type'
+
+        else:
+            # cnst will be max/min of the constant arguments
+            cnst = None  
+
+            lg = 1
+            for f in s:
+                if type(f) is int or type(f) is float: 
+                    f = matrix(f, tc='d')
+
+                if _isdmatrix(f) and f.size[1] == 1:
+                    if cnst is None: 
+                        cnst = +f
+                    elif self._ismax: 
+                        cnst = _vecmax(cnst,f)
+                    else:
+                        cnst = _vecmin(cnst,f)
+
+                elif type(f) is variable or type(f) is _function:
+                    self._flist += [+f]
+
+                else:
+                    raise TypeError, 'unsupported argument type'
+
+                lgf = len(f)
+                if 1 != lg != lgf != 1:
+                    raise ValueError, 'incompatible dimensions'
+                elif 1 == lg != lgf: 
+                    lg = lgf
+
+            if cnst: self._flist += [_function()+cnst]
+
+
+    def __len__(self):
+
+        if len(self._flist) == 1: return 1
+        for f in self._flist:
+            lg = len(f)
+            if len(f) > 1: return lg
+        return 1
+        
+
+    def __repr__(self):
+
+        if self._ismax: s = 'maximum'
+        else: s = 'minimum'
+
+        if len(self._flist) == 1:
+            return '<' + s + ' component of a function of length %d>'\
+                %len(self._flist[0])
+        else:
+            return "<componentwise " + s + " of %d functions of "\
+                "length %d>" %(len(self._flist),len(self))
+
+
+    def __str__(self):
+
+        s = repr(self)[1:-1] + ':'
+        if len(self._flist) == 1:
+            s += '\n' + repr(self._flist[0])[1:-1]
+        else:
+            for k in xrange(len(self._flist)):
+                s += "\nfunction %d: " %k + repr(self._flist[k])[1:-1]
+        return s
+
+
+    def value(self):
+ 
+        if self._ismax:
+            return _vecmax(*[f.value() for f in self._flist])
+        else:
+            return _vecmin(*[f.value() for f in self._flist])
+
+
+    def variables(self):
+
+        l = varlist()
+        for f in self._flist:
+            l += [v for v in f.variables() if v not in l]
+        return l
+
+
+    def __pos__(self):
+         
+        if self._ismax:
+            f = _minmax('max', *[+fk for fk in self._flist])
+        else:
+            f = _minmax('min', *[+fk for fk in self._flist])
+        
+        return f
+
+
+    def __neg__(self):
+
+        if self._ismax:
+            f = _minmax('min', *[-fk for fk in self._flist])
+        else:
+            f = _minmax('max', *[-fk for fk in self._flist])
+        return f
+
+
+    def __mul__(self,other):
+
+        if type(other) is int or type(other) is float or \
+            (_ismatrix(other) and other.size == (1,1)):
+            if _ismatrix(other): other = other[0]
+
+            if other >= 0.0: 
+                if self._ismax:
+                    f = _minmax('max', *[other*fk for fk in 
+                        self._flist])
+                else:
+                    f = _minmax('min', *[other*fk for fk in
+                        self._flist])
+
+            else: 
+                if self._ismax:
+                    f = _minmax('min', *[other*fk for fk in 
+                        self._flist])
+                else:
+                    f = _minmax('max', *[other*fk for fk in 
+                        self._flist])
+                
+            return f 
+
+        else:
+            return NotImplemented
+
+                
+    def __rmul__(self,other):
+
+        return self.__mul__(other)
+
+
+    def __imul__(self,other):
+
+        if _isscalar(other):
+            if type(other) is matrix: other = other[0]
+            for f in self._flist:  f *= other
+            if other < 0.0: self._ismax = not self._ismax
+            return self
+
+        raise NotImplementedError, 'in-place multiplication is only '\
+            'defined for scalars'
+
+
+    def __getitem__(self,key):
+
+        lg = len(self)
+        l = _keytolist(key,lg)
+        if not l: raise ValueError, 'empty index set'
+
+        if len(self._flist) == 1: fl = list(self._flist[0])    
+        else: fl = self._flist
+
+        if self._ismax: f = _minmax('max')
+        else: f = _minmax('min')
+
+        for fk in fl:
+            if 1 == len(fk) != lg:  f._flist += [+fk]
+            else:  f._flist += [fk[l]]
+
+        return f
+
+
+
+def max(*s):
+
+    """
+    Identical to the built-in max except when some of the arguments are 
+    variables or functions.
+
+    f = max(s1,s2,...) returns the componentwise maximum of s1,s2,..,
+    as a convex function with len(f) = max(len(si)).
+    The arguments si can be scalars, 1-column dense 'd' matrices, 
+    variables, or functions.  At least one argument must be a function 
+    or a variable.  The arguments can be scalars or vectors with length 
+    equal to len(f).
+
+    f = max(s) with len(s) > 1 returns the maximum component of s as 
+    a function with len(f) = 1.  The argument can be a variable or a 
+    function.
+
+    f = max(s) with len(s) = 1 and s[0] a function returns s[0].
+
+    f = max(s) with s a list or tuple of variables, functions, 
+    constants, returns f = max(*s).
+
+    Does not work with generators (Python 2.4).
+    """
+
+    try: return __builtin__.max(*s)
+    except NotImplementedError:
+        f = _function()
+        try: 
+            f._cvxterms = [_minmax('max',*s)]
+            return f
+        except: 
+            # maybe s[0] is a list or tuple of variables, functions
+            # and constants
+            try: return max(*s[0])
+            except: raise NotImplementedError
+
+
+
+def min(*s):
+
+    """
+    Identical to the built-in min except when some of the arguments are 
+    variables or functions.
+
+    f = min(s1,s2,...) returns the componentwise minimum of s1,s2,..,
+    as function with len(f) = max(len(si)).
+    The arguments si can be scalars, 1-column dense 'd' matrices, 
+    variables, or functions.  At least one argument must be a function 
+    or a variable.  The arguments can be scalars or vectors with length 
+    equal to len(f).
+
+    f = min(s) with len(s) > 1 returns the minimum component of s as 
+    a function with len(f) = 1.  The argument can be a variable or a 
+    function.
+
+    f = min(s) with len(s) = 1 returns s[0].
+
+    f = min(s) with s a list or tuple of variables, functions, 
+    constants, returns f = min(*s).
+
+    Does not work with generators (Python 2.4).
+    """
+
+    try: return __builtin__.min(*s)
+    except NotImplementedError:
+        f = _function()
+        try: 
+            f._ccvterms = [_minmax('min',*s)]
+            return f
+        except:
+            # maybe s[0] is a list or tuple of variables, functions
+            # and constants
+            try: return min(*s[0])
+            except: raise NotImplementedError
+
+
+
+class _sum_minmax(_minmax):
+
+    """
+    Sum of componentwise maximum or minimum of functions.  
+
+    A function of the form f = sum(max(f1,f2,...,fm)) or 
+    f = sum(min(f1,f2,...,fm)) with each fi an object of 
+    type _function.  
+
+    m must be greater than 1.  len(f) = 1.
+    Each fi has length 1 or length equal to max_i len(fi)).
+
+
+    Attributes:
+
+    _flist       [f1,f2,...,fm]
+    _ismax       True for 'max', False for 'min'
+
+
+    Methods:
+
+    value()      returns the value of the function
+    variables()  returns a copy of the list of variables
+    _length()    number of terms in the sum
+    """
+
+    def __init__(self,op,*s):  
+
+        _minmax.__init__(self,op,*s)
+        if len(self._flist) == 1: 
+            raise TypeError, 'expected more than 1 argument'
+
+
+    def __len__(self):
+
+        return 1
+
+
+    def _length(self):
+
+        for f in self._flist:
+            lg = len(f)
+            if len(f) > 1: return lg
+        return 1
+
+
+    def __repr__(self):
+
+        if self._ismax: s = 'maximum'
+        else: s = 'minimum'
+        return "<sum of componentwise " + s + " of %d functions of "\
+            "length %d>" %(len(self._flist),len(self))
+
+
+    def __str__(self):
+
+        s = repr(self)[1:-1] 
+        for k in xrange(len(self._flist)):
+            s += "\nfunction %d: " %k + repr(self._flist[k])[1:-1]
+        return s
+
+
+    def value(self):
+ 
+        if self._ismax:
+            return matrix(sum(_vecmax(*[f.value() for f in 
+                self._flist])), tc='d')
+        else:
+            return matrix(sum(_vecmin(*[f.value() for f in 
+                self._flist])), tc='d')
+
+
+    def __pos__(self):
+         
+        if self._ismax:
+            f = _sum_minmax('max', *[+fk for fk in self._flist])
+        else:
+            f = _sum_minmax('min', *[+fk for fk in self._flist])
+        
+        return f
+
+
+    def __neg__(self):
+
+        if self._ismax:
+            f = _sum_minmax('min', *[-fk for fk in self._flist])
+        else:
+            f = _sum_minmax('max', *[-fk for fk in self._flist])
+        return f
+
+
+    def __mul__(self,other):
+
+        if type(other) is int or type(other) is float or \
+            (_ismatrix(other) and other.size == (1,1)):
+
+            if _ismatrix(other): other = other[0]
+
+            if other >= 0.0: 
+                if self._ismax:
+                    f = _sum_minmax('max', *[other*fk for fk in 
+                        self._flist])
+                else:
+                    f = _sum_minmax('min', *[other*fk for fk in
+                        self._flist])
+
+            else: 
+                if self._ismax:
+                    f = _sum_minmax('min', *[other*fk for fk in 
+                        self._flist])
+                else:
+                    f = _sum_minmax('max', *[other*fk for fk in 
+                        self._flist])
+                
+            return f 
+
+        else:
+            return NotImplemented
+
+                
+    def __rmul__(self,other):
+
+        return self.__mul__(other)
+
+
+    def __getitem__(self,key):
+
+        l = _keytolist(key,1)
+        if not l: raise ValueError, 'empty index set'
+
+        # expand sum and convert to a  _function
+        if self._ismax: f = sum(_minmax('max',*self._flist))
+        else: f = sum(_minmax('min',*self._flist))
+
+        return f[l]
+
+
+
+class constraint(object):
+
+    """
+    Equality or inequality constraint.
+
+    constraint(f, ctype='=', name='') constructs a constraint
+    f=0 (if ctype is '=') or f<=0 (if ctype is '<').
+
+
+    Arguments:
+
+    f                convex function if '<', affine function if '='
+    ctype            '=' or '<'
+    name             string with the constraint name
+
+
+    Attributes:
+
+    multiplier       a variable of length len(f).  multiplier.name is 
+                     the constraint name with '_mul' appended.
+    name             constraint name.  Writing to .name also modifies 
+                     the name of .multiplier.  
+    _f               the constraint function (borrowed reference)
+    _type            '=' or '<'
+
+
+    Methods:
+
+    value()          returns the value of the constraint function
+    variables()      returns the variables of the constraint function
+    type()           returns ._type 
+    _aslinearineq()  converts convex piecewise-linear inequality into 
+                     an equivalent set of linear inequalities
+    """
+
+    def __init__(self, f, ctype='=', name=''):
+
+        if ctype == '=' or ctype  == '<':
+            self._type = ctype
+        else:
+            raise TypeError, "'ctype' argument must be '<' or '='"
+
+        if type(f) is not _function:
+            raise TypeError, "'f' argument must be a function"
+        
+        if ctype == '=':
+            if f._isaffine(): self._f = f
+            else:
+                raise TypeError, "constraint function must be affine"
+        
+        else:
+            if f._isconvex(): self._f = f
+            else:
+                raise TypeError, "constraint function must be convex"
+ 
+        self.name = name
+        self.multiplier = variable(len(self), name + '_mul')
+        
+
+    def __len__(self):
+    
+        return len(self._f)
+
+
+    def __repr__(self):
+
+        lg = len(self)
+
+        if self._type == '=': s = 'equality'
+        else: s = 'inequality'
+
+        if lg == 1: t = "<scalar %s" %s
+        else: t = "<%s in R^%d" %(s,lg)
+
+        if self.name != '': return t + ", '" + self.name + "'>"
+        else: return t + ">"
+
+
+    def __str__(self):
+
+        return repr(self)[1:-1] + '\nconstraint function:\n' + \
+            str(self._f)
+
+
+    def __setattr__(self,name,value):
+
+        if name == 'name':
+            if type(value) is str:
+                object.__setattr__(self,name,value)
+                if hasattr(self,'multiplier'): 
+                    self.multiplier.name = value + '_mul'
+            else:
+                raise TypeError, "invalid type for attribute 'name'"
+
+        elif name == 'multiplier' or name == '_type' or name == '_f': 
+            object.__setattr__(self,name,value)
+
+        else:
+            raise AttributeError, "'constraint' object has no "\
+                "attribute '%s'" %name
+
+
+    def type(self):
+
+        """ Returns '=' for equality constraints, '<' for inequality."""
+        
+        return self._type
+
+
+    def value(self):
+
+        """ Returns value of the constraint function."""
+
+        return self._f.value()
+
+
+    def variables(self):
+
+        """ Returns a list of variables of the constraint function."""
+
+        return self._f.variables()
+
+
+    def _aslinearineq(self):
+
+        """ 
+        Converts a convex PWL inequality into an equivalent set of 
+        linear inequalities. 
+
+        Returns a tuple (ineqs, aux_ineqs, aux_vars).  
+
+        If self is a linear inequailty, then ineqs = [self], 
+        aux_ineqs = [], aux_vars = [].
+
+        If self is PWL then ineqs and aux_ineqs are two lists of 
+        linear inequalities that together are equivalent to self.
+        They are separated in two sets so that the multiplier for self 
+        depends only on the multipliers of the constraints in ineqs:
+        - if len(self) == max(len(ineqs[k])), then the multiplier of 
+          self is sum_k ineqs[k].multiplier
+        - if len(self) == max(len(ineqs[k])), then the multiplier of 
+          self is sum(sum_k ineqs[k].multiplier)
+
+        aux_vars is a varlist with new auxiliary variables.
+        """
+
+        if self.type() != '<': 
+            raise TypeError, 'constraint must be an inequality'
+
+        ineqs, aux_ineqs, aux_vars = [], [], varlist()
+
+        # faff._constant and faff._linear are references to the 
+        # affine part of the constraint function
+        faff = _function()
+        faff._constant = self._f._constant 
+        faff._linear = self._f._linear
+
+        cvxterms = self._f._cvxterms
+        if not cvxterms:  # inequality is linear
+            ineqs += [self]
+
+        elif len(cvxterms) == 1 and type(cvxterms[0]) is _minmax:
+            # constraint is of the form f = faff + max() <= 0
+
+            if len(cvxterms[0]._flist) == 1:
+                # constraint of the form f = faff + max(f0) <= 0 
+                f0 = cvxterms[0]._flist[0]
+
+                if len(faff) == 1:
+                    # write as scalar + f0 <= 0 with f0 possibly a 
+                    # vector
+                    c = faff + f0 <= 0
+                    c.name = self.name
+                    c, caux, newvars = c._aslinearineq()
+                    ineqs += c
+                    aux_ineqs += caux
+                    aux_vars += newvars
+
+                else:
+                    # write as vector + f0[k] <= 0 for all k
+                    for k in xrange(len(f0)):
+                        c = faff + f0[k] <= 0
+                        c.name = self.name + '(%d)' %k 
+                        c, caux, newvars = c._aslinearineq()
+                        ineqs += c
+                        aux_ineqs += caux
+                        aux_vars += newvars
+
+            else:
+                # constraint of the form f = faff + max(f0,f1,...) <= 0
+                for k in xrange(len(cvxterms[0]._flist)):
+                    c = faff + cvxterms[0]._flist[k] <= 0
+                    c.name = self.name + '(%d)' %k 
+                    c, caux, newvars = c._aslinearineq()
+                    ineqs += c
+                    aux_ineqs += caux
+                    aux_vars += newvars
+
+        else:
+            # constraint is of the form f = faff + g1 + g2 .... <= 0 
+            # with gi = max() or sum max() and the number of gi's can
+            # be one.
+
+            sumt = _function()
+
+            for k in xrange(len(cvxterms)):
+                if type(cvxterms[k]) is _minmax:
+                    # gk is max(f0,f1,...)
+
+                    tk = variable(len(cvxterms[k]), 
+                        self.name + '_x' + str(k))
+                    aux_vars += [tk]
+                    sumt = sumt + tk
+
+                    if len(cvxterms[k]._flist) == 1:
+                        # add constraint gk = max(f0) <= tk
+
+                        f0 = cvxterms[k]._flist[0]
+                        c = f0 <= tk
+                        c.name = self.name + '[%d]' %k
+                        c, caux, newvars = c._aslinearineq()
+                        aux_ineqs += c + caux
+                        aux_vars += newvars
+
+                    else:
+                        # add constraint gk = max(f0,f1, ... ) <= tk
+
+                        for j in xrange(len(cvxterms[k]._flist)):
+                            fj = cvxterms[k]._flist[j]
+                            c = fj <= tk
+                            c.name = self.name + '[%d](%d)' %(k,j)
+                            c, caux, newvars = c._aslinearineq()
+                            aux_ineqs += c + caux
+                            aux_vars += newvars
+
+                else:
+                    # gk is sum(max(f0,f1,...)
+
+                    tk = variable(cvxterms[k]._length(), self.name + 
+                        '_x' + str(k))
+                    aux_vars += [tk]
+                    sumt = sumt + sum(tk)
+
+                    # add contraint max(f0,f1, ... ) <= tk
+                    for j in xrange(len(cvxterms[k]._flist)):
+                        fj = cvxterms[k]._flist[j]
+                        c = fj <= tk
+                        c.name = self.name + '[%d](%d)' %(k,j)
+                        c, caux, newvars = c._aslinearineq()
+                        aux_ineqs += c + caux
+                        aux_vars += newvars
+
+            c = faff + sumt <= 0 
+            c.name = self.name
+            ineqs += [c] 
+                   
+        return (ineqs, aux_ineqs, aux_vars)
+
+
+
+class op(object):
+
+    """
+    An optimization problem.
+
+    op(objective=0.0, constraints=None, name '') constructs an 
+    optimization problem.
+
+
+    Arguments:
+
+    objective       scalar (int, float, 1x1 dense 'd' matrix), scalar 
+                    variable, scalar affine function or scalar convex
+                    piecewise-linear function.  Scalars and variables 
+                    are converted to affine functions.  
+    constraints     None, a single constraint, or a list of constraints
+                    None means the same as an empty list.  A single 
+                    constraint means the same as a singleton list.
+    name            string with the name of the LP
+
+
+    Attributes:
+
+    objective       the objective function (borrowed reference to the 
+                    function passed as argument).  
+    name            the name of the optimization problem
+    status          initially None.  After solving the problem, 
+                    summarizes the outcome.
+    _inequalities   list of inequality constraints 
+    _equalities     list of equality constraints 
+    _variables      a dictionary {v: dictionary with keys 'o','i','e'}
+                    The keys v are the variables in the problem.
+                    'o': True/False depending on whether v appears in 
+                    the objective or not;
+                    'i': list of inequality constraints v appears in;
+                    'e': list of equality constraints v appears in.
+               
+
+    Methods:
+
+    variables()     returns a list of variables.  The list is a varlist
+                    (defined below), ie, a subclass of 'list'.
+    constraints()   returns a list of constraints 
+    inequalities()  returns a list of inequality constraints
+    equalities()    returns a list of equality constraints
+    delconstraint() deletes a constraint 
+    addconstraint() adds a constraint
+    _inmatrixform() returns an equivalent LP in matrix form
+    solve()         solves the problem
+    tofile()        if the problem is an LP, writes it to an MPS file
+    fromfile()      reads an LP from an MPS file
+    """
+     
+    def __init__(self, objective=0.0, constraints=None, name=''):
+
+        self._variables = dict()
+
+        self.objective = objective   
+        for v in self.objective.variables():
+            self._variables[v] = {'o': True, 'i': [], 'e': []}
+
+        self._inequalities, self._equalities = [], []
+        if constraints is None: 
+            pass
+        elif type(constraints) is constraint:
+            if constraints.type() == '<':
+                self._inequalities += [constraints]
+            else:
+                self._equalities += [constraints]
+        elif type(constraints) == list and not [c for c in constraints
+            if type(c) is not constraint]:
+            for c in constraints:
+                if c.type() == '<':
+                    self._inequalities += [c]
+                else:
+                    self._equalities += [c]
+        else: 
+            raise TypeError, 'invalid argument for constraints' 
+
+        for c in self._inequalities:
+            for v in c.variables():
+                if self._variables.has_key(v):
+                    self._variables[v]['i'] += [c]
+                else:
+                    self._variables[v] = {'o': False, 'i': [c], 'e': []}
+
+        for c in self._equalities:
+            for v in c.variables():
+                if self._variables.has_key(v):
+                    self._variables[v]['e'] += [c]
+                else:
+                    self._variables[v] = {'o': False, 'i': [], 'e': [c]}
+
+        self.name = name
+        self.status = None
+
+
+    def __repr__(self):
+
+        n = sum(map(len,self._variables))
+        m = sum(map(len,self._inequalities))
+        p = sum(map(len,self._equalities))
+        return "<optimization problem with %d variables, %d inequality"\
+            " and %d equality constraint(s)>" %(n,m,p)
+
+
+    def __setattr__(self,name,value):
+
+        if name == 'objective':
+
+            if _isscalar(value):
+                value = _function() + value
+            elif type(value) is variable and len(value) == 1:
+                value = +value
+            elif type(value) is _function and value._isconvex() and \
+                len(value) == 1:
+                pass
+            else:
+                raise TypeError, "attribute 'objective' must be a "\
+                    "scalar affine or convex PWL function"
+
+            # remove variables in _variables that only appear in current
+            # objective 
+            for v in self.variables():
+                if not self._variables[v]['i'] and not \
+                    self._variables[v]['e']: del self._variables[v]
+
+            object.__setattr__(self,'objective',value)
+
+            # update _variables
+            for v in self.objective.variables():
+                if not self._variables.has_key(v):
+                    self._variables[v] = {'o': True, 'i': [], 'e': []}
+                else:
+                    self._variables[v]['o'] = True
+
+        elif name == 'name':
+            if type(value) is str:
+                object.__setattr__(self,name,value)
+            else:
+                raise TypeError, "attribute 'name' must be string"
+
+        elif name == '_inequalities' or name == '_equalities' or \
+            name == '_variables' or name == 'status':
+            object.__setattr__(self,name,value)
+
+        else:
+            raise AttributeError, "'op' object has no attribute "\
+                "'%s'" %name
+
+
+    def variables(self):    
+    
+        """ Returns a list of variables of the LP. """
+
+        return varlist(self._variables.keys())
+
+
+    def constraints(self):
+
+        """ Returns a list of constraints of the LP."""
+
+        return self._inequalities + self._equalities
+
+
+    def equalities(self):
+    
+        """ Returns a list of equality constraints of the LP."""
+
+        return list(self._equalities)
+
+
+    def inequalities(self):
+
+        """ Returns a list of inequality constraints of the LP."""
+        
+        return list(self._inequalities)
+
+
+    def delconstraint(self,c):
+
+        """ 
+        Deletes constraint c from the list of constrains  
+        """
+
+        if type(c) is not constraint:
+            raise TypeError, "argument must be of type 'constraint'"
+
+        try: 
+            if c.type() == '<': 
+                self._inequalities.remove(c)
+                for v in c.variables():
+                    self._variables[v]['i'].remove(c)
+            else: 
+                self._equalities.remove(c)
+                for v in c.variables():
+                    self._variables[v]['e'].remove(c)
+            if not self._variables[v]['o'] and \
+                not self._variables[v]['i'] and \
+                not self._variables[v]['e']:
+                del self._variables[v]
+
+        except ValueError:  # c is not a constraint
+           pass
+
+
+    def addconstraint(self,c):
+
+        """ 
+        Adds constraint c to the list of constraints. 
+        """
+
+        if type(c) is not constraint:
+            raise TypeError, 'argument must be of type constraint'
+
+        if c.type() == '<': self._inequalities += [c]             
+        if c.type() == '=': self._equalities += [c]             
+        for v in c.variables():
+            if c.type() == '<':
+                if self._variables.has_key(v):
+                    self._variables[v]['i'] += [c]
+                else:
+                    self._variables[v] = {'o': False, 'i': [c], 'e': []}
+            else:
+                if self._variables.has_key(v):
+                    self._variables[v]['e'] += [c]
+                else:
+                    self._variables[v] = {'o': False, 'i': [], 'e': [c]}
+
+
+    def _islp(self):
+
+        """ 
+        Returns True if self is an LP; False otherwise.
+        """
+
+        if not self.objective._isaffine(): return False
+        for c in self._inequalities:
+            if not c._f._isaffine(): return False
+        for c in self._equalities: 
+            if not c._f._isaffine(): return False
+        return True
+
+
+    def _inmatrixform(self, format='dense'):
+
+        """ 
+        Converts self to an LP in matrix form 
+
+                minimize    c'*x+d
+                subject to  G*x <= h
+                            A*x = b.
+
+        c, h, b are dense column matrices; G and A sparse or dense 
+        matrices depending on format ('sparse' or 'dense').   
+
+        If self is already an LP in matrix form with the correct matrix
+        types, then _inmatrixform() returns None.  Otherwise it returns 
+        a tuple (newlp, vmap, mmap).
+
+        newlp is an LP in matrix form with the correct format and 
+        matrix types.
+
+        vmap is a dictionary with the variables of self as keys and
+        affine functions as values.  For each variable v of self, 
+        vmap[v] is a function of the new variable x that can be 
+        evaluated to obtain the solution v from the solution x.
+
+        mmap is a dictionary with the constraints of self as keys and
+        affine functions as values.  For each constraint c of self, 
+        mmap[c] is a function of the multipliers of the new lp that can
+        be evaluated to obtain the optimal multiplier for c.
+        """
+
+        variables, aux_variables = self.variables(), varlist()   
+
+        # lin_ineqs is a list of linear inequalities in the original
+        # problem.  pwl_ineqs is a dictionary {i: [c1,c2,...], ...} 
+        # where i is a PWL inequality in the original problem.
+        # aux_ineqs are new auxiliary inequalities that together
+        # with the ck constraints in pwl_ineqs are equivalent to the
+        # original ones.  The sum of the multipliers of the constraints
+        # in pwl_ineqs[i] forms the multiplier of i.
+
+        lin_ineqs, pwl_ineqs, aux_ineqs = [], dict(), []
+        for i in self._inequalities:
+            if i._f._isaffine(): lin_ineqs += [i]
+            else: pwl_ineqs[i] = []
+
+        equalities = self._equalities
+        objective = +self.objective
+
+        # return None if self is already an LP in the requested form 
+        if objective._isaffine() and len(variables) == 1 and \
+            not pwl_ineqs and len(lin_ineqs) <= 1 and \
+            len(equalities) <= 1:
+            v = variables[0]
+
+            if lin_ineqs: G = lin_ineqs[0]._f._linear._coeff[v]
+            else: G = None
+
+            if equalities: A = equalities[0]._f._linear._coeff[v]
+            else: A = None
+
+            if (format == 'dense' and (G is None or _isdmatrix(G)) and 
+                (A is None or _isdmatrix(A))) or \
+                (format == 'sparse' and (G is None or _isspmatrix(G)) 
+                and (A is None or _isspmatrix(A))):  
+                return None
+
+
+        # convert PWL objective to linear
+        if not objective._isaffine():
+
+            # f = affine + sum_k fk with each fk a maximum of convex 
+            # functions or a sum of a maximum of convex functions.  
+            # If fk is a maximum of convex functions we introduce a
+            # new variable tk and replace fk in the objective with tk,
+            # with a new constraint fk <= tk.
+            # If fk is sum(gk) where gk is a maximum of convex 
+            # functions we introduce a new variable tk and replace fk 
+            # in the objective with sum(tk) with a new constraint 
+            # gk <= tk.
+
+            newobj = _function()
+            newobj._constant = +objective._constant
+            newobj._linear = +objective._linear
+
+            for k in xrange(len(objective._cvxterms)):
+                fk = objective._cvxterms[k]
+                
+                if type(fk) is _minmax:
+                    tk = variable(1, self.name + '_x' + str(k))
+                    newobj += tk
+                else:
+                    tk = variable(fk._length(), self.name + 
+                        '_x' + str(k))
+                    newobj += sum(tk)
+
+                aux_variables += [tk]
+
+                for j in xrange(len(fk._flist)):
+                    c = fk._flist[j] <= tk
+                    if xrange(len(fk._flist)) > 1:
+                        c.name = self.name + '[%d](%d)' %(k,j)
+                    else:
+                        c.name = self.name + '[%d]' %k
+                    c, caux, newvars = c._aslinearineq()  
+                    aux_ineqs += c + caux
+                    aux_variables +=  newvars
+            objective = newobj
+
+
+        # convert PWL inequalities to linear
+        for i in pwl_ineqs:
+            pwl_ineqs[i], caux, newvars = i._aslinearineq()
+            aux_ineqs += caux
+            aux_variables += newvars
+
+
+        # n is the length of x, c
+        # The variables are available in variables and aux_variables.
+        # variable v is stored in x[vslc[v]]
+        vslc = dict()
+        n = 0
+        for v in variables + aux_variables:
+            vslc[v] = slice(n, n+len(v))
+            n += len(v)
+        c = matrix(0.0, (1,n))
+        for v,cf in objective._linear._coeff.iteritems():
+            if _isscalar(cf): 
+                c[vslc[v]] = cf[0]
+            elif _isdmatrix(cf):  
+                c[vslc[v]] = cf[:]
+            else:  
+                c[vslc[v]] = matrix(cf[:], tc='d')
+        if n > 0:
+            x = variable(n)
+            cost = c*x + objective._constant
+        else:
+            cost = _function() + objective._constant[0]
+        vmap = dict()
+        for v in variables: vmap[v] = x[vslc[v]]
+
+
+        # m is the number of rows of G, h
+        # The inequalities are available in lin_lineqs, pwl_ineqs,
+        # aux_ineqs.
+        # inequality i is stored in G[islc[i],:]*x <= h[islc[i]]
+        islc = dict()
+        for i in lin_ineqs + aux_ineqs:  islc[i] = None
+        for c in pwl_ineqs:
+            for i in pwl_ineqs[c]: islc[i] = None
+        m = 0
+        for i in islc:
+            islc[i] = slice(m, m+len(i))
+            m += len(i)
+        if format == 'sparse': 
+            G = spmatrix(0.0, [], [], (m,n))   
+        else:   
+            G = matrix(0.0, (m,n))
+        h = matrix(0.0, (m,1))
+
+        for i in islc:
+            lg = len(i)
+            for v,cf in i._f._linear._coeff.iteritems():
+                if cf.size == (lg, len(v)):
+                    if _isspmatrix(cf) and _isdmatrix(G):
+                        G[islc[i], vslc[v]] = matrix(cf, tc='d')
+                    else:
+                        G[islc[i], vslc[v]] = cf
+                elif cf.size == (1, len(v)):
+                    if _isspmatrix(cf) and _isdmatrix(G):
+                        G[islc[i], vslc[v]] = \
+                            matrix(cf[lg*[0],:], tc='d')
+                    else:
+                        G[islc[i], vslc[v]] = cf[lg*[0],:]
+                else: #cf.size[0] == (1,1):
+                    G[islc[i].start+m*vslc[v].start:
+                        islc[i].stop+m*vslc[v].stop:m+1] = cf[0]
+            if _isscalar(i._f._constant):
+                h[islc[i]] = -i._f._constant[0]
+            else:
+                h[islc[i]] = -i._f._constant[:]
+
+
+        # p is the number of rows in A, b
+        # equality e is stored A[eslc[e],:]*x == b[eslc[e]]
+        eslc = dict()
+        p = 0
+        for e in equalities:
+            eslc[e] = slice(p, p+len(e))
+            p += len(e)
+        if format == 'sparse':
+            A = spmatrix(0.0, [], [], (p,n))  
+        else:
+            A = matrix(0.0, (p,n))
+        b = matrix(0.0, (p,1))
+
+        for e in equalities:
+            lg = len(e)
+            for v,cf in e._f._linear._coeff.iteritems():
+                if cf.size == (lg,len(v)):
+                    if _isspmatrix(cf) and _isdmatrix(A):
+                        A[eslc[e], vslc[v]] = matrix(cf, tc='d')
+                    else:
+                        A[eslc[e], vslc[v]] = cf
+                elif cf.size == (1, len(v)):
+                    if _isspmatrix(cf) and _isdmatrix(A):
+                        A[eslc[e], vslc[v]] = \
+                            matrix(cf[lg*[0],:], tc='d')
+                    else:
+                        A[eslc[e], vslc[v]] = cf[lg*[0],:]
+                else: #cf.size[0] == (1,1):
+                    A[eslc[e].start+p*vslc[v].start:
+                        eslc[e].stop+p*vslc[v].stop:p+1] = cf[0]
+            if _isscalar(e._f._constant):
+                b[eslc[e]] = -e._f._constant[0]
+            else:
+                b[eslc[e]] = -e._f._constant[:]
+
+        constraints = []
+        if n:
+            if m: constraints += [G*x<=h] 
+            if p: constraints += [A*x==b]
+        else:
+            if m: constraints += [_function()-h <= 0] 
+            if p: constraints += [_function()-b == 0]
+            
+        mmap = dict()
+
+        for i in  lin_ineqs:
+            mmap[i] = constraints[0].multiplier[islc[i]]
+
+        for i in  pwl_ineqs:
+            mmap[i] = _function()
+            for c in pwl_ineqs[i]:
+                mmap[i] = mmap[i] + constraints[0].multiplier[islc[c]]
+            if len(i) == 1 != len(mmap[i]):
+                mmap[i] = sum(mmap[i])
+
+        for e in  equalities:
+            mmap[e] = constraints[1].multiplier[eslc[e]]
+        return (op(cost, constraints), vmap, mmap)
+
+
+    def solve(self, format='dense', solver = 'default'):
+
+        """
+        Solves LP using dense or sparse solver.
+
+        format is 'dense' or 'sparse' 
+
+        solver is 'default', 'glpk' or 'mosek'
+
+        solve() sets self.status, and if status is 'optimal', also 
+        the value attributes of the variables and the constraint 
+        multipliers.  If solver is 'python' then if status is 
+        'primal infeasible', the constraint multipliers are set to
+        a proof of infeasibility; if status is 'dual infeasible' the
+        variables are set to a proof of dual infeasibility.
+        """
+
+        t = self._inmatrixform(format)
+
+        if t is None:
+            lp1 = self
+        else:
+            lp1, vmap, mmap = t[0], t[1], t[2]
+
+        variables = lp1.variables()
+        if not variables: 
+            raise TypeError, 'lp must have at least one variable'
+        x = variables[0]
+        c = lp1.objective._linear._coeff[x]
+        if _isspmatrix(c): c = matrix(c, tc='d')
+
+        inequalities = lp1._inequalities
+        if not inequalities:
+            raise TypeError, 'lp must have at least one inequality'
+        G = inequalities[0]._f._linear._coeff[x]
+        h = -inequalities[0]._f._constant
+
+        equalities = lp1._equalities
+        if equalities:
+            A = equalities[0]._f._linear._coeff[x]
+            b = -equalities[0]._f._constant
+        elif format == 'dense':
+            A = matrix(0.0, (0,len(x)))
+            b = matrix(0.0, (0,1))
+        else:
+            A = spmatrix(0.0, [], [],  (0,len(x)))
+            b = matrix(0.0, (0,1))
+
+        sol = solvers.lp(c[:], G, h, A, b, solver=solver)
+
+        x.value = sol['x']
+        inequalities[0].multiplier.value = sol['z']
+        if equalities: equalities[0].multiplier.value = sol['y']
+
+        self.status = sol['status']
+        if type(t) is tuple:
+            for v,f in vmap.iteritems(): v.value = f.value()
+            for c,f in mmap.iteritems(): c.multiplier.value = f.value()
+         
+
+
+    def tofile(self, filename):
+
+        ''' 
+        writes LP to file 'filename' in MPS format.
+        '''
+
+        if not self._islp(): raise TypeError, 'problem must be an LP'
+
+        constraints = self.constraints()
+        variables = self.variables()
+        inequalities = self.inequalities()
+        equalities = self.equalities()
+
+        f = open(filename,'w')
+        f.write('NAME')
+        if self.name: f.write(10*' ' + self.name[:8].rjust(8))
+        f.write('\n')
+
+        f.write('ROWS\n') 
+        f.write(' N  %8s\n' %'cost')
+        for k in xrange(len(constraints)):
+            c = constraints[k]
+            for i in xrange(len(c)):
+                if c._type == '<':
+                    f.write(' L  ')
+                else:
+                    f.write(' E  ')
+                if c.name:
+                    name = c.name 
+                else:
+                    name = str(k) 
+                name = name[:(7-len(str(i)))] + '_' + str(i)
+                f.write(name.rjust(8))
+                f.write('\n')
+
+        f.write('COLUMNS\n') 
+        for k in xrange(len(variables)):
+            v = variables[k]
+            for i in xrange(len(v)):
+                if v.name: 
+                    varname = v.name
+                else:
+                    varname = str(k)
+                varname = varname[:(7-len(str(i)))] + '_' + str(i)
+
+                if self.objective._linear._coeff.has_key(v):
+                    cf = self.objective._linear._coeff[v]
+                    if cf[i] != 0.0:
+                        f.write(4*' ' + varname[:8].rjust(8))
+                        f.write(2*' ' + '%8s' %'cost')
+                        f.write(2*' ' + '% 7.5E\n' %cf[i])
+
+                for j in xrange(len(constraints)):
+                     c = constraints[j]
+                     if c.name:
+                         cname = c.name 
+                     else:
+                         cname = str(j) 
+                     if c._f._linear._coeff.has_key(v):
+                         cf = c._f._linear._coeff[v]
+                         if cf.size == (len(c),len(v)):
+                             nz = [k for k in xrange(cf.size[0]) 
+                                 if cf[k,i] != 0.0]
+                             for l in nz:
+                                 conname = cname[:(7-len(str(l)))] \
+                                     + '_' + str(l)
+                                 f.write(4*' ' + varname[:8].rjust(8))
+                                 f.write(2*' ' + conname[:8].rjust(8))
+                                 f.write(2*' ' + '% 7.5E\n' %cf[l,i])
+                         elif cf.size == (1,len(v)):
+                             if cf[0,i] != 0.0:
+                                 for l in xrange(len(c)):
+                                     conname = cname[:(7-len(str(l)))] \
+                                         + '_' + str(l)
+                                     f.write(4*' ' + 
+                                         varname[:8].rjust(8))
+                                     f.write(2*' ' + 
+                                         conname[:8].rjust(8))
+                                     f.write(2*' '+'% 7.5E\n' %cf[0,i])
+                         elif _isscalar(cf):
+                             if cf[0,0] != 0.0:
+                                 conname = cname[:(7-len(str(i)))] \
+                                     + '_' + str(i)
+                                 f.write(4*' ' + varname[:8].rjust(8))
+                                 f.write(2*' ' + conname[:8].rjust(8))
+                                 f.write(2*' ' + '% 7.5E\n' %cf[0,0])
+                        
+        f.write('RHS\n') 
+        for j in xrange(len(constraints)):
+            c = constraints[j]
+            if c.name:
+                cname = c.name 
+            else:
+                cname = str(j) 
+            const = -c._f._constant
+            for l in xrange(len(c)):
+                 conname = cname[:(7-len(str(l)))] + '_' + str(l)
+                 f.write(14*' ' + conname[:8].rjust(8))
+                 if const.size[0] == len(c):
+                     f.write(2*' ' + '% 7.5E\n' %const[l])
+                 else:
+                     f.write(2*' ' + '% 7.5E\n' %const[0])
+
+        f.write('RANGES\n') 
+
+        f.write('BOUNDS\n') 
+        for k in xrange(len(variables)):
+            v = variables[k]
+            for i in xrange(len(v)):
+                if v.name:
+                    varname = v.name
+                else:
+                    varname = str(k)
+                varname = varname[:(7-len(str(i)))] + '_' + str(i)
+                f.write(' FR ' + 10*' ' + varname[:8].rjust(8) + '\n')
+
+        f.write('ENDATA\n')
+        f.close()
+
+
+    def fromfile(self, filename):
+
+        ''' 
+        Reads LP from file 'filename' assuming it is a fixed format 
+        ascii MPS file.
+
+        Does not include serious error checking. 
+
+        MPS features that are not allowed: comments preceded by 
+        dollar signs, linear combinations of rows, multiple righthand
+        sides, ranges columns or bounds columns.
+        '''
+
+        self._inequalities = []
+        self._equalities = []
+        self.objective = _function()
+        self.name = ''
+
+        f = open(filename,'r')
+
+        s = f.readline()
+        while s[:4] != 'NAME': 
+            s = f.readline()
+            if not s: 
+                raise SyntaxError, "EOF reached before 'NAME' section "\
+                    "was found" 
+        self.name = strip(s[14:22])
+
+        s = f.readline()
+        while s[:4] != 'ROWS': 
+            if not s: 
+                raise SyntaxError, "EOF reached before 'ROWS' section "\
+                    "was found" 
+            s = f.readline()
+        s = f.readline()
+
+
+        # ROWS section
+        functions = dict()   # {MPS row label: affine function}
+        rowtypes = dict()    # {MPS row label: 'E', 'G' or 'L'}
+        foundobj = False     # first occurrence of 'N' counts
+        while s[:7] != 'COLUMNS': 
+            if not s: raise SyntaxError, "file has no 'COLUMNS' section"
+            if len(strip(s)) == 0 or s[0] == '*': 
+                pass
+            elif strip(s[1:3]) in ['E','L','G']:
+                rowlabel = strip(s[4:12])
+                functions[rowlabel] = _function()
+                rowtypes[rowlabel] = strip(s[1:3])
+            elif strip(s[1:3]) == 'N':
+                rowlabel = strip(s[4:12])
+                if not foundobj:
+                    functions[rowlabel] = self.objective
+                    foundobj = True
+            else: 
+                raise ValueError, "unknown row type '%s'" %strip(s[1:3])
+            s = f.readline()
+        s = f.readline()
+
+
+        # COLUMNS section
+        variables = dict()   # {MPS column label: variable}
+        while s[:3] != 'RHS': 
+            if not s: 
+                raise SyntaxError, "EOF reached before 'RHS' section "\
+                    "was found" 
+            if len(strip(s)) == 0 or s[0] == '*': 
+                pass
+            else:
+                if strip(s[4:12]): collabel = strip(s[4:12])
+                if not variables.has_key(collabel):
+                    variables[collabel] = variable(1,collabel)
+                v = variables[collabel]
+                rowlabel = strip(s[14:22])
+                if not functions.has_key(rowlabel):
+                    raise KeyError, "no row label '%s'" %rowlabel
+                functions[rowlabel]._linear._coeff[v] = \
+                    matrix(float(s[24:36]), tc='d')
+                rowlabel = strip(s[39:47])
+                if rowlabel:
+                    if not functions.has_key(rowlabel):
+                        raise KeyError, "no row label '%s'" %rowlabel
+                    functions[rowlabel]._linear._coeff[v] =  \
+                        matrix(float(s[49:61]), tc='d')
+            s = f.readline()
+        s = f.readline()
+
+
+        # RHS section
+        # The RHS section may contain multiple right hand sides,
+        # identified with different labels in s[4:12].
+        # We read in only one rhs, the one with the first rhs label 
+        # encountered.
+        rhslabel = None
+        while s[:6] != 'RANGES' and s[:6] != 'BOUNDS' and \
+            s[:6] != 'ENDATA':
+            if not s: raise SyntaxError, \
+                "EOF reached before 'ENDATA' was found"
+            if len(strip(s)) == 0 or s[0] == '*': 
+                pass
+            else:
+                if None != rhslabel != strip(s[4:12]):
+                    # skip if rhslabel is different from 1st rhs label
+                    # encountered
+                    pass  
+                else:
+                    if rhslabel is None: rhslabel = strip(s[4:12])
+                    rowlabel = strip(s[14:22])
+                    if not functions.has_key(rowlabel):
+                        raise KeyError, "no row label '%s'" %rowlabel
+                    functions[rowlabel]._constant = \
+                        matrix(-float(s[24:36]), tc='d')
+                    rowlabel = strip(s[39:47])
+                    if rowlabel:
+                        if not functions.has_key(rowlabel):
+                            raise KeyError, "no row label '%s'" \
+                                %rowlabel
+                        functions[rowlabel]._constant = \
+                            matrix(-float(s[49:61]), tc='d')
+            s = f.readline()
+
+
+        # RANGES section
+        # The RANGES section may contain multiple range vectors,
+        # identified with different labels in s[4:12].
+        # We read in only one vector, the one with the first range label
+        # encountered.
+        ranges = dict()
+        for l in rowtypes.iterkeys(): 
+            ranges[l] = None   # {rowlabel: range value}
+        rangeslabel = None
+        if s[:6] == 'RANGES':
+            s = f.readline()
+            while s[:6] != 'BOUNDS' and s[:6] != 'ENDATA':
+                if not s: raise SyntaxError, \
+                    "EOF reached before 'ENDATA' was found"
+                if len(strip(s)) == 0 or s[0] == '*': 
+                    pass
+                else:
+                    if None != rangeslabel != strip(s[4:12]):
+                        pass  
+                    else:
+                        if rangeslabel == None: 
+                            rangeslabel = strip(s[4:12])
+                        rowlabel = strip(s[14:22])
+                        if not rowtypes.has_key(rowlabel):
+                            raise KeyError, "no row label '%s'"%rowlabel
+                        ranges[rowlabel] = float(s[24:36])
+                        rowlabel = strip(s[39:47])
+                        if rowlabel != '':
+                            if not functions.has_key(rowlabel):
+                                raise KeyError, "no row label '%s'" \
+                                    %rowlabel
+                            ranges[rowlabel] =  float(s[49:61])
+                s = f.readline()
+
+
+        # BOUNDS section
+        # The BOUNDS section may contain bounds vectors, identified 
+        # with different labels in s[4:12].
+        # We read in only one bounds vector, the one with the first 
+        # label encountered.
+        boundslabel = None
+        bounds = dict()
+        for v in variables.iterkeys():  
+            bounds[v] = [0.0, None] #{column label: [l.bound, u. bound]}
+        if s[:6] == 'BOUNDS':
+            s = f.readline()
+            while s[:6] != 'ENDATA':
+                if not s: raise SyntaxError, \
+                    "EOF reached before 'ENDATA' was found"
+                if len(strip(s)) == 0 or s[0] == '*': 
+                    pass
+                else:
+                    if None != boundslabel != strip(s[4:12]):
+                        pass  
+                    else:
+                        if boundslabel is None: 
+                            boundslabel = strip(s[4:12])
+                        collabel = strip(s[14:22])
+                        if not variables.has_key(collabel):
+                            raise ValueError, 'unknown column label ' \
+                                + "'%s'" %collabel
+                        if strip(s[1:3]) == 'LO': 
+                            if bounds[collabel][0] != 0.0:
+                                raise ValueError, "repeated lower "\
+                                    "bound for variable '%s'" %collabel
+                            bounds[collabel][0] = float(s[24:36])
+                        elif strip(s[1:3]) == 'UP': 
+                            if bounds[collabel][1] != None:
+                                raise ValueError, "repeated upper "\
+                                    "bound for variable '%s'" %collabel
+                            bounds[collabel][1] = float(s[24:36])
+                        elif strip(s[1:3]) == 'FX': 
+                            if bounds[collabel] != [0, None]:
+                                raise ValueError, "repeated bounds "\
+                                    "for variable '%s'" %collabel
+                            bounds[collabel][0] = float(s[24:36])
+                            bounds[collabel][1] = float(s[24:36])
+                        elif strip(s[1:3]) == 'FR': 
+                            if bounds[collabel] != [0, None]:
+                                raise ValueError, "repeated bounds "\
+                                    "for variable '%s'" %collabel
+                            bounds[collabel][0] = None
+                            bounds[collabel][1] = None
+                        elif strip(s[1:3]) == 'MI': 
+                            if bounds[collabel][0] != 0.0:
+                                raise ValueError, "repeated lower " \
+                                    "bound for variable '%s'" %collabel
+                            bounds[collabel][0] = None
+                        elif strip(s[1:3]) == 'PL': 
+                            if bounds[collabel][1] != None:
+                                raise ValueError, "repeated upper " \
+                                    "bound for variable '%s'" %collabel
+                        else:
+                            raise ValueError, "unknown bound type '%s'"\
+                                %strip(s[1:3])
+                s = f.readline()
+
+        for l, type in rowtypes.iteritems():
+
+            if type == 'L':   
+                c = functions[l] <= 0.0
+                c.name = l
+                self._inequalities += [c]
+                if ranges[l] != None:
+                    c = functions[l] >= -abs(ranges[l])     
+                    c.name = l + '_lb'
+                    self._inequalities += [c]
+            if type == 'G':   
+                c = functions[l] >= 0.0
+                c.name = l
+                self._inequalities += [c]
+                if ranges[l] != None:
+                    c = functions[l] <= abs(ranges[l])     
+                    c.name = l + '_ub'
+                    self._inequalities += [c]
+            if type == 'E':   
+                if ranges[l] is None or ranges[l] == 0.0:
+                    c = functions[l] == 0.0
+                    c.name = l
+                    self._equalities += [c]
+                elif ranges[l] > 0.0:
+                    c = functions[l] >= 0.0
+                    c.name = l + '_lb'
+                    self._inequalities += [c]
+                    c = functions[l] <= ranges[l]
+                    c.name = l + '_ub'
+                    self._inequalities += [c]
+                else:
+                    c = functions[l] <= 0.0
+                    c.name = l + '_ub'
+                    self._inequalities += [c]
+                    c = functions[l] >= ranges[l]
+                    c.name = l + '_lb'
+                    self._inequalities += [c]
+
+        for l,bnds in bounds.iteritems():
+            v = variables[l]
+            if None != bnds[0] != bnds[1]:
+                c = v >= bnds[0]
+                self._inequalities += [c]
+            if bnds[0] != bnds[1] != None:
+                c = v  <= bnds[1]
+                self._inequalities += [c]
+            if None != bnds[0] == bnds[1]:
+                c = v == bnds[0]
+                self._equalities += [c]
+
+        # Eliminate constraints with no variables
+        for c in self._inequalities + self._equalities:
+            if len(c._f._linear._coeff) == 0:
+                if c.type() == '=' and c._f._constant[0] != 0.0:
+                    raise ValueError, "equality constraint '%s' "\
+                       "has no variables and a nonzero righthand side"\
+                       %c.name
+                elif c.type() == '<' and c._f._constant[0] > 0.0:
+                    raise ValueError, "inequality constraint '%s' "\
+                       "has no variables and a negative righthand side"\
+                       %c.name
+                else:
+                    print "removing redundant constraint '%s'" %c.name
+                    if c.type() == '<': self._inequalities.remove(c)
+                    if c.type() == '=': self._equalities.remove(c)
+
+
+        self._variables = dict()
+        for v in self.objective._linear._coeff.keys():
+            self._variables[v] = {'o': True, 'i': [], 'e': []}
+        for c in self._inequalities:
+            for v in c._f._linear._coeff.keys():
+                if self._variables.has_key(v):
+                    self._variables[v]['i'] += [c]
+                else:
+                    self._variables[v] = {'o': False, 'i': [c], 'e': []}
+        for c in self._equalities:
+            for v in c._f._linear._coeff.keys():
+                if self._variables.has_key(v):
+                    self._variables[v]['e'] += [c]
+                else:
+                    self._variables[v] = {'o': False, 'i': [], 'e': [c]}
+           
+        self.status = None
+
+        f.close()
+
+
+
+def dot(x,y):
+
+    """
+    Inner products of variable or affine function with constant vector.
+    """ 
+    
+    if _isdmatrix(x) and _isdmatrix(y):
+        return blas.dot(x,y)
+
+    elif _isdmatrix(x) and (type(y) is variable or 
+        (type(y) is _function and y._isaffine()) and  
+        x.size == (len(y),1)):
+        return x.trans() * y
+
+    elif _isdmatrix(y) and (type(x) is variable or 
+        (type(x) is _function and x._isaffine()) and 
+        y.size == (len(x),1)):
+        return y.trans() * x
+
+    else:
+        raise TypeError, 'invalid argument types or incompatible '\
+            'dimensions' 
+
+
+
+def _isscalar(a):   
+
+    """ True if a is an int or float or 1x1 dense 'd' matrix. """
+
+    if type(a) is int or type(a) is float or (_isdmatrix(a) and
+        a.size == (1,1)): return True
+    else: return False
+
+
+
+def _isdmatrix(a):   
+
+    """ True if a is a nonempty dense 'd' matrix. """
+
+    if type(a) is matrix and a.typecode == 'd' and min(a.size) != 0: 
+        return True
+    else: 
+        return False
+
+
+
+def _isspmatrix(a):   
+
+    """ True if a is a nonempty sparse 'd' matrix. """
+
+    if type(a) is spmatrix and a.typecode == 'd' and min(a.size) != 0: 
+        return True
+    else: 
+        return False
+
+
+
+def _ismatrix(a):   
+
+    """ True if a is a nonempty 'd' matrix. """
+
+    if type(a) in (matrix, spmatrix) and a.typecode == 'd' and \
+        min(a.size) != 0: 
+        return True
+    else: 
+        return False
+
+
+
+def _keytolist(key,n):
+
+    """
+    Converts indices, index lists, index matrices, and slices of
+    a length n sequence into lists of integers.
+
+    key is the index passed to a call to __getitem__().
+    """
+
+    if type(key) is int:
+        if -n <= key < 0:  
+            l = [key+n] 
+        elif 0 <= key < n:  
+            l = [key] 
+        else:  
+            raise IndexError, 'variable index out of range'
+
+    elif (type(key) is list and not [k for k in key if type(k) is not 
+        int]) or (type(key) is matrix and key.typecode == 'i'):
+        l = [k for k in key if -n <= k < n]
+        if len(l) != len(key):
+            raise IndexError, 'variable index out of range'
+        for i in xrange(len(l)): 
+            if l[i] < 0: l[i] += n
+        
+    elif type(key) is slice:
+            
+        ind = key.indices(n)
+        l = range(ind[0],ind[1],ind[2])
+
+    else: 
+        raise TypeError, 'invalid key'
+
+    return l
+
+
+
+class varlist(list):
+ 
+    """
+    Standard list with __contains__() redefined to use 'is' 
+    instead of '=='.
+    """
+
+    def __contains__(self,item):
+            
+        for k in xrange(len(self)): 
+            if self[k] is item: return True
+        return False
+
+
+
+def _vecmax(*s):
+
+    """
+    _vecmax(s1,s2,...) returns the componentwise maximum of s1, s2,... 
+    _vecmax(s) returns the maximum component of s.
+    
+    The arguments can be None, scalars or 1-column dense 'd' vectors 
+    with lengths equal to 1 or equal to the maximum len(sk).  
+
+    Returns None if one of the arguments is None.  
+    """
+
+    if not s:
+        raise TypeError, "_vecmax expected at least 1 argument, got 0"
+
+    val = None
+    for c in s:
+
+        if c is None: 
+            return None
+
+        elif type(c) is int or type(c) is float: 
+            c = matrix(c, tc='d')
+
+        elif not _isdmatrix(c) or c.size[1] != 1:
+            raise TypeError, "incompatible type or size" 
+
+        if val is None:
+            if len(s) == 1:  return matrix(max(c), tc='d')
+            else: val = +c
+
+        elif len(val) == 1 != len(c): 
+            val = matrix([max(val[0],x) for x in c], tc='d')
+
+        elif len(val) != 1 == len(c):
+            val = matrix([max(c[0],x) for x in val], tc='d')
+
+        elif len(val) == len(c):
+            val = matrix( [max(val[k],c[k]) for k in xrange(len(c))], 
+                tc='d' )
+    
+        else: 
+            raise ValueError, 'incompatible dimensions'
+
+    return val
+
+
+
+def _vecmin(*s):
+
+    """
+    _vecmin(s1,s2,...) returns the componentwise minimum of s1, s2,... 
+    _vecmin(s) returns the minimum component of s.
+    
+    The arguments can be None, scalars or 1-column dense 'd' vectors 
+    with lengths equal  to 1 or equal to the maximum len(sk).  
+
+    Returns None if one of the arguments is None.  
+    """
+
+    if not s:
+        raise TypeError, "_vecmin expected at least 1 argument, got 0"
+
+    val = None
+    for c in s:
+
+        if c is None: 
+            return None
+
+        elif type(c) is int or type(c) is float: 
+            c = matrix(c, tc='d')
+
+        elif not _isdmatrix(c) or c.size[1] != 1:
+            raise TypeError, "incompatible type or size" 
+
+        if val is None:
+            if len(s) == 1:  return matrix(min(c), tc='d')
+            else: val = +c
+
+        elif len(val) == 1 != len(c): 
+            val = matrix( [min(val[0],x) for x in c], tc='d' )
+
+        elif len(val) != 1 == len(c):
+            val = matrix( [min(c[0],x) for x in val], tc='d' )
+
+        elif len(val) == len(c):
+            val = matrix( [min(val[k],c[k]) for k in xrange(len(c))], 
+                tc='d' )
+    
+        else: 
+            raise ValueError, 'incompatible dimensions'
+
+    return val
diff --git a/src/python/solvers.py b/src/python/solvers.py
new file mode 100644
index 0000000..5184dab
--- /dev/null
+++ b/src/python/solvers.py
@@ -0,0 +1,24 @@
+"""
+Convex optimization solvers.
+
+conelp:  solves semidefinite programs specified via functions.
+cp:      solves nonlinear convex problems.
+lp:      solves linear programs.
+gp:      solves geometric programs.
+nlcp:    solves nonlinear convex problems specified via functions.
+qp:      solves quadratic programs.
+sdp:     solves semidefinite programs.
+options: dictionary with customizable algorithm parameters.
+"""
+
+# This file is part of CVXOPT version 0.8.2.
+# Copyright 2004-2007 J. Dahl and L. Vandenberghe.
+
+import cvxopt
+from cvxopt.cvxprog import cp, qp, gp, nlcp
+from cvxopt.coneprog import conelp, lp, sdp
+solvecp, solveqp, solvegp, solvelp, solvesdp = cp, qp, gp, lp, sdp
+options = {}
+cvxopt.cvxprog.options = options
+cvxopt.coneprog.options = options
+__all__ = ['conelp', 'cp', 'lp', 'gp', 'nlcp', 'qp', 'sdp']
diff --git a/src/setup.py b/src/setup.py
new file mode 100644
index 0000000..d3fb1dd
--- /dev/null
+++ b/src/setup.py
@@ -0,0 +1,165 @@
+from distutils.core import setup, Extension
+from os import listdir
+
+# directory containing libblas and liblapack
+ATLAS_LIB_DIR = '/usr/lib'
+
+# Set to 1 if you are installing the fftw module.
+BUILD_FFTW = 0
+
+# directory containing libfftw3 (used only when BUILD_FFTW = 1)
+FFTW_LIB_DIR = '/usr/lib'       
+
+# directory containing fftw.h (used only when BUILD_FFTW = 1)
+FFTW_INC_DIR = '/usr/include'  
+
+# Set to 1 if you are installing the glpk module.
+BUILD_GLPK = 0
+
+# directory containing libglpk (used only when BUILD_GLPK = 1)
+GLPK_LIB_DIR = '/usr/lib'       
+
+# directory containing glpk.h (used only when BUILD_GLPK = 1)
+GLPK_INC_DIR = '/usr/include'  
+
+# Set to 1 if you are installing the MOSEK 4.0 module.
+BUILD_MOSEK = 0
+
+# directory containing libmosek (used only when BUILD_MOSEK = 1)
+MOSEK_LIB_DIR = '/usr/local/mosek/4/tools/platform/linux32x86/bin'  
+
+# directory containing mosek.h (used only when BUILD_MOSEK = 1)
+MOSEK_INC_DIR = '/usr/local/mosek/4/tools/platform/linux32x86/h'
+
+# Set to 1 if you are installing the DSDP module.
+BUILD_DSDP = 0
+
+# directory containing libdsdp.a (used only when BUILD_DSDP = 1)
+DSDP_LIB_DIR = '/usr/lib'
+ 
+# directory containing dsdp5.h (used only when BUILD_DSDP = 1)
+DSDP_INC_DIR = '/usr/include'
+
+extmods = []
+
+# optional modules
+
+if BUILD_FFTW:
+    fftw = Extension('fftw', libraries = ['fftw3', 'blas'],
+        include_dirs = [ FFTW_INC_DIR ],
+        library_dirs = [ FFTW_LIB_DIR, ATLAS_LIB_DIR ],
+        sources = ['C/fftw.c'] )
+    extmods += [fftw];
+
+if BUILD_GLPK:
+    glpk = Extension('glpk', libraries = ['glpk'],
+        include_dirs = [ GLPK_INC_DIR ],
+        library_dirs = [ GLPK_LIB_DIR ],
+        sources = ['C/glpk.c'] )
+    extmods += [glpk];
+
+# If the MOSEK module fails to build, modify the script according to  
+# http://www.mosek.com/products/4_0/tools/doc/html/tools/node20.html,
+# section 18.13.
+if BUILD_MOSEK:
+    mosek = Extension('mosek', 
+        include_dirs = [ MOSEK_INC_DIR ],
+        library_dirs = [ MOSEK_LIB_DIR ],
+        libraries = ['mosek', 'pthread', 'c', 'dl', 'm'],
+        sources = ['C/mosek.c'] )
+    extmods += [mosek];
+
+if BUILD_DSDP:
+    dsdp = Extension('dsdp', libraries = ['dsdp', 'blas', 'lapack'],
+        include_dirs = [ DSDP_INC_DIR ],
+        library_dirs = [ DSDP_LIB_DIR, ATLAS_LIB_DIR ],
+        sources = ['C/dsdp.c'] )
+    extmods += [dsdp];
+
+
+# required modules
+
+# Modify this for compilation on Windows.
+# Set to True if your BLAS/LAPACK do not use trailing underscores 
+# (eg, on Windows).
+BLAS_NOUNDERSCORES = False
+if BLAS_NOUNDERSCORES:
+    MACROS = [('BLAS_NO_UNDERSCORE','')]
+else:    
+    MACROS = []
+
+base = Extension('base', libraries = ['m','lapack','blas','g2c'],
+    library_dirs = [ ATLAS_LIB_DIR ],
+    define_macros = MACROS,
+    sources = ['C/base.c','C/dense.c','C/sparse.c']) 
+
+random = Extension('random',
+    sources = ['C/random.c', 'C/rngs/rngs.c', 'C/rngs/rvgs.c'])
+
+blas = Extension('blas', libraries = ['blas','g2c'],
+    library_dirs = [ ATLAS_LIB_DIR ],
+    define_macros = MACROS,
+    sources = ['C/blas.c'] )
+
+lapack = Extension('lapack', libraries = ['lapack','blas','g2c'],
+    library_dirs = [ ATLAS_LIB_DIR ],
+    define_macros = MACROS,
+    sources = ['C/lapack.c'] )
+
+umfpack = Extension('umfpack', 
+    include_dirs = [ 'C/SuiteSparse/UMFPACK/Include',
+        'C/SuiteSparse/AMD/Include', 'C/SuiteSparse/AMD/Source', 
+        'C/SuiteSparse/UFconfig' ],
+    library_dirs = [ ATLAS_LIB_DIR ],
+    define_macros = MACROS,
+    libraries = [ 'blas', 'lapack', 'g2c'],
+    sources = [ 'C/umfpack.c',
+        'C/SuiteSparse/UMFPACK/Source/umfpack_global.c',
+        'C/SuiteSparse/UMFPACK/Source/umfpack_tictoc.c' ] +
+        ['C/SuiteSparse_cvxopt_extra/umfpack/' + s for s in
+            listdir('C/SuiteSparse_cvxopt_extra/umfpack')])
+
+
+# Build for int or long? 
+import sys
+if sys.maxint > 2**31: MACROS += [('DLONG','')]
+
+cholmod = Extension('cholmod',
+    library_dirs = [ ATLAS_LIB_DIR ],
+    libraries = ['lapack', 'blas', 'g2c'],
+    include_dirs = [ 'C/SuiteSparse/CHOLMOD/Include', 
+        'C/SuiteSparse/COLAMD', 'C/SuiteSparse/AMD/Include', 
+        'C/SuiteSparse/UFconfig' ],
+    define_macros = MACROS + [('NPARTITION', '1')],
+    sources = [ 'C/cholmod.c' ] +
+        ['C/SuiteSparse/AMD/Source/' + s for s in ['amd_global.c',
+            'amd_postorder.c', 'amd_post_tree.c', 'amd_2.c']] +
+        ['C/SuiteSparse/COLAMD/' + s for s in ['colamd.c',
+            'colamd_global.c']] +
+        ['C/SuiteSparse/CHOLMOD/Core/' + s for s in
+            listdir('C/SuiteSparse/CHOLMOD/Core') if s[-2:] == '.c' and
+            s[0] == 'c'] +
+        ['C/SuiteSparse/CHOLMOD/Cholesky/' + s for s in
+            listdir('C/SuiteSparse/CHOLMOD/Cholesky') if s[-2:] == '.c'
+            and s[0] == 'c'] +
+        ['C/SuiteSparse/CHOLMOD/Check/cholmod_check.c'] +
+        ['C/SuiteSparse/CHOLMOD/Supernodal/' + s for s in
+            listdir('C/SuiteSparse/CHOLMOD/Supernodal') if 
+            s[-2:] == '.c' and s[0] == 'c'] )
+
+amd = Extension('amd', 
+    include_dirs = [ 'C/SuiteSparse/AMD/Include', 
+        'C/SuiteSparse/UFconfig' ],
+    define_macros = MACROS,
+    sources = [ 'C/amd.c' ] + [ 'C/SuiteSparse/AMD/Source/' + s for s in
+        listdir('C/SuiteSparse/AMD/Source') if s[-2:] == '.c' ])
+
+extmods += [base, blas, lapack, random, umfpack, cholmod, amd] 
+
+setup (name = 'cvxopt', 
+    description = 'Convex optimization package',
+    version = '0.8.2', 
+    ext_package = "cvxopt",
+    ext_modules = extmods,
+    package_dir = {"cvxopt": "python"},
+    packages = ["cvxopt"])

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/cvxopt.git



More information about the debian-science-commits mailing list